mysql proxy的性能分析

作者:默默地前行  发布日期:2013-01-24 08:37:04
1. 硬件配置
    Summary: Intel S5500WBV, 2 x Xeon E5620 2.40GHz,23.5GB / 24GB 1067MHz
    System: Intel S5500WBV
    Processors: 2 x Xeon E5620 2.40GHz 133MHz FSB (HTenabled, 8 cores, 16 threads)
    Memory: 23.5GB / 24GB 1067MHz == 6 x 4GB, 2 xempty
    千兆网卡

2. 测试case

    长连接每个连接发送100,000 select 1的请求报文(即请求报文大小为13,响应报文大小为56)。

    建议在测试server前先用netperf测试一下网络环境,正常的局域网网络应该发送上面的报文应该可以达到   300,000 PPS;

    并发60直接连接mysql-server qps可以达到90000。

     CMD:bin/mysql-proxy --daemon --pid-file=log/proxy.pid--proxy-address=:4040 --log-level=debug --log-file=log/proxy.log--proxy-backend-addresses=10.232.64.76:17907 --event-threads=16,

     即下面的测试不走lua脚本,也没有连接池 c-cons:b-cons = 1:1。

3. 实验数据
     事件线程    并发连接    QPS     CPU    CS

     1                 1           3800   30%   

     1                10       30000   96%  

     1                30       33000   100%

     4                  1         4200    48%    

     4                    10        37400  300%   400

     4                    30        53000  360%   120000

     4                    50        69131  350%   150000

     4                    80        67000  350%   150000

    12                   1          3797    50%    110000

    12                   5          20000  300%  500000

    12                   12        37233  600%  600000

    12                   30        51890  800%  480000

    12                   50        53255  900%  400000

    12                   80        53426  950%  350000

    16                   10        29308  850%  832000

    16                   30        48390  1110% 580000

    16                   50        48056  1200% 400000

    16                   80        47000  1350% 300000

 

    在测试的过程中通过mpstat -I SUM -u -P ALL 1,发现所有的网卡中断都只跑在0 CPU上,之前的网卡SMP是设置好的,然后使用perf导致机器挂了几次,重启后之前的SMP设置就无效了。

    所有上面的所有数据都是没有开通网卡SMP的数据。

    后面又试着把网卡的SMP开启,发现数据还不如上面的,不过差别不大低2000左右,本来以为开启了可以将intr及soft分摊到各个CPU上,以此来提高性能,最后摊是摊开了,但qps并没有上去。

    看来性能并不在内核网络处理上,集中式的单CPU处理已经可以达到上面我们的QPS甚至更高的要求,而开通SMP对于这种压力不够的影响可能是负的,

    至于原因超出了我现在的知识范围(可能是代码的亲缘性上去了,欢迎大牛指点);

    当然我们这里并不是说开通网卡的SMP会比不开好,只是我们现在的瓶颈还不在网卡的处理上,当我们上层的处理能力超过单CPU的网卡接收能力的话,那么此时开通网卡SMP,应该就可以达到更高的性能。

4. Mysql-proxy的网络模型

     mysql-proxy是通过libevent的事件驱动的模型,但缺少介绍多线程在之个模型中的作用及关系:在mysql-proxy上线程是event-thread,即处理event的线程。

     Mysql-proxy主要有三类event fd:listen fd、socketpair[2]、net-read(write)。

    第一个很明显就是mysql的监听端口默认4040,这个事件只注册在main-thread线程上;

    第二个是一个socket对,即两个socket fd,其中socketpair[0]用于读(所有的线程都会关心这个event readable,回调函数chassis_event_handle),socketpair[1]用于写,

              当要add一个event(这个event就是第三类的event)的时候(chassis_event_add),会将该event放到一个全局的队列里,然后往socketpair[1]写一个”.”,

              然后所有线程都会被唤醒一次,唤醒后它们从全局队列里取得刚才保存的event,然后将这个event注册到自己的event-base上,那么当该event被触发的话,

             将由新的这个取得的线程来处理,另外,被唤醒的线程将尽量多取点event,只要它能够获得取队列的锁;

    第三类就是用于实际报文传送的read/write socket(它们的回调函数都是network_mysqld_con_handle),这一类与第二类的关系是:

               当我们要去recv或send socket的时候出现EAGAIN 错误,那么我们就应该去重新注册一下该事件(所有的第三类事件都是非EV_PERSIST),

               此时就会调用chassis_event_add函数,这就将触发新的event可能被别的线程获得处理。

    扩展一下当多个event-threads的时候将会出现什么情况:

                ①多个线程竞争一个event-queue;

                ②当一个第三类socket出现EAGAIN,那么将唤醒所有的线程(惊群);

                ③一个连接的client/severe socket不是固定在一个线程上执行,即任何的第三类event将随机的在任意线程上运行,在每次交互过程中都会发生变化迁移。

                简而言之就是event-thread不关心event是属于哪个连接的,它只关心这个event可用与否,当出现不可用时,它就该这个event push到全局的event-queue,然后唤醒所有的线程去竞争它。
       上面是mysql-proxy的网络模型下面我们再来看一下核心处理流程。

       这个处理流程主要包括下面4个部分:

             报文接收发送event处理(network_mysqld_con_handle),该函数完成报文的读写、状态的判断转移;然后调用plugin_call,该函数根据状态获得相应状态下的hook function;

             再接下来执行状态的回调函数(proxy_read_auth_result,proxy_send_query_result,proxy_connect_server…);

             最后就是回调函数再去调用lua scripq里的相应函数,完成定制的任务(如读写分离,输出select报文,结果集等一系列的操作)。

          注:前面三个都是由代码编译后写死了,但第4个过程我们可以定制,修改,这也是mysql-proxy留着一个扩展的地方。

                另外即使我们上面没有指定lua scripq,但是前面三个过程都是要走的,只是第4个不会被调用。

5. 数据分析

   了解了网络模型后,我们再来看一下上面的数据:

          首先对于1个event-thread的30个连接的时候CPU已经吃满了,显然再多个并发连接数也无益了。

          所以我们可以看到当event-thread增加到4的时候,同样的并发连接数QPS都上去了,另一个显著的变化是CS也上去了,这个就是因为上面我们说的惊群现象,

          它把所有的线程都唤醒一次,而且醒来后  还得去竞争event-queue,这就无形中增加了多个上下文切换的时机。

          所以同样可以解释当并发越多的时候,CS就越大(在并发连接数相同的情况下),另外一个比较好解释的现象是在event-thread相同的情况下并发连接数越多,CS上升,

          然而奇怪的是当并发连接数再大的话CS反而下降,这个可能的原因是因为chassis_event_handle在取event的时候是尽可能多的取,当并发连接数多的时候,

          它可能一次会获得多个event,减少了event的扩散。
          当然最令我不解的是为什么event-thread增加了QPS却下降了,我们以4个thread为参考值,那么我们系统16CPU,即使不能线性,那么折半应该不过分吧,那么多少也得69131 * 2 ~= 100000这个级别。

           当然有一种可能的解释是CS太多了,但以我个人的经验一般CS是果并不是因,也就是有其它真正的原因导致CS高,然后间接影响QPS,

            或者并不是CS的原因(因为当解决了这个瓶颈之后CS可能也会跟着下降下去),另外在16个event-threads的时候每个CPU上有user:sys:soft:idle大概=12%:65%:8%:15%;

           上面的现象MS现在通过代码不能那么容易的解释(个人实力未达),所以只能借助各种工具。

6. 工具分析

        为了防止某个逻辑CPU单独执行某一种操作,影响测试结果,所以我们在进行性能排查的时候,我们又把网卡SMP设置为多个CPU。我们这里使用的检测工具是perf。

         通过perf record -g -p PID的方式,获得详细性能数据:

         可以看到两个大头分别是调用futex_wake、futex_wait;上面我们说到核心处理流程有4个过程, www.it165.net

         通过上面的perf report可以看到出现了前面两个过程(network_mysqld_con_handle,plugin_call),我们再回代码里:

        Plugin_call(…)

       {…

          LOCK_LUA(srv->priv->sc); <===> g_mutex_lock(sc->mutex);

          ret = (*func)(srv, con);

          UNLOCK_LUA(srv->priv->sc);

        }

        Perf果然是神器,之前一直在看网络模型,怀疑的重点也在惊群上,完全没注意到这个地方。

        至于原因也非常的简单,虽然说在第二个过程plugin_call还没开始调用lua相关函数,但是在第三个过程里就要使用到,所有的线程共享相同的一些全局luatable,可见这个锁粒度还是挺大的。

7. 验证

        这里只是先说一下理论:

           一、防止惊群,将由一对socketpair改为多对即每个线程一对;

           二、现在的所有event是随机的由任何一个线程来处理,是否可以将一对event(client与backend server)固定为一个线程来处理,减少线程数据迁移?

           三、减少LOCK_LUA(srv->priv->sc)的锁粒度,或者去掉lua部分。


Tag标签: mysql   proxy   性能分析  
  • 专题推荐

About IT165 - 广告服务 - 隐私声明 - 版权申明 - 免责条款 - 网站地图 - 网友投稿 - 联系方式
本站内容来自于互联网,仅供用于网络技术学习,学习中请遵循相关法律法规