共计 9195 个字符,预计需要花费 23 分钟才能阅读完成。
redis
redis 是单线程的,然而个别的作为缓存应用的话,redis 足够了,因为它的读写速度太快了。
官网的一个简略测试:
测试实现了 50 个并发执行 100000 个申请。
设置和获取的值是一个 256 字节字符串。
后果: 读的速度是 110000 次 /s, 写的速度是 81000 次 /s
但对于访问量特地大的服务来说,还是稍有有余。那么,如何晋升 redis 的性能呢?搭建集群。
redis 次要提供三种集群策略:
- 主从复制
- 集群
- 哨兵
一、主从复制
在主从复制中,数据库分为俩类,主数据库 (master) 和从数据库(slave)。
1.1 主从复制有如下特点:
- 主数据库能够进行读写操作,当读写操作导致数据变动时会主动将数据同步给从数据库
- 从数据库个别都是只读的,并且接管主数据库同步过去的数据
- 一个 master 能够领有多个 slave,然而一个 slave 只能对应一个 master
1.2 工作机制
- slave 从节点服务启动并连贯到 Master 之后,它将被动发送一个 SYNC 命令。Master 服务主节点收到同步命令后将启动后盾存盘过程,同时收集所有接管到的用于批改数据集的命令,在后盾过程执行结束后,Master 将传送整个数据库文件到 Slave,以实现一次齐全同步。而 Slave 从节点服务在接管到数据库文件数据之后将其存盘并加载到内存中。尔后,Master 主节点持续将所有曾经收集到的批改命令,和新的批改命令顺次传送给 Slaves,Slave 将在本次执行这些数据批改命令,从而达到最终的数据同步。
- 复制初始化后,master 每次接管到的写命令都会同步发送给 slave,保障主从数据一致性。
- 如果 Master 和 Slave 之间的链接呈现断连景象,Slave 能够主动重连 Master,然而在连贯胜利之后,一次齐全同步将被主动执行。
1.3 主从配置
redis 默认是主数据,所以 master 无需配置,咱们只须要批改 slave 的配置即可。
设置须要连贯的 master 的 ip 端口:
slaveof 192.168.0.107 6379
如果 master 设置了明码。须要配置:
masterauth master-password
连贯胜利进入命令行后,能够通过以下命令行查看连贯该数据库的其余库信息:
info replication
1.3 长处
- 同一个 Master 能够同步多个 Slaves。
- Slave 同样能够承受其它 Slaves 的连贯和同步申请,这样能够无效的分载 Master 的同步压力。因而咱们能够将 Redis 的 Replication 架构视为图构造。
- Master Server 是以非阻塞的形式为 Slaves 提供服务。所以在 Master-Slave 同步期间,客户端依然能够提交查问或批改申请。
- Slave Server 同样是以非阻塞的形式实现数据同步。在同步期间,如果有客户端提交查问申请,Redis 则返回同步之前的数据
- 为了分载 Master 的读操作压力,Slave 服务器能够为客户端提供只读操作的服务,写服务依然必须由 Master 来实现。即便如此,零碎的伸缩性还是失去了很大的进步。
- Master 能够将数据保留操作交给 Slaves 实现,从而防止了在 Master 中要有独立的过程来实现此操作。
- 反对主从复制,主机会主动将数据同步到从机,能够进行读写拆散。
1.4 毛病
- Redis 不具备主动容错和复原性能,主机从机的宕机都会导致前端局部读写申请失败,须要期待机器重启或者手动切换前端的 IP 能力复原。
- 主机宕机,宕机前有局部数据未能及时同步到从机,切换 IP 后还会引入数据不统一的问题,升高了零碎的可用性。
- Redis 的主从复制采纳全量复制,复制过程中主机会 fork 出一个子过程对内存做一份快照,并将子过程的内存快照保留为文件发送给从机,这一过程须要确保主机有足够多的空余内存。若快照文件较大,对集群的服务能力会产生较大的影响,而且复制过程是在从机新退出集群或者从机和主机网络断开重连时都会进行,也就是网络稳定都会造成主机和从机间的一次全量的数据复制,这对理论的零碎经营造成了不小的麻烦。
- Redis 较难反对在线扩容,在集群容量达到下限时在线扩容会变得很简单。为防止这一问题,运维人员在零碎上线时必须确保有足够的空间,这对资源造成了很大的节约。
- 其实 redis 的主从模式很简略,在理论的生产环境中是很少应用的,我也不倡议在理论的生产环境中应用主从模式来提供零碎的高可用性,之所以不倡议应用都是由它的毛病造成的,在数据量十分大的状况,或者对系统的高可用性要求很高的状况下,主从模式也是不稳固的。
二、哨兵
该模式是从 Redis 的 2.6 版本开始提供的,然而过后这个版本的模式是不稳固的,直到 Redis 的 2.8 版本当前,这个哨兵模式才稳定下来,无论是主从模式,还是哨兵模式,这两个模式都有一个问题,不能程度扩容,并且这两个模式的高可用个性都会受到 Master 主节点内存的限度。
2.1 哨兵的作用是监控 redis 零碎的运行状况,性能如下
- 监控主从数据库是否失常运行。
- master 呈现故障时,主动将它的其中一个 slave 转化为 master。
- master 和 slave 服务器切换后,master 的 redis.conf、slave 的 redis.conf 和 sentinel.conf 的配置文件的内容都会产生相应的扭转,即,saster 主服务器的 redis.conf 配置文件中会多一行 slaveof 的配置,sentinel.conf 的监控指标会随之调换。
- 当被监控的某个 Redis 节点呈现问题时, 哨兵(sentinel) 能够通过 API 向管理员或者其余应用程序发送告诉。
- 多哨兵配置的时候,哨兵之间也会主动监控。
- 多个哨兵能够监控同一个 redis。
2.2 哨兵工作机制
- 哨兵过程启动时会读取配置文件的内容,通过 sentinel monitor master-name ip port quorum 查找到 master 的 ip 端口。一个哨兵能够监控多个 master 数据库,只须要提供多个该配置项即可。
- 配置文件还定义了与监控相干的参数,比方 master 多长时间无响应即即断定位为下线。
- 哨兵启动后,会与要监控的 master 建设俩条连贯:
3.1 一条连贯用来订阅 master 的sentinel:hello 频道,并获取其余监控该 master 的哨兵节点信息
3.2 另一条连贯定期向 master 发送 INFO 等命令获取 master 自身的信息 - 与 master 建设连贯后,哨兵会执行三个操作,这三个操作的发送频率都能够在配置文件中配置:
4.1 定期向 master 和 slave 发送 INFO 命令
4.2 定期向 master 和 slave 的sentinel:hello 频道发送本人的信息
4.3 定期向 master、slave 和其余哨兵发送 PING 命令
这三个操作的意义十分重大,发送 INFO 命令能够获取以后数据库的相干信息从而实现新节点的主动发现。所以说哨兵只须要配置 master 数据库信息就能够主动发现其 slave 信息。获取到 slave 信息后,哨兵也会与 slave 建设俩条连贯执行监控。通过 INFO 命令,哨兵能够获取主从数据库的最新信息,并进行相应的操作,比方角色变更等。
- 接下来哨兵向主从数据库的sentinel:hello 频道发送信息,并与同样监控这些数据库的哨兵共享本人的信息,发送内容为哨兵的 ip 端口、运行 id、配置版本、master 名字、master 的 ip 端口还有 master 的配置版本。这些信息有以下用途:
5.1 其余哨兵能够通过该信息判断发送者是否是新发现的哨兵,如果是的话会创立一个到该哨兵的连贯用于发送 ping 命令。
5.2 其余哨兵通过该信息能够判断 master 的版本,如果该版本高于间接记录的版本,将会更新 - 当实现了主动发现 slave 和其余哨兵节点后,哨兵就能够通过定期发送 ping 命令定时监控这些数据库和节点有没有进行服务。发送频率能够配置,然而最长间隔时间为 1s,能够通过 sentinel down-after-milliseconds mymaster 600 设置。
- 如果被 ping 的数据库或者节点超时未回复,哨兵认为其主观下线。如果下线的是 master,哨兵会向其余哨兵点发送命令询问他们是否也认为该 master 主观下线。如果一个 master 主服务器被标记为主观下线(SDOWN),则正在监督这个 Master 主服务器的所有 Sentinel(哨兵)过程要以每秒一次的频率确认 Master 主服务器确实进入了主观下线状态。如果达到肯定数目(即配置文件中的 quorum)投票,哨兵会认为该 master 曾经主观下线(ODOWN),并选举领头的哨兵节点对主从零碎发动故障复原。
- 如上文所说,哨兵认为 master 主观下线后,故障复原的操作须要由选举的领头哨兵执行,选举采纳 Raft 算法:
8.1 发现 master 下线的哨兵节点(咱们称他为 A)向每个哨兵发送命令,要求对方选本人为领头哨兵
8.2 如果指标哨兵节点没有选过其他人,则会批准选举 A 为领头哨兵
8.3 如果有超过一半的哨兵批准选举 A 为领头,则 A 入选
8.4 如果有多个哨兵节点同时参选领头,此时有可能存在一轮投票无竞选者胜出,此时每个参选的节点期待一个随机工夫后再次发动参选申请,进行下一轮投票精选,直至选举出领头哨兵
8.5 选出领头哨兵后,领头者开始对进行故障复原,从呈现故障的 master 的从数据库 slave 中筛选一个来入选新的 master, 抉择规定如下:
8.5.1 所有在线的 slave 中抉择优先级最高的,优先级能够通过 slave-priority 配置
8.5.2 如果有多个最高优先级的 slave,则选取复制偏移量最大(即复制越残缺)的入选
8.5.3 如果以上条件都一样,选取 id 最小的 slave - 挑选出须要继任的 slaver 后,领头哨兵向该数据库发送命令使其升格为 master,而后再向其余 slave 发送命令承受新的 master,最初更新数据。将曾经进行的旧的 master 更新为新的 master 的从数据库,使其复原服务后以 slave 的身份持续运行。
2.3 哨兵配置
哨兵配置的配置文件为 sentinel.conf,设置主机名称,地址,端口,以及选举票数即复原时起码须要几个哨兵节点批准。只有配置须要监控的 master 就能够了,哨兵会监控连贯该 master 的 slave。
sentinel monitor mymaster 192.168.0.107 6379 1
启动哨兵节点:
redis-server sentinel.conf --sentinel &
呈现以下相似信息即启动哨兵胜利
3072:X 12 Apr 22:40:02.554 ### Sentinel runid is e510bd95d4deba3261de72272130322b2ba650e7
3072:X 12 Apr 22:40:02.554 ### +monitor master mymaster 192.168.0.107 6379 quorum 1
3072:X 12 Apr 22:40:03.516 * +slave slave 192.168.0.108:6379 192.168.0.108 6379 @ mymaster 192.168.0.107 6379
3072:X 12 Apr 22:40:03.516 * +slave slave 192.168.0.109:6379 192.168.0.109 6379 @ mymaster 192.168.0.107 6379
能够在任何一台服务器上查看指定哨兵节点信息:
bin/redis-cli -h 192.168.0.110 -p 26379 info Sentinel
控制台输入哨兵信息
redis-cli -h 192.168.0.110 -p 26379 info Sentinel
### Sentinel
sentinel_masters:1
sentinel_tilt:0
sentinel_running_scripts:0
sentinel_scripts_queue_length:0
master0:name=mymaster,status=ok,address=192.168.0.107:6379,slaves=2,sentinels=1
三、集群
3.1 特点
3.0 版本之前的 redis 是不反对集群的,咱们的徐子睿老师说,那个时候,咱们的 redis 如果想要集群的话,就须要一个中间件,而后这个中间件负责将咱们须要存入 redis 中的数据的 key 通过一套算法计算得出一个值。而后依据这个值找到对应的 redis 节点,将这些数据存在这个 redis 的节点中。在取值的时候,同样先将 key 进行计算,失去对应的值,而后就去找对应的 redis 节点,从对应的节点中取出对应的值。这样做有很多不好的中央,比如说咱们的这些计算都须要在零碎中去进行,所以会减少零碎的累赘。还有就是这种集群模式下,某个节点挂掉,其余的节点无奈晓得。而且也不容易对每个节点进行负载平衡。
从 redis 3.0 版本开始反对 redis-cluster 集群,redis-cluster 采纳无核心构造,每一个节点都保留有这个集群所有主节点以及从节点的信息,及集群状态,每个节点都和其余节点连贯。所以 redis-cluster 是一种服务端分片技术。
- 每个节点都和 n - 1 个节点通信,这被称为集群总线(cluster bus)。它们应用非凡的端口号,即对外服务端口号加 10000。所以要保护好这个集群的每个节点信息,不然会导致整个集群不可用,其外部采纳非凡的二进制协定优化传输速度和带宽。
- redis-cluster 把所有的物理节点映射到[0,16383]slot(槽)上,cluster 负责保护 node–slot–value。
- 集群事后给所有节点分好 16384 个桶,每个节点失去局部桶,当须要在 redis 集群中插入数据时,依据 CRC16(KEY) mod 16384 的值,决定将一个 key 放到哪个桶中。
- 客户端与 redis 节点直连,不须要连贯集群所有的节点,连贯集群中任何一个可用节点即可。整个 cluster 被看做是一个整体,客户端可连贯任意一个节点进行操作,当客户端操作的 key 没有调配在该节点上时,redis 会返回转向指令,指向正确的节点。
- redis-trib.rb 脚本(rub 语言)为集群的管理工具,比方主动增加节点,布局槽位,迁徙数据等一系列操作。
- 节点的 fail 是通过集群中超过半数的节点检测生效时才失效。集群节点之间通过相互的 ping-pong 判断是否能够连贯上。如果有一半以上的节点去 ping 一个节点的时候没有回应,集群就认为这个节点宕机了,而后去连贯它的备用节点。如果某个节点和所有从节点全副挂掉,集群就进入 fail 状态,也能够了解成集群的 slot 映射 [0-16383] 不残缺时进入 fail 状态。如果有一半以上的主节点宕机,那么无论这些节点有没有从节点,集群同样进入 fail 状态。这就是 redis 的投票机制。
- 为了减少集群的可拜访性,官网举荐的计划是将 node 配置成主从构造,即一个 master 主节点,挂 n 个 slave 从节点。如果主节点生效,redis cluster 会依据选举算法从 slave 节点中抉择一个回升为 master 节点,整个集群持续对外提供服务。
3.2 配置
1.redis 集群依赖 ruby,需装置 ruby 环境,ruby 版本需高于 2.2
yum install ruby
yum install rubygems
gem install redis
2. 批改配置文件
bind 192.168.0.107
### 配置端口
port 6380
### 配置快照保留门路,6 个节点配置不同门路
dir /usr/local/redis-cluster/6380/
### 开启集群
cluster-enabled yes
### 为节点设置不同的工作目录,6 个节点配置不同目录
cluster-config-file nodes-6380.conf
### 集群生效工夫
cluster-node-timeout 15000
3. 开启集群中的所有节点
redis-service …/6380/redis.conf
redis-service …/6381/redis.conf
redis-service …/6382/redis.conf
redis-service …/6383/redis.conf
redis-service …/6384/redis.conf
redis-service …/6385/redis.conf
4. 将节点退出集群中,中途须要输出 yes 确定创立集群
redis-trib.rb create –replicas 1 192.168.0.107:6380 192.168.0.107:6381 192.168.0.107:6382 192.168.0.107:6383 192.168.0.107:6384 192.168.0.107:6385
5. 进入集群中任何一个节点
redis-cli -c -h 192.168.0.107 -p 6381
6. 查看集群中的节点
cluster nodes
[root@buke107 src]### redis-cli -c -h 192.168.0.107 -p 6381
192.168.0.107:6381> cluster nodes
868456121fa4e6c8e7abe235a88b51d354a944b5 192.168.0.107:6382 master - 0 1523609792598 3 connected 10923-16383
d6d01fd8f1e5b9f8fc0c748e08248a358da3638d 192.168.0.107:6385 slave 868456121fa4e6c8e7abe235a88b51d354a944b5 0 1523609795616 6 connected
5cd3ed3a84ead41a765abd3781b98950d452c958 192.168.0.107:6380 master - 0 1523609794610 1 connected 0-5460
b8e047aeacb9398c3f58f96d0602efbbea2078e2 192.168.0.107:6383 slave 5cd3ed3a84ead41a765abd3781b98950d452c958 0 1523609797629 1 connected
68cf66359318b26df16ebf95ba0c00d9f6b2c63e 192.168.0.107:6384 slave 90b4b326d579f9b5e181e3df95578bceba29b204 0 1523609796622 5 connected
90b4b326d579f9b5e181e3df95578bceba29b204 192.168.0.107:6381 myself,master - 0 0 2 connected 5461-10922
如上所示,三主三从节点已创立胜利
7. 减少集群节点
cluster meet ip port
其余集群实现形式
中间件
一、twemproxy
- twemproxy 又称 nutcracker,起源于推特零碎中 redis、memcached 集群的轻量级代理。
- Redis 代理中间件 twemproxy 是一种利用中间件做分片的技术。twemproxy 处于客户端和服务器的两头,将客户端发来的申请,进行肯定的解决后(sharding),再转发给后端真正的 redis 服务器。也就是说,客户端不间接拜访 redis 服务器,而是通过 twemproxy 代理中间件间接拜访。升高了客户端直连后端服务器的连贯数量,并且反对服务器集群程度扩大。
- twemproxy 中间件的外部解决是无状态的,它自身能够很轻松地集群,这样能够防止单点压力或故障。
- 从上面架构图看到 twemproxy 是一个单点,很容易对其造成很大的压力,所以通常会联合 keepalived 来实现 twemproy 的高可用。这时,通常只有一台 twemproxy 在工作,另外一台处于备机,当一台挂掉当前,vip 主动漂移,备机接替工作。对于 keepalived 的用法可自行网上查阅材料。
二、codis
codis 是一个分布式的 Redis 解决方案,由豌豆荚开源,对于下层的利用来说,连贯 codis proxy 和连贯原生的 redis server 没什么显著的区别,下层利用能够像应用单机的 redis 一样应用,codis 底层会解决申请的转发,不停机的数据迁徙等工作,所有后边的事件,对于后面的客户端来说是通明的,能够简略的认为后边连贯的是一个内存无限大的 redis 服务。
客户端分片
分区的逻辑在客户端实现,由客户端本人抉择申请到哪个节点。计划可参考一致性哈希,这种计划通常实用于用户对客户端的行为有齐全控制能力的场景。
一、Jedis sharding 集群
Redis Sharding 能够说是在 Redis cluster 进去之前业界广泛的采纳形式,其次要思维是采纳 hash 算法将存储数据的 key 进行 hash 散列,这样特定的 key 会被定为到特定的节点上。
庆幸的是,Java Redis 客户端驱动 Jedis 已反对 Redis Sharding 性能,即 ShardedJedis 以及联合缓存池的 ShardedJedisPool
Jedis 的 Redis Sharding 实现具备如下特点:
- 采纳一致性哈希算法,将 key 和节点 name 同时 hashing,而后进行映射匹配,采纳的算法是 MURMUR_HASH。采纳一致性哈希而不是采纳简略相似哈希求模映射的次要起因是当减少或缩小节点时,不会产生因为从新匹配造成的 rehashing。一致性哈希只影响相邻节点 key 调配,影响量小。
- 为了防止一致性哈希只影响相邻节点造成节点调配压力,ShardedJedis 会对每个 Redis 节点依据名字 (没有,Jedis 会赋予缺省名字) 会虚拟化出 160 个虚构节点进行散列。依据权重 weight,也可虚拟化出 160 倍数的虚构节点。用虚构节点做映射匹配,能够在减少或缩小 Redis 节点时,key 在各 Redis 节点挪动再调配更平均,而不是只有相邻节点受影响。
- ShardedJedis 反对 keyTagPattern 模式,即抽取 key 的一部分 keyTag 做 sharding,这样通过正当命名 key,能够将一组相关联的 key 放入同一个 Redis 节点,这在防止跨节点拜访相干数据时很重要。
- 当然,Redis Sharding 这种轻量灵便形式必然在集群其它能力方面做出斗争。比方扩容,当想要减少 Redis 节点时,只管采纳一致性哈希,毕竟还是会有 key 匹配不到而失落,这时须要键值迁徙。
- 作为轻量级客户端 sharding,解决 Redis 键值迁徙是不事实的,这就要求利用层面容许 Redis 中数据失落或从后端数据库从新加载数据。但有些时候,击穿缓存层,间接拜访数据库层,会对系统拜访造成很大压力。