一、介绍
1、简介
Twemproxy也叫nutcraker,是twtter开源的一个redis和memcache代理服务器程序。redis作为一个高效的缓存服务器,非常具有应用价值。但在用户数据量增大时,需要运行多个redis实例,此时将迫切需要一种工具统一管理多个redis实例,避免在每个客户端管理所有连接带来的不方便和不易维护,Twemproxy即为此目标而生。
Twemproxy 通过引入一个代理层,将其后端的多台 Redis实例进行统一管理与分配,使应用程序只需要在 Twemproxy 上进行操作,而不用关心后面具体有多少个真实的 Redis实例。
2、Twemproxy 示意图
3、特点
单线程工作,用C语言开发;
直接支持大部分的redis指令,redis客户端可以像访问正常redis实例一样访问TwemProxy。
支持失败节点自动删除;可以设置重新连接该节点的时间,还可以设置连接多少次之后删除该节点
支持设置HashTag;通过HashTag可以自己设定将同一类型的key映射到同一个实例上去。
减少与redis的直接连接数,保持与redis的长连接,可设置代理与后台每个redis连接的数目
自带一致性hash算法,能够将数据自动分片到后端多个redis实例上;支持多种hash算法,可以设置后端实例的权重,目前redis支持的hash算法有:one_at_a_time、md5、crc16、crc32、fnv1_64、fnv1a_64、fnv1_32、fnv1a_32、hsieh、murmur、jenkins。
支持redis pipelining request,将多个连接请求,组成reids pipelining统一向redis请求。
支持状态监控;可设置状态监控ip和端口,访问ip和端口可以得到一个json格式的状态信息串;可设置监控信息刷新间隔时间。
高效;对连接的管理采用epoll机制,内部数据传输采用“Zero Copy”技术,以提高运行效率,TwemProxy是目前效率最高的代理程序,与直接访问redis项目其效率损失只有10%左右。
4、生产常用架构
1)LVS集群:实现twemproxy的负载均衡,提高proxy的可用性和可扩张能力,使twemproxy的扩容对应用透明。
2)Twemproxy集群: 多个同构twemproxy(配置相同)同时工作,接受客户端的请求并转发请求给后端的redis。
3)Redis Master-Slave集群:redis master存储实际的数据,并处理twemproxy转发过来的数据读写请求。数据按照hash算法分布在多个redis实例上。
redis slave复制master的数据,作为数据备份。在master失效的时候,由sentinel把slave提升为master。
4)Sentinel集群:检测master主从存活状态,当redis master失效的时候,把slave提升为新master。
另外,通过调用一个notify script发送配置更改命令到每个twemproxy,twemproxy更新配置。之后的数据请求将会转发到更新后的redis master。
二、redis实例准备
配置并启动三个redis master示例,可参考前面的文章
机器ip为
10.0.0.107
10.0.0.106
10.0.0.105
vim /usr/local/redis/conf/redis.conf
bind 0.0.0.0 #监听地址更改,0.0.0.0代表监控所有网卡
port 6379 #监听端口更改,6379为默认
daemonize yes #是否后台启动, Redis 默认不是以守护进程的方式运行,可以通过该配置项修改,使用 yes 启用守护进程(Windows 不支持守护线程的配置为 no )
pidfile "/data/redis/redis.pid" #pid存放目录 当 Redis 以守护进程方式运行时,Redis 默认会把 pid 写入 /var/run/redis.pid 文件,可以通过 pidfile 指定,这里改为/data/redis/redis.pid
logfile "/data/redis/redis.log" #日志存放目录 日志记录方式,默认为标准输出stdout,如果配置 Redis 为守护进程方式运行,而这里又配置为日志记录方式为标准输出,则日志将会发送给 /dev/null
dir /data/redis/ #工作目录 指定本地数据库存放目录
#当这个redis为主时需要的密码
requirepass "123456"
#当这个redis为从时连接主使用的密码
masterauth "123456"
启动三个redis实例
/usr/local/redis/bin/redis-server /usr/local/redis/conf/redis.conf
查看状态,都是主实例
[root@localhost ~]# redis-cli
127.0.0.1:6379> auth 123456
OK
127.0.0.1:6379> info Replication
# Replication
role:master
connected_slaves:0
master_replid:463c2f80c5cead1107bf28e3c5f061b6ad97b8e2
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0
三、twemproxy安装
1、下载安装
在10.0.0.107上安装twemproxy,如果是centos6需要手动升级一下autoconf
yum install wget unzip libtool autoconf -y
wget 'https://codeload.github.com/twitter/twemproxy/zip/master'
unzip master
cd twemproxy-master
#测试一下环境,如果没报错则可以编译安装
CFLAGS="-ggdb3 -O0" autoreconf -fvi
./configure --prefix=/usr/local/twemproxy --enable-debug=log
make
make install
2、 安装验证,创建配置和日志文件夹
/usr/local/twemproxy/sbin/nutcracker -V
cd /usr/local/twemproxy/; mkdir -pv conf logs
3、twemproxy配置
vim /usr/local/twemproxy/conf/nutcracker.yml
beta:
listen: 10.0.0.107:22122
hash: fnv1a_64
hash_tag: "{}"
distribution: ketama
auto_eject_hosts: false
timeout: 400
redis: true
redis_auth: 123456
servers:
- 10.0.0.107:6379:1 master1
- 10.0.0.106:6379:1 master2
- 10.0.0.105:6379:1 master3
配置说明
beta为自定义服务器池的名字,可以设置多个服务器池
(1)listen
twemproxy监听的端口。可以以ip:port或name:port的形式来书写。
(2)hash
可以选择的key值的hash算法: one_at_a_time、md5、crc16、crc32 、crc32a 、fnv1_64、fnv1a_64、fnv1_32、fnv1a_32、hsieh、murmur、jenkins ,如果没选择,默认是fnv1a_64。 用于将键映射为一个散列值
(3)hash_tag
hash_tag允许根据key的一个部分来计算key的hash值。hash_tag由两个字符组成,一个是hash_tag的开始,另外一个是hash_tag的结束,在hash_tag的开始和结束之间,是将用于计算key的hash值的部分,计算的结果会用于选择服务器。 例如:如果hash_tag被定义为”{}”,那么key值为"user:{user1}:ids"和"user:{user1}:tweets"的hash值都是基于”user1”,最终会被映射到相同的服务器。而"user:user1:ids"将会使用整个key来计算hash,可能会被映射到不同的服务器。
(4) distribution
存在ketama、modula和random3种可选的配置。决定键被分布到哪个服务器,其含义如下:
ketama一致性hash算法,会根据服务器构造出一个hash ring,并为ring上的节点分配hash范围。ketama的优势在于单个节点添加、删除之后,会最大程度上保持整个群集中缓存的key值可以被重用。
modula非常简单,就是根据key值的hash值取模,根据取模的结果选择对应的服务器。
random是无论key值的hash是什么,都随机的选择一个服务器作为key值操作的目标。
(5)timeout
单位是毫秒,是连接到server的超时值。默认是永久等待。
(6)backlog
监听TCP 的backlog(连接等待队列)的长度,默认是512。
(7)preconnect
是一个boolean值,指示twemproxy是否应该预连接pool中的server。默认是false。
(8)redis
是一个boolean值,用来识别到服务器的通讯协议是redis还是memcached。默认是false。
(9)server_connections
每个server可以被打开的连接数。默认,每个服务器开一个连接。
(10)auto_eject_hosts
是一个boolean值,用于控制twemproxy是否应该根据server的连接状态重建群集。这个连接状态是由server_failure_limit阀值来控制。 默认是false。
(11)server_retry_timeout
单位是毫秒,控制服务器连接的时间间隔,在auto_eject_host被设置为true的时候产生作用。默认是30000 毫秒。
(12)server_failure_limit
控制连接服务器的次数,在auto_eject_host被设置为true的时候产生作用。默认是2。
(13)servers
一个pool中的服务器的地址、端口和权重的列表,包括一个可选的服务器的名字,如果提供服务器的名字,将会使用它决定server的次序,从而提供对应的一致性hash的hash ring。否则,将使用server被定义的次序。
4、twemproxy 测试配置语法
[root@localhost redis]# /usr/local/twemproxy/sbin/nutcracker -t -c /usr/local/twemproxy/conf/nutcracker.yml
nutcracker: configuration file '/usr/local/twemproxy/conf/nutcracker.yml' syntax is ok
5、启动 twemproxy
/usr/local/twemproxy/sbin/nutcracker -d -c /usr/local/twemproxy/conf/nutcracker.yml -p /usr/local/twemproxy/logs/redisproxy.pid -o /usr/local/twemproxy/logs/redisproxy.log
[root@localhost redis]# /usr/local/twemproxy/sbin/nutcracker -d -c /usr/local/twemproxy/conf/nutcracker.yml -p /usr/local/twemproxy/logs/redisproxy.pid -o /usr/local/twemproxy/logs/redisproxy.log
nutcracker用法与命令选项
Usage: nutcracker [-?hVdDt] [-v verbosity level] [-o output file]
[-c conf file] [-s stats port] [-a stats addr]
[-i stats interval] [-p pid file] [-m mbuf size]
Options:
-h, –help : 查看帮助文档,显示命令选项
-V, –version : 查看nutcracker版本
-t, –test-conf : 测试配置脚本的正确性
-d, –daemonize : 以守护进程运行
-D, –describe-stats : 打印状态描述
-v, –verbosity=N : 设置日志级别 (default: 5, min: 0, max: 11)
-o, –output=S : 设置日志输出路径,默认为标准错误输出 (default: stderr)
-c, –conf-file=S : 指定配置文件路径 (default: conf/nutcracker.yml)
-s, –stats-port=N : 设置状态监控端口,默认22222 (default: 22222)
-a, –stats-addr=S : 设置状态监控IP,默认0.0.0.0 (default: 0.0.0.0)
-i, –stats-interval=N : 设置状态聚合间隔 (default: 30000 msec)
-p, –pid-file=S : 指定进程pid文件路径,默认关闭 (default: off)
-m, –mbuf-size=N : 设置mbuf块大小,以bytes单位 (default: 16384 bytes)
6、查看进程及日志
[root@localhost redis]# ps -ef |grep nutcarcker
root 12040 5054 0 15:25 pts/0 00:00:00 grep --color=auto nutcarcker
[root@localhost redis]# tail /usr/local/twemproxy/logs/redisproxy.log
[2020-10-12 15:24:56.850] nc.c:187 nutcracker-0.4.1 built for Linux 3.10.0-862.el7.x86_64 x86_64 started on pid 12028
[2020-10-12 15:24:56.850] nc.c:192 run, rabbit run / dig that hole, forget the sun / and when at last the work is done / don't sit down / it's time to dig another one
[2020-10-12 15:24:56.851] nc_core.c:43 max fds 10240 max client conns 10204 max server conns 4
[2020-10-12 15:24:56.851] nc_stats.c:851 m 4 listening on '0.0.0.0:22222'
[2020-10-12 15:24:56.862] nc_proxy.c:217 p 6 listening on '10.0.0.107:22122' in redis pool 0 'beta' with 3 servers
7、进行测试
(1)访问twemproxy端口,-a 指定密码,设置一个key:value
[root@localhost redis]# redis-cli -h 10.0.0.107 -a 123456 -p 22122
10.0.0.107:22122> get name
(nil)
10.0.0.107:22122> set name wangxiaoyu
OK
10.0.0.107:22122> get name
"wangxiaoyu"
(2)访问各个redis实例,查看key在哪个实例上,可以看到在10.0.0.106这个redis实例上
10.0.0.107
[root@localhost ~]# redis-cli -a 123456
127.0.0.1:6379> info Keyspace
# Keyspace
10.0.0.106
[root@localhost ~]# redis-cli -a 123456
127.0.0.1:6379> info Keyspace
# Keyspace
db0:keys=1,expires=0,avg_ttl=0
10.0.0.105
[root@localhost ~]# redis-cli -a 123456
127.0.0.1:6379> info Keyspace
# Keyspace
8、往redis集群批量写数据,查看500个key的分布情况
(1)执行命令批量写入key
for line in `seq -w 500` ;do redis-cli -h 10.0.0.107 -a 123456 -p 22122 set key3_${line} value_${line}; done
(2)然后查看各个实例的key分布情况,可以看到根据算法分布到了各个实例上
10.0.0.107
127.0.0.1:6379> info Keyspace
# Keyspace
db0:keys=319,expires=0,avg_ttl=0
10.0.0.106
127.0.0.1:6379> info Keyspace
# Keyspace
db0:keys=101,expires=0,avg_ttl=0
10.0.0.105
127.0.0.1:6379> info Keyspace
# Keyspace
db0:keys=81,expires=0,avg_ttl=0