一、问题描述

在大访问量的Web服务中,MC集群作为缓解后端数据源访问压力的中间层已经成为了不可缺少的一部分,机器数量越来越大,维护成本也变得越来越高了,其中的问题有:

  • 故障机器自动剔除。后端某台MC机器宕机时,需要及时发现并将该机器从集群中移除。
  • 透明运维。需要能够在不用业务方做任何修改的情况下,快速的增加或迁移机器。
  • 跨机房同步。MC夸多个机房,并且每个机房的数据独立时,就需要考虑MC数据的一致性问题。

面临以上问题,传统的直接将MC服务器IP写在配置文件中无法满足及时响应的需求。为了解决这些问题,huati.weibo.com曾使用了一个基于Zookeeper的中间件来自动同步配置,但或多或少存在一些问题,于是我们决定尝试WCCS.

二、WCCS介绍

WCCS是由 @laruence 带领的微博主站架构研发部发起,由 @猫爷宋Qi 同学主导开发的一个MC中间件服务,它参考Twemproxy实现了自动检查MC的存活情况并自动剔除故障节点的功能,它支持根据key的前缀做正则匹配后在集群中定制分发策略,还可对hot key进行多机复制以达到分散压力的效果等。

除此之外WCCS还根据微博的业务特点,提供了多个集群间数据同步的功能,这样就可以将机房A的数据自动同步机房B,显著的提高了可用性。在进程模型方面,WCSS采用了和apache类似的多进程模型,通过worker进程接受和分发MC请求,配置为长连接方式并启动后,每个worker进程与后端的每个MC维持固定个数的连接。并支持对同一个pool中的不同MC端口设定不同的权重,以达到一定程度上的SLA。

下面用一个配置文件来展示WCCS的功能:

server: {

host = "0.0.0.0";  //监听的IP

port = 2888; //监听的端口

daemon = true; //是否以daemon方式运行

workers_num = 10; //启动多少个子进程

pid = "/usr/local/sinasrv2/var/run/wccs.pid";

};

pool:       //WCCS使用pool的方式对MC进行分组管理

(

{

name = "PoolDefault";    //pool的名字

timeout = 1000;    //与MC连接的超时时间

preconnect = true;    //是否使用持久连接

auto_eject_hosts = true;    //是否开启自动剔除故障MC实例

backend_connections = 20;    //每个worker与每个MC实例的连接数

backend_failure_limit = 500;  //触发自动剔除的最大失败次数

backend_retry_timeout = 30000; //自动重连被剔除机器的时间间隔,单位为毫秒

backend:     //pool对应的MC实例

(

{ ip = "10.73.19.37"; port = 7943; weight = 1 }, //weight指定MC实例权重

//....

);

},

);

keymap:

(

{

prefix = "*"; //路由前缀, WCCS支持将指定前缀的key分发到指定的pool中

pool = "PoolDefault"; //pool的名字

distribution = "ketama"; //分布策略采用一致性Hash,支持多种分发算法

hash = "md5";  //使用md5作为hash策略,支持多种hash算法

hash_tag = "{}";

need_sync = false; //是否开启跨机房同步

},

);

###以下为跨机房同步相关配置
                sync: {    //WCCS同步相关配置

dir = “/var/wccsdata”,  //开启跨机房同步时,用于记录MC的更新操作日志

backend :    //需要同步的WCCS端口

(

{ip = “127.0.0.1”; port = 2888},    // 位于机房B的WCCS集群

{ip = “127.0.0.1”; port = 2810}    // 位于机房C的WCCS集群

//....

)

            }

三、 对WCCS的一些测试

为了了解WCCS的特性,我对它进行了一些测试,重点测试了以下几点:

  1. keymap机制是如何工作的?
  2. 是否能及时自动剔除故障机器?
  3. 性能如何?
  4. 参数如何配配置才能够达到最大性能?

压测工具采用mcperf. 支持高并发访问,并可以输出清晰的测试报告。同时使用memcache-top观察后端MC的使用状况。

测试环境准备

  • 机器配置:
  • 网卡:1000M/s
  • CPU: 2.4GHz   12(逻辑)核心
  • IP : 10.13.2.143
  • 内存:48G

部署方式:

在10.13.2.143上同时部署MC和WCCS,MC端口为11211,11212,各分配1G的最大使用内

存,WCCS端口为2888,WCCS上仅配置一个默认池

下面是我的测试步骤

1. keymap机制是如何工作的

给WCCS配置两个pool, DefaultPool和UserPool,其中DefaultPool

pool:       
(
    {
        name = "DefaultPool"; 
        backend: 
        (
             { ip = "10.2.13.143"; port = 21111; weight = 1 }, //仅一个实例,端口21111
        );
        //...
    },
      {
        name = "UserPool"; 
        backend: 
        (
             { ip = "10.2.13.143"; port = 21112; weight = 1 }, //仅一个实例,端口21112
        );
        //...
    },
);
keymap: (
    {
        prefix = "*";
        pool = "DefaultPool";
        distribution = "ketama";
        hash = "md5";
        hash_tag = "{}";
    },
    {
        prefix = "user";
        pool = "UserPool";
        distribution = "ketama";
        need_sync = true;
        hash = "md5";
        hash_tag = "{}";
    }
);

尝试写入user前缀和非user前缀的key,并查看key被写入到了哪个Pool中

小结:通过上面的截图可以看到,WCCS按照预期完成了key的分发。配置keymap时,必须包含一个prefix="*"的默认规则。这里需要注意的是,key前缀的匹配是贪婪的,即如果一个key可以匹配keymap中的多个前缀,key最终会被发送到前缀匹配最长的pool中。利用WCCS的keymap机制让key在集群分发机制也对业务变的透明了,是不是很cool?

2. 自动处理故障端口功能测试

首先修改配置

backend_failure_limit = 5; //连续失败五次后触发自动剔除

backend_retry_timeout =30000; //30秒

a) set key1 为frank,发现key1落在端口11212上,get key1,成功;直接连接11211端口,并执行 将key1设置为hello

b) kill掉11212端口

c) get key1 提示SERVER_ERROR unknown, 连续5次get,仍然提示错误,等待30s后, get key1返回hello, 说明key1已经读取到了11211端口上的数据,auto_reject已经完成

d) 启动11211端口,等待30s

e) 在WCCS端口上执行get key1得到结果为空,说明已经自动重连到已经恢复服务的11212端口.

小结:auto_reject开启后,自动剔除功能工作正常,在连续访问失败backend_failure_limit次后,经过 backend_retry_timeout 秒,WCCS会自动重连。重启MC后,无需重启WCCS。

3. 性能测试

写入数据1k-2k之间的数据

mcperf -s 10.13.2.143 -p 2888 --linger=0 --timeout=2--conn-rate=6000 --call-rate=1000 --num-calls=20  --num-conns=6000 --method=set--sizes=u1024,2048

参考线上MC压力峰值,并发数选择6000

mcperf -s 10.13.2.143 -p 11211 --linger=0 --timeout=0.2--conn-rate=6000 --call-rate=1000 --num-calls=15  --num-conns=6000 --method=get

原生MC


WCCS


小结:从上面可以看出WCCS的可以充分发挥后端的MC性能,在数据的平均大小为1.5k时,get的峰值可以达到71000/s。

值得注意的是,MC中value的大小直接影响了MC的性能,我将数据的平均大小调整到了0.65k, 又进行了一次测试:

重启MC, 注入1byte-1.3k之间的数据:

mcperf -s 10.13.2.143 -p2888 --linger=0 --timeout=2 --conn-rate=1000 --call-rate=100--num-calls=2000  --num-conns=1000--method=set --sizes=u1, 1331

MC的资源占用情况:

测试WCCS性能:

mcperf -s 10.13.2.143 -p 2888 --linger=0 --timeout=0.2--conn-rate=6000 --call-rate=1000 --num-calls=29  --num-conns=6000 --method=get

从上面的数据可以看出,当平均数据大小在0.65k左右时,WCCS的get操作的TPS可以达到16w/s,这个结果已经非常理想了。

小结:测试环境下,并发6000/s,平均数据大小1.5k(1k-2k之间)时,get可以达到的TPS为7w/s,当平均数据大小为0.65k时(0-1.3k之间)时,get可以达到的TPS为16w/s。这说明WCCS的性能是足够高的。另外通过综合测试,还发现WCCS挂载两个MC端口时,综合性能无法达到2台MC的处理性能, 跟单个MC端口性能相近。

4.  调整配置文件中的参数值,比较不同的配置对性能的影响

调整workers_num, backend_connections的值,并测试性能变化。具体过程略。

调整workers_num和backend_connections的值后发现影响WCCS的性能的主要因素是WCCS于后端MC维持的长连接数量,这个数值等于

workers_num*backend_connections*pool中MC端口数

线上配置时需要注意总连接数不要超过MC设置的最大值。测试后发现当这个值维持在300左右时,就可以足以达到上面16w/s的TPS了。

backend_failure_limit是所有的worker共享的,考虑到push情况下MC失败也会比较多,启用auto_reject时,为了防止误判,可以将这个值设置的稍微大一些(如500)。

5.同步功能测试

启动两个WCCS端口2888和2889,并将2888 need_sync设置为true,    2888端口上的相关配置如下:

sync: {    //WCCS同步相关配置

dir = “/var/wccsdata”,  //开启跨机房同步时,用于记录MC的更新操作日志

backend :    //需要同步的WCCS端口

(

{ip = “127.0.0.1”; port = 2888}

{ip = “127.0.0.1”; port = 2889}

)

}

keymap:

(

{

prefix = "*"; //路由前缀, WCCS支持将指定前缀的key分发到指定的pool中

pool = "PoolDefault";

distribution = "ketama"; //分布策略采用一致性Hash

hash = "md5";  //使用md5作为hash策略

hash_tag = "{}";

need_sync = true; //开启同步

},

);

在2888端口上写入数据,并尝试从2889端口上读取。通过终端操作时,发现数据可以被正确同步。

提示:MC数据同步功能开启后,数据可以立即被同步,但是使用PHP客户端测试时发现,同步到2889端口上的数据丢失flag了字段,使用PHP MC客户端写入一个数组后,读取出的类型为字符串,没有对象进行自动解析,这一点使用的时候需要注意。

6. 其他注意问题:

a. WCSS会维持比较多的连接,需要通过ulimit放宽系统支持的文件描述符的数量

b. /O是影响WCCS性能的主要因素,需要通过Irqbalance打开中断优化,防止所有的I/O都阻塞在同一个CPU上。

c. WCCS在实例之间自动同步数据的功能实现方式为,首先记录接受到的MC数据更新命令到发送到本地的日志文件中,WCCS使用单独的进程对日志进行扫描,并发将幂等命令直接发送到需要被同步的机房中,非幂等的add、incr、decr、cas操作都会被转换为delete操作。

7. WCCS一些可以改进的方面

目前WCCS没有提供使用情况监控功能,使用中间件后,将无法通过监控后端MC的连接数评估连接的情况,只能通过netstat查看socket的连接数。

WCCS没有提供通过一个key获取key所在的机器的功能,不过如果知道MC的 IP列表,可以自行遍历个个实例获得。

MC中间件WCCS的更多相关文章

  1. django的中间件

    aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAA2EAAAGUCAIAAAAzrr3rAAAgAElEQVR4nOy9d5wcx3kmzAXl80m6zy

  2. 分布式数据库中间件–(3) Cobar对简单select命令的处理过程

    友情提示:非原文链接可能会影响您的阅读体验,欢迎查看原文.(http://blog.geekcome.com) 原文地址:http://blog.geekcome.com/archives/284 在 ...

  3. Python 之Memcache中间件

    一.引子 Memcached 是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载,它通过在内存中缓存数据和减少读取数据库的次数,从而提高动态数据库驱动网站的速度.Memcache ...

  4. [置顶] flume高并发优化——(15)中间件版本升级

    在系统平稳运行一年的基础上,为提供更好的服务,现针对java,kafka,flume,zk,统一进行版本升级,请各位小伙伴跟着走起来,不要掉队啊! 名称 老版本号 新版本号 jdk 1.7.0_25 ...

  5. ASP.NET Core如何使用压缩中间件提高Web应用程序性能

    前言 压缩可以大大的降低我们Web服务器的响应速度,压缩从而提高我们网页的加载速度,以及节省一定的带宽. 何时使用相应压缩中间件 在IIS,Apache,Nginx中使用基于服务端的响应压缩技术.中间 ...

  6. 亿级用户下的新浪微博平台架构 前端机(提供 API 接口服务),队列机(处理上行业务逻辑,主要是数据写入),存储(mc、mysql、mcq、redis 、HBase等)

    https://mp.weixin.qq.com/s/f319mm6QsetwxntvSXpKxg 亿级用户下的新浪微博平台架构 炼数成金前沿推荐 2014-12-04 序言 新浪微博在2014年3月 ...

  7. ASP.NET Core 中的那些认证中间件及一些重要知识点

    前言 在读这篇文章之间,建议先看一下我的 ASP.NET Core 之 Identity 入门系列(一,二,三)奠定一下基础. 有关于 Authentication 的知识太广,所以本篇介绍几个在 A ...

  8. ASP.NET Core应用的错误处理[3]:ExceptionHandlerMiddleware中间件如何呈现“定制化错误页面”

    DeveloperExceptionPageMiddleware中间件利用呈现出来的错误页面实现抛出异常和当前请求的详细信息以辅助开发人员更好地进行纠错诊断工作,而ExceptionHandlerMi ...

  9. ASP.NET Core应用的错误处理[2]:DeveloperExceptionPageMiddleware中间件如何呈现“开发者异常页面”

    在<ASP.NET Core应用的错误处理[1]:三种呈现错误页面的方式>中,我们通过几个简单的实例演示了如何呈现一个错误页面,这些错误页面的呈现分别由三个对应的中间件来完成,接下来我们将 ...

随机推荐

  1. 工厂模式 - 程序实现(java)

    09年5月CSDN一网友提出如下问题: 设计一个用于管理银行客户的类BankCustomer: 仅描述客户的几个重要方面: 帐号.身份证号.姓名.联系方式.密码.账户余额. 所有的成员变量均用priv ...

  2. android自定义控件,动态设置Button的样式

    原文  http://www.cnblogs.com/landptf/p/4562203.html 今天来看一个通过重写Button来动态实现一些效果,如圆角矩形.圆形.按下改变字体,改变背景色,改变 ...

  3. requireJS入门

    RequireJS 下载地址 : http://requirejs.org 什么是 requireJS ?以下是官方网站上的解释: RequireJS is a JavaScript file and ...

  4. 高效 css 整理

    避免通用规则 请确保规则不以通用类型作为结束! 不要用标签名或 classes 来限制 ID 规则 如果规则的关键选择器为 ID 选择器,则没有必要为规则增加标签名.因为 ID 是唯一的,增加标签只会 ...

  5. Java——(七)Map之HashMap和Hashtable实现类

    ------Java培训.Android培训.iOS培训..Net培训.期待与您交流! ------- Map Map用于具有映射关系的数据,因此Map集合里保存着两组值,一组值用于保存Map里的ke ...

  6. mvc Action上面加 [HttpPost]

    mvc  Action上面加 [HttpPost]  意思就是这个action只能响应post请求. 如果发get请求这里是没有响应的

  7. 一道阿里面试题(js)

    写一个求和的函数sum,达到下面的效果 // Should equal 15 sum(1, 2, 3, 4, 5); //Should equal 0 sum(5, 'abc', -5); //Sho ...

  8. GridView中某一列值的总和(web)

    protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)    {        if (e.Row.R ...

  9. linux 命令学习(4)

    Linux中常用的关机和重新启动命令有shutdown.halt.reboot以及init,它们都可以达到关机和重新启动的目的,但是每个命令的内部工作过程是不同的,下面将逐一进行介绍. 1. shut ...

  10. oracle行列转换总结-转载自ITPUB

    原贴地址:http://www.itpub.net/thread-1017026-1-1.html 谢谢原贴大人 最近论坛很多人提的问题都与行列转换有关系,所以我对行列转换的相关知识做了一个总结, 希 ...