时间:2021-07-01 10:21:17 帮助过:38人阅读
另外一些站点放弃了mysql,采用了NoSQL,比如TokyoCabinet/Tyrant等等。
不可否认,在做一些简单查询(尤其是primary key 查询)的时候,NoSQL比mysql要快很多很多。而且网站上的绝大多数查询都是这样的简单查询。
但是DeNA公司却一直使用mysql和memcached,并且在单台普通服务器上创造了每秒750,000次简单查询的记录。
或许你们不会相信单台mysql可以做到750,000 qps,但这是事实,下面就来详细说说。
DeNA 公司的应用经常要进行primary key(PK)查询。比如根据user id取出userinfo,根据diary id取出日志内容, memcached和NoSQL很适合做这种事情。
如果进行memcached 的测试,很有可能每秒可以进行400,000次get操作,即使memcached和client位于不同的服务器。
在一台2.5GHz8核Nehalem 3块千M网卡的服务器上,libmemcached和memcached每秒可以进行420,000次get 操作。
mysql5呢?每秒可以做多少次PK查询?
innodb:
- [matsunobu@host ~]$ mysqlslap --query="select user_name,.. from test.user where user_id=1" /
- --number-of-queries=10000000 --concurrency=30 --host=xxx -uroot -p
此外也可以使用 sysbench或者super-smack等工具进行benchmark。
新开一个shell看一下:
- [matsunobu@host ~]$ mysqladmin extended-status -i 1 -r -uroot /
- | grep -e "Com_select"
- | Com_select | 107069 |
- | Com_select | 108873 |
- | Com_select | 108921 |
- | Com_select | 109511 |
- | Com_select | 108084 |
- | Com_select | 108115 |
100,000 qps 大概是memcached的1/4左右。
为什么会慢这么多呢?
服务器内存足够,这些数据应该都在内存中。
同样是内存操作,为什么mysql比memcached慢这么多?
vmstat数据如下:
- [matsunobu@host ~]$ vmstat 1
- r b swpd free buff cache in cs us sy id wa st
- 23 0 0 963004 224216 29937708 58242 163470 59 28 12 0 0
- 24 0 0 963312 224216 29937708 57725 164855 59 28 13 0 0
- 19 0 0 963232 224216 29937708 58127 164196 60 28 12 0 0
- 16 0 0 963260 224216 29937708 58021 165275 60 28 12 0 0
- 20 0 0 963308 224216 29937708 57865 165041 60 28 12 0 0
%user和%system占用的CPU都相当高。
再看看oprofile统计出来的信息:
ps:这个工具不错,内核级别的。
- 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是5.x版本中的,在4.x中是YYparse
MYSQLparse() 和 MYSQLlex()是在mysql解析sql语句的时候调用到的。
make_join_statistics()和JOIN::optimize() 是在query optimization(查询优化)阶段调用到的。
正是因为使用了SQL语句,才会有这些额外的负担。
从oprofile的输出可以得到如下结论:
SQL层严重影响到了mysql查询的性能。
与memcached和SQL比起来,mysql要额外做一些工作:
* Parsing SQL statements 解析sql语句
* Opening, locking tables 打开并锁定表
* Making SQL execution plans ???
* Unlocking, closing tables 解锁并关闭表
花荣注:使用mysqli 中的prepared statement API可以避免解析sql语句。
mysql还必须要做大量的并发控制,比如在发送/接收网络数据包的时候,fcntl()就要被调用很多很多次。
Global mutexes :LOCK_open LOCK_thread_count 也被频繁地调用。
所以在oprofile的输出中,排在第二位的是my_pthread_fastmutex_lock()。并且%system占用的CPU相当高(28%)。
其实 mysql开发团队和一些外围的开发团体都了解大量并发控制对性能的影响,
他们在mysql 5.5中已经解决了某些问题。未来的mysql中,%system占用的cpu会越来越少。
但是,%user占用的60%cpu怎样处理呢?
- Mutex contentions result in %system increase, not %user increase
即使所有的并发问题都得到处理,估计也很难做到300,000 qps。
或许你听说过HANDLER statement的性能也不错。
可是HANDLER statement需要query parsing,需要open/close table。
不会有太大的帮助。
如果只有一小部分数据能够进入内存,那么SQL语句的解析带来的额外负担已经不算什么了。
因为磁盘的IO操作会消耗更长的时间。
在我们的mysql服务器中,内存是大大的,几乎所有的数据都可以放进内存。
SQL层就变成了额外负担,占用了大量的cpu资源。
在线上的应用中,我们要进行大量的PK查询。即使70-80%的查询都是在同一张表上进行的, mysql还是每次都要parse/open/lock/unlock/close,看起来就感觉效率低下。
- We needed to execute lots of primary key lookups(i.e. SELECT x FROM t WHERE id=?) or limited range scans. Even though 70-80% of queries were simple PK lookups
- from the same table (difference was just values in WHERE), every time
- MySQL had to parse/open/lock/unlock/close, which seemed not efficient for us.
花荣注:难道说mysql中的table_open_cache不是用来减少table open的次数的么。。
有没有办法在sql层进行优化呢?
http://dev.mysql.com/doc/ndbapi/en/index.html
如果你使用mysql cluster, NDBAPI会是最佳解决方案。
- It’s recommended using NDBAPI for frequent access patterns,
- and using SQL + MySQL + NDB for ad-hoc or infrequent query patterns.
这就是我们想要的:
1 faster access API.
2 sql语句仍然要可用,以处理一些特定的或者复杂的查询。
但是,把innodb转化成ndb可不是一件轻松的事情。
最好的办法是在mysql内部实现一个NoSQL的网络服务。daemon plugin。
它监听在某个端口,接受NoSQL 协议/API的数据包,使用Mysql internal storage engine API直接在innodb数据表上进行操作,并且返回相应的数据。
关于mysql internal storage engine API可以看这个文档:
http://www.gxlcms.com/
这个概念首先被Cybozu Labs 的Kazuho Oku 提出,然后他写了一个MyCached UDF,用的是memcached的协议。
http://developer.cybozu.co.jp/kazuho/2009/08/mycached-memcac.html
随后,Akira Higuchi 写了另外一个plugin: HandlerSocket。
http://github.com/ahiguti/HandlerSocket-Plugin-for-MySQL
从图中可以看到,客户端既可以使用普通的mysql api来操作mysql(3306端口),
也可以使用HandlerSocket API对数据库进行PK查询,以及INSERT/UPDATE/DELETE操作(9998与9999端口)。
在使用HandlerSocket操作的时候,省去了SQL parsing, Opening table, Making Query Plans, Closing table等步骤。
而且数据都是保存在原来的INNODB表中的。
在HandlerSocket操作innodb数据表的时候,显然也需要open/close table。
但它只打开一次,然后会reuse。
由于open/close table非常耗时,并且会带来严重的mutex竞争,所以这种改进,极大地提升了性能。
Of course HandlerSocket closes tables when traffics become small etc so that it won’t block administrative commands (DDL) forever.
memcached主要用来缓存数据集(database records)。
因为memcached的get操作比mysql的PK查询要快得多。
如果HandlerSocket获取数据的速度比memcached还要快,那么我们就没必要再使用memcached来缓存数据集了。做做其它缓存还是可以的。比如生成出来的HTML代码,还有一些统计数据等等。
花荣注:貌似我从来没有直接把mysql的数据集扔到memcached中。一直都是把中间结果保存到里面。难道走偏了?
看下面这张user表:
- CREATE TABLE user (
- user_id INT UNSIGNED PRIMARY KEY,
- user_name VARCHAR(50),
- user_email VARCHAR(255),
- created DATETIME
- ) ENGINE=InnoDB;
在mysql中取出数据的方法如下:
- mysql> SELECT user_name, user_email, created FROM user WHERE user_id=101;
- +---------------+-----------------------+---------------------+
- | user_name | user_email | created |
- +---------------+-----------------------+---------------------+
- | Yukari Takeba | yukari.takeba@dena.jp | 2010-02-03 11:22:33 |
- +---------------+-----------------------+---------------------+
在HandlerSocket中怎样操作呢?
详细文档看这里:
http://github.com/ahiguti/HandlerSocket-Plugin-for-MySQL/blob/master/docs-en/installation.en.txt
大概安装步骤如下:
1 下载
http://github.com/ahiguti/HandlerSocket-Plugin-for-MySQL
2 编译 HandlerSocket客户端和服务器端程序:
- ./configure --with-mysql-source=... --with-mysql-bindir=... ; make; make install
3 安装插件
- mysql> INSTALL PLUGIN 'HandlerSocket' SONAME 'HandlerSocket.so';
安装完毕。不需要修改mysql的源代码。
mysql需要5.1或者以后版本。
目前HandlerSocket客户端只有C++ 和 Perl的库。还没有php和C的。
|
|
这段脚本从user表中取出来了 user_name, user_email 和created字段。
- [matsunobu@host ~]$ perl sample.pl
- Yukari Takeba yukari.takeba@dena.jp 2010-02-03 11:22:33
对于HandlerSocket,推荐使用persistent connection。以减少数据库连接的次数。
HandlerSocket协议 is a small-sized text based protocol。
与memcached类似,可以使用telnet来获取数据。
- [matsunobu@host ~]$ telnet 192.168.1.2 9998
- Trying 192.168.1.2...
- Connected to xxx.dena.jp (192.168.1.2).Escape character is '^]'.
- P 0 test user PRIMARY user_name,user_email,created
- 0 1
- 0 = 1 101
- 0 3 Yukari Takeba yukari.takeba@dena.jp 2010-02-03 11:22:33
测试环境:
- CPU: Nehalem 8 cores, E5540 @ 2.53GHz
- RAM: 32GB (all data fit in the buffer pool)
- MySQL Version: 5.1.50 with InnoDB Plugin
- memcached/libmemcached version: 1.4.5(memcached), 0.44(libmemcached)
- Network: Broadcom NetXtreme II BCM5709 1000Base-T x 3
仍然使用上面的user表,数据大概100w行。
SQL语句为:
- SELECT user_name, user_email, created FROM user WHERE userid=?
memcached和HandlerSocket的客户端代码都用C/C++编写。
所有的客户端程序都位于另外一台机器上。通过TCP/IP与MYSQL/memcached服务器连接。
测试结果如下:
- approx qps server CPU util
- MySQL via SQL 105,000 %us 60% %sy 28%
- memcached 420,000 %us 8% %sy 88%
- HandlerSocket 750,000 %us 45% %sy 53%
HandlerScket比传统的mysql快了7.5倍,而且%us的cpu使用率为mysql的3/4。
说明SQL层还是相当耗时的。避开SQL层之后,性能得到了明显的提升。
HandlerSocket比memcached快了78%。而且%sy占用的cpu比memcached要少得多。
虽然memcached是一个优秀的产品,但是还有很大的提升空间。
花荣注:比如七夜就改写了memcached的部分代码。
再来看一下HandlerSocket测试的时候oprofile的输出:
- 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
大部分的CPU用在了网络数据包的处理,取出数据,等。
排在首位的bnx2是网卡驱动程序。
由于HandlerSocket只是一个插件,最终还会调用innodb引擎的函数去取数据,
所以我们仍然可以使用mysql命令来获取到统计数据。
- $ mysqladmin extended-status -uroot -i 1 -r -p| grep “InnoDB_rows_read”
- …| Innodb_rows_read | 750192 |
- | Innodb_rows_read | 751510 |
- | Innodb_rows_read | 757558 |
- | Innodb_rows_read | 747060 |
- | Innodb_rows_read | 748474 |
- | Innodb_rows_read | 759344 |
- | Innodb_rows_read | 753081 |
- | Innodb_rows_read | 754375 |
作者注:memcached和HandlerSocket的性能都会受到网络IO的限制。
上面的测试是在3块千M网卡的环境下进行的。如果换成单网卡,HandlerSocket大概每秒处理260,000次查询,memcached每秒处理220,000次查询。
PK肯定没问题
unique key也可以。
普通key也可以。
limit 语句也可以。
IN 也没问题。
INSERT/UPDATE/DELETE也没问题。
不过,一定要用到索引才行。
不使用索引的操作不被支持。 Operations that do not use any index are not supported。
详细说明看这里:http://www.gxlcms.com/
HandlerSocket employs epoll() and worker-thread/thread-pooling architecture,the number of MySQL internal threads is limited 。
所以放心地使用persistent connection吧。不会导致mysql connection太高的。
Not only HandlerSocket eliminates SQL related function calls, but also it optimizes around network/concurrency issues
HandlerSocket不仅避开了SQL层,而且优化了网络层,并解决了并发的一些问题。
与mysql协议相比,HandlerSocket协议的数据包更简单更小。
从总体上来看,网络传输的数据量会减少。
不会导致mysql connection太高。
当HandlerSocket接受到请求的时候,每一个处理线程都会收集尽可能多的请求,
然后一次把这些请求执行完毕,并返回数据。
看起来没什么神奇的,但是却可以大大地提升性能。
代价是每个请求的响应时间略微变长。
*** Can reduce the number of fsync() calls
*** Can reduce replication delay
至于详细情况,作者会再写其它文章。很期待。
我们使用memcached的时候,数据会同时缓存到innodb的buffer pool与memcached中。
算是重复的cache吧。
HandlerSocket自身没有缓存,它完全听从InnoDB storage engine。
缓存的一大问题就是数据何时过期。
HandlerSocket没有缓存,也就不存在这种问题。
InnoDB还是相当可靠的。
innodb-flush-log-at-trx-commit=1 加上这句就更保险了。
最多会丢失死机前1秒内的数据。
我们仍然可以使用SQL语句进行复杂的查询。
确实方便很多啊。
HandlerSocket作为插件运行于mysql内部,所以mysql的操作,比如SQL, 热备份,主从,Nagios监视等等,都是支持的。
通过 show global status, show engine innodb status , show processlist 这些都可以看到HandlerSocket的状态。
无需改动mysql的源代码或者重新编译mysql。
线上的环境可以直接使用HandlerSocket。
理论上讲,HandlerSocket支持任何的存储引擎,比如myisam,memory?
不过目前只在mysql5.1 5.5 InnoDB的环境下进行过测试和应用。
目前只有C++和PERL库可用。以后肯定会有php扩展出现。
就像其它的NoSQL数据一样,HandlerSocket没有任何安全方面的功能。比如权限控制之类的。
HandlerSocket的工作线程使用system权限,所以你的应用可以存取所有的表。
当然可以使用防火墙来限制访问。
如果你的内存不够大,内存要与硬盘交换数据,那么HandlerSocket的优势就体现不出来了。
We use HandlerSocket on servers that almost all data fit in memory.
DeNA公司已经在生产环境上使用HandlerSocket了。
The results are great!
有了HandlerSocket可以省掉很大一批memcached服务器与mysql从服务器。
而且带宽占用也得到了缓解。
- We’ve been very satisfied with the results。
- Since HandlerSocket plugin is Open Source, feel free to try. We’d be appreciated if you give us any feedback.
以上就是[转]Mysql的HandlerSocket插件 的内容,更多相关内容请关注PHP中文网(www.gxlcms.com)!