技术分类
场景——分布式下session存储问题:
解决
存在客户端cookie——不安全,网络负担效率低
session——session数据冗余,节点越多浪费越大
存在文件服务器或者数据库里——大量IO效率问题
nosql 数据库 解决session问题——完全在内存中,速度快,数据结构简单
Redis的特点
数据都在内存中,支持持久化,主要用作备份恢复
与memcahed一样,区别的是Redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件
除了支持简单的key-value模式,还支持多种数据结构的存储,比如list,set,hash,zset等
这些数据类型都支持push/pop,add/remove及取交集和差集及更丰富的操作
在此之上,Redis支持各种不同方式的排序
一般是作为缓存数据库辅助持久化的数据库
MongoDB
可以根据数据的特点替代RDBMS,成为独立的数据库。或者配合RDBMS,存储特定的数据
wget http:``//download.redis.io/releases/redis-6.2.1.tar.gz
tar -zxvf redis-6.2.1.tar.gz
make
make install
前台启动(不推荐) redis-server
后台启动(推荐)
redis.conf 复制一份
redis.conf 设置daemonize no改为yes /daemon 搜索
启动 redis-server /etc/redis.conf
redis-cli 操作入口
redis-cli 输入shutdown 关闭
多路复用是指使用一个线程来检查多个文件描述符(Socket)的就绪状态,比如调用 select 和 poll 函数,传入多个文件描述符,如果有一个文件描述符就绪,则返回,否则阻塞直到超时。得到就绪状态后进行真正的操作可以在同一个线程里执行,也可以启动线程执行(比如使用线程池)。
黄牛如果买到票会通知人拿票,人没拿到票就接着干自己的活
key * 查看当前库所有key (匹配: keys*1)
exists key判断某个key是否存在
type key 查看你的key是什么类型
del key 删除指定的key数据
unlink key 根据value选择非阻塞删除
仅将keys从keyspace元数据中删除,真正的删除会在后续异步操作
expire key 10 10秒钟 :为给定的key设置过期时间
ttl key查看还有多少秒过期,-1表示永不过期,-2表示已过期
select 切换库
dbsize 查看当前数据库的key的数量
flushdb 清空当前库
flushdb 通杀全部数据库
将key中储存的数字值增1 减1
只能对数字值操作,如果为空,新增值为1/-1
原子性——不会被线程调度打断的操作(因为redis单线程)
String 的数据结构为简单动态字符串 (Simple Dynamic String, 缩写 SDS),是可以修改的字符串,内部结构实现上类似于 Java 的 ArrayList,采用预分配冗余空间的方式来减少内存的频繁分配.
如图中所示,内部为当前字符串实际分配的空间 capacity 一般要高于实际字符串长度 len。当字符串长度小于 1M 时,扩容都是加倍现有的空间,如果超过 1M,扩容时一次只会多扩 1M 的空间。需要注意的是字符串最大长度为 512M。
单键多值 一个key 多个value
Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
它的底层实际是个双向链表,对两端的操作性能很高,通过索引下标的操作中间的节点性能会较差。
List 的数据结构为快速链表 quickList。
首先在列表元素较少的情况下会使用一块连续的内存存储,这个结构是 ziplist,也即是压缩列表。它将所有的元素紧挨着一起存储,分配的是一块连续的内存。
当数据量比较多的时候才会改成 quicklist。因为普通的链表需要的附加指针空间太大,会比较浪费空间。比如这个列表里存的只是 int 类型的数据,结构上还需要两个额外的指针 prev 和 next。
Redis 将链表和 ziplist 结合起来组成了 quicklist。也就是将多个 ziplist 使用双向指针串起来使用。这样既满足了快速的插入删除性能,又不会出现太大的空间冗余。
Redis hash 是一个键值对集合。
Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。
类似 Java 里面的 Map
用户 ID 为查找的 key,存储的 value 用户对象包含姓名,年龄,生日等信息,如果用普通的 key/value 结构来存储,主要有以下 2 种存储方式:
方法一:每次修改用户的某个属性需要,先反序列化改好后再序列化回去。开销较大。
方法二:用户 ID 数据冗余。
通过 key (用户 ID) + field (属性标签) 就可以操作对应属性数据了,既不需要重复存储数据,也不会带来序列化和并发修改控制的问题。
Hash 类型对应的数据结构是两种:ziplist(压缩列表),hashtable(哈希表)。当 field-value 长度较短且个数较少时,使用 ziplist,否则使用 hashtable。
SortedSet (zset) 是 Redis 提供的一个非常特别的数据结构,一方面它等价于 Java 的数据结构 Map
zset 底层使用了两个数据结构:
数组不便元素的插入、删除;平衡树或红黑树虽然效率高但结构复杂;链表查询需要遍历所有效率低。Redis 采用的是跳跃表,跳跃表效率堪比红黑树,实现远比红黑树简单
跳跃表
从第 2 层开始,1 节点比 51 节点小,向后比较;
21 节点比 51 节点小,继续向后比较,后面就是 NULL 了,所以从 21 节点向下到第 1 层;、
在第 1 层,41 节点比 51 节点小,继续向后,61 节点比 51 节点大,所以从 41 向下;
在第 0 层,51 节点为要查找的节点,节点被找到,共查找 4 次。
从此可以看出跳跃表比有序链表效率要高。
Redis 提供了 Bitmaps 这个 “数据类型” 可以实现对位的操作:
bitcount 统计1的数量
bitop and or xor 并集 或集 异或集 (bitop and unique:user : and : 20201104_03)
假设网站有 1 亿用户, 每天独立访问的用户有 5 千万, 如果每天用集合类型和 Bitmaps 分别存储活跃用户可以得到表:
set 和 Bitmaps 存储一天活跃用户对比 | |||
---|---|---|---|
数据类型 | 每个用户 id 占用空间 | 需要存储的用户量 | 全部内存量 |
集合 | 64 位 | 50000000 | 64 位 * 50000000 = 400MB |
Bitmaps | 1 位 | 100000000 | 1 位 * 100000000 = 12.5MB |
很明显, 这种情况下使用 Bitmaps 能节省很多的内存空间, 尤其是随着时间推移节省的内存还是非常可观的。
set 和 Bitmaps 存储独立用户空间对比 | |||
---|---|---|---|
数据类型 | 一天 | 一个月 | 一年 |
集合 | 400MB | 12GB | 144GB |
Bitmaps | 12.5MB | 375MB | 4.5GB |
但 Bitmaps 并不是万金油, 假如该网站每天的独立访问用户很少, 例如只有 10 万(大量的僵尸用户) , 那么两者的对比如下表所示, 很显然, 这时候使用 Bitmaps 就不太合适了, 因为基本上大部分位都是 0。
set 和 Bitmaps 存储一天活跃用户对比(用户比较少) | |||
---|---|---|---|
数据类型 | 每个 userid 占用空间 | 需要存储的用户量 | 全部内存量 |
集合 | 64 位 | 100000 | 64 位 * 100000 = 800KB |
Bitmaps | 1 位 | 100000000 | 1 位 * 100000000 = 12.5MB |
在工作当中,我们经常会遇到与统计相关的功能需求,比如统计网站 PV(PageView 页面访问量),可以使用 Redis 的 incr、incrby 轻松实现。
但像 UV(UniqueVisitor 独立访客)、独立 IP 数、搜索记录数等需要去重和计数的问题如何解决?这种求集合中不重复元素个数的问题称为基数问题。
解决基数问题有很多种方案:
数据存储在 MySQL 表中,使用 distinct count 计算不重复个数。
使用 Redis 提供的 hash、set、bitmaps 等数据结构来处理。
以上的方案结果精确,但随着数据不断增加,导致占用空间越来越大,对于非常大的数据集是不切实际的。能否能够降低一定的精度来平衡存储空间?Redis 推出了 HyperLogLog。
Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是:在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定的、并且是很小的。
在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。
但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。
pfadd
pfcount
pfmerge
Redis 3.2 中增加了对 GEO 类型的支持。GEO,Geographic,地理信息的缩写。该类型,就是元素的 2 维坐标,在地图上就是经纬度。redis 基于该类型,提供了经纬度设置,查询,范围查询,距离查询,经纬度 Hash 等常见操作。
geoadd 例子:geoadd china:city 121.47 31.23 shanghai
geopos
geodist
geodius
Redis支持byte 不支持bits 大小写不敏感
bind 127.0.0.1 只能本地连接 注解之后能远程访问
protected-mode no 保护模式 yes 能远程访问
backlog其实是一个连接队列,backlog队列总和=未完成三次队列+已经完成三次握手队列(高并发环境下你需要一个高backlog值来避免慢客户端连接问题)
timeout
tcp-keepalive 300
pidfile 存放pid文件的位置,每个实例会产生一个不同的pid文件
logfile “” 设置文件的输出路径
客户端可以订阅频道如下图:可以订阅1,2,3 三个频道
当给这个频道发布消息后,消息就会发送给订阅的客户端:(可以不止一个channel)
打开一个客户端订阅 channel1:
打开另一个客户端,给 channel1 发布消息 hello:‘
打开第一个客户端可以看到发送的消息:
注:发布的消息没有持久化,如果在订阅的客户端收不到hello,只能收到订阅后发布的消息
Redis 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。
Redis 事务的主要作用就是串联多个命令防止别的命令插队。
Redis 事务中有 Multi、Exec 和 discard 三个指令,在 Redis 中,从输入 Multi 命令开始,输入的命令都会依次进入命令队列中,但不会执行,
直到输入 Exec 后,Redis 会将之前的命令队列中的命令依次执行。
而组队的过程中可以通过 discard 来放弃组队。
案例:成功
失败
想想一个场景:有很多人有你的账户,同时去参加双十一抢购
一个请求想给金额减 8000;
一个请求想给金额减 5000;
一个请求想给金额减 1000。
最终我们可以发现,总共金额是 10000,如果请求全部执行,那最后的金额变为 - 4000,很明显不合理。
悲观锁
悲观锁 (Pessimistic Lock),顾名思义,就是很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会 block 直到它拿到锁。传统的关系型数据库里边就用到了很多这种锁机制,比如行锁,表锁等,读锁,写锁等,都是在做操作之前先上锁。
乐观锁 (Optimistic Lock),顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号等机制。乐观锁适用于多读的应用类型,这样可以提高吞吐量。Redis 就是利用这种 check-and-set 机制实现事务的
在执行 multi 之前,先执行 watch key1 [key2],可以监视一个 (或多个) key ,如果在事务执行之前这个 (或这些) key 被其他命令所改动,那么事务将被打断。
unwatch
取消 WATCH 命令对所有 key 的监视。如果在执行 WATCH 命令之后,EXEC 命令或 DISCARD 命令先被执行了的话,那么就不需要再执行 UNWATCH 了。
public class SecKill_redis {
public static void main(String[] args) {
Jedis jedis =new Jedis("192.168.44.168",6379);
System.out.println(jedis.ping());
jedis.close();
}
//秒杀过程
public static boolean doSecKill(String uid,String prodid) throws IOException {
//1 uid和prodid非空判断
if(uid == null || prodid == null) {
return false;
}
//2 连接redis
//Jedis jedis = new Jedis("192.168.44.168",6379);
//通过连接池得到jedis对象
JedisPool jedisPoolInstance = JedisPoolUtil.getJedisPoolInstance();
Jedis jedis = jedisPoolInstance.getResource();
//3 拼接key
// 3.1 库存key
String kcKey = "sk:"+prodid+":qt";
// 3.2 秒杀成功用户key
String userKey = "sk:"+prodid+":user";
//监视库存
jedis.watch(kcKey);
//4 获取库存,如果库存null,秒杀还没有开始
String kc = jedis.get(kcKey);
if(kc == null) {
System.out.println("秒杀还没有开始,请等待");
jedis.close();
return false;
}
// 5 判断用户是否重复秒杀操作
if(jedis.sismember(userKey, uid)) {
System.out.println("已经秒杀成功了,不能重复秒杀");
jedis.close();
return false;
}
//6 判断如果商品数量,库存数量小于1,秒杀结束
if(Integer.parseInt(kc)<=0) {
System.out.println("秒杀已经结束了");
jedis.close();
return false;
}
//7 秒杀过程
//使用事务
Transaction multi = jedis.multi();
//组队操作
multi.decr(kcKey);
multi.sadd(userKey,uid);
//执行
List<Object> results = multi.exec();
if(results == null || results.size()==0) {
System.out.println("秒杀失败了....");
jedis.close();
return false;
}
//7.1 库存-1
//jedis.decr(kcKey);
//7.2 把秒杀成功用户添加清单里面
//jedis.sadd(userKey,uid);
System.out.println("秒杀成功了..");
jedis.close();
return true;
}
}
秒杀过程
连接redis——通过连接池得到jedis对象
拼接key
3.1 库存key
3.2 秒杀成功用户key
监视库存
判断用户是否重复秒杀操作 清单用set 不可重复
判断如果商品数量,库存数量小于1,秒杀结束
秒杀过程 使用事务
8.1 库存-1
8.2 把秒杀成功用户添加清单里面
下载 并发测试工具类 yum install httpd-tools
通过 ab 测试
im postfile 模拟表单提交参数, 以 & 符号结尾,存放当前目录。
内容:prodid=0101&
执行:ab -n 2000 -c 200 -k -p ~/postfile -T application/x-www-form-urlencoded
访问:http://192.168.2.115:8081/Seckill/doseckill
连接池解决
乐观锁造成的库存遗留问题 解决:lua脚本
LUA 脚本在 Redis 中的优势
jedis.scriptLoad;
jedis.evalsha;
在指定的时间间隔内将内存中的数据集快照写入磁盘, 也就是行话讲的 Snapshot 快照,它恢复时是将快照文件直接读到内存里。
Redis 会单独创建(fork)一个子进程来进行持久化,首先会将数据写入到一个临时文件中,待持久化过程都结束了,再用这个临时文件替换上次持久化好的文件。整个过程中,主进程是不进行任何 IO 操作的,这就确保了极高的性能。如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那 RDB 方式要比 AOF 方式更加的高效。
在 redis.conf 中配置文件名称,默认为 dump.rdb。
rdb 文件的保存路径,也可以修改。默认为 Redis 启动时命令行所在的目录下 “dir ./”
配置文件中默认的快照配置

save :save 时只管保存,其它不管,全部阻塞。手动保存,不建议。
bgsave:Redis 会在后台异步进行快照操作, 快照同时还可以响应客户端请求。
可以通过 lastsave 命令获取最后一次成功执行快照的时间。
flushall 命令
执行 flushall 命令,也会产生 dump.rdb 文件,但里面是空的,无意义。
如何停止
动态停止 RDB:redis-cli config set save “”#save 后给空值,表示禁用保存策略。
以日志的形式来记录每个写操作(增量保存),将 Redis 执行过的所有写指令记录下来 (读操作不记录), 只许追加文件但不可以改写文件,redis 启动之初会读取该文件重新构建数据,换言之,redis 重启的话就根据日志文件的内容将写指令从前到后执行一次以完成数据的恢复工作。
可以在 redis.conf 中配置文件名称默认为 appendonly.aof 文件中开启,AOF 文件的保存路径,同 RDB 的路径一致。
AOF 和 RDB 同时开启,系统默认取 AOF 的数据(数据不会存在丢失)。
AOF 的备份机制和性能虽然和 RDB 不同,但是备份和恢复的操作同 RDB 一样,都是拷贝备份文件,需要恢复时再拷贝到 Redis 工作目录下,启动系统即加载。
正常恢复
异常恢复
AOF 采用文件追加方式,文件会越来越大为避免出现此种情况,新增了重写机制,当 AOF 文件的大小超过所设定的阈值时,Redis 就会启动 AOF 文件的内容压缩,只保留可以恢复数据的最小指令集,可以使用命令 bgrewriteaof。
AOF 文件持续增长而过大时,会 fork 出一条新进程来将文件重写 (也是先写临时文件最后再 rename),redis4.0 版本后的重写,是指把 rdb 的快照,以二进制的形式附在新的 aof 头部,作为已有的历史数据,替换掉原来的流水账操作。
如果 no-appendfsync-on-rewrite=yes ,不写入 aof 文件只写入缓存,用户请求不会阻塞,但是在这段时间如果宕机会丢失这段时间的缓存数据。(降低数据安全性,提高性能)
如果 no-appendfsync-on-rewrite=no,还是会把数据往磁盘里刷,但是遇到重写操作,可能会发生阻塞。(数据安全,但是性能降低)
Redis 会记录上次重写时的 AOF 大小,默认配置是当 AOF 文件大小是上次 rewrite 后大小的一倍且文件大于 64M 时触发。
重写虽然可以节约大量磁盘空间,减少恢复时间。但是每次重写还是有一定的负担的,因此设定 Redis 要满足一定条件才会进行重写。
官方推荐两个都启用:
官网建议
性能建议:
主机数据更新后根据配置和策略, 自动同步到备机的 master/slaver 机制,Master 以写为主,Slave 以读为主,主从复制节点间数据是全量的。
作用:
读写分离,性能扩展
容灾快速恢复(一主多从)
不能有多个主服务器
假如有两个主服务器 set a1 v1 和 set a1 v11 没有办法决定复制哪一个
步骤
创建/myredis文件夹
复制redis.conf配置文件到文件夹中
配置一主两从
redis6379.conf
redis6380.conf
redis6381.conf
在三个配置文件写入内容
include/myredis/redis.conf
pidfile/var/run/redis_6379.pid
port 6379
dbfilename dump6379.rdb
从服务器挂掉了会怎么样?再重启就会变master
主服务器挂掉之后,重启之后还是主服务器
从服务器(主动)Slave 启动成功连接到 master 后会发送一个 sync 命令;
主服务器Master 接到命令启动后台的存盘进程,同时收集所有接收到的用于修改数据集命令,在后台进程执行完毕之后,master 将传送整个rdb数据文件到 slave,以完成一次完全同步。
全量复制:slave 服务器在接收到数据库文件数据后,将其存盘并加载到内存中。
增量复制:Master 继续将新的所有收集到的修改命令依次传给 slave,完成同步。(每次主服务器进行写操作之后,和从服务器进行数据同步)
但是只要是重新连接 master,一次完全同步(全量复制) 将被自动执行。
一个从服务器下面再挂一个从服务器
当一个 master 宕机后,后面的 slave 可以立刻升为 master,其后面的 slave 不用做任何修改。用 slaveof no one 指令将从机变为主机。
而哨兵模式是反客为主的自动版,能够后台监控主机是否故障,如果故障了根据投票数自动将从库转换为主库。
sentinel monitor mymaster 127.0.0.1 6379 1
其中mymaster 为监控对象起的服务器名称,1为至少有多少个哨兵同意迁移的数量
redis-sentinel sentinel.conf
(大概10秒左右可以看到哨兵窗口日志,切换了新的主机)
哪个从机会被选举为主机呢?根据优先级别:slave-priority
原主机重启后会变为从机
由于所有的写操作都是先在 Master 上操作,然后同步更新到 Slave 上,所以从 Master 同步到 Slave 机器有一定的延迟,当系统很繁忙的时候,延迟问题会更加严重,Slave 机器数量的增加也会使这个问题更加严重
优先级:在 redis.conf 中默认(replica) slave-priority 100,值越小优先级越高。
偏移量:指获得原主机数据最全的概率(从机和主机同步的数据量最高)。
runid:每个 redis 实例启动后都会随机生成一个 40 位的 runid
之前通过代理主机来解决,但是 redis3.0 中提供了解决方案。就是无中心化集群配置。(任何一台服务器都可以作为集群的入口)
Redis 集群(包括很多小集群)实现了对 Redis 的水平扩容,即启动 N 个 redis 节点,将整个数据库分布存储在这 N 个节点中,每个节点存储总数据的 1/N,即一个小集群存储 1/N 的数据,每个小集群里面维护好自己的 1/N 的数据。
Redis 集群通过分区(partition)来提供一定程度的可用性(availability): 即使集群中有一部分节点失效或者无法进行通讯, 集群也可以继续处理命令请求。
该模式的 redis 集群特点是:分治、分片。
问题
普通方式登录:可能直接进入读主机,存储数据时,会出现 MOVED 重定向操作,所以,应该以集群方式登录。
集群登录:redis-cli -c -p 6379 采用集群策略连接,设置数据会自动切换到相应的写主机.
一个 Redis 集群包含 16384 个插槽(hash slot),数据库中的每个键都属于这 16384 个插槽的其中一个。集群使用公式 CRC16 (key) % 16384 来计算键 key 属于哪个槽, 其中 CRC16 (key) 语句用于计算键 key 的 CRC16 校验和 。
集群中的每个节点负责处理一部分插槽。 举个例子, 如果一个集群可以有主节点, 其中:
在 redis-cli 每次录入、查询键值,redis 都会计算出该 key 应该送往的插槽,如果不是该客户端对应服务器的插槽,redis 会报错,并告知应前往的 redis 实例地址和端口。
redis-cli 客户端提供了 –c 参数实现自动重定向。如 redis-cli -c –p 6379 登入后,再录入、查询键值对可以自动重定向。不在一个 slot 下的键值,是不能使用 mget,mset 等多键操作
如果所有某一段插槽的主从节点都宕掉,redis 服务是否还能继续?
问题描述
key 对应的数据在数据源并不存在,每次针对此 key 的请求从缓存获取不到,请求都会压到数据源(数据库),从而可能压垮数据源。比如
用一个不存在的用户 id 获取用户信息,不论缓存还是数据库都没有,若黑客利用此漏洞进行攻击可能压垮数据库。
缓存穿透发生的条件:
其实 redis 在这个过程中一直平稳运行,崩溃的是我们的数据库(如 MySQL)。
缓存穿透发生的原因:黑客或者其他非正常用户频繁进行很多非正常的 url 访问,使得 redis 查询不到数据库
解决方案:
key 对应的数据存在,但在 redis 中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端数据库加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端数据库压垮
缓存击穿的现象:
缓存击穿发生的原因:redis 某个 key 过期了,大量访问使用这个 key(热门 key)
解决方案
key 可能会在某些时间点被超高并发地访问,是一种非常 “热点” 的数据。
key 对应的数据存在,但在 redis 中过期,此时若有大量并发请求过来,这些请求发现缓存过期一般都会从后端数据库加载数据并回设到缓存,这个时候大并发的请求可能会瞬间把后端数据库压垮。
缓存雪崩与缓存击穿的区别在于这里针对很多 key 缓存,前者则是某一个 key 正常访问
解决方案
Redlock 是一种算法,Redlock 也就是 Redis Distributed Lock,可用实现多节点 redis 的分布式锁。RedLock 官方推荐,Redisson 完成了对 Redlock 算法封装。
此种方式具有以下特性:
解锁的时候,删除操作缺乏原子性
分布式锁可用,至少要确保锁的实现同时满足以下四个条件:
Redis ACL 是 Access Control List (访问控制列表)的缩写,该功能允许根据可以执行的命令和可以访问的键来限制某些连接
在Redis5版本之前,Redis安全规则只有密码控制还有通过rename来调整高危命令比如flushdb,KEY*,shutdown等。Redis 6则提供ACL的功能对用户进行更细粒度的权限控制
(1)接入权限:用户名和密码
(2)可以执行的命令
(3)可以操作的KEY
acl list
acl cat
IO 多线程其实指客户端交互部分的网络 IO 交互处理模块 多线程,而非执行命令多线程。Redis6 执行命令依然是单线程
Redis 6 加入多线程,但跟 Memcached 这种从 IO 处理到数据访问多线程的实现模式有些差异。Redis 的多线程部分只是用来处理网络数据的读写和协议解析,执行命令仍然是单线程。之所以这么设计是不想因为多线程而变得复杂,需要去控制 key、lua、事务,LPUSH/LPOP 等等的并发问题。整体的设计大体如下
另外,多线程 IO 默认也是不开启的,需要再配置文件中配置:
之前老版Redis 想要搭建集群需要单独安装ruby环境,Redis 5将redis-trib.rb的功能集成到redis-cli。另外官方redis-benchmark工具开始支持cluster模式了,通过多线程方式对多个分片进行压测
【尚硅谷】Redis 6 入门到精通 超详细 教程_哔哩哔哩_bilibili
Redis | ZC 的学习录 (zhangc233.github.io)