一:redis 高可用与集群
虽然Redis可以实现单机的数据持久化,但无论是RDB也好或者AOF也好,都解决不了单点宕机问题,即一旦redis服务器本身出现系统故障、硬件故障等问题后,就会直接造成数据的丢失,因此需要使用另外的技术来解决单点问题。
1:配置reids 主从
主备模式,可以实现Redis数据的跨主机备份。
程序端连接到高可用负载的VIP,然后连接到负载服务器设置的Redis后端real server,此模式不需要在程序里面配置Redis服务器的真实IP地址,当后期Redis服务器IP地址发生变更只需要更改redis 相应的后端real server即可,可避免更改程序中的IP地址设置。
1.1:Slave主要配置
Redis Slave 也要开启持久化并设置和master同样的连接密码,因为后期slave会有提升为master的可能,Slave端切换master同步后会丢失之前的所有数据。
一旦某个Slave成为一个master的slave,Redis Slave服务会清空当前redis服务器上的所有数据并将master的数据导入到自己的内存,但是断开同步关系后不会删除当前已经同步过的数据。
1.1.1:Slave的配置的两种方法
1.1.1.1:修改配置文件
1 | [root@slave-redis ~]#vim /etc/redis.conf |
1.1.1.2:命令行配置
当前状态为master,需要转换为slave角色并指向master服务器的IP+PORT+Password1
2
3
4
5
6[root@slave-redis ~]#redic-cli
127.0.0.1:6379> SLAVEOF 192.168.183.155 6379
OK
127.0.0.1:6379> CONFIG SET masterauth 123456
OK
#上面是临时生效
1.1.2:同步日志
1 | [root@slave-redis ~]#tail /var/log/redis/redis.log |
1.1.3:当前slave状态
1 | 127.0.0.1:6379> info Replication |
1.1.4:存配置到redis.conf:
1 | 127.0.0.1:6379> config rewrite |
1.1.5:重启slave验证
1 | [root@slave-redis ~]#systemctl restart redis |
1.1.6:验证slave数据
1 | 127.0.0.1:6379> keys * |
1.1.7:slave 状态只读无法写入数据
1 | 127.0.0.1:6379> set key1 value1 |
1.1.8:Master日志
1 | [root@master-redis ~]#tail /var/log/redis/redis.log |
1.1.9:主从复制过程
Redis支持主从复制分为全量同步和增量同步,首次同步是全量同步,主从同步可以让从服务器从主服务器备份数据,而且从服务器还可与有从服务器,即另外一台redis服务器可以从一台从服务器进行数据同步,redis 的主从同步是非阻塞的,其收到从服务器的sync(2.8版本之前是PSYNC)命令会fork一个子进程在后台执行bgsave命令,并将新写入的数据写入到一个缓冲区里面,bgsave执行完成之后并生成的将RDB文件发送给客户端,客户端将收到后的RDB文件载入自己的内存,然后主redis将缓冲区的内容在全部发送给从redis,之后的同步从服务器会发送一个offset的位置(等同于MySQL的binlog的位置)给主服务器,主服务器检查后位置没有错误将此位置之后的数据包括写在缓冲区的积压数据发送给redis从服务器,从服务器将主服务器发送的挤压数据写入内存,这样一次完整的数据同步,再之后再同步的时候从服务器只要发送当前的offset位 置给主服务器,然后主服务器根据响应的位置将之后的数据发送给从服务器保存到其内存即可。
Redis全量复制一般发生在Slave初始化阶段,这时Slave需要将Master上的所有数据都复制一份。具体步骤如下:
1)从服务器连接主服务器,发送SYNC命令;
2)主服务器接收到SYNC命名后,开始执行BGSAVE命令生成RDB快照文件并使用缓冲区记录此后执行的所有写命令;
3)主服务器BGSAVE执行完后,向所有从服务器发送快照文件,并在发送期间继续记录被执行的写命令;
4)从服务器收到快照文件后丢弃所有旧数据,载入收到的快照;
5)主服务器快照发送完毕后开始向从服务器发送缓冲区中的写命令;
6)从服务器完成对快照的载入,开始接收命令请求,并执行来自主服务器缓冲区的写命令;
7)后期同步会先发送自己slave_repl_offset位置,只同步新增加的数据,不再全量同步。
1.1.10:主从同步优化
Redis在2.8版本之前没有提供增量部分复制的功能,当网络闪断或者slave Redis重启之后会导致主从之间的全量同步,即从2.8版本开始增加了部分复制的功能。
repl-diskless-sync no #yes为支持disk,master将RDB文件先保存到磁盘在发送给slave,no为maste直接将RDB文件发送给slave,默认即为使用no,Master RDB文件不需要与磁盘交互。
repl-diskless-sync-delay 5 #Master准备好RDB文件后等等待传输时间
repl-ping-slave-period 10 #slave端向server端发送pings的时间区间设置,默认为10秒
repl-timeout 60 #设置超时时间
repl-disable-tcp-nodelay no #是否启用TCP_NODELAY,如设置成yes,则redis会合并小的TCP包从而节省带宽,但会增加同步延迟(40ms),造成master与slave数据不一致,假如设置成no,则redis master会立即发送同步数据,没有延迟,前者关注性能,后者关注一致性
repl-backlog-size 1mb #master的写入数据缓冲区,用于记录自上一次同步后到下一次同步过程中间的写入命令,计算公式:b repl-backlog-size = 允许从节点最大中断时长 主实例offset每秒写入量,比如master每秒最大写入64mb,最大允许60秒,那么就要设置为64mb60秒=3840mb(3.8G)=
repl-backlog-ttl 3600 #如果一段时间后没有slave连接到master,则backlog size的内存将会被释放。如果值为0则表示永远不释放这部份内存。
slave-priority 100 #slave端的优先级设置,值是一个整数,数字越小表示优先级越高。当master故障时将会按照优先级来选择slave端进行恢复,如果值设置为0,则表示该slave永远不会被选择。
min-slaves-to-write 0 #
min-slaves-max-lag 10 #设置当一个master端的可用slave少于N个,延迟时间大于M秒时,不接收写操作。
Master的重启会导致master_replid发生变化,slave之前的master_replid就和master不一致从而会引发所有slave的全量同步。
1.1.11:slave切换master
当前状态:
1 | 127.0.0.1:6379> info Replication |
停止slave同步并查看当前状态:
1 | 127.0.0.1:6379> SLAVEOF no one #临时生效 |
测试能否写入数据:
1 | 127.0.0.1:6379> set key3 value3 |
####
1 |
二:redis 集群
上一个步骤的主从架构无法实现master和slave角色的自动切换,即当master出现redis服务异常、主机断电、磁盘损坏等问题导致master无法使用,而redis高可用无法实现自故障转移(将slave提升为master),需要手动改环境配置才能切换到slave redis服务器,另外也无法横向扩展Redis服务的并行写入性能,当单台Redis服务器性能无法满足业务写入需求的时候就必须需要一种方式解决以上的两个核心问题,即:
1.master和slave角色的无缝切换,让业务无感知从而不影响业务使用 ;
2.可以横向动态扩展Redis服务器,从而实现多台服务器并行写入以实现更高并发的目的。
Redis 集群实现方式:客户端分片 代理分片 Redis Cluster
2.1:Sentinel(哨兵)
Sentinel 进程是用于监控redis集群中Master主服务器工作的状态,在Master主服务器发生故障的时候,可以实现Master和Slave服务器的切换,保证系统的高可用,其已经被集成在redis2.6+的版本中,Redis的哨兵模式到了2.8版本之后就稳定了下来。一般在生产环境也建议使用Redis的2.8版本的以后版本。哨兵(Sentinel) 是一个分布式系统,你可以在一个架构中运行多个哨兵(sentinel) 进程,这些进程使用流言协议(gossipprotocols)来接收关于Master主服务器是否下线的信息,并使用投票协议(Agreement Protocols)来决定是否执行自动故障迁移,以及选择哪个Slave作为新的Master。
每个哨兵(Sentinel)进程会向其它哨兵(Sentinel)、Master、Slave定时发送消息,以确认对方是否”活”着,如果发现对方在指定配置时间(可配置的)内未得到回应,则暂时认为对方已掉线,也就是所谓的”主观认为宕机” ,英文名称:Subjective Down,简称SDOWN。
当“哨兵群”中的多数Sentinel进程在对Master主服务器做出 SDOWN 的判断,并且通过 SENTINEL is-master-down-by-addr 命令互相交流之后,得出的Master Server下线判断,这种方式就是“客观宕机”,英文名称是:Objectively Down, 简称 ODOWN。
通过一定的vote算法,从剩下的slave从服务器节点中,选一台提升为Master服务器节点,然后自动修改相关配置,并开启故障转移(failover)。
Sentinel 机制可以解决master和slave角色的切换问题。
2.1.1:配置redis主从服务器
2.1.1.1:手动配置master
需要手动先指定某一台Redis服务器为master,然后将其他slave服务器使用命令配置为master服务器的slave
1 | [root@master-redis ~]#vim /etc/redis.conf |
2.1.1.2:服务器A配置slave
1 | [root@slave-redis ~]#vim /etc/redis.conf |
2.1.1.3:服务器B配置slave
1 | [root@slave1-redis ~]#vim /etc/redis.conf |
2.1.1.4:当前master状态
1 | [root@master-redis ~]#redis-cli -a 123456 |
2.1.2:编辑配置文件sentinel.conf
2.1.2.1:master 配置
哨兵可以不和Redis服务器部署在一起,
1 | [root@master-redis ~]#vim /etc/redis-sentinel.conf |
2.1.2.2:Slave 配置
1 | [root@slave-redis ~]#vim /etc/redis-sentinel.conf |
2.1.2.3:Slave1配置
1 | [root@slave1-redis ~]#vim /etc/redis-sentinel.conf |
2.1.2.4:启动哨兵
三台哨兵都要启动
1 | [root@master-redis ~]#systemctl start redis-sentinel.service |
2.1.2.3:验证端口
1 | [root@master-redis ~]#ss -ntl |
2.1.2.4:哨兵日志
1 | [root@master-redis ~]#tail /var/log/redis/sentinel.log |
2.1.2.5:当前redis 状态
1 | 127.0.0.1:6379> info replication |
2.1.2.6:当前sentinel状态
尤其是最后一行,涉及到master IP是多少,有几个slave,有几个sentinels,必须是符合全部服务器数量的。
1 | [root@master-redis ~]#redis-cli -p 26379 |
2.1.2.7:停止Redis Master测试故障转移
1 | [root@master-redis ~]#systemctl stop redis |
查看master信息:
1 | 127.0.0.1:6379> info replication |
查看哨兵信息:
1 | [root@master-redis ~]#redis-cli -p 26379 |
故障转移时sentinel 的信息:
1 | [root@master-redis ~]#tail -n20 /var/log/redis/sentinel.log |
2.1.2.8:故障转移后的redis配置文件
故障转移后redis.conf中的replicaof行的master IP会被修改,sentinel.conf中的sentinel monitor IP会被修改。
1 | [root@slave-redis ~]#vim /etc/redis.conf |
2.1.2.9:当前reids状态
1 | [root@slave-redis ~]#redis-cli -a 123456 |
2.2:Redis Cluster部署
Redis cluster之前的分布式方案:
1) 客户端分区:由客户端程序决定key写分配和写入的redis node,但是需要客户端自己处理写入分配、高可用管理和故障转移等
2)代理方案:基于三方软件实现redis proxy,客户端先连接之代理层,由代理层实现key的写入分配,对客户端来说是有比较简单,但是对于集群管节点增减相对比较麻烦,而且代理本身也是单点和性能瓶颈。
在哨兵sentinel机制中,可以解决redis高可用的问题,即当master故障后可以自动将slave提升为master从而可以保证redis服务的正常使用,但是无法解决redis单机写入的瓶颈问题,即单机的redis写入性能受限于单机的内存大小、并发数量、网卡速率等因素,因此redis官方在redis 3.0版本之后推出了无中心架构的redis cluster机制,在无中心的redis集群汇中,其每个节点保存当前节点数据和整个集群状态,每个节点都和其他所有节点连接,特点如下:
1:所有Redis节点使用(PING-PING机制)互联
2:集群中某个节点的实效是整个集群中超过半数的节点监测都实效才算真正的实效
3:客户端不需要proxy即可直接连接redis,且客户端不需要连接集群中的所有节点,只要连接集群中的任何一个节点即可。
4:redis cluster把所有的redisnode映射到 0-16383个槽位(slot)上,读写需要到指定的redis node上进行操作,因此有多少个reids node相当于redis 并发扩展了多少倍。
5:Redis集群预先分配16384个(slot)槽位,当需要在redis集群中写入一个key -value的时候,会使用CRC16(key) mod 16384之后的值,决定将key写入值哪一个槽位从而决定写入哪一个Redis节点上,从而有效解决单机瓶颈。
2.2.1:部署redis集群
环境准备:
三台服务器,每台服务器启动6379端口,(192.168.183.155:6379 192.168.183.154:6379
192.168.183.153:6379 )
2.2.1.1:创建redis cluster集群的前提:
1.每个redis node节点采用相同的硬件配置、相同的密码
2.每个节点必须开启参数,设置配置文件,启用集群功能;
1 | [root@redis1 ~]#vim /etc/redis.conf |
2.2.1.2:启动redis后为每个节点分配slots;
1 | [root@redis1 ~]#redis-cli -a 123456 |
2.2.1.3:设定集群成员关系;(CLUSTE MEET)
1 | 127.0.0.1:6379> CLUSTER MEET 192.168.183.154 6379 |
2.3:redis扩展集群方案:
除了Redis 官方自带的Redis cluster集群之外,还有一写开源的集群解决方案可供参考使用。
2.3.1:codis:
Codis 是一个分布式 Redis 解决方案, 对于上层的应用来说, 连接到 Codis Proxy 和连接原生的 Redis Server 没有显著区别 (不支持的命令列表), 上层应用可以像使用单机的 Redis 一样使用, Codis 底层会处理请求的转发, 不停机的数据迁移等工作, 所有后边的一切事情, 对于前面的客户端来说是透明的, 可以简单的认为后边连接的是一个内存无限大的 Redis 服务。
codis-proxy相当于redis,即连接codis-proxy和连接redis是没有任何区别的,codis-proxy无状态,不负责记录是否在哪保存,数据在zookeeper记录,即codis proxy向zookeeper查询key的记录位置,proxy 将请求转发到一个组进行处理,一个组里面有一个master和一个或者多个slave组成,默认有1024个槽位,redis cluster 默认有16384个槽位,其把不同的槽位的内容放在不同的group。
Github 地址:https://github.com/CodisLabs/codis/blob/release3.2/doc/tutorial_zh.md
2.3.2:twemproxy:
由Twemproxy代替客户端实现分片,即代替用户将数据分片并到不同的后端服务器进行读写,其还支持memcached,可以为proxy配置算法,缺点为twemproxy是瓶颈,不支持数据迁移,官方github地址https://github.com/twitter/twemproxy/
Github 地址:https://github.com/twitter/twemproxy
三:memcached
Memcache官网:http://memcached.org/
memcache本身没有像redis所具备的数据持久化功能,比如RDB和AOF都没有,但是可以通过做集群同步的方式,让各memcache服务器的数据进行同步,从而实现数据的一致性,即保证各memcache的数据是一样的,即使有任何一台或多台memcache发生故障,只要集群种有一台memcache可用就不会出现数据丢失,当其他memcache重新加入到集群的时候可以自动从有数据的memcache当中自动获取数据并提供服务。
Memcache借助了操作系统的libevent工具做高效的读写。libevent是个程序库,它将Linux的epoll、BSD类操作系统的kqueue等事件处理功能封装成统一的接口。即使对服务器的连接数增加,也能发挥高性能。memcached使用这个libevent库,因此能在Linux、BSD、Solaris等操作系统上发挥其高性能。
Memcache支持最大的内存存储对象为1M,超过1M的数据可以使用客户端压缩或拆分报错到做个key中,比较大的数据在进行读取的时候需要消耗的时间比较长,memcache最适合报错用户的session实现session共享,Memcached存储数据时, Memcached会去申请1MB的内存, 把该块内存称为一个slab, 也称为一个page。
memcached具有多种语言的客户端开发包,包括:Perl/PHP/JAVA/C/Python/Ruby/C#/
3.1:单机部署:
3.1.1:yum安装与启动:
通过yum 安装是相对简单的安装方式
1 | yum install memcached –y |
3.1.2:编译安装:
1 | yum install libevent libevent-devel –y |
3.2:memcached集群部署架构:
3.2.1:基于magent的部署架构:
该部署方式依赖于magent实现高可用,应用端通过负载服务器连接到magent,然后再由magent代理用户应用请求到memcached处理,底层的memcached为双主结构会自动同步数据,本部署方式存在magent单点问题因此需要两个magent做高可用。
3.2.2:简化后的部署架构:
但magent已经有很长时间没有更新,因此可以不再使用magent,直接通过负载均衡连接之memcached,任然有两台memcached做高可用,memcached会自动同步数据保持数据一致性,即使一台memcached故障也不影响业务正常运行,故障的memcached修复上线后再自动从另外一台同步数据即可保持数据一致性。
4.1.3:部署repcached