一 redis高可用分布式方案
- 项目采用的是predixy + redis-cluster 的组合,predixy充当代理,集群三组三从总共六个节点。
- 有三台Linux专门用来部署redis,每台有两个节点,每个节点的内存是23G。每台都有一个代理predixy,其中predixy代理六个节点。
- 硬负载配置三台predixy代理进行轮询,服务端配置硬负载地址。这块具体是保密的,我们没接触到。只知道大概架构。
二 为什么要选择Redis Cluster集群?
Redis如果要扩展的话有纵向扩展、横向扩展。
纵向扩展
-
好处 实施起来简单、直接
-
缺点 随着数据量增加,需要的内存也会增加,主线程fork子进程时就可能会阻塞;受到硬件和成本的限制
横向扩展
- 只需增加Redis实例个数就行,面向百万、千万级别的用户规模横向扩展的Redis切片集群会使一个非常好的选择。
Redis Cluster集群
步骤:
-
首先根据键值对的key,按照CRC16算法计算一个16bit的值。
-
用这个16bit值对16384取模,得到0~16383范围内的模数,每个模数代表一个相应编号的哈希槽
Redis实例会把⾃⼰的哈希槽信息发给和它相连接的其它实例,来完成哈希槽分配信息的扩散。当实例之间相互连接后,每个实例就有所有哈希槽的映射关系了。
客户端收到哈希槽信息后,会把哈希槽信息缓存在本地。当客户端请求键值对时,会先计算键所对应的哈希槽,然后就可以给相应的实例发送请求了。
在集群中,实例有新增或删除,Redis需要重新分配哈希槽;为了负载均衡,Redis需要把哈希槽在所有实例上重新分布⼀遍。
集群的实例增减,或者是为了实现负载均衡⽽进⾏的数据重新分布,会导致哈希槽和实例的映射关系发⽣变化,客户端发送请求时,会收到命令执⾏报错信息。
三 MOVED & ASK
当客户端把⼀个键值对的操作请求发给⼀个实例时,如果这个实例上并没有这个键值对映射的哈希槽,那么,这个实例就会给客户端返回下⾯的MOVED命令响应结果,这个结果中就包含了新实例的访问地址。
GET hello:key(error) MOVED 13320 172.16.19.5:6379
MOVED命令表⽰,客户端请求的键值对所在的哈希槽13320,实际是在172.16.19.5这个实例上。通过返回的MOVED命令,就相当于把哈希槽所在的新实例的信息告诉给客户端了。这样⼀来,客户端就可以直接和172.16.19.5连接,并发送操作请求了。
客户端向实例2发送请求,但此时,Slot 2中的数据只有⼀部分迁移到了实例3,还有部分数据没有迁移。会出现一下错误:
GET hello:key(error) ASK 13320 172.16.19.5:6379
ASK命令表⽰两层含义:第⼀,表明Slot数据还在迁移中;第⼆,ASK命令把客户端所请求数据的最新实例地址返回给客户端,此时,客户端需要给实例3发送ASKING命令,然后再发送操作命令。
四 本地部署 predixy + redis-cluster
主要思路:
1. 首先我们要去官网下载 redis-6.2.6.tar.gz包到本地并解压
2. 进入目录编译 make,之后进入目录创建redis-cluster文件夹,在该文件夹下创建文件夹7001、7002、7003、7004、7005、7006 以及redis-data、run的文件夹
3. 在7001文件夹下创建redis-7001.conf配置文件,之后复制到其他文件夹下
这是redis-7001.conf的内容
# 配置实例端口
port 7001
# 配置rdb文件名
dbfilename 7001-dump.rdb
# 配置cluster生成节点数据的文件名,注意如果要重启服务,重新组成cluster集群需要删除所有的这个文件。
cluster-config-file nodes-7001.conf
# 配置pid文件名和存储目录
pidfile /Users/APPLE/Documents/software/redis-cluster-predixy/redis-6.2.6/redis-cluster/run/redis_7001.pid
dir /Users/APPLE/Documents/software/redis-cluster-predixy/redis-6.2.6/redis-cluster/redis-data
# 生成的文件存储目录(包括rdb文件和node的conf文件)
# 作为守护线程运行
daemonize yes
# 不绑定ip
bind 0.0.0.0
logfile ""
# 关闭保护模式
protected-mode no
# 密码 (全部实例设置成同一个)
# requirepass 123456
# 从节点访问主节点的密码(和上面的密码一样并且,全部实例设置成同一个)
# masterauth 123456
# 超时时间
cluster-node-timeout 12000
#开启cluster
cluster-enabled yes
## 其余配置比如aof什么的视情况自己改就好了
loadmodule /Users/APPLE/Documents/software/redis-cluster/redisbloom.so
4. 配置完后我们就可以指定配置文件启动redis,进到src文件夹下启动。
5. cluster的通信组装
./redis-cli -a sjwkk123456 --cluster create 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006 --cluster-replicas 1
6. 完成以上步骤就可以使用redis-cli命令查看集群状态
7. 安装predixy
编译、安装好后,配置【predixy.conf】和【cluster.conf】以及【auth.conf】这3个文件,因为这个redis我也有安装插件布隆过滤器,所以【command.conf】也有配置。
################################### GENERAL ####################################
## Predixy configuration file example
## Specify a name for this predixy service
## redis command INFO can get this
Name Predixy7617
## Specify listen address, support IPV4, IPV6, Unix socket
## Examples:
# Bind 127.0.0.1:7617
# Bind 0.0.0.0:7617
# Bind /tmp/predixy
## Default is 0.0.0.0:7617
Bind 0.0.0.0:7617
## Worker threads
WorkerThreads 1
## Memory limit, 0 means unlimited
## Examples:
# MaxMemory 100M
# MaxMemory 1G
# MaxMemory 0
## MaxMemory can change online by CONFIG SET MaxMemory xxx
## Default is 0
# MaxMemory 0
## Close the connection after a client is idle for N seconds (0 to disable)
## ClientTimeout can change online by CONFIG SET ClientTimeout N
## Default is 0
ClientTimeout 300
## IO buffer size
## Default is 4096
# BufSize 4096
################################### LOG ########################################
## Log file path
## Unspecify will log to stdout
## Default is Unspecified
# Log ./predixy.log
## LogRotate support
## 1d rotate log every day
## nh rotate log every n hours 1 <= n <= 24
## nm rotate log every n minutes 1 <= n <= 1440
## nG rotate log evenry nG bytes
## nM rotate log evenry nM bytes
## time rotate and size rotate can combine eg 1h 2G, means 1h or 2G roate a time
## Examples:
# LogRotate 1d 2G
# LogRotate 1d
## Default is disable LogRotate
## In multi-threads, worker thread log need lock,
## AllowMissLog can reduce lock time for improve performance
## AllowMissLog can change online by CONFIG SET AllowMissLog true|false
## Default is true
# AllowMissLog false
## LogLevelSample, output a log every N
## all level sample can change online by CONFIG SET LogXXXSample N
LogVerbSample 0
LogDebugSample 0
LogInfoSample 10000
LogNoticeSample 1
LogWarnSample 1
LogErrorSample 1
################################### AUTHORITY ##################################
Include auth.conf
################################### SERVERS ####################################
Include cluster.conf
# Include sentinel.conf
# Include try.conf
################################### DATACENTER #################################
## LocalDC specify current machine dc
# LocalDC bj
## see dc.conf
# Include dc.conf
################################### COMMAND ####################################
## Custom command define, see command.conf
Include command.conf
################################### LATENCY ####################################
## Latency monitor define, see latency.conf
#Include latency.conf
ClusterServerPool {
MasterReadPriority 100 #这个是主节点访问权重,如果是只把备节点用作备份不去做读写分离,直接将这个配置成100只去读主节点就好了。
Password sjwkk123456 # redis实例的访问密码
StaticSlaveReadPriority 0 # 读写分离功能,从静态redis slave节点执行读请求的优先级,所谓静态节点,是指在本配置文件中显示列出的redis节点,不指定的话为0
DynamicSlaveReadPriority 0 # 功能见上,所谓动态节点是指在本配置文件中没有列出,但是通过redis sentinel动态发现的节点,不指定的话为0
RefreshInterval 1 # predixy会周期性的请求redis sentinel以获取最新的集群信息,该参数以秒为单位指定刷新周期,不指定的话为1秒
ServerTimeout 1 # 请求在predixy中最长的处理/等待时间,如果超过该时间redis还没有响应的话,那么predixy会关闭同redis的连接,并给客户端一个错误响应,对于blpop这种阻塞式命令,该选项不起作用,为0则禁止此功能,即如果redis不返回就一直等待,不指定的话为0
ServerFailureLimit 10 # 一个redis实例出现多少次才错误以后将其标记为失效,不指定的话为10
ServerRetryTimeout 1 # 一个redis实例失效后多久后去检查其是否恢复正常,不指定的话为1秒
KeepAlive 120 #predixy与redis的连接tcp keepalive时间,为0则禁止此功能,不指定的话为0
Servers {
## 配置所有节点地址就好了
+ 127.0.0.1:7001
+ 127.0.0.1:7002
+ 127.0.0.1:7003
+ 127.0.0.1:7004
+ 127.0.0.1:7005
+ 127.0.0.1:7006
}
}
Authority {
Auth "123456" {
Mode admin
}
}
CustomCommand {
bf.reserve {
Mode write
MinArgs 4
MaxArgs 7
}
bf.add {
Mode write
MinArgs 3
MaxArgs 3
}
bf.madd {
Mode write
MinArgs 3
MaxArgs 9999
}
bf.insert {
Mode write
MinArgs 4
MaxArgs 9999
}
bf.exists {
Mode read
MinArgs 3
MaxArgs 3
}
bf.mexists {
Mode read
MinArgs 3
MaxArgs 9999
}
bf.scandump {
Mode admin
MinArgs 3
MaxArgs 3
}
bf.loadchunk {
Mode admin
MinArgs 4
MaxArgs 4
}
bf.info {
Mode read
}
cf.reserve {
Mode write
MinArgs 3
MaxArgs 9
}
cf.add {
Mode write
MinArgs 3
MaxArgs 3
}
cf.addnx {
Mode write
MinArgs 3
MaxArgs 3
}
cf.insert {
Mode write
MinArgs 4
MaxArgs 9999
}
cf.insertnx {
Mode write
MinArgs 4
MaxArgs 9999
}
cf.exists {
Mode read
MinArgs 3
MaxArgs 3
}
cf.del {
Mode read
MinArgs 3
MaxArgs 3
}
cf.count {
Mode read
MinArgs 3
MaxArgs 3
}
cf.scandump {
Mode admin
MinArgs 3
MaxArgs 3
}
cf.loadchunk {
Mode admin
MinArgs 4
MaxArgs 4
}
cf.info {
Mode read
}
}
8. ok 启动 ./src/predixy ./conf/predixy.conf
五 总结
predixy + redis-cluster 就是我们项目实际用的redis高可用模式,实际上还有一层就是硬负载对三个predixy进行轮询请求,这块我们是接触不到的。