Predixy
Predixy 是一款高性能全特征redis代理,支持redis-sentinel和redis-cluster
特性
- 高性能并轻量级
- 支持多线程
- 多平台支持:Linux、OSX、BSD、Windows(Cygwin)
- 支持Redis Sentinel,可配置一组或者多组redis
- 支持Redis Cluster
- 支持redis阻塞型命令,包括blpop、brpop、brpoplpush
- 支持scan命令,无论是单个redis还是多个redis实例都支持
- 多key命令支持: mset/msetnx/mget/del/unlink/touch/exists
- 支持redis的多数据库,即可以使用select命令
- 支持事务,当前仅限于Redis Sentinel下单一redis组可用
- 支持脚本,包括命令:script load、eval、evalsha
- 支持发布订阅机制,也即Pub/Sub系列命令
- 多数据中心支持,读写分离支持
- 扩展的AUTH命令,强大的读、写、管理权限控制机制,健空间限制机制
- 日志可按级别采样输出,异步日志记录避免线程被io阻塞
- 日志文件可以按时间、大小自动切分
- 丰富的统计信息,包括CPU、内存、请求、响应等信息
- 延迟监控信息,可以看到整体延迟,分后端redis实例延迟
编译
Predixy可以在所有主流平台下编译,推荐在linux下使用,需要支持C++11的编译器。
编译非常简单,下载或者git clone代码后进到predixy目录,直接执行:
1 | $ make |
编译后会在src目录生成一个可执行文件predixy
编译debug版本:
1 | $ make debug |
更多编译选项:
- CXX=c++compiler,指定c++编译器,缺省是g++,可以指定为其它,例如:CXX=clang++
- EV=epoll|poll|kqueue,指定异步io模型,缺省情况下是根据平台来检测
- MT=false, 关闭多线程支持
- TS=true, 开启函数调用耗时分析,该选项仅用于开发模式
一些使用参数编译的例子:
1 | $ make CXX=clang++ |
安装
简单的只要拷贝src/predixy到目标路径即可
1 | $ cp src/predixy /path/to/bin |
配置 详细文档
predixy的配置类似redis, 具体配置项的含义在配置文件里有详细解释,请参考下列配置文件:
- predixy.conf,整体配置文件,会引用下面的配置文件
- cluster.conf,用于Redis Cluster时,配置后端redis信息
- sentinel.conf,用于Redis Sentinel时,配置后端redis信息
- auth.conf,访问权限控制配置,可以定义多个验证密码,可每个密码指定读、写、管理权限,以及定义可访问的健空间
- dc.conf,多数据中心支持,可以定义读写分离规则,读流量权重分配
- latency.conf, 延迟监控规则定义,可以指定需要监控的命令以及延时时间间隔
提供这么多配置文件实际上是按功能分开了,所有配置都可以写到一个文件里,也可以写到多个文件里然后在主配置文件里引用进来。
运行
1 | $ src/predixy conf/predixy.conf |
使用默认的配置文件predixy.conf, predixy将监听地址0.0.0.0:7617,后端的redis是Redis Cluster 127.0.0.1:6379。通常,127.0.0.1:6379并不是运行在Redis Clusterr模式下,因此Predixy将会有大量的错误日志输出。不过你依然可以用redis-cli连接predixy来试用一下:
1 | $ redis-cli -p 7617 info |
执行上条命令后可以看到predixy自身的一些信息,如果127.0.0.1:6379在运行的话,你可以试试其它redis命令,看看效果如何。
更多的启动命令行参数请看帮助:
1 | $ src/predixy -h |
统计信息
和redis一样,predixy用INFO命令来给出统计信息。
在redis-cli连接下执行下面的命令:
1 | redis> INFO |
你将看到类似redis执行INFO命令的输出,不过这里是predixy的统计信息。
特别提一下predixy里面的延迟监控信息,可以通过在配置里定义的延迟监控名来看延迟信息
1 | redis> INFO Latency <latency-name> |
引言
无论是为了解决redis的高可用问题、还是为了可扩展性、或者是为了维护方便,用一款redis代理都是上佳的选择。在github上有众多开源的redis代理,本文中选取三个流行的,并且各具特色的代理来和本文所要推介的predixy进行对比。
predixy
twemproxy
codis
redis-cerberus
特性 | predixy | twemproxy | codis | redis-cerberus |
---|---|---|---|---|
高可用 | Redis Sentinel或Redis Cluster | 一致性哈希 | Redis Sentinel | Redis Cluster |
可扩展 | Key哈希分布或Redis Cluster | Key哈希分布 | Key哈希分布 | Redis Cluster |
开发语言 | C++ | C | GO | C++ |
多线程 | 是 | 否 | 是 | 是 |
事务 | Redis Sentinel模式单Redis组下支持 | 不支持 | 不支持 | 不支持 |
BLPOP/BRPOP/BLPOPRPUSH | 支持 | 不支持 | 不支持 | 支持 |
Pub/Sub | 支持 | 不支持 | 不支持 | 支持 |
Script | 支持load | 不支持 | 不支持 | 不支持 |
Scan | 支持 | 不支持 | 不支持 | 不支持 |
Select DB | 支持 | 不支持 | 支持 | Redis Cluster只有一个DB |
Auth | 支持定义多个密码,给予不同读写及管理权限和Key访问空间 | 不支持 | 同redis | 不支持 |
读从节点 | 支持,可定义丰富规则读指定的从节点 | 不支持 | 支持,简单规则 | 支持,简单规则 |
多机房支持 | 支持,可定义丰富规则调度流量 | 不支持 | 有限支持 | 有限支持 |
统计信息 | 丰富 | 丰富 | 丰富 | 简单 |
简单来说,predixy既支持Redis Sentinel也支持Redis Cluster
后端为Redis Sentinel监控的一组Redis,功能完全等同于原始Redis
后端为Redis Sentinel监控的多组Redis,则有部分功能受限
后端为Redis Cluster,功能完全等同于Redis Cluster
操作
对github 搜predixy,第一个就是,然后进去带你release会有编译好的predixy
自己编译需要c++ 11的编译器
https://github.com/joyieldInc/predixy/releases/download/1.0.5/predixy-1.0.5-bin-amd64-linux.tar.gz
1 | cd /root/soft |
sentinel.conf
1 | ## redis sentinel server pool define |
predixy.conf
1 | ################################### GENERAL #################################### |
Predixy配置文档说明
要正常运行predixy服务,一个配置文件是必不可少的,启动一个正常的predixy服务需执行以下命令:
1 | $ predixy <config-file> [--ArgName=ArgValue]... |
predixy首先读取config-file文件中的配置信息,如果有命令行参数指定的话,则会用命令行参数的值覆盖配置文件中定义的相应值。
配置文件格式说明
配置文件是以行为单位的文本文件,每一行是以下几种类型之一
- 空行或注释
- Key Value
- Key Value {
- }
规则
- 以#开始的内容为注释内容
- Include是一个特殊的Key,表示引用Value指明的文件,如果不是绝对路径的话,则相对路径是当前这个文件所在的路径
- Value可以为空, 如果Value本身包括#,双引号的话,应该用双引号括起来,里面的双引号加反斜杠转义, 例如: “A "#special#" value”
- 多个行定义同一个Key的话,最后出现的行会覆盖之前的定义
基本配置部分
Name
定义predixy服务的名字,在用INFO命令的时候会输出这个内容
例子:
1 | Name PredixyUserInfo |
Bind
定义predixy服务监听的地址,支持ip:port以及unix socket
例子:
1 | Bind 0.0.0.0:7617 |
未指定时为: 0.0.0.0:7617
WorkerThreads
指定工作线程数
例子:
1 | WorkerThreads 4 |
未指定时为: 1
MaxMemory
指定predixy最大可申请分配的内存,可以带单位(G/M/K)指定,为0时表示不限制
例子:
1 | MaxMemory 1024000 |
未指定时为: 0
ClientTimeout
指定客户端超时时间,以秒为单位,即客户端在空闲时间超过该时间以后将主动断开客户端连接,为0时表示禁止该功能,不主动断开客户端连接
例子:
1 | ClientTimeout 300 |
未指定时为: 0
BufSize
IO Buffer大小,predixy内部分配BufSize大小的缓冲区用于接受客户端命令和服务端响应,完全零拷贝的转发给服务端或者客户端,该值太小的话影响性能,太大的话浪费空间也可能对性能无益。但是具体多少合适要看实际应用场景,predixy默认设该值为4096
例子:
1 | BufSize 8192 |
未指定时为: 4096
Log
指定日志文件名
例子:
1 | Log /var/log/predixy.log |
未指定时predixy的行为是将日志写向标准输出
LogRotate
日志自动切分选项,可以按时间指定,也可以按文件大小指定,还可以两者都指定。按时间指定支持如下格式:
- 1d 一天
- nh 1<= n <= 24 n小时
- nm 1 <= n <= 1440 n分钟
按文件大小指定支持G和M单位
例子:
1 | LogRotate 1d #每天切分一次 |
未定义时禁用该功能
LogXXXSample
日志输出采样率,表示每多少条该级别的日志输出一条到Log中,为0时则表示不输出该级别日志。支持的级别如下:
- LogVerbSample
- LogDebugSample
- LogInfoSample
- LogNoticeSample
- LogWarnSample
- LogErrorSample
例子:
1 | LogVerbSample 0 |
这几个参数可以在线修改,像redis一样,通过config set命令:
1 | CONFIG SET LogDebugSample 1 |
在predixy中,执行config命令需要管理权限
权限控制配置部分
predixy扩展了redis中AUTH命令的功能,支持定义多个认证密码,可以为每个密码指定权限,权限包括读权限、写权限和管理权限,其中写权限包括读权限,管理权限又包括写权限。还可以指定每个密码所能读写的健空间,健空间的定义是指健具有某个前缀。
权限控制的定义格式如下:
1 | Authority { |
Authority里面可以定义多个Auth,每个Auth指定一个密码,可以为每个Auth定义权限和健空间。
参数说明:
- Mode: 必须指定,只能是read、write、admin三者之一,分别表示读、写、管理权限
- KeyPrefix: 可选项,可以定义健空间,多个健空间用空格隔开
- ReadKeyPrefix: 可选项,可以定义可读的健空间,多个健空间用空格隔开
- WriteKeyPrefix: 可选项,可以定义可写的健空间,多个健空间用空格隔开
对于可读的健空间,如果定义了ReadKeyPrefix,则由ReadKeyPrefix决定,否则由KeyPrefix决定,如果两者都没有,则不限制。可写的健空间解释也一样。需要注意的是,有写权限就表示有读权限,但是读写健空间是完全独立的,即WriteKeyPrefix不会默认包括ReadKeyPrefix的内容。
例子:
1 | Authority { |
上面的例子定义了三个认证密码
- 空密码,因为密码为空,所以这个认证是默认的认证,它具有读权限,由于指定了KeyPrefix,因此它最终的权限是只能读取具有前缀Info的key
- readonly密码,这个认证具有读权限,没有健空间限制,它可以读所有key
- modify密码,这个认证具有写权限,分别定义了可读健空间User和Stats,因此它能读取具有这两个前缀的key,而可写健空间定义为User,因此它能写具有前缀User的key,但是不能写具有前缀Stats的key
缺省的predixy权限控制定义如下:
1 | Authority { |
它表示无需密码即可读写所有的key,但是管理权限要求输入密码#a complex password#
redis实例配置部分
predixy支持Redis Sentinel和Redis Cluster来使用redis,一个配置里这两种形式只能出现一种。
Redis Sentinel形式
定义格式如下:
1 | SentinelServerPool { |
参数说明:
- Password: 指定连接redis实例默认的密码,不指定的情况下表示redis不需要密码
- Databases: 指定redis db数量,不指定的情况下为1
- Hash: 指定对key算哈希的方法,当前只支持atol和crc16
- HashTag: 指定哈希标签,不指定的话为{}
- Distribution: 指定分布key的方法,当前只支持modula和random
- MasterReadPriority: 读写分离功能,从redis master节点执行读请求的优先级,为0则禁止读redis master,不指定的话为50
- StaticSlaveReadPriority: 读写分离功能,从静态redis slave节点执行读请求的优先级,所谓静态节点,是指在本配置文件中显示列出的redis节点,不指定的话为0
- DynamicSlaveReadPolicy: 功能见上,所谓动态节点是指在本配置文件中没有列出,但是通过redis sentinel动态发现的节点,不指定的话为0
- RefreshInterval: predixy会周期性的请求redis sentinel以获取最新的集群信息,该参数以秒为单位指定刷新周期,不指定的话为1秒
- ServerTimeout: 请求在predixy中最长的处理/等待时间,如果超过该时间redis还没有响应的话,那么predixy会关闭同redis的连接,并给客户端一个错误响应,对于blpop这种阻塞式命令,该选项不起作用,为0则禁止此功能,即如果redis不返回就一直等待,不指定的话为0
- ServerFailureLimit: 一个redis实例出现多少次才错误以后将其标记为失效,不指定的话为10
- ServerRetryTimeout: 一个redis实例失效后多久后去检查其是否恢复正常,不指定的话为1秒
- KeepAlive: predixy与redis的连接tcp keepalive时间,为0则禁止此功能,不指定的话为0
- Sentinels: 里面定义redis sentinel实例的地址
- Group: 定义一个redis组,Group的名字应该和redis sentinel里面的名字一致,Group里可以显示列出redis的地址,列出的话就是上面提到的静态节点
一个例子:
1 | SentinelServerPool { |
这个Redis Sentinel集群定义指定了三个redis sentinel实例,分别是10.2.2.2:7500、10.2.2.3:7500、10.2.2.4:7500,定义了两组redis,分别是shard001、shard002。没有指定任何静态redis节点。所有redis实例都没有开启密码认证,它们都具有16个db。predixy用crc16计算key的哈希值,然后通过modula也就是求模的办法将key分布到shard001或shard002中去。由于MasterReadPriority为60,比DynamicSlaveReadPriority的50要大,所以读请求都会分发到redis master节点,RefreshInterval为1,每一秒钟向redis sentinel发送请求刷新集群信息。redis实例失败累计达到10次后将该redis实例标记失效,每间隔1秒钟后检查其是否恢复。
Redis Cluster形式
定义格式如下:
1 | ClusterServerPool { |
参数说明:
- 可选的参数和Redis Sentinel模式同名参数含义一样
- Servers:在这里列出redis cluster里的redis实例,列出的为静态节点,未列出而是通过集群信息发现的则为动态节点
一个例子:
1 | ClusterServerPool { |
该定义指定通过redis实例192.168.2.107:2211和192.168.2.107:2212来发现集群信息,指定MasterReadPriority为0,表示不要将读请求分发到redis master节点。
多数据中心配置部分
predixy支持多数据中心,在redis部署跨数据中心的时候,可以将读请求分发给本数据中心的redis实例,避免跨数据中心访问。套用数据中心的概念,实际上即便没有多数据中心,也可以在需要从节点来分担读请求的时候通过本配置来控制请求分配,此时比如可以认为一个机架就是一个数据中心。
多数据中心配置格式:
1 | LocalDC name |
参数说明:
- LocalDC: 指定当前predixy所在的数据中心
- DC: 定义一个数据中心
- AddrPrefix: 定义该数据中心包括的ip前缀
- ReadPolicy: 定义从该数据中心读其它(包括自己)数据中心的优先级及权重
如果不用数据中心功能,那么不提供LocalDC和DataCenter定义即可。
一个多数据中心配置的例子:
1 | DataCenter { |
这个例子定义了三个数据中心,分别是bj、sh、sz。其中bj数据中心包括ip前缀为10.1的redis实例,这样predixy通过redis sentinel或者redis cluster发现节点的时候如果看到redis实例的地址前缀是10.1则会认为该实例在bj数据中心。predixy根据自身所在的数据中心来选择相应的读请求策略。
假设predixy在bj数据中心,bj读bj的优先级为50,高于另外两个,所以predixy会优先选择bj数据中心进行读操作,如果bj数据中心没有可用的redis节点,则会是sh数据中心,如果sh还没有节点,才会选择sz。
假设predixy在sh数据中心,predixy优先选择sh数据中心,如果sh数据中心没有可用的redis实例,因为bj和sh的优先级都为20,那么则会根据权重设置来分配流量,在这里,5份的请求去bj数据中心,2份的请求去sz。
前面在定义集群的时候有说过可以定义主从节点的读优先级,数据中心这里又有读优先级的概念,那么它们是如何工作的?原则就是在启用了数据中心的功能之后,先根据数据中心读策略选取数据中心、然后再在数据中心内应用集群的主从读优先级选择最终的redis实例。
延迟监控配置部分
predixy提供了强大的延迟监控的功能,可以记录predixy处理请求的时间,对predixy来说,这个时间其实主要就是请求redis的时间。
延迟监控定义格式如下:
1 | LatencyMonitor name { |
参数说明:
- LatencyMonitor: 定义一个延迟监控
- Commands: 指定该延迟监控记录哪些redis命令,+ cmd表示监控该命令,- cmd表示不监控该命令,如果cmd为all则表示所有命令。
- TimeSpan: 定义延迟桶,以微秒为单位,必须是一个严格递增的序列。
可以定义多个LatencyMonitor以便监控不同的命令。
延迟监控配置例子:
1 | LatencyMonitor all { |
上面的例子定义了三个延迟监控,其中all监控除了blpop/brpop/brpoplpush外的所有命令,get监控get命令,set监控set/setnx/setex命令。这里的耗时桶定义并不适用与所有情况,在实际使用的时候需要调整以更精确的反应真实的耗时情况。
查看耗时监控,通过INFO命令来查看,有三种使用方式:
查看所有延迟定义的整体信息
命令:
1 | redis> INFO |
此时看到的结果列在最后的就是整体的延迟信息。
查看单个延迟定义的信息
命令:
1 | redis> INFO Latency <name> |
其中
查看某个后端redis实例延迟信息
命令:
1 | redis> INFO ServerLatency <serv> [name] |
其中
延迟信息格式说明,下面是延迟定义all的整体信息一个例子:
1 | LatencyMonitorName:all |
- 第一列为<=,则第二列表示小于等于该耗时,第三列表示这个范围耗时的总和,第四列表示请求数,第五列表示累计的请求占总请求的百分比,
- 第一列为>,则第二列表示大于该耗时的请求,后两列含义同上。本行最多只会出现一次,如果位于本行的请求数过多,则说明延迟定义指定的耗时桶不够合适。
- 第一列为T,这一行只会出现一次,且总在最后。第二列表示所有请求的平均耗时,第三列表示总的请求耗时之和,第四列表示总的请求数。
- 本文作者: 忘忧症
- 本文链接: https://NepenthesZGW.github.io/2020/08/25/redis/predixy/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!