SlideShare a Scribd company logo
1 of 11
Download to read offline
MySQL HandlerSocket




                顾春江
            2011 年,4月
目 录
概要..........................................................................................................................3
 性能瓶颈................................................................................................................4
 HandlerSocket 结构...................................................................................................5
 使用了 HandlerSocket 之后的性能................................................................................7
 特点.......................................................................................................................8
   HS 支持 Handler 语句风格......................................................................................8
   HS 内置线程池.....................................................................................................8
   性能非常高效......................................................................................................8
   不再有重复的 Cache,数据保持一致........................................................................9
   HS 不影响正常数据库功能的使用............................................................................9
   HS 以插件的形式存在...........................................................................................9
 限制.......................................................................................................................9
   没有安全性.........................................................................................................9
   对于磁盘 IO 向的场景没有效果...............................................................................9
   性能瓶颈从 CPU 向转到网卡向...............................................................................9
   加重 slave 的复制压力...........................................................................................9
 安装和测试过程.......................................................................................................9
概要
 关于 SQL 和 NoSQL 的比较已经有很多了,在开源界一直以来 MySQL 都是通用存储的角色,搭配若干
其他高性能 key/value 或者是 graph 类型的数据存储方案。下面是一个 web 公司存储技术发展的典型例子:
 1: PHP + MySQL
 2: PHP + MySQL (Master + Slaves)
 3: PHP + MySQL (Master + Slaves) + Memcached (Middleware)
 4: PHP + MySQL (Sharding + Master + Slaves) + Memcached (Middleware)
 5: PHP + MySQL (Sharding + Master + Slaves) + Memcached (Middleware) + NoSQL
 会走用 NoSQL 这条路的,都是不满足于 MySQL 对于简单数据的操作的效率。但是在很多情况下,
MySQL 会在这些操作上慢的原因是由于低效的 SQL 语句引起的,或者说臃肿/分散的表组织引起的(比如
表文件已经很稀疏,或者索引不合理,太庞大)。最近 MySQL 的 HandlerSocket 的出现,打破了 MySQL
对于简单数据操作慢的传统。这要从 MySQL 的内部结构说起,先看下图:




Illustration 1: MySQL 内部结构
   这个图是 MySQL 的整个结构,客户端连接到达 MySQL 后,需要经过很多模块才能真正返回数据。
  首先是第一层, mysqld 层,也就是主服务器层,它包含四个模块: SQL 接口模块(判断 SQL 类型),
Parser 模块(解析器,解析 SQL 语法树),Optimizer 模块(优化器,语法树收敛),Cache&Buffer 模块
(缓冲层,包含主服务器缓冲,也可接受底层引擎的内存申请请求)。
然后是第二层,存储插件层,这一层包含了所有的可用存储引擎,像著名的 MyISAM 和 InnoDB,都是
在这一层,它们会接到来自主服务器层的 io 请求,然后负责调度对底层文件系统的 io 请求。
 最后是第三层,那就是文件系统了,这一层也有可能会包含操作系统的 cache,取决于引擎读写磁盘的方
式。
    我们要解决的问题是找到这几层之间会影响性能的热点。


性能瓶颈
 传统数据库的追求通用性和缺乏高速的简单操作接口,导致了 NoSQL 的出现。NoSQL 的应用场景主要
是:适量的热点数据,快速响应。对于 MySQL 来说,即便是使用 memory table,还是无法去除主服务器层
的 SQL 解析操作,SQL 解析在设备 IO 占主导时,的确不是什么问题,但是在纯内存数据场景中,SQL 解
析所占的 CPU 时间不再无足轻重。我们可以做一个例子,纯内存场景,客户端使用 SQL 接口,等值查询
PK(借鉴作者的做法,使用一个简单的带 INT 主键的 InnoDB 表,随机产生50 million 行的数据)。
    原始状态下的 select 能力:
$mysqlslap --query="select user_name from test.user where user_id=1000" 
  --number-of-queries=10000000 --concurrency=30 --host=mysql15 -uxxx -p

$mysqladmin extended-status -i 1 -r -uroot | grep -e "Com_select"

|   Com_select                                   |   86234          |
|   Com_select                                   |   82345          |
|   Com_select                                   |   85972          |
|   Com_select                                   |   84270          |
|   Com_select                                   |   84281          |
|   Com_select                                   |   83951          |
|   Com_select                                   |   85317          |
 以上数据显示,通过正常的 SQL 接口,MySQL 可以达到84 k/s 的读取次数。这里就暂不比较
Memcache 的读取能力了,一般 Memcache 在 MySQL 的四五倍以上。
    另外同时查看 vmstat 的数据:
$ vmstat 1
 r b swpd        free      buff    cache        in       cs   us   sy   id wa st
18 0       4   1276402   184176   17348613   68371   212346   55   36    9 0 0
16 0       4   1276402   184176   17348613   68610   213710   53   34   13 0 0
21 0       4   1276402   184176   17348613   69137   218767   56   33   11 0 0
17 0       4   1276402   184176   17348613   67392   209756   54   31   15 0 0
18 0       4   1276402   184176   17348613   68437   213386   54   35   11 0 0
 从 vmstat 的结果来看,user 时间超过 sys 时间不少,这个结果大概能说明,锁并非是占用 CPU 时间最多
的(MySQL 在 kernel space 执行 mutex),相反 user 时间占了一半多的比例,那接下来我们用 oprofile
来看看 MySQL 到底在 user space 做了些什么。(这边采用原作者的测试案例,大致情景相似,我们的服务
器上暂不方便测试)
samples %         app name                 symbol name
259130    4.5199 mysqld                    MYSQLparse(void*)
196841    3.4334 mysqld                    my_pthread_fastmutex_lock
106439    1.8566 libc-2.5.so               _int_malloc
94583     1.6498 bnx2                      /bnx2
84550     1.4748 ha_innodb_plugin.so.0.0.0 ut_delay
67945     1.1851 mysqld                    _ZL20make_join_statistics
P4JOINP10TABLE_LISTP4ItemP16st_dynamic_array
63435     1.1065 mysqld                    JOIN::optimize()
55825     0.9737 vmlinux                   wakeup_stack_begin
55054     0.9603 mysqld                    MYSQLlex(void*, void*)
50833     0.8867 libpthread-2.5.so         pthread_mutex_trylock
49602     0.8652 ha_innodb_plugin.so.0.0.0 row_search_for_mysql
47518     0.8288 libc-2.5.so               memcpy
46957      0.8190    vmlinux                      .text.elf_core_dump
46499      0.8111    libc-2.5.so                  malloc
  可以看到,MYSQLparse()占用了最多的 CPU 时间,另外 make_join 和 JOIN::optimize()和
MYSQLlex()也榜上有名。这些都是 mysqld 的 SQL 解析功能,如果能跳过这些步骤直达数据层,那么
user space 的效率还能提升很多,而且这种读取方式将和 NoSQL 非常类似。
(my_pthread_fastmutex_lock 数值很高是 mysqld 在做 SQL 解析时,需要不停地打开/关闭/锁定表对象造
成的,如果跳过 SQL 解析,此部分也会随之下降)
 接下来,就要想办法如果降低或跳过 MySQL 的 SQL 解析操作。一般的客户端要取得数据,需要经过如
下几个步骤:
   1. SQL Parser 解析 SQL 语句
   2. 打开表对象句柄,申请 mutex
   3. 根据表信息生成 SQL 执行计划
   4. IO 读写
   5. 释放 mutex,关闭表对象句柄
 这5个步骤中,只有第四步是 IO 向的,其余都是 CPU 向,如果 InnoDB 的一个表的数据都能被缓存到内
存(NoSQL 场景),那么步骤4不再重要,而剩下的四个步骤将成为主角,如何削减这些步骤显得额外重要。
  解决的办法,目前大概有如下:
 MySQL 有一个 HANDLER1语法,和一般的 SQL 语句一样,它也由 SQL Parser 来解析(步骤1没法省
略),但是由于这个语法是直接指定索引来进行遍历的,那么就可以省去步骤3,因此在 NoSQL 场景中,
这个语句能够做到只要1,2,5,不过还有提升的空间。
  MySQL Cluster 有个底层的 API 叫 NDBAPI2,这个 API 可以完全跳过步骤1,3,直接根据需要去操作
表。根据 HS 的作者讲,这种访问方式的效率是标准 SQL 接口的数倍。这样的访问方式看起来非常符合
NoSQL 的应用场景,只需要步骤2,5就可。

HandlerSocket 结构
  HandlerSocket 正是根据上述2种思想,然后通过 MySQL Internal Storage Engine API3绕开 mysqld 的
SQL 解析器,直接访问存储层。下面是 HS 的结构图:




1 http://dev.mysql.com/doc/refman/5.5/en/handler.html
2 http://dev.mysql.com/doc/ndbapi/en/index.html
3 http://forge.mysql.com/wiki/MySQL_Internals_Custom_Engine
HandlerSocket 以 MySQL 插件的形式启动,启动后监听2个特殊端口,分别接受读请求和写请求,并且
fork 出可配置数量的服务线程。这些服务线程将轮番处理客户端请求,并对多次分散的请求做合并处理。
HS 不会不停地打开/关闭表对象句柄,它在打开后会保持一段时间,如果在一段时间内没有请求才会关闭,
以方便句柄重用。HS 自己实现了一套基于文本的通信协议(类似 Memcache 的协议,很简洁,不用构建语
法树也不需要优化),支持 telnet 的调试。
 下图是 MySQL 搭配 NoSQL 的场景:
这个场景和 HS 的场景作比较的话,可以发现 HS 已经实现了 Memcached 的基本功能,而且不存在数据
变质的问题。


使用了 HandlerSocket 之后的性能
 在 mySQL 上创建了一个简单的带主键的 InnoDB 表,插入随机数据5,000,000条,然后用客户端分别通
过 SQL 接口和 HS 接口分别并行访问相同的数据,然后观察 MySQL 的实时 select 能力。(测试通过 perl
客户端做的,c++客户端有点问题还没法测)
$ mysqladmin extended-status -uxxx -p -i 1 -r | grep   "InnoDB_rows_read"
...
| Innodb_rows_read                      | 328512       |
| Innodb_rows_read                      | 340128       |
| Innodb_rows_read                      | 312134       |
| Innodb_rows_read                      | 338072       |
| Innodb_rows_read                      | 342387       |
| Innodb_rows_read                      | 399023       |
| Innodb_rows_read                      | 312494       |
| Innodb_rows_read                      | 353918       |
 这次的 qps 平均在330 k/s,和原来的84 k/s 的提升幅度是相当大的,有400%左右的提升。等 c++客户
端好了可以再和 Memcached 放在一起做个对比。
    同时我们可以再看看这次原来占用很多 CPU 时间的线程是如何表现的:(再次借用作者的数据)
samples %         app name                 symbol name
984785    5.9118 bnx2                      /bnx2
847486    5.0876 ha_innodb_plugin.so.0.0.0 ut_delay
545303    3.2735 ha_innodb_plugin.so.0.0.0 btr_search_guess_on_hash
317570    1.9064 ha_innodb_plugin.so.0.0.0 row_search_for_mysql
298271    1.7906 vmlinux                   tcp_ack
291739    1.7513 libc-2.5.so               vfprintf
264704    1.5891 vmlinux                   .text.super_90_sync
248546    1.4921 vmlinux                   blk_recount_segments
244474    1.4676 libc-2.5.so               _int_malloc
226738    1.3611 ha_innodb_plugin.so.0.0.0 _ZL14build_template
P19row_prebuilt_structP3THDP8st_tablej
206057    1.2370 HandlerSocket.so          dena::hstcpsvr_worker::run_one_ep()
183330    1.1006 ha_innodb_plugin.so.0.0.0 mutex_spin_wait
175738    1.0550 HandlerSocket.so          dena::dbcontext::
cmd_find_internal(dena::dbcallback_i&, dena::prep_stmt const&,
ha_rkey_function, dena::cmd_exec_args const&)
169967    1.0203 ha_innodb_plugin.so.0.0.0 buf_page_get_known_nowait
165337    0.9925 libc-2.5.so               memcpy
149611    0.8981 ha_innodb_plugin.so.0.0.0 row_sel_store_mysql_rec
148967    0.8943 vmlinux                   generic_make_request
 这次,原来很多镜像名是 mysqld 的线程已经不在列表上了,SQL Parser 相关的线程已经全部消失,倒是
有了很多 InnoDB 相关的线程上来了,说明优化已经奏效。那个镜像名是 bnx2 的线程是网络设备驱动,也
说明性能瓶颈开始从 CPU 转向网卡了。
    测试环境:
    •   mysql15
    •   8 core at 2.93GHZ
    •   32G(所有数据都缓冲在内存里)
特点

HS 支持 Handler 语句风格
 除了不支持非索引列的遍历,HS 基本支持 Handler 语句的所有写法。


HS 内置线程池
 内部采用了基于 epoll()的线程池,数量限制可在 my.cnf 里配置。
 以下是一个新启动的 MySQL 实例,HS 已开启,默认根据配置文件,已经有了17个服务线程:
mysql>SHOW PROCESSLIST;
+----+-------------+-----------------+---------------+---------+------
+-------------------------------------------+------------------+
| Id | User        | Host            | db            | Command | Time |   State
| Info             |
+----+-------------+-----------------+---------------+---------+------
+-------------------------------------------+------------------+
| 1 | system user | connecting host | NULL           | Connect | NULL |   handlersocket:
mode=rd, 0 conns, 0 active | NULL             |
| 2 | system user | connecting host | NULL           | Connect | NULL |   handlersocket:
mode=rd, 0 conns, 0 active | NULL             |
| 3 | system user | connecting host | NULL           | Connect | NULL |   handlersocket:
mode=rd, 0 conns, 0 active | NULL             |
| 4 | system user | connecting host | NULL           | Connect | NULL |   handlersocket:
mode=rd, 0 conns, 0 active | NULL             |
| 5 | system user | connecting host | NULL           | Connect | NULL |   handlersocket:
mode=rd, 0 conns, 0 active | NULL             |
| 6 | system user | connecting host | NULL           | Connect | NULL |   handlersocket:
mode=rd, 0 conns, 0 active | NULL             |
| 7 | system user | connecting host | NULL           | Connect | NULL |   handlersocket:
mode=rd, 0 conns, 0 active | NULL             |
| 8 | system user | connecting host | NULL           | Connect | NULL |   handlersocket:
mode=rd, 0 conns, 0 active | NULL             |
| 9 | system user | connecting host | NULL           | Connect | NULL |   handlersocket:
mode=rd, 0 conns, 0 active | NULL             |
| 10 | system user | connecting host | NULL          | Connect | NULL |   handlersocket:
mode=rd, 0 conns, 0 active | NULL             |
| 11 | system user | connecting host | NULL          | Connect | NULL |   handlersocket:
mode=rd, 0 conns, 0 active | NULL             |
| 12 | system user | connecting host | NULL          | Connect | NULL |   handlersocket:
mode=rd, 0 conns, 0 active | NULL             |
| 13 | system user | connecting host | NULL          | Connect | NULL |   handlersocket:
mode=rd, 0 conns, 0 active | NULL             |
| 14 | system user | connecting host | NULL          | Connect | NULL |   handlersocket:
mode=rd, 0 conns, 0 active | NULL             |
| 15 | system user | connecting host | NULL          | Connect | NULL |   handlersocket:
mode=rd, 0 conns, 0 active | NULL             |
| 16 | system user | connecting host | NULL          | Connect | NULL |   handlersocket:
mode=rd, 0 conns, 0 active | NULL             |
| 17 | system user | connecting host | handlersocket | Connect | NULL |   handlersocket:
mode=wr, 0 conns, 0 active | NULL             |
| 18 | root        | localhost       | NULL          | Query   |    0 |   NULL
| SHOW PROCESSLIST |
+----+-------------+-----------------+---------------+---------+------
+-------------------------------------------+------------------+


性能非常高效
   •   因为没有像安全验证、性能检测等附属功能,HS 的网络协议包非常简洁。
•   服务线程可控,能尽可能避免 mutex 过量。
   •   合并客户端请求,重用表对象句柄,提高吞吐率。
   •   能够减少 fsync()的次数。


不再有重复的 Cache,数据保持一致
 有这样的效率,Memcached 完全可以省了,也没有数据变质的烦恼,另外 MySQL 还有失败从 binlog 恢
复的功能,Memcached 没有。


HS 不影响正常数据库功能的使用
 Hs 使用的是特殊端口,正常的 SQL 端口仍然可用。所有的 HS 操作都是合法的数据库底层操作,因此
mysqld 的性能统计,binlog,replication 都不影响。

HS 以插件的形式存在
 插件的好处是不用重新编译 MySQL。
  HS 使用 MySQL Internal Storage Engine API,因此是在 mysqld 层的服务,和底层引擎类型无关。

限制

没有安全性
 Hs 的网络协议还非常简单,没有安全性可言。而且 HS 的服务线程以系统用户的权限运行,所以可以访
问任何表的任何数据。


对于磁盘 IO 向的场景没有效果
 对于这种场景,CPU 会消耗大量时间在 wait 状态,HS 的 CPU 优化意义不大。


性能瓶颈从 CPU 向转到网卡向
 在 CPU 方面做好优化了之后,网卡的处理能力成为了性能瓶颈。


加重 slave 的复制压力
 如果通过 HS 进行高速的数据修改,而 slave 仍然使用传统的基于语句的复制,那么 slave 有可能会跟不上,
毕竟只有单线程在做 SQL 接口的复制,复制协议有必要加上 HS 接口。




安装和测试过程
# Install HandlerSocket
tar xvfz ahiguti-HandlerSocket-Plugin-for-MySQL.tar.gz
cd ahiguti-HandlerSocket-Plugin-for-MySQL/
./autogen.sh
./configure --with-mysql-source=${DIR}/mysql --with-mysql-bindir=${DIR}/mysql/bin
make
sudo make install
# Install the Perl dependency
cd perl-Net-HandlerSocket
perl Makefile.PL
Writing Makefile for Net::HandlerSocket
make
sudo make install

${DIR}/mysql/bin/mysql -uroot
mysql> INSTALL PLUGIN HandlerSocket SONAME 'handlersocket.so';
mysql> SHOW PLUGINS;
+---------------+----------+----------------+------------------+---------+
| Name          | Status   | Type           | Library          | License |
+---------------+----------+----------------+------------------+---------+
| binlog        | ACTIVE   | STORAGE ENGINE | NULL             | GPL     |
| partition     | ACTIVE   | STORAGE ENGINE | NULL             | GPL     |
| ARCHIVE       | ACTIVE   | STORAGE ENGINE | NULL             | GPL     |
| BLACKHOLE     | ACTIVE   | STORAGE ENGINE | NULL             | GPL     |
| CSV           | ACTIVE   | STORAGE ENGINE | NULL             | GPL     |
| FEDERATED     | DISABLED | STORAGE ENGINE | NULL             | GPL     |
| MEMORY        | ACTIVE   | STORAGE ENGINE | NULL             | GPL     |
| InnoDB        | ACTIVE   | STORAGE ENGINE | NULL             | GPL     |
| MyISAM        | ACTIVE   | STORAGE ENGINE | NULL             | GPL     |
| MRG_MYISAM    | ACTIVE   | STORAGE ENGINE | NULL             | GPL     |
| handlersocket | ACTIVE   | DAEMON         | handlersocket.so | BSD     |
+---------------+----------+----------------+------------------+---------+
11 rows in set (0.00 sec)

# set my.cnf parameters
cd ${DIR}/mysql
echo "[mysqld]
plugin-load=handlersocket.so
loose_handlersocket_port = 9998 # the port number to bind to (for read requests)
loose_handlersocket_port_wr = 9999 # the port number to bind to (for write requests)
loose_handlersocket_threads = 16 # the number of worker threads (for read requests)
loose_handlersocket_threads_wr = 1 # the number of worker threads (for write requests)" >>
my.cnf

# test table
CREATE TABLE user (
  user_id INT UNSIGNED NOT NULL,
  name VARCHAR(50) NOT NULL,
  email VARCHAR(255) NOT NULL,
  created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY(user_id)
) ENGINE=InnoDB;

# populate data
INSERT INTO user (user_id,name, email) VALUES
(1,'name test','mail test'),
...
(5000000,'name test','mail test');


# perl test script
$ cat retrieve.pl
#!/usr/bin/perl

use strict;
use warnings;
use Net::HandlerSocket;

#1. establishing a connection
my $args = { host => '172.29.1.115', port => 9998 };
my $hs = new Net::HandlerSocket($args);

#2. initializing an index so that we can use in main logics.
 # MySQL tables will be opened here (if not opened)
my $res = $hs->open_index(0, 'test', 'user', 'PRIMARY',
    'name,email,created');
die $hs->get_error() if $res != 0;

#3. main logic
  #fetching rows by id
  #execute_single (index id, cond, cond value, max rows, offset)
for (my $i = 0; $i < 10000000; ++$i) {
   $res = $hs->execute_single(0, '=', [ '100' ], 1, 0);
}

#4. closing the connection
$hs->close();


# telnet testing
$ telnet 172.29.1.115 9998
Trying 172.29.1.115...
Connected to mysql15 (172.29.1.115).
Escape character is '^]'.
P       0        test    user     PRIMARY user_name,user_email,created
0       1
0       =        1       100
0       3        test name    test user   null

More Related Content

What's hot

2011 06-12-lamp-mysql-顾春江
2011 06-12-lamp-mysql-顾春江2011 06-12-lamp-mysql-顾春江
2011 06-12-lamp-mysql-顾春江thinkinlamp
 
MySQL新技术探索与实践
MySQL新技术探索与实践MySQL新技术探索与实践
MySQL新技术探索与实践Lixun Peng
 
My sql 同步
My sql 同步My sql 同步
My sql 同步Yiwei Ma
 
A.oracle 查询结果的缓存问题
A.oracle 查询结果的缓存问题A.oracle 查询结果的缓存问题
A.oracle 查询结果的缓存问题WASecurity
 
MySQL源码分析.03.InnoDB 物理文件格式与数据恢复
MySQL源码分析.03.InnoDB 物理文件格式与数据恢复MySQL源码分析.03.InnoDB 物理文件格式与数据恢复
MySQL源码分析.03.InnoDB 物理文件格式与数据恢复Lixun Peng
 
Cassandra的初步使用及一些简单的操作
Cassandra的初步使用及一些简单的操作Cassandra的初步使用及一些简单的操作
Cassandra的初步使用及一些简单的操作zhubin885
 
浅谈 My sql 性能调优
浅谈 My sql 性能调优浅谈 My sql 性能调优
浅谈 My sql 性能调优thinkinlamp
 
Csdn Emag(Oracle)第二期
Csdn Emag(Oracle)第二期Csdn Emag(Oracle)第二期
Csdn Emag(Oracle)第二期yiditushe
 
Essential oracle security internal for dba
Essential oracle security internal for dbaEssential oracle security internal for dba
Essential oracle security internal for dbamaclean liu
 
PostgreSQL 9 Standby
PostgreSQL 9 StandbyPostgreSQL 9 Standby
PostgreSQL 9 StandbyMarch Liu
 
Sql调优clustering factor影响数据删除速度一例
Sql调优clustering factor影响数据删除速度一例Sql调优clustering factor影响数据删除速度一例
Sql调优clustering factor影响数据删除速度一例maclean liu
 
配置Oracle 10g 双向流复制
配置Oracle 10g 双向流复制配置Oracle 10g 双向流复制
配置Oracle 10g 双向流复制maclean liu
 
Database.Cache&Buffer&Lock
Database.Cache&Buffer&LockDatabase.Cache&Buffer&Lock
Database.Cache&Buffer&LockLixun Peng
 
TomCat迁移步骤简述以及案例
TomCat迁移步骤简述以及案例TomCat迁移步骤简述以及案例
TomCat迁移步骤简述以及案例maclean liu
 
对MySQL应用的一些总结
对MySQL应用的一些总结对MySQL应用的一些总结
对MySQL应用的一些总结Lixun Peng
 
Mysql 培训-优化篇
Mysql 培训-优化篇Mysql 培训-优化篇
Mysql 培训-优化篇sunmonth
 
深入了解Oracle自动内存管理asmm
深入了解Oracle自动内存管理asmm深入了解Oracle自动内存管理asmm
深入了解Oracle自动内存管理asmmmaclean liu
 
基于MHA的MySQL高可用方案
基于MHA的MySQL高可用方案基于MHA的MySQL高可用方案
基于MHA的MySQL高可用方案Louis liu
 
Row Set初步学习V1.1
Row Set初步学习V1.1Row Set初步学习V1.1
Row Set初步学习V1.1Zianed Hou
 

What's hot (20)

2011 06-12-lamp-mysql-顾春江
2011 06-12-lamp-mysql-顾春江2011 06-12-lamp-mysql-顾春江
2011 06-12-lamp-mysql-顾春江
 
Mysql集群
Mysql集群Mysql集群
Mysql集群
 
MySQL新技术探索与实践
MySQL新技术探索与实践MySQL新技术探索与实践
MySQL新技术探索与实践
 
My sql 同步
My sql 同步My sql 同步
My sql 同步
 
A.oracle 查询结果的缓存问题
A.oracle 查询结果的缓存问题A.oracle 查询结果的缓存问题
A.oracle 查询结果的缓存问题
 
MySQL源码分析.03.InnoDB 物理文件格式与数据恢复
MySQL源码分析.03.InnoDB 物理文件格式与数据恢复MySQL源码分析.03.InnoDB 物理文件格式与数据恢复
MySQL源码分析.03.InnoDB 物理文件格式与数据恢复
 
Cassandra的初步使用及一些简单的操作
Cassandra的初步使用及一些简单的操作Cassandra的初步使用及一些简单的操作
Cassandra的初步使用及一些简单的操作
 
浅谈 My sql 性能调优
浅谈 My sql 性能调优浅谈 My sql 性能调优
浅谈 My sql 性能调优
 
Csdn Emag(Oracle)第二期
Csdn Emag(Oracle)第二期Csdn Emag(Oracle)第二期
Csdn Emag(Oracle)第二期
 
Essential oracle security internal for dba
Essential oracle security internal for dbaEssential oracle security internal for dba
Essential oracle security internal for dba
 
PostgreSQL 9 Standby
PostgreSQL 9 StandbyPostgreSQL 9 Standby
PostgreSQL 9 Standby
 
Sql调优clustering factor影响数据删除速度一例
Sql调优clustering factor影响数据删除速度一例Sql调优clustering factor影响数据删除速度一例
Sql调优clustering factor影响数据删除速度一例
 
配置Oracle 10g 双向流复制
配置Oracle 10g 双向流复制配置Oracle 10g 双向流复制
配置Oracle 10g 双向流复制
 
Database.Cache&Buffer&Lock
Database.Cache&Buffer&LockDatabase.Cache&Buffer&Lock
Database.Cache&Buffer&Lock
 
TomCat迁移步骤简述以及案例
TomCat迁移步骤简述以及案例TomCat迁移步骤简述以及案例
TomCat迁移步骤简述以及案例
 
对MySQL应用的一些总结
对MySQL应用的一些总结对MySQL应用的一些总结
对MySQL应用的一些总结
 
Mysql 培训-优化篇
Mysql 培训-优化篇Mysql 培训-优化篇
Mysql 培训-优化篇
 
深入了解Oracle自动内存管理asmm
深入了解Oracle自动内存管理asmm深入了解Oracle自动内存管理asmm
深入了解Oracle自动内存管理asmm
 
基于MHA的MySQL高可用方案
基于MHA的MySQL高可用方案基于MHA的MySQL高可用方案
基于MHA的MySQL高可用方案
 
Row Set初步学习V1.1
Row Set初步学习V1.1Row Set初步学习V1.1
Row Set初步学习V1.1
 

Viewers also liked

Santo andre gproj abc 26 -gep - grupo construtavel
Santo andre gproj abc 26 -gep - grupo construtavelSanto andre gproj abc 26 -gep - grupo construtavel
Santo andre gproj abc 26 -gep - grupo construtavelMarco Coghi
 
юрій єфімов
юрій єфімовюрій єфімов
юрій єфімовindrih
 
ティナシーリグ氏による創造性を高める9つのポイント
ティナシーリグ氏による創造性を高める9つのポイントティナシーリグ氏による創造性を高める9つのポイント
ティナシーリグ氏による創造性を高める9つのポイントTetsu Kanaya
 
Curriculum_PVA
Curriculum_PVACurriculum_PVA
Curriculum_PVAsamgomdor
 
Juceles diapositivas
Juceles diapositivasJuceles diapositivas
Juceles diapositivascarmenzale
 
Joaopessoa gp04-aq-atendimentonota10
Joaopessoa gp04-aq-atendimentonota10Joaopessoa gp04-aq-atendimentonota10
Joaopessoa gp04-aq-atendimentonota10Marco Coghi
 
cursus nieuwsbrief schrijven
cursus nieuwsbrief schrijvencursus nieuwsbrief schrijven
cursus nieuwsbrief schrijvenASW
 
Introducció a Android
Introducció a AndroidIntroducció a Android
Introducció a AndroidTarracoDroid
 
โครงการปีการศึกษา 2554
โครงการปีการศึกษา 2554โครงการปีการศึกษา 2554
โครงการปีการศึกษา 2554Nang Ka Nangnarak
 
Campinas-OTMMA3ppm-Integração-Usina Atlantida.pdf
Campinas-OTMMA3ppm-Integração-Usina Atlantida.pdfCampinas-OTMMA3ppm-Integração-Usina Atlantida.pdf
Campinas-OTMMA3ppm-Integração-Usina Atlantida.pdfMarco Coghi
 
2011年中国公益组织资源匹配与筹资培训
2011年中国公益组织资源匹配与筹资培训2011年中国公益组织资源匹配与筹资培训
2011年中国公益组织资源匹配与筹资培训vim background
 
Construtora Papini Faria Vaz (PRJ Terminal Rod e Vest)
Construtora Papini Faria Vaz (PRJ Terminal Rod e Vest)Construtora Papini Faria Vaz (PRJ Terminal Rod e Vest)
Construtora Papini Faria Vaz (PRJ Terminal Rod e Vest)Marco Coghi
 
Comites proyectos y celebraciones
Comites proyectos y celebracionesComites proyectos y celebraciones
Comites proyectos y celebracioneshildebon
 
Introdução a educação digital
Introdução a educação digitalIntrodução a educação digital
Introdução a educação digitalJosé Luis Carneiro
 

Viewers also liked (20)

Santo andre gproj abc 26 -gep - grupo construtavel
Santo andre gproj abc 26 -gep - grupo construtavelSanto andre gproj abc 26 -gep - grupo construtavel
Santo andre gproj abc 26 -gep - grupo construtavel
 
юрій єфімов
юрій єфімовюрій єфімов
юрій єфімов
 
ティナシーリグ氏による創造性を高める9つのポイント
ティナシーリグ氏による創造性を高める9つのポイントティナシーリグ氏による創造性を高める9つのポイント
ティナシーリグ氏による創造性を高める9つのポイント
 
Curriculum_PVA
Curriculum_PVACurriculum_PVA
Curriculum_PVA
 
Go!! blog
Go!! blogGo!! blog
Go!! blog
 
новогодний проект 2012
новогодний проект 2012новогодний проект 2012
новогодний проект 2012
 
Juceles diapositivas
Juceles diapositivasJuceles diapositivas
Juceles diapositivas
 
Joaopessoa gp04-aq-atendimentonota10
Joaopessoa gp04-aq-atendimentonota10Joaopessoa gp04-aq-atendimentonota10
Joaopessoa gp04-aq-atendimentonota10
 
cursus nieuwsbrief schrijven
cursus nieuwsbrief schrijvencursus nieuwsbrief schrijven
cursus nieuwsbrief schrijven
 
Wordpress
WordpressWordpress
Wordpress
 
Introducció a Android
Introducció a AndroidIntroducció a Android
Introducció a Android
 
Fiscais
FiscaisFiscais
Fiscais
 
Slide jailani
Slide jailaniSlide jailani
Slide jailani
 
โครงการปีการศึกษา 2554
โครงการปีการศึกษา 2554โครงการปีการศึกษา 2554
โครงการปีการศึกษา 2554
 
Campinas-OTMMA3ppm-Integração-Usina Atlantida.pdf
Campinas-OTMMA3ppm-Integração-Usina Atlantida.pdfCampinas-OTMMA3ppm-Integração-Usina Atlantida.pdf
Campinas-OTMMA3ppm-Integração-Usina Atlantida.pdf
 
2011年中国公益组织资源匹配与筹资培训
2011年中国公益组织资源匹配与筹资培训2011年中国公益组织资源匹配与筹资培训
2011年中国公益组织资源匹配与筹资培训
 
Construtora Papini Faria Vaz (PRJ Terminal Rod e Vest)
Construtora Papini Faria Vaz (PRJ Terminal Rod e Vest)Construtora Papini Faria Vaz (PRJ Terminal Rod e Vest)
Construtora Papini Faria Vaz (PRJ Terminal Rod e Vest)
 
Comites proyectos y celebraciones
Comites proyectos y celebracionesComites proyectos y celebraciones
Comites proyectos y celebraciones
 
Redes Sociais
Redes Sociais  Redes Sociais
Redes Sociais
 
Introdução a educação digital
Introdução a educação digitalIntrodução a educação digital
Introdução a educação digital
 

Similar to Mysql handlersocket

2011 06-12-lamp-mysql
2011 06-12-lamp-mysql2011 06-12-lamp-mysql
2011 06-12-lamp-mysqlpwesh
 
Osc scott linux下的数据库优化for_postgresql
Osc scott linux下的数据库优化for_postgresqlOsc scott linux下的数据库优化for_postgresql
Osc scott linux下的数据库优化for_postgresqlOpenSourceCamp
 
MySQL基础技能与原理——基本原理
MySQL基础技能与原理——基本原理MySQL基础技能与原理——基本原理
MySQL基础技能与原理——基本原理Michael Zhang
 
基于Innodb开发的最佳实践
基于Innodb开发的最佳实践基于Innodb开发的最佳实践
基于Innodb开发的最佳实践wubx
 
Mysql性能分析之临时表(共享)
Mysql性能分析之临时表(共享)Mysql性能分析之临时表(共享)
Mysql性能分析之临时表(共享)beiyu95
 
海量日志分析系统实践,Dba
海量日志分析系统实践,Dba海量日志分析系统实践,Dba
海量日志分析系统实践,DbaCevin Cheung
 
数据库极限性能测试
数据库极限性能测试数据库极限性能测试
数据库极限性能测试helbreathszw
 
Lamp高性能设计
Lamp高性能设计Lamp高性能设计
Lamp高性能设计锐 张
 
Showinnodbstatus公开
Showinnodbstatus公开Showinnodbstatus公开
Showinnodbstatus公开longxibendi
 
Mysql遇到的一些问题
Mysql遇到的一些问题Mysql遇到的一些问题
Mysql遇到的一些问题wang tongchao
 
高性能LAMP程序设计
高性能LAMP程序设计高性能LAMP程序设计
高性能LAMP程序设计fuchaoqun
 
Mysql proxy cluster
Mysql proxy clusterMysql proxy cluster
Mysql proxy clusterYiwei Ma
 
百度分布式数据实践与进展
百度分布式数据实践与进展百度分布式数据实践与进展
百度分布式数据实践与进展yp_fangdong
 
手机之家的数据访问层实践
手机之家的数据访问层实践手机之家的数据访问层实践
手机之家的数据访问层实践guestf5121c
 
手机之家的数据访问层实践
手机之家的数据访问层实践手机之家的数据访问层实践
手机之家的数据访问层实践xcq
 
MySQL Replication新功能介绍
MySQL Replication新功能介绍 MySQL Replication新功能介绍
MySQL Replication新功能介绍 orczhou
 
MySQL5.6&5.7 Cluster 7.3 Review
MySQL5.6&5.7 Cluster 7.3 ReviewMySQL5.6&5.7 Cluster 7.3 Review
MySQL5.6&5.7 Cluster 7.3 Review郁萍 王
 
构建基于Lamp的网站架构
构建基于Lamp的网站架构构建基于Lamp的网站架构
构建基于Lamp的网站架构Cosey Lee
 
Mysql introduction-and-performance-optimization
Mysql introduction-and-performance-optimizationMysql introduction-and-performance-optimization
Mysql introduction-and-performance-optimizationisnull
 

Similar to Mysql handlersocket (20)

2011 06-12-lamp-mysql
2011 06-12-lamp-mysql2011 06-12-lamp-mysql
2011 06-12-lamp-mysql
 
Osc scott linux下的数据库优化for_postgresql
Osc scott linux下的数据库优化for_postgresqlOsc scott linux下的数据库优化for_postgresql
Osc scott linux下的数据库优化for_postgresql
 
MySQL基础技能与原理——基本原理
MySQL基础技能与原理——基本原理MySQL基础技能与原理——基本原理
MySQL基础技能与原理——基本原理
 
基于Innodb开发的最佳实践
基于Innodb开发的最佳实践基于Innodb开发的最佳实践
基于Innodb开发的最佳实践
 
Mysql性能分析之临时表(共享)
Mysql性能分析之临时表(共享)Mysql性能分析之临时表(共享)
Mysql性能分析之临时表(共享)
 
海量日志分析系统实践,Dba
海量日志分析系统实践,Dba海量日志分析系统实践,Dba
海量日志分析系统实践,Dba
 
Optimzing mysql
Optimzing mysqlOptimzing mysql
Optimzing mysql
 
数据库极限性能测试
数据库极限性能测试数据库极限性能测试
数据库极限性能测试
 
Lamp高性能设计
Lamp高性能设计Lamp高性能设计
Lamp高性能设计
 
Showinnodbstatus公开
Showinnodbstatus公开Showinnodbstatus公开
Showinnodbstatus公开
 
Mysql遇到的一些问题
Mysql遇到的一些问题Mysql遇到的一些问题
Mysql遇到的一些问题
 
高性能LAMP程序设计
高性能LAMP程序设计高性能LAMP程序设计
高性能LAMP程序设计
 
Mysql proxy cluster
Mysql proxy clusterMysql proxy cluster
Mysql proxy cluster
 
百度分布式数据实践与进展
百度分布式数据实践与进展百度分布式数据实践与进展
百度分布式数据实践与进展
 
手机之家的数据访问层实践
手机之家的数据访问层实践手机之家的数据访问层实践
手机之家的数据访问层实践
 
手机之家的数据访问层实践
手机之家的数据访问层实践手机之家的数据访问层实践
手机之家的数据访问层实践
 
MySQL Replication新功能介绍
MySQL Replication新功能介绍 MySQL Replication新功能介绍
MySQL Replication新功能介绍
 
MySQL5.6&5.7 Cluster 7.3 Review
MySQL5.6&5.7 Cluster 7.3 ReviewMySQL5.6&5.7 Cluster 7.3 Review
MySQL5.6&5.7 Cluster 7.3 Review
 
构建基于Lamp的网站架构
构建基于Lamp的网站架构构建基于Lamp的网站架构
构建基于Lamp的网站架构
 
Mysql introduction-and-performance-optimization
Mysql introduction-and-performance-optimizationMysql introduction-and-performance-optimization
Mysql introduction-and-performance-optimization
 

Mysql handlersocket

  • 1. MySQL HandlerSocket 顾春江 2011 年,4月
  • 2. 目 录 概要..........................................................................................................................3 性能瓶颈................................................................................................................4 HandlerSocket 结构...................................................................................................5 使用了 HandlerSocket 之后的性能................................................................................7 特点.......................................................................................................................8 HS 支持 Handler 语句风格......................................................................................8 HS 内置线程池.....................................................................................................8 性能非常高效......................................................................................................8 不再有重复的 Cache,数据保持一致........................................................................9 HS 不影响正常数据库功能的使用............................................................................9 HS 以插件的形式存在...........................................................................................9 限制.......................................................................................................................9 没有安全性.........................................................................................................9 对于磁盘 IO 向的场景没有效果...............................................................................9 性能瓶颈从 CPU 向转到网卡向...............................................................................9 加重 slave 的复制压力...........................................................................................9 安装和测试过程.......................................................................................................9
  • 3. 概要 关于 SQL 和 NoSQL 的比较已经有很多了,在开源界一直以来 MySQL 都是通用存储的角色,搭配若干 其他高性能 key/value 或者是 graph 类型的数据存储方案。下面是一个 web 公司存储技术发展的典型例子: 1: PHP + MySQL 2: PHP + MySQL (Master + Slaves) 3: PHP + MySQL (Master + Slaves) + Memcached (Middleware) 4: PHP + MySQL (Sharding + Master + Slaves) + Memcached (Middleware) 5: PHP + MySQL (Sharding + Master + Slaves) + Memcached (Middleware) + NoSQL 会走用 NoSQL 这条路的,都是不满足于 MySQL 对于简单数据的操作的效率。但是在很多情况下, MySQL 会在这些操作上慢的原因是由于低效的 SQL 语句引起的,或者说臃肿/分散的表组织引起的(比如 表文件已经很稀疏,或者索引不合理,太庞大)。最近 MySQL 的 HandlerSocket 的出现,打破了 MySQL 对于简单数据操作慢的传统。这要从 MySQL 的内部结构说起,先看下图: Illustration 1: MySQL 内部结构 这个图是 MySQL 的整个结构,客户端连接到达 MySQL 后,需要经过很多模块才能真正返回数据。 首先是第一层, mysqld 层,也就是主服务器层,它包含四个模块: SQL 接口模块(判断 SQL 类型), Parser 模块(解析器,解析 SQL 语法树),Optimizer 模块(优化器,语法树收敛),Cache&Buffer 模块 (缓冲层,包含主服务器缓冲,也可接受底层引擎的内存申请请求)。
  • 4. 然后是第二层,存储插件层,这一层包含了所有的可用存储引擎,像著名的 MyISAM 和 InnoDB,都是 在这一层,它们会接到来自主服务器层的 io 请求,然后负责调度对底层文件系统的 io 请求。 最后是第三层,那就是文件系统了,这一层也有可能会包含操作系统的 cache,取决于引擎读写磁盘的方 式。 我们要解决的问题是找到这几层之间会影响性能的热点。 性能瓶颈 传统数据库的追求通用性和缺乏高速的简单操作接口,导致了 NoSQL 的出现。NoSQL 的应用场景主要 是:适量的热点数据,快速响应。对于 MySQL 来说,即便是使用 memory table,还是无法去除主服务器层 的 SQL 解析操作,SQL 解析在设备 IO 占主导时,的确不是什么问题,但是在纯内存数据场景中,SQL 解 析所占的 CPU 时间不再无足轻重。我们可以做一个例子,纯内存场景,客户端使用 SQL 接口,等值查询 PK(借鉴作者的做法,使用一个简单的带 INT 主键的 InnoDB 表,随机产生50 million 行的数据)。 原始状态下的 select 能力: $mysqlslap --query="select user_name from test.user where user_id=1000" --number-of-queries=10000000 --concurrency=30 --host=mysql15 -uxxx -p $mysqladmin extended-status -i 1 -r -uroot | grep -e "Com_select" | Com_select | 86234 | | Com_select | 82345 | | Com_select | 85972 | | Com_select | 84270 | | Com_select | 84281 | | Com_select | 83951 | | Com_select | 85317 | 以上数据显示,通过正常的 SQL 接口,MySQL 可以达到84 k/s 的读取次数。这里就暂不比较 Memcache 的读取能力了,一般 Memcache 在 MySQL 的四五倍以上。 另外同时查看 vmstat 的数据: $ vmstat 1 r b swpd free buff cache in cs us sy id wa st 18 0 4 1276402 184176 17348613 68371 212346 55 36 9 0 0 16 0 4 1276402 184176 17348613 68610 213710 53 34 13 0 0 21 0 4 1276402 184176 17348613 69137 218767 56 33 11 0 0 17 0 4 1276402 184176 17348613 67392 209756 54 31 15 0 0 18 0 4 1276402 184176 17348613 68437 213386 54 35 11 0 0 从 vmstat 的结果来看,user 时间超过 sys 时间不少,这个结果大概能说明,锁并非是占用 CPU 时间最多 的(MySQL 在 kernel space 执行 mutex),相反 user 时间占了一半多的比例,那接下来我们用 oprofile 来看看 MySQL 到底在 user space 做了些什么。(这边采用原作者的测试案例,大致情景相似,我们的服务 器上暂不方便测试) samples % app name symbol name 259130 4.5199 mysqld MYSQLparse(void*) 196841 3.4334 mysqld my_pthread_fastmutex_lock 106439 1.8566 libc-2.5.so _int_malloc 94583 1.6498 bnx2 /bnx2 84550 1.4748 ha_innodb_plugin.so.0.0.0 ut_delay 67945 1.1851 mysqld _ZL20make_join_statistics P4JOINP10TABLE_LISTP4ItemP16st_dynamic_array 63435 1.1065 mysqld JOIN::optimize() 55825 0.9737 vmlinux wakeup_stack_begin 55054 0.9603 mysqld MYSQLlex(void*, void*) 50833 0.8867 libpthread-2.5.so pthread_mutex_trylock 49602 0.8652 ha_innodb_plugin.so.0.0.0 row_search_for_mysql 47518 0.8288 libc-2.5.so memcpy
  • 5. 46957 0.8190 vmlinux .text.elf_core_dump 46499 0.8111 libc-2.5.so malloc 可以看到,MYSQLparse()占用了最多的 CPU 时间,另外 make_join 和 JOIN::optimize()和 MYSQLlex()也榜上有名。这些都是 mysqld 的 SQL 解析功能,如果能跳过这些步骤直达数据层,那么 user space 的效率还能提升很多,而且这种读取方式将和 NoSQL 非常类似。 (my_pthread_fastmutex_lock 数值很高是 mysqld 在做 SQL 解析时,需要不停地打开/关闭/锁定表对象造 成的,如果跳过 SQL 解析,此部分也会随之下降) 接下来,就要想办法如果降低或跳过 MySQL 的 SQL 解析操作。一般的客户端要取得数据,需要经过如 下几个步骤: 1. SQL Parser 解析 SQL 语句 2. 打开表对象句柄,申请 mutex 3. 根据表信息生成 SQL 执行计划 4. IO 读写 5. 释放 mutex,关闭表对象句柄 这5个步骤中,只有第四步是 IO 向的,其余都是 CPU 向,如果 InnoDB 的一个表的数据都能被缓存到内 存(NoSQL 场景),那么步骤4不再重要,而剩下的四个步骤将成为主角,如何削减这些步骤显得额外重要。 解决的办法,目前大概有如下: MySQL 有一个 HANDLER1语法,和一般的 SQL 语句一样,它也由 SQL Parser 来解析(步骤1没法省 略),但是由于这个语法是直接指定索引来进行遍历的,那么就可以省去步骤3,因此在 NoSQL 场景中, 这个语句能够做到只要1,2,5,不过还有提升的空间。 MySQL Cluster 有个底层的 API 叫 NDBAPI2,这个 API 可以完全跳过步骤1,3,直接根据需要去操作 表。根据 HS 的作者讲,这种访问方式的效率是标准 SQL 接口的数倍。这样的访问方式看起来非常符合 NoSQL 的应用场景,只需要步骤2,5就可。 HandlerSocket 结构 HandlerSocket 正是根据上述2种思想,然后通过 MySQL Internal Storage Engine API3绕开 mysqld 的 SQL 解析器,直接访问存储层。下面是 HS 的结构图: 1 http://dev.mysql.com/doc/refman/5.5/en/handler.html 2 http://dev.mysql.com/doc/ndbapi/en/index.html 3 http://forge.mysql.com/wiki/MySQL_Internals_Custom_Engine
  • 6. HandlerSocket 以 MySQL 插件的形式启动,启动后监听2个特殊端口,分别接受读请求和写请求,并且 fork 出可配置数量的服务线程。这些服务线程将轮番处理客户端请求,并对多次分散的请求做合并处理。 HS 不会不停地打开/关闭表对象句柄,它在打开后会保持一段时间,如果在一段时间内没有请求才会关闭, 以方便句柄重用。HS 自己实现了一套基于文本的通信协议(类似 Memcache 的协议,很简洁,不用构建语 法树也不需要优化),支持 telnet 的调试。 下图是 MySQL 搭配 NoSQL 的场景:
  • 7. 这个场景和 HS 的场景作比较的话,可以发现 HS 已经实现了 Memcached 的基本功能,而且不存在数据 变质的问题。 使用了 HandlerSocket 之后的性能 在 mySQL 上创建了一个简单的带主键的 InnoDB 表,插入随机数据5,000,000条,然后用客户端分别通 过 SQL 接口和 HS 接口分别并行访问相同的数据,然后观察 MySQL 的实时 select 能力。(测试通过 perl 客户端做的,c++客户端有点问题还没法测) $ mysqladmin extended-status -uxxx -p -i 1 -r | grep "InnoDB_rows_read" ... | Innodb_rows_read | 328512 | | Innodb_rows_read | 340128 | | Innodb_rows_read | 312134 | | Innodb_rows_read | 338072 | | Innodb_rows_read | 342387 | | Innodb_rows_read | 399023 | | Innodb_rows_read | 312494 | | Innodb_rows_read | 353918 | 这次的 qps 平均在330 k/s,和原来的84 k/s 的提升幅度是相当大的,有400%左右的提升。等 c++客户 端好了可以再和 Memcached 放在一起做个对比。 同时我们可以再看看这次原来占用很多 CPU 时间的线程是如何表现的:(再次借用作者的数据) samples % app name symbol name 984785 5.9118 bnx2 /bnx2 847486 5.0876 ha_innodb_plugin.so.0.0.0 ut_delay 545303 3.2735 ha_innodb_plugin.so.0.0.0 btr_search_guess_on_hash 317570 1.9064 ha_innodb_plugin.so.0.0.0 row_search_for_mysql 298271 1.7906 vmlinux tcp_ack 291739 1.7513 libc-2.5.so vfprintf 264704 1.5891 vmlinux .text.super_90_sync 248546 1.4921 vmlinux blk_recount_segments 244474 1.4676 libc-2.5.so _int_malloc 226738 1.3611 ha_innodb_plugin.so.0.0.0 _ZL14build_template P19row_prebuilt_structP3THDP8st_tablej 206057 1.2370 HandlerSocket.so dena::hstcpsvr_worker::run_one_ep() 183330 1.1006 ha_innodb_plugin.so.0.0.0 mutex_spin_wait 175738 1.0550 HandlerSocket.so dena::dbcontext:: cmd_find_internal(dena::dbcallback_i&, dena::prep_stmt const&, ha_rkey_function, dena::cmd_exec_args const&) 169967 1.0203 ha_innodb_plugin.so.0.0.0 buf_page_get_known_nowait 165337 0.9925 libc-2.5.so memcpy 149611 0.8981 ha_innodb_plugin.so.0.0.0 row_sel_store_mysql_rec 148967 0.8943 vmlinux generic_make_request 这次,原来很多镜像名是 mysqld 的线程已经不在列表上了,SQL Parser 相关的线程已经全部消失,倒是 有了很多 InnoDB 相关的线程上来了,说明优化已经奏效。那个镜像名是 bnx2 的线程是网络设备驱动,也 说明性能瓶颈开始从 CPU 转向网卡了。 测试环境: • mysql15 • 8 core at 2.93GHZ • 32G(所有数据都缓冲在内存里)
  • 8. 特点 HS 支持 Handler 语句风格 除了不支持非索引列的遍历,HS 基本支持 Handler 语句的所有写法。 HS 内置线程池 内部采用了基于 epoll()的线程池,数量限制可在 my.cnf 里配置。 以下是一个新启动的 MySQL 实例,HS 已开启,默认根据配置文件,已经有了17个服务线程: mysql>SHOW PROCESSLIST; +----+-------------+-----------------+---------------+---------+------ +-------------------------------------------+------------------+ | Id | User | Host | db | Command | Time | State | Info | +----+-------------+-----------------+---------------+---------+------ +-------------------------------------------+------------------+ | 1 | system user | connecting host | NULL | Connect | NULL | handlersocket: mode=rd, 0 conns, 0 active | NULL | | 2 | system user | connecting host | NULL | Connect | NULL | handlersocket: mode=rd, 0 conns, 0 active | NULL | | 3 | system user | connecting host | NULL | Connect | NULL | handlersocket: mode=rd, 0 conns, 0 active | NULL | | 4 | system user | connecting host | NULL | Connect | NULL | handlersocket: mode=rd, 0 conns, 0 active | NULL | | 5 | system user | connecting host | NULL | Connect | NULL | handlersocket: mode=rd, 0 conns, 0 active | NULL | | 6 | system user | connecting host | NULL | Connect | NULL | handlersocket: mode=rd, 0 conns, 0 active | NULL | | 7 | system user | connecting host | NULL | Connect | NULL | handlersocket: mode=rd, 0 conns, 0 active | NULL | | 8 | system user | connecting host | NULL | Connect | NULL | handlersocket: mode=rd, 0 conns, 0 active | NULL | | 9 | system user | connecting host | NULL | Connect | NULL | handlersocket: mode=rd, 0 conns, 0 active | NULL | | 10 | system user | connecting host | NULL | Connect | NULL | handlersocket: mode=rd, 0 conns, 0 active | NULL | | 11 | system user | connecting host | NULL | Connect | NULL | handlersocket: mode=rd, 0 conns, 0 active | NULL | | 12 | system user | connecting host | NULL | Connect | NULL | handlersocket: mode=rd, 0 conns, 0 active | NULL | | 13 | system user | connecting host | NULL | Connect | NULL | handlersocket: mode=rd, 0 conns, 0 active | NULL | | 14 | system user | connecting host | NULL | Connect | NULL | handlersocket: mode=rd, 0 conns, 0 active | NULL | | 15 | system user | connecting host | NULL | Connect | NULL | handlersocket: mode=rd, 0 conns, 0 active | NULL | | 16 | system user | connecting host | NULL | Connect | NULL | handlersocket: mode=rd, 0 conns, 0 active | NULL | | 17 | system user | connecting host | handlersocket | Connect | NULL | handlersocket: mode=wr, 0 conns, 0 active | NULL | | 18 | root | localhost | NULL | Query | 0 | NULL | SHOW PROCESSLIST | +----+-------------+-----------------+---------------+---------+------ +-------------------------------------------+------------------+ 性能非常高效 • 因为没有像安全验证、性能检测等附属功能,HS 的网络协议包非常简洁。
  • 9. 服务线程可控,能尽可能避免 mutex 过量。 • 合并客户端请求,重用表对象句柄,提高吞吐率。 • 能够减少 fsync()的次数。 不再有重复的 Cache,数据保持一致 有这样的效率,Memcached 完全可以省了,也没有数据变质的烦恼,另外 MySQL 还有失败从 binlog 恢 复的功能,Memcached 没有。 HS 不影响正常数据库功能的使用 Hs 使用的是特殊端口,正常的 SQL 端口仍然可用。所有的 HS 操作都是合法的数据库底层操作,因此 mysqld 的性能统计,binlog,replication 都不影响。 HS 以插件的形式存在 插件的好处是不用重新编译 MySQL。 HS 使用 MySQL Internal Storage Engine API,因此是在 mysqld 层的服务,和底层引擎类型无关。 限制 没有安全性 Hs 的网络协议还非常简单,没有安全性可言。而且 HS 的服务线程以系统用户的权限运行,所以可以访 问任何表的任何数据。 对于磁盘 IO 向的场景没有效果 对于这种场景,CPU 会消耗大量时间在 wait 状态,HS 的 CPU 优化意义不大。 性能瓶颈从 CPU 向转到网卡向 在 CPU 方面做好优化了之后,网卡的处理能力成为了性能瓶颈。 加重 slave 的复制压力 如果通过 HS 进行高速的数据修改,而 slave 仍然使用传统的基于语句的复制,那么 slave 有可能会跟不上, 毕竟只有单线程在做 SQL 接口的复制,复制协议有必要加上 HS 接口。 安装和测试过程 # Install HandlerSocket tar xvfz ahiguti-HandlerSocket-Plugin-for-MySQL.tar.gz cd ahiguti-HandlerSocket-Plugin-for-MySQL/ ./autogen.sh ./configure --with-mysql-source=${DIR}/mysql --with-mysql-bindir=${DIR}/mysql/bin make sudo make install
  • 10. # Install the Perl dependency cd perl-Net-HandlerSocket perl Makefile.PL Writing Makefile for Net::HandlerSocket make sudo make install ${DIR}/mysql/bin/mysql -uroot mysql> INSTALL PLUGIN HandlerSocket SONAME 'handlersocket.so'; mysql> SHOW PLUGINS; +---------------+----------+----------------+------------------+---------+ | Name | Status | Type | Library | License | +---------------+----------+----------------+------------------+---------+ | binlog | ACTIVE | STORAGE ENGINE | NULL | GPL | | partition | ACTIVE | STORAGE ENGINE | NULL | GPL | | ARCHIVE | ACTIVE | STORAGE ENGINE | NULL | GPL | | BLACKHOLE | ACTIVE | STORAGE ENGINE | NULL | GPL | | CSV | ACTIVE | STORAGE ENGINE | NULL | GPL | | FEDERATED | DISABLED | STORAGE ENGINE | NULL | GPL | | MEMORY | ACTIVE | STORAGE ENGINE | NULL | GPL | | InnoDB | ACTIVE | STORAGE ENGINE | NULL | GPL | | MyISAM | ACTIVE | STORAGE ENGINE | NULL | GPL | | MRG_MYISAM | ACTIVE | STORAGE ENGINE | NULL | GPL | | handlersocket | ACTIVE | DAEMON | handlersocket.so | BSD | +---------------+----------+----------------+------------------+---------+ 11 rows in set (0.00 sec) # set my.cnf parameters cd ${DIR}/mysql echo "[mysqld] plugin-load=handlersocket.so loose_handlersocket_port = 9998 # the port number to bind to (for read requests) loose_handlersocket_port_wr = 9999 # the port number to bind to (for write requests) loose_handlersocket_threads = 16 # the number of worker threads (for read requests) loose_handlersocket_threads_wr = 1 # the number of worker threads (for write requests)" >> my.cnf # test table CREATE TABLE user ( user_id INT UNSIGNED NOT NULL, name VARCHAR(50) NOT NULL, email VARCHAR(255) NOT NULL, created TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY(user_id) ) ENGINE=InnoDB; # populate data INSERT INTO user (user_id,name, email) VALUES (1,'name test','mail test'), ... (5000000,'name test','mail test'); # perl test script $ cat retrieve.pl #!/usr/bin/perl use strict; use warnings; use Net::HandlerSocket; #1. establishing a connection my $args = { host => '172.29.1.115', port => 9998 };
  • 11. my $hs = new Net::HandlerSocket($args); #2. initializing an index so that we can use in main logics. # MySQL tables will be opened here (if not opened) my $res = $hs->open_index(0, 'test', 'user', 'PRIMARY', 'name,email,created'); die $hs->get_error() if $res != 0; #3. main logic #fetching rows by id #execute_single (index id, cond, cond value, max rows, offset) for (my $i = 0; $i < 10000000; ++$i) { $res = $hs->execute_single(0, '=', [ '100' ], 1, 0); } #4. closing the connection $hs->close(); # telnet testing $ telnet 172.29.1.115 9998 Trying 172.29.1.115... Connected to mysql15 (172.29.1.115). Escape character is '^]'. P 0 test user PRIMARY user_name,user_email,created 0 1 0 = 1 100 0 3 test name test user null