简介
由于单个redis实例对大内存管理能力有限(经验是6-8G比较适合,而内存的总大小尽量在系统内存的60%~80%,因为客户端、主从复制都是需要内存的,所以一个128G的内存最好分配称8G*10的redis实例),过大内存将导致redis性能大幅下降。所以我们需要redis集群来提高redis性能。
虽然2015年4月2号的时候redis的3.0.0发布了,支持redis cluster,但是还没有过生产环境的大幅应用来验证其可靠性,所以Twemproxy就成了我们现在对redis集群的最佳选择。
下面是其简单介绍,介绍的已经很详细了:
http://www.oschina.net/translate/twemproxy-a-twitter-redis-proxy
其实Twemproxy就是一个redis的代理,用于实现分片、HashTag、减少连接数等功能;尤其在有大量应用服务器的场景下Twemproxy的角色就凸显了,能有效减少连接数。
下面是集群的架构图

特性
- 支持失败节点自动删除
可以设置重新连接该节点的时间 可以设置连接多少次之后删除该节点 该方式适合作为cache存储
- 支持设置HashTag
通过HashTag可以自己设定将两个KEYhash到同一个实例上去。
- 减少与redis的直接连接数
保持与redis的长连接 可设置代理与后台每个redis连接的数目
- 自动分片到后端多个redis实例上
多种hash算法:能够使用不同的策略和散列函数支持一致性hash。 可以设置后端实例的权重
- 避免单点问题
可以平行部署多个代理层.client自动选择可用的一个
- 支持redis pipelining request
支持请求的流式与批处理,降低来回的消耗
- 支持状态监控
可设置状态监控ip和端口,访问ip和端口可以得到一个json格式的状态信息串 可设置监控信息刷新间隔时间
- 高吞吐量
连接复用,内存复用。 将多个连接请求,组成reids pipelining统一向redis请求。
缺点与不足
不支持针对多个值的操作,比如取sets的子交并补等(MGET 和 DEL 除外)。
不支持Redis的事务操作。
出错提示还不够完善。(发现错误命令就会返回服务器关闭了连接)
也不支持select操作。
其实Twemproxy不支持很多命令,但是大体上不影响使用,有些命令只支持根据分片规则设置过分片标签的key,下面会详细介绍各个配置参数。具体支持与不支持的命令如下:
https://github.com/twitter/twemproxy/blob/master/notes/redis.md
构建Twemproxy
在linux上是非常容易构建的,但是需要这几个工具:autoconf、automake、libtool。安装方式大家自己google吧。接着执行如下命令构建:
$ git clone git@github.com:twitter/twemproxy.git
$ cd twemproxy
$ autoreconf –fvi
$ ./configure --enable-debug=full
$ make
$ src/nutcracker –h
这里要注意下,如上安装方式在有些服务器上可能在大量如mset时可能导致Twemproxy崩溃,需要使用如 CFLAGS="-O1" ./configure && make或CFLAGS="-O3 -fno-strict-aliasing" ./configure && make来安装。其实这些官方github上都有介绍:
https://github.com/twitter/twemproxy
配置
配置文件在conf/nutcracker.yml,下面是简单的配置样例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
alpha: listen: 127.0.0.1:22121 hash: fnv1a_64 distribution: ketama auto_eject_hosts: true redis: true server_retry_timeout: 2000 server_failure_limit: 1 servers: - 127.0.0.1:6379:1 beta: listen: 127.0.0.1:22122 hash: fnv1a_64 hash_tag: "{}" distribution: ketama auto_eject_hosts: false timeout: 400 redis: true servers: - 127.0.0.1:6380:1 server1 - 127.0.0.1:6381:1 server2 - 127.0.0.1:6382:1 server3 - 127.0.0.1:6383:1 server4 |
alpha:是给当前分片配置起的名字,一个配置可以有多个分片策略。
listen:监听的ip和端口(ip:port或者name:port)。
hash:散列算法。
hash_tag:哈希标签。
distribution:分片算法。
timeout:连接后端Redis或接收响应的超时时间,默认是永久等待。
redis:是否是redis代理,如果是false则是memcached代理。
servers:代理的服务器列表,该列表会使用distribution配置的分片算法进行分片。
hash算法
one_at_a_time
md5
crc16
crc32 (crc32 implementation compatible with libmemcached)
crc32a (correct crc32 implementation as per the spec)
fnv1_64
fnv1a_64
fnv1_32
fnv1a_32
hsieh
murmur
Jenkins
哈希标签
允许使用key的一部分来分配键的存储位置。比如设置为{},则p:{id}:c和p:{id}:n会散列到一台服务器上。(我们仔细看下官方命令支持的文档,发现里面有一部分命令需要在一个实例的时候才支持使用,比如SUNION)
分片算法
- ketama(一致性Hash算法):
ketama一致性hash算法,会根据服务器构造出一个hash ring,并为ring上的节点分配hash范围。ketama的优势在于单个节点添加、删除之后,会最大程度上保持整个群集中缓存的key值可以被重用。
- modula(取模):
modula就是根据key值的hash值取模,根据取模的结果选择对应的服务器。
- random(随机算法):
andom就是无论key值的hash是什么,都随机的选择一个服务器作为key值操作的目标。这种分片适合只读缓存。
servers
这个格式如下:
servers:
- ip:port:weight alias
- ip:port:weight alias
最好加上别名,这样可以在一个实例宕机的时候,更换机器只需要使用之前机器的别名,就可以继续映射了,如果没有别名,就得全部重新对应。
其他参数:
backlog |
监听TCP 的backlog(连接等待队列)的长度,默认是512。 |
preconnect |
是一个boolean值,指示twemproxy是否应该预连接pool中的server。默认是false。 |
server_connections |
每个server可以被打开的连接数。默认,每个服务器开一个连接。 |
auto_eject_hosts |
是一个boolean值,用于控制twemproxy是否应该根据server的连接状态重建群集。这个连接状态是由server_failure_limit阀值来控制。 默认是false。 (是否在节点故障无法响应时自动摘除该节点,如果作为存储需要设置为为false) |
server_retry_timeout |
单位是毫秒,控制服务器连接的时间间隔(重新连接一个临时摘掉的故障节点的间隔),在auto_eject_host被设置为true的时候产生作用。默认是30000 毫秒。 |
server_failure_limit |
控制连接服务器的次数(节点故障无法响应多少次从一致性Hash环临时摘掉它),在auto_eject_host被设置为true的时候产生作用。默认是2。 |
关于key值长度的限制
memcache限制key值在250字符以内,redis则没什么限制,由于twemproxy将key值存放在连续的内存之中,所以twemproxy的key值的最大长度受到mbuf长度的限制。
mbuf的长度由-m指定,默认是16384字节,一般够用了。如果遇到key值过长的问题,可以调整这个参数。
mbuf的含义&调整
最小512字节,最大65536字节,默认16384字节。可以通过命令行的-m参数调整。
mbuf是twemproxy引以为傲的zero-copy技术的底层支撑,zero-copy意味着从客户端接收的数据直接被提交到redis-server,不需要经过中间的copy环节(看似不难,实际上操作起来很难做到)。
很明显,大尺寸的mbuf会增加性能,减少分包的次数,但是会增加对内存的消耗。
如何估计twemproxy的mbuf对内存的需求呢?公式如下:
max(client_connections, server_connections) * 2 * mbuf-size
因为存在client->twemproxy以及twemproxy->redis-server两个连接,所以mbuf是需要双份的。
大多客户端的连接会大于服务器连接池预设的连接数。我们假设1000个客户端连接,mbuf-size是16KB,那么大概会消耗掉1000*2*16KB=32M左右的内存。
启动
下面是启动参数:
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 : this help
-V, --version : show version and exit
-t, --test-conf : test configuration for syntax errors and exit
-d, --daemonize : run as a daemon
-D, --describe-stats : print stats description and exit
-v, --verbose=N : set logging level (default: 5, min: 0, max: 11)
-o, --output=S : set logging file (default: stderr)
-c, --conf-file=S : set configuration file (default: conf/nutcracker.yml)
-s, --stats-port=N : set stats monitoring port (default: 22222)
-a, --stats-addr=S : set stats monitoring ip (default: 0.0.0.0)
-i, --stats-interval=N : set stats aggregation interval in msec (default: 30000 msec)
-p, --pid-file=S : set pid file (default: off)
-m, --mbuf-size=N : set size of mbuf chunk in bytes (default: 16384 bytes)
小结
使用Twemproxy时为了避免单点故障的问题,我们可以同时使用两个Twemproxy都代理那些redis节点,然后使用Jedis分片来使用。
另外豆瓣在去年年底出的Codis也是非常不错的,架构略有不同;同时使用Pre-Sharding机制,事先定好支持1024片,使得其扩容比较容易。性能测试结果好像很不错,同时支持Twemproxy的无缝迁移。
Redis Cluster
在这种机制下,没有中心节点(和代理模式的重要不同之处)。所以,一切开心和不开心的事情,都将基于此而展开。Redis Cluster将所有Key映射到16384个Slot中,集群中每个Redis实例负责一部分,业务程序通过集成的Redis Cluster客户端进行操作。客户端可以向任一实例发出请求,如果所需数据不在该实例中,则该实例引导客户端自动去对应实例读写数据。Redis Cluster的成员管理(节点名称、IP、端口、状态、角色)等,都通过节点之间两两通讯,定期交换并更新。
由此可见,这是一种非常“重”的方案。已经不是Redis单实例的“简单、可依赖”了。可能这也是延期多年之后,才近期发布的原因之一。
本文原创于赵伊凡BLOG
©原创文章,转载请注明来源: 赵伊凡's Blog
©本文链接地址: Twemproxy,Twitter 发布的 Redis 代理中间件
Twemproxy 已经被twitter弃用,而且不能支持resharding,自身集群管理功能很弱,建议使用codis
嗯,文中也提到了可以无缝迁移到Codis,这个可以考虑下。
弃用的消息哪来的,Codis的好处不可否认。
Twitter has multiple attempts at building a Redis cluster. Twemproxy which is not used by Twitter internally, it was built for Twemcache and Redis support was added. Two more solutions were based on proxy style routing
http://highscalability.com/blog/2014/9/8/how-twitter-uses-redis-to-scale-105tb-ram-39mm-qps-10000-ins.html