Twemproxy介绍Twitter的Twemproxy(https://github.com/twitter/twemproxy)是目前市面上使用最广泛的,用于redis集群服务。由于redis是单线程的,而且官方的集群也不是很稳定,应用广泛。Twemproxy是一种代理分片机制。Twemproxy作为代理,可以接受多个程序的访问,根据路由规则转发到后台的各个Redis服务器,然后原路返回。该方案很好地解决了单个Redis实例的承载问题。当然,Twemproxy本身也是单点的,需要使用Keepalived作为高可用方案(或LVS)。通过Twemproxy可以使用多台服务器横向扩展redis服务,可以有效避免单点故障问题。虽然使用Twemproxy需要更多的硬件资源,并且对redis的性能有一定的损失(在twitter测试中大概有20%左右),但是对于提高整个系统的HA也是相当划算的。其实twemproxy不仅实现了redis协议,还实现了memcached协议。这意味着什么?也就是说,twemproxy不仅可以代理redis,还可以代理memcached。Twemproxy的优点:1)对外暴露一个访问节点,降低程序复杂度。2)支持自动删除失效节点,可以设置重连节点的时间,可以设置连接次数删除节点,这种方式适用于缓存存储,否则会丢失Key;3)支持HashTag,可以通过HashTag自己设置两个KEYhash必须分配给同一个实例。4)多种hash算法,后台实例权重可设置。5)减少redis直连数:与redis保持长期连接,后台设置agent与每个redis的连接数,后台自动分片到多个redis实例。6)避免单点问题:可以并行部署多个代理层,客户端自动选择可用的。7)高吞吐量:连接多路复用,内存多路复用,多个连接请求形成redis流水线统一请求redis。Twemproxy的缺点:1)不支持对多值的操作,比如取子交集,集合求补。2)不支持Redis事务操作。3)申请的内存不会被释放。所有机器内存一定要大,需要定时重启,否则会出现客户端连接错误。4)不支持动态增删节点,修改配置后需要重启。5)改变节点时,系统不会重新分配现有数据。如果不写数据迁移的脚本,会丢失一些key(key本身存在于某个redis上,但是key散列到其他节点,导致“丢失”)。6)权重直接影响key的哈希结果,改变一个节点的权重会导致部分key丢失。7)Twemproxy默认是单线程的,但是大部分使用Twemproxy的公司都会进行二次开发,改成多线程。总体来说twemproxy还是很靠谱的。虽然性能上有所损失,但相对来说还是值得的,并且经过测试和广泛使用。有关更多详细信息,请参阅官方文档。另外,twemproxy只适用于静态集群,不适合需要动态增删节点和手动调整负载的场景。如果我们直接使用它,我们需要做开发和改进工作。https://github.com/wandoulabs/codis本系统基于twemproxy,增加了动态数据迁移等功能,具体使用方法有待进一步测试。Twemproxy使用的第一类架构:单节点Twemproxyps:节省硬件资源,但容易出现单点故障。第二种:高可用TwemproxyPS:浪费一半资源,但节点高可用。第三种:负载均衡TwemproxyPS:如果你是大型Redis或者Memcached应??用场景,可以做Twemproxy负载军和场景,即在高可用Twemproxy的基础上增加LVS节点,使用LVS(Linuxvirtualserver)来做Twemproxy的负载均衡,LVS是一种四层负载均衡技术,具有非常强大的代理能力,具体可以看本博客LVS章节的介绍。但是当你使用LVS时,Twemproxy和单点故障的问题又出现了。这时候就需要为LVS做高可用了。但是LVS也支持负载均衡,这可以通过使用OSPF路由技术来完成。而这个架构就是我目前在工作中使用的架构。另外,无论采用以上哪种架构方式,都无法避免Redis的单点故障,Redis的持久化也无法避免硬件故障的问题。如果一定要保证Redis数据访问的不间断,那么应该使用Redis集群模式。集群模式目前对JAVA支持的很好,在工作中也用的比较多。安装Twemproxy1,下载Twemproxygitclonehttps://github.com/twitter/twemproxy.git2,安装TwemproxyTwemproxy需要使用Autoconf编译配置。GNUAutoconf是一个工具,用于制作在Bourneshell下编译、安装和打包软件的配置脚本。Autoconf不受编程语言的限制,常用于C、C++、Erlang和Objective-C。配置脚本控制特定系统上软件包的安装。经过一系列的测试,configure脚本根据模板生成makefile和header文件,为某个系统调整软件包。Autoconf、Automake、Libtool等软件构成了GNU构建系统。Autoconf由DavidMacKenzie于1991年夏天编写,以支持他在自由软件基金会的编程工作。从那时起,Autoconf包含了许多人编写的改进,成为使用最广泛的自由编译配置软件。让我们开始使用autoreconf来编译和配置twemproxy:[root@wwwtwemproxy]#autoreconfconfigure.ac:8:error:Autoconfversion2.64orhigherisrequiredconfigure.ac:8:thetoplevelautom4te:/usr/bin/m4failedwithexitstatus:63aclocal:autom4tefailedwithexitstatus:63autoreconf:withexitstatus:63autoreconf:withexitstatus[acitstatusroot@wwwtwemproxy]#autoconf--versionautoconf(GNUAutoconf)2.63提示autoreconf版本太低,上面使用的是autoconf2.63版本,所以下载autoconf2.69版本编译安装。注意,如果你是CentOS6,那么你的默认版本是2.63,如果你是CentOS7,那么你的默认版本应该是2.69,如果你是Debian8或者Ubuntu16,那么你的默认版本也应该是2.69。反正如果执行autoreconf报错,说明版本低,需要自己编译安装。编译安装Autoconf[root@www~]#wgethttp://ftp.gnu.org/gnu/autoconf/autoconf-2.69.tar.gz[root@www~]#tarxvfautoconf-2.69.tar.gz[root@www~]#cdautoconf-2.69[root@wwwautoconf-2.69]#./configure--prefix=/usr[root@wwwautoconf-2.69]#make&&makeinstall[root@wwwautoconf-2.69]#autoconf--versionautoconf(GNUAutoconf)2.69编译和安装Twemproxy[root@www~]#cd/root/twemproxy/[root@wwwtwemproxy]#autoreconf-fvi[root@wwwtwemproxy]#./configure--prefix=/etc/twemproxyCFLAGS="-DGRACEFUL-g-O2"--enable-debug=full[root@wwwtwemproxy]#make&&makeinstall如果autoreconf-fvi报如下错误,是安装libtool工具,需要依赖libtool(如果是CentOS直接使用yuminstalllibtool,如果Debian,直接使用apt-getinstalllibtool即可)。autoreconf:Enteringdirectory`.'autoreconf:configure.ac:notusingGettextautoreconf:running:aclocal--force-Im4autoreconf:configure.ac:tracingautoreconf:configure.ac:addingsubdirectorycontrib/yaml-0.1.4toautoreconfautoreconf:Enteringdirectory`contrib/yaml-0.1.4'autoreconf:configure.ac:notusingAutoconfautoreconf:Leavingdirectory`contrib/yaml-0.1.4'autoreconf:configure.ac:notusingLibtooreconf:running:/usr/bin/autoconf--forceconfigure.ac:36:error:possiblyundefinedmacro:AC_PROG_LIBTOOLIfthistokenandothersarelegitimate,pleaseusem4_pattern_allow.SeetheAutoconfdocumentation.autoreconf:/usr/bin/autoconffailedwithexitstatus:1Twemproxy添加配置文件[root@wwtwemproxy]#mkdir/etc/twemproxy/conf[root@wwtwemproxy]#cat/etc/twemproxy/conf/nutcracker.ymlredis-cluster:listen:0.0.0.0:22122hash:fnv1a_64distribution:ketamatimeout:400backlog:65535preconnect:trueredis:trueserver_connections:1auto_eject_hosts:trueserver_retry_timeout:60000server_failure_limit:3servers:-172.16.0.172:6546:1redis01-172.16.0.172:6547:1redis02配置选项介绍:redis-cluster:给这个配置节起个名字,可以有多个配置节;listen:设置监听IP和port端口;hash:具体的hash函数,支持md5、crc16、crc32、finv1a_32、fnv1a_64、hsieh、murmur、jenkins等十多种,一般fnv1a_64就可以,默认也是fnv1a_64;hash_tag:hash_tag允许根据key的一部分计算key的hash值hash_tag由两个字符组成,一个是hash_tag的开头,一个是hash_tag的结尾,在开头和结尾之间hash_tag是计算key的hash值的部分,计算结果将用于选择服务器。例如:如果hash_tag定义为“{}”,那么“user:{user1}:ids”和“user:{user1}:tweets”的哈希值都是以“user1”为基础的,最终会是映射到同一服务器。而“user:user1:ids”会使用整个key来计算hash,可能映射到不同的服务器。distribution:指定hash算法,决定了上述hash后的key如何分布在多台服务器上。默认是“ketama”一致性哈希。ketama:ketama一致性哈希算法会根据服务器构造一个哈希环,并为环上的节点分配一个哈希范围。ketama的好处是在单个节点添加或删除后,可以最大程度的复用整个集群缓存的键值。modula:modula很简单,就是根据key值的hash值取模,根据取模的结果选择对应的server。random:随机就是随机选择一台服务器作为key-value操作的目标,不管key-value的hash是什么。timeout:设置twemproxy的超时时间。设置超时后,如果超过超时时间还没有服务器响应,则会向客户端发送超时错误信息SERVER_ERRORConnectiontimeout。backlog:监控TCPbacklog(连接等待队列的长度),默认为512。preconnect:指定twemproxy是否在系统启动时与所有redis建立连接,默认为false,布尔值;redis:指定该配置部分是否作为Redis的代理,如果redis不加true,则可以memcachedCluster作为代理(这是Twemproxy作为redis或memcachedcluster代理的唯一区别);redis_auth:如果你的后端Redis开启了鉴权,那么你需要redis_auth来指定鉴权密码;server_connections:twemproxy与每个redisserver的连接数,默认为1,如果大于1,可能会导致用户命令发送到不同的连接,可能导致命令的实际执行顺序与用户不一致-指定(类似于并发);auto_eject_hosts:当节点无法响应时是否拒绝,默认为true,但需要注意的是节点被移除后,由于机器数量的减少和机器hash位置的变化,一些密钥将无法被破解,但如果不删除程序连接会报错;server_retry_timeout:控制服务器连接的时间间隔,单位为毫秒,当auto_eject_hosts设置为true时,默认为30000毫秒;server_failure_limit:Redis连续超时的次数,如果超过这个次数,则视为无法连接,如果auto_eject_hosts设置为true,则此Redis将被移除;服务器:池中服务器的地址、端口和权重的列表,包括可选的服务器名称。如果提供了服务器名称,将用于确定服务器的顺序,从而提供相应的一致性哈希哈希环。否则,将使用定义服务器的顺序,并且可以用两种字符串格式指定“host:port:weight”或“host:port:weightname”。一般使用第二个别名,这样当其中一个Redis节点出现问题时,可以直接添加一个新的Redis节点而不用更改服务器名,这样twemproxy仍然使用相同的服务器名做hashring,所以other数据节点的数据不会有问题(只是挂点机器的数据丢失)。PS:一定要严格遵守Twemproxy配置文件的格式,否则会出现语法错误;另外,可以在Twemproxy配置文件中同时设置代理Redis集群或者Memcached集群,只需要定义不同的配置段即可。启动twemproxy(nutcracker),刚刚添加了配置文件,现在测试配置文件:[root@wwwtwemproxy]#/etc/twemproxy/sbin/nutcracker-tnutcracker:configurationfile'c??onf/nutcracker.yml'syntaxisok表示配置文件已经成功,现在开始运行nutcracker:[root@www~]#/etc/twemproxy/sbin/nutcracker-c/etc/twemproxy/conf/nutcracker.yml-p/var/run/nutcracker.pid-o/var/log/nutcracker.log-d选项说明:-h,--help#查看帮助文档,显示命令选项;-V,--version#查看nutcracker版本;-c,--conf-file=S#指定配置文件路径(default:conf/nutcracker.yml);-p,--pid-file=S#指定进程pid文件路径,默认关闭(default:off);-o,--output=S#设置日志输出路径,默认是标准错误输出(default:stderr);-d,--daemonize#作为守护进程运行;-t,--test-conf#测试配置脚本的正确性;-D,--describe-stats#打印状态描述;-v,--verbosity=N#设置日志级别(default:5,min:0,max:11);-s,--stats-port=N#设置状态监控端口,默认22222(default:22222);-a,--stats-addr=S#设置状态监控IP,default0.0.0.0(default:0.0.0.0);-i,--stats-interval=N#设置状态聚合间隔(default:30000msec);-m,--mbuf-size=N#设置mbufblockSize,单位字节(默认值:16384字节);PS:一般在生产环境中,都会使用进程管理工具来管理twemproxy的启动。比如supervisor或者pm2工具,避免进程挂掉时自动拉起进程验证是否正常启动/etc/twemproxy/conf/nutcracker.yml-p/var/run/nutcracker.pid-o/var/log/nutcracker.log-droot200060.00.0103252832pts/0S+18:480:00grepnutcracker[root@www~]#netstat-nplt|grep22122tcp000.0.0.0:221220.0.0.0:*LISTEN20002/nutcrackerTwemproxy代理Redis集群这里我们使用第一种方案在同一台主机上测试Twemproxy代理Redis集群,一个twemproxy和两个Redis节点(想加更多也可以)。Twemproxy使用上面的配置,下面只需要添加两个Redis节点。安装配置Redis在安装Redis之前,需要先安装Redis的依赖程序tcl。如果不安装tcl,Redis执行maketest时会报错。[root@www~]#yuminstall-ytcl[root@www~]#wgethttps://github.com/antirez/redis/archive/3.2.0.tar.gz[root@www~]#tarxvf3.2.0.tar.gz-C/usr/local[root@www~]#cd/usr/local/[root@wwwlocal]#mvredis-3.2.0redis[root@wwwlocal]#cdredis[root@wwwredis]#make[root@wwwredis]#maketest[root@wwwredis]#makeinstall配置两个Redis节点[root@www~]#mkdir/data/redis-6546[root@www~]#mkdir/data/redis-6547[root@www~]#cat/data/redis-6546/redis.confdaemonizeyespidfile/var/run/redis/redis-server.pidport6546bind0.0.0.0loglevelnoticelogfile/var/log/redis/redis-6546.log[root@www~]#cat/data/redis-6547/redis.confdaemonizeyespidfile/var/run/redis/redis-server.pidport6547bind0.0.0.0loglevelnoticelogfile/var/log/redis/redis-6547.logPS:简单提供两个Redis配置文件。如果开启了Redis鉴权,那么还需要在twemproxy中填写Redis密码。启动两个Redis节点[root@www~]#/usr/local/redis/src/redis-server/data/redis-6546/redis.conf[root@www~]#/usr/local/redis/src/redis-server/data/redis-6547/redis.conf[root@www~]#psaux|grepredisroot236560.00.0402043332?Ssl20:140:00redis-server0.0.0.0:6546root2426??30.00.0402043332?Ssl20:160:00redis-server0。0.0.0:6547验证Twemproxy读写数据。首先必须正确配置twemproxy配置项中的hostofservers,然后连接到Twemproxy的22122端口进行测试。[root@www~]#redis-cli-p22122127.0.0.1:22122>setkeyvlaueOK127.0.0.1:22122>getkey"vlaue"127.0.0.1:22122>FLUSHALLError:Serverclosedtheconnection127.0.0.1:22122>退出我们设置一个key,然后通过twemproxy获取数据,一切正常。但是在twemproxy中使用flushall命令是不行的,不支持。然后我们去连接两个redis节点,看数据是否出现在某个节点上。如果是,则说明twemproxy运行正常。[root@www~]#redis-cli-p6546127.0.0.1:6546>getkey(nil)127.0.0.1:6546>从上面的结果可以看出,数据是存放在6547节点上的。目前还没有很好的办法可以清楚的知道某个key存放在某个后端节点中。如何重新加载twemproxy?因为twemproxy没有提供启动脚本,所以是通过命令行参数启动的。所以不能使用twemproxy的reload操作。在生产环境中,无法重新加载(重新加载配置文件)的应用程序是一场灾难。给twemproxy添加或删除节点时,如果直接使用restart,肯定会影响线上业务。所以最好的办法就是重新加载。由于twemproxy没有提供,可以用kill命令加上一个signal,然后跟上twemproxy主进程的进度号。kill-SIGHUPPID注意PID是twemproxy主进程。
