1、主从复制
psync-> runid->runid是?则是全量->返回fullresync和runid和复制进度->bgsave命令准备RDB文件->之后的命令写入replication_buffer->发送RDB->发送replication_buffer的信息
repl_backlog_buffer环型缓冲区,主节点只有一个
psync-> runid->runid在repl_backlog_buffer中则是增量同步->定位repl_backlog_buffer中offset位置->将信息转到replication_buffer
replication_buffer每个从节点对应一个
2、redis集群
Gossip协议进行节点之间的状态交换
哈希槽2^14=16384个,因为算法是CRC16计算得出16bit的结果,然后跟2^14取余
MOVED错误(返回目标节点的信息,IP+端口)
3、redis线程
核心读写是单线程事件驱动模型,网络是I/O多路复用多线程(同步I/O),默认是禁用的
4、redis数据格式
String :最大512M
hash
list:支持两端推、弹出数据
set:使用hash表实现
Sorted set/Zset:每个元素都有个评分,用于排序,底层用跳表实现,支持快速的范围查询。
bitmap:位图
hyperloglog:估算集合的基数(cardinality),即集合中不重复元素的数量。误差在0.81%,用于UV(unique visitor)统计
stream:
5、hash数据的命令
hget/hset/hdel/hmget/hmset/hincrby(全部应该大写)
6、lua脚本
redis.call和redis.pcall
7、redis的pipeline,最多一次10K个命令
8、redis的大key问题,redis-cli --bigkeys
9、热点key:
解决热点key:拆分key,读写分离主从复制增加从节点,多级缓存,限流熔断
查看热点key:业务经验、集群监控:QPS倾斜、hotkey监控(实时性不好)、monitor命令(性能损坏特别大)、客户端收集、代理层收集
10、redis持久化:
RDB(redis database):快照,压缩的二进制文件,数据恢复不全。
redis.conf文件可以配置在x秒内至少有y个key发生变化会触发命令进行持久话操作
save命令:在主线程生成RDB文件,主线程无法执行其他命令
bgsave命令:子进程执行RDB生成命令,不会阻塞主线程,但不是完全非阻塞测,默认使用bgsave
AOF(Append Only file):体积大,重写会消耗更多资源。
混合持久化:aof-use-rdb-preamble配置开启混合持久化。先生成RDB快照,然后将新的操作追加到AOF文件中。
AOF写回策略:always(每次写操作后立即fsync,不能保证数据不丢失,因为是先执行后写入aof),everysec(每秒调用一次,默认使用这种策略),no(操作系统决定何时写入)
AOF重写机制:合理的压缩写命令,可以手动触发BGREWRITEAOF,使用auto-aof-rewrite-min-size和auto-aof-rewrite-percentage自动触发操作
redis-check-aof工具修复AOF损坏的文件,这个工具会截断文件中不完整的命令,使其恢复到一致状态。
写时复制:当主进程fork出一个子进程后,是让主进程和子进程共享相同的内存页面,他们映射同一个物理内存地址。当主进程收到写命令需要修改数据时,主进程会将对应数据所在的页复制一份,对复制的副本进行修改。
11、redis哨兵机制:高可用解决方案,完成主从切换
12、redis的主从模式的脑裂
13、redisson看门狗机制:客户端加锁后不设置过期时间,而是启动一个定时任务来检测锁,每10s一次,每次续期30s。配置参数为lockwatchdogtimeout
14、redis内存碎片化:默认使用jemalloc内存分配器,需要8K,分配器给12K。使用INFO memory命令查看内存碎片。MEMORY PURGE命令手动清理碎片,但会阻塞主线程。配置activefrag选项,redis可以在运行时尝试整理内存碎片,合并小的内存。
15、在redis6中使用listpack替换ziplist,因为ziplist在节点中存放了上一个元素的长度,如果长度超过长度记录的上限,那么可能会引起连锁更新,非常影响性能
16、redis的watch命令:乐观锁机制,但是并不是真正的锁
17、redis从节点复制缓冲区:client-output-buffer-limit配置间接控制缓冲区大小
18、redis的quicklist:每个quicklist节点都是一个ziplist,相当与限定了ziplist的阈值,当超过ziplist,就用多个ziplist。ziplist+quicklist用于实现redis的链表功能
19、redis中list命令:lpush插入队头、rpush、lpop、rpop、lrange获取范围内元素、lindex通过索引获取元素、llen列表长度、lset设置制定索引的值、lrem移除列表中参与匹配的元素、ltrim裁剪list使其只包含指定范围内的元素
ltrim mylist 1 2:保留索引1到2的元素,其他的删除
lrem mylist 1 a:异常第一个a元素
lrange mylist 0 -1:返回mylist中所有元素
20、redis列表存储结构:当列表元素较多时使用linked list,便于从两端快速添加和删除,如果列表元素较少或总大小较小时,可以使用Ziplist
21、redis中的原生批处理命令:MSET/MGET。他们是原子性的,并且执行速度比pipeline更快(有优化),但是只能用于批量的写入和读取键值对,灵活性上pipeline更好。但pipeline会占用大量内存,某些redis命令不支持pipeline。
MSET key1 value1 key2 value2 key3 value3
MGET key1 key2 key3
22、redis限制字符串最大只能是512M
23、jedis、lettuce、redisson
24、GEO地理信息:geolocation。底层采用sorted set,每一个地理位置被编码为一个Geohash值,并使用Geohash的排序特性来存储在Redis的Sorted Set中,分数则是通过Geohash生成的。Geohash是一种空间编码方法,将二维地理坐标编码成一个字符串,这样在对地理坐标排序时,可以通过Geohash生成的值实现近似的范围查找
添加地理坐标:GEOADD locations 13.26589 38.65985 "member"
计算地理位置距离:GEODIST locations "member" "member1" km
查找指定位置附近范围内的所有点(弃用):GEORADIUS locations 15 37 200 km
以某个已存在位置为中心,查找指定范围内的地点(弃用):GEORADIUSBYMEMBER locations "member" 100 km
按长方型或者圆形查找位置:GEOSEARCH用于替代GEORADIUS
将搜索结果存储到一个新的key中:GEOSEARCHSTORE
25、hyperloglog结构约12K,即使是统计百万用户,内存开销依然是恒定的12K
PFADD key element 添加一个或多个元素
PFCOUNT key 返回HyperLogLog结构中不重复元素的近似数量
PFMERGE destkey sourcekey 将多个HyperLogLog合并为一个
26、redis中的String类型底层主要基于SDS(Simple Dynamic String),并结合int/embstr/raw等不同的编码方式进行优化存储。如果一个字符串可以被解析为整数且数值比较小就会实用int编码,当字符串长度小于等于44字节,就会实用embstr编码,将字符串元数据和字符数据放在连续的内存块中redisObject和sds一起放。当超过44字节,redis会实用raw编码,这种编码方式将结构体和实际字符串数据分开存储,redisObject和sds分开放。
为什么不用C里面的字符串?:获取长度复杂、结尾用\0表示,字符串操作函数不高效、不安全,可能缓冲区溢出
27、缓存击穿、缓存穿透、缓存雪崩
28、Red Lock:红锁,用于解决在分布式环境中使用Redis实现分布式锁时的安全性问题,比如主节点宕机,主从切换,从节点没有同步到锁信息。使用Red Lock需要至少5个主库实例,集群部署(不是主从或者哨兵),客户端对这5个实例依次申请锁,过半则红锁申请成功,反之失败。红锁并非无懈可击,很多情况会导致失效。
29、redis常用命令合集:
字符串:
# 设置键值
SET key value
SET name "张三"
SET age 25# 获取值
GET key
GET name# 设置过期时间
SETEX key seconds value
SETEX session:123 3600 "user_data"# 批量设置
MSET key1 value1 key2 value2
MSET name "李四" age 30 city "北京"# 批量获取
MGET key1 key2
MGET name age city# 递增
INCR key
INCR counter# 递减
DECR key
DECR counter# 增加指定数值
INCRBY key increment
INCRBY score 10# 追加字符串
APPEND key value
APPEND message " 追加内容"#获取分布式锁
SET key value EX seconds NX
哈希操作:
# 设置哈希字段
HSET key field value
HSET user:1 name "王五"
HSET user:1 age 28# 获取哈希字段
HGET key field
HGET user:1 name# 获取所有字段
HGETALL key
HGETALL user:1# 批量设置哈希字段
HMSET key field1 value1 field2 value2
HMSET user:2 name "赵六" age 32 email "zhao@example.com"# 批量获取哈希字段
HMGET key field1 field2
HMGET user:2 name age# 删除哈希字段
HDEL key field1 field2
HDEL user:1 age# 检查字段是否存在
HEXISTS key field
HEXISTS user:1 name# 获取所有字段名
HKEYS key
HKEYS user:1# 获取所有字段值
HVALS key
HVALS user:1
列表操作:
# 从左侧推入
LPUSH key value1 value2
LPUSH queue "任务1" "任务2"# 从右侧推入
RPUSH key value1 value2
RPUSH queue "任务3" "任务4"# 从左侧弹出
LPOP key
LPOP queue# 从右侧弹出
RPOP key
RPOP queue# 获取列表长度
LLEN key
LLEN queue# 获取列表元素
LRANGE key start stop
LRANGE queue 0 -1
LRANGE queue 0 2# 根据索引获取元素
LINDEX key index
LINDEX queue 0# 插入元素
LINSERT key BEFORE|AFTER pivot value
LINSERT queue BEFORE "任务2" "新任务"# 删除元素
LREM key count value
LREM queue 1 "任务1"
集合操作
# 添加成员
SADD key member1 member2
SADD tags "redis" "database" "cache"# 获取所有成员
SMEMBERS key
SMEMBERS tags# 检查成员是否存在
SISMEMBER key member
SISMEMBER tags "redis"# 获取集合大小
SCARD key
SCARD tags# 删除成员
SREM key member1 member2
SREM tags "cache"# 随机获取成员
SRANDMEMBER key count
SRANDMEMBER tags 2# 集合运算
SUNION key1 key2
SINTER key1 key2
SDIFF key1 key2
SUNION tags1 tags2
有序集合操作:
# 添加成员
ZADD key score member
ZADD leaderboard 100 "玩家1"
ZADD leaderboard 200 "玩家2"# 获取成员分数
ZSCORE key member
ZSCORE leaderboard "玩家1"# 获取排名
ZRANK key member
ZRANK leaderboard "玩家1"# 获取范围
ZRANGE key start stop
ZRANGE leaderboard 0 -1
ZRANGE leaderboard 0 9# 按分数范围获取
ZRANGEBYSCORE key min max
ZRANGEBYSCORE leaderboard 100 200# 获取集合大小
ZCARD key
ZCARD leaderboard# 删除成员
ZREM key member
ZREM leaderboard "玩家1"# 增加分数
ZINCRBY key increment member
ZINCRBY leaderboard 50 "玩家1"
键操作:
# 检查键是否存在
EXISTS key
EXISTS user:1# 删除键
DEL key1 key2
DEL user:1 user:2# 设置过期时间
EXPIRE key seconds
EXPIRE session:123 3600# 查看剩余过期时间
TTL key
TTL session:123# 获取所有键
KEYS pattern
KEYS user:*
KEYS *# 重命名键
RENAME oldkey newkey
RENAME user:1 user:1001# 获取键类型
TYPE key
TYPE user:1
发布订阅:
# 发布消息
PUBLISH channel message
PUBLISH news "重要新闻"# 订阅频道
SUBSCRIBE channel1 channel2
SUBSCRIBE news sports# 取消订阅
UNSUBSCRIBE channel
UNSUBSCRIBE news# 模式订阅
PSUBSCRIBE pattern
PSUBSCRIBE news:*
事务操作:
# 开始事务
MULTI# 执行命令
SET key1 value1
SET key2 value2
INCR counter# 执行事务
EXEC# 取消事务
DISCARD# 监视键
WATCH key1 key2
MULTI
SET key1 newvalue
EXEC
持久化操作:
# 保存数据到磁盘
SAVE# 异步保存数据到磁盘
BGSAVE# 获取最后保存时间
LASTSAVE# 获取Redis信息
INFO# 获取配置信息
CONFIG GET parameter
CONFIG GET maxmemory