Jamzy Wang

life is a struggle,be willing to do,be happy to bear~~~

redis分片代理Twemproxy

2014-10-16 12:19

redis 3.0版正式引入了cluster这个特性(目前cluster还没有正式release,还在beta中),在这之前redis并没有提供集群服务。那么在redis 3.0之前redis集群是如何实现的呢? 数据是如何分片的呢? 本文将具体介绍一种被广泛应用到redis集群的工具——Twemproxy

redis集群中的核心问题是数据如何分片,在何时分片。redis实现的方案有如下几种:

1) 客户端分片

客户端使用算法完成hash, 比如使用consistent hash。

2) 代理分片

通过proxy层来完成,proxy通过hash算法,完成映射,如Twemproxy。antirez写过一篇对twemproxy的介绍http://antirez.com/news/44,他认为twemproxy是目前Redis 分片管理的最好方案,虽然antirez的Redis cluster正在实现并且对其给予厚望,但是我从现有的cluster实现上还是认为cluster除了增加redis复杂度,对于集群的管理没有twemproxy来的轻量和有效。

3) 请求路由

client 的请求叫做“query”,clients随便选择一个节点将query发出,位于分布式集群内的节点完成query的路由,保证将query路由到正确的query执行方,有点类似于IP网络的数据包的路由了。redis cluster使用这种方式的一个改进版本,当集群内机器知道需要将query forward到目标时,自己不进行proxy,而是返回client端一个redirect(类似http请求的302)让cleint来重定向。

twemproxy

twemproxy,也叫nutcraker。是twitter开源的一个redis和memcache代理服务器。 那么它做了什么呢?

1
2
3
1) 在客户端和众多redis实例间作为代理。
2) 在配置的redis实例之间进行自动数据分片。
3) 支持不同的分片策略和哈希方法。

此处输入图片的描述

twemproxy部署

twemproxy的安装非常简单,参考官网即可,下面简单说明一下twemproxy的配置。twemproxy的配置文件位于conf/nutcracker.yml,下面是简单几个配置样例:

1
2
3
4
5
6
7
8
9
10
11
12
13
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:6379:1 server1
   - 127.0.0.1:6380:2 server2
   - 127.0.0.1:6381:3 server3
   - 127.0.0.1:6382:1 server4

上述配置项代表的含义如下:

beta:当前分片配置起的名字,一个配置可以有多个分片策略,也就是说可以有多个上述配置块。

listen:twemproxy监听的ip和端口,客户端的请求将被发往这个ip和端口。

hash:对key进行哈希的哈希算法,当前支持的hash算法有: md5、crc16、crc32 、crc32a、fnv1_64、fnv1a_64、fnv1_32、fnv1a_32、hsieh、murmur、jenkins

hash_tag:哈希标签,只对“{}”部分的key进行哈希。

distribution:分片算法,当前支持的分片算法有:ketama(一致性hash算法的一种实现)、modula、random

timeout:连接后端redis或接收响应的超时时间,默认是永久等待。 redis:是否是redis代理,如果是false则是memcached代理。

servers:代理服务器列表,该列表会使用distribution配置的分片算法进行分片。servers中IP地址后的数字代表服务器的权重,权重越高,分片到该服务器的数据越多。

twemproxy特性

支持失败节点自动删除

可以设置重新连接该节点的时间,也可以设置连接多少次之后删除该节点。twemproxy最重要的一个特性就在于它能在节点失败的时候删除它,然后可以在一段时间以后重新尝试连接,又或者可以严格按照配置文件中写的键与服务器之间对应关系进行连接。这意味着twemproxy能胜任把redis当做数据存储的场景,也能够胜任当做缓存来使用。

支持设置HashTag

通过HashTag可以自己设定将两个key哈希到同一个实例上去。

减少与redis的直接连接数

保持与redis的长连接

减少了客户端直接与服务器连接的连接数量

自动分片到后端多个redis实例上

多种hash算法:md5、crc16、crc32 、crc32a、fnv1_64、fnv1a_64、fnv1_32、fnv1a_32、hsieh、murmur、jenkins

多种分片算法:ketama(一致性hash算法的一种实现)、modula、random

可以设置后端实例的权重

避免单点问题

可以平行部署多个代理层,通过HAProxy做负载均衡,将redis的读写分散到多个twemproxy上。

支持状态监控

可设置状态监控ip和端口,访问ip和端口可以得到一个json格式的状态信息串

可设置监控信息刷新间隔时间

使用 pipelining 处理请求和响应

连接复用,内存复用

将多个连接请求,组成reids pipelining统一向redis请求

并不是支持所有redis命令

不支持redis的事务操作

使用SIDFF, SDIFFSTORE, SINTER, SINTERSTORE, SMOVE, SUNION and SUNIONSTORE命令需要保证key都在同一个分片上。

twemproxy支持的redis命令。

twemproxy性能

根据 redis 作者的测试结果,在大多数情况下,twemproxy 的性能相当不错,和直接操作redis 相比,最多只有20%的性能损失。这对于它带来的好处来说真的是微不足道了。

twemproxy官方给出的性能测试数据:

PerformanceSetup

1
2
3
4
5
6
7
  * redis-server running on machine A.
  * nutcracker running on machine A as a local proxy to redis-server.
  * redis-benchmark running on machine B.
  * machine A != machine B.
  * nutcracker built with --enable-debug=no
  * nutcracker running with mbuf-size of 512 (-m 512)
  * redis-server built from redis 2.6 branch

redis-benchmark against redis-server

1
2
3
4
5
6
7
8
9
10
11
12
13
$ redis-benchmark -h <machine-A> -q -t set,get,incr,lpush,lpop,sadd,spop,lpush,lrange -c 100 -p 6379
SET: 89285.71 requests per second
GET: 92592.59 requests per second
INCR: 89285.71 requests per second
LPUSH: 90090.09 requests per second
LPOP: 90090.09 requests per second
SADD: 90090.09 requests per second
SPOP: 93457.95 requests per second
LPUSH (needed to benchmark LRANGE): 89285.71 requests per second
LRANGE_100 (first 100 elements): 36496.35 requests per second
LRANGE_300 (first 300 elements): 15748.03 requests per second
LRANGE_500 (first 450 elements): 11135.86 requests per second
LRANGE_600 (first 600 elements): 8650.52 requests per second

redis-benchmark against nutcracker proxing redis-servernormal

1
2
3
4
5
6
7
8
9
10
11
12
13
$ redis-benchmark -h <machine-A> -q -t set,get,incr,lpush,lpop,sadd,spop,lpush,lrange -c 100 -p 22121
SET: 85470.09 requests per second
GET: 86956.52 requests per second
INCR: 85470.09 requests per second
LPUSH: 84745.77 requests per second
LPOP: 86206.90 requests per second
SADD: 84745.77 requests per second
SPOP: 86956.52 requests per second
LPUSH (needed to benchmark LRANGE): 84745.77 requests per second
LRANGE_100 (first 100 elements): 29761.90 requests per second
LRANGE_300 (first 300 elements): 12376.24 requests per second
LRANGE_500 (first 450 elements): 8605.85 requests per second
LRANGE_600 (first 600 elements): 6587.62 requests per second

下面我们来测试一下twemproxy的功能特性,redis机器的配置如下,twemproxy中的配置同前文。

1
2
3
4
5
6
7
8
master:
192.168.137.250:6379
192.168.137.251:6379
192.168.137.252:6379
192.168.137.253:6379
twemproxy:
192.168.137.250:22122
192.168.137.251:22122

我们得到的测试结论如下:

(1) redis 数据能基本上根据 key 来进行比较均衡的分布。

(2) 一台 redis 挂掉后twemproxy 能够自动摘除。恢复后twemproxy 能够自动识别、恢复并重新加入到 redis 组中重新使用。

(3) redis挂掉后数据是否丢失依据 redis 本身的策略配置,与 twemproxy 基本无关。

(4) 如果要新增加一台 redis,twemproxy需要重启才能生效并且数据不会自动重新reblance,需要人工单独写脚本来实现。

(5) 如同时部署多个 twemproxy,配置文件一致(测试配置为 distribution:ketama,modula),则可以从任意一个读取,都可以正确读取 key 对应的值。

(6) 如原来已经有 2 个节点 redis,后续有增加 2 个 redis,则数据分布计算与原来的 redis 分布无关,现有数据如果需要分布均匀的话,需要人工单独处理。

(7) 如果 twemproxy 的后端节点数量发生变化,twemproxy 相同算法的前提下,原来的数据 必须重新处理分布,否则会存在找不到 key 值的情况。

Ref

Comments