技术开发 频道

NoSQL:单服务器如何应付每秒75万次查询

  接下来需要编写HandlerSocket客户端代码,我们提供了C++和Perl客户端库,下面是一个简单的Perl代码示例,它通过主键查询获取一行记录。

#!/usr/bin/perl  
use strict;  
use warnings;  
use Net::HandlerSocket;  
#
1. establishing a connection  my $args = { host => 'ip_to_remote_host', 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',      'user_name,user_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)  $res
= $hs->execute_single(0, '=', [ '101' ], 1, 0);  
die $hs->get_error() if $res->[0] != 0;  
shift(@$res);  
for (my $row = 0; $row < 1; ++$row)
{    
my $user_name
= $res->[$row + 0];  
my $user_email
= $res->[$row + 1];    
my $created
= $res->[$row + 2];    
print
"$user_name\t$user_email\t$created\n";  
}  
#
4. closing the connection  $hs->close();

 

  上面的代码从user表查询user_name,user_email和created列,查询条件是user_id=101,因此查询结果和前面的SELECT语句一样。

  对于大多数Web应用程序而言,保持轻量级的HandlerSocket连接是一个很好的做法(持续连接),让大量的请求可以集中于主要逻辑(上面代码中的#3部分)。

  HandlerSocket协议是一个小尺寸的基于文本的协议,和Memcached文本协议类似,你可以使用telnet通过HandlerSocket获取数据。

[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

 

  绿色表示请求数据包,字段必须用Tab键分隔。

  基准测试

  现在是时候展示我们的基准测试结果了,我使用上面的user表,从多线程远程客户端测试了执行主键查询操作的次数,所有用户数据都装入到内存中(我测试了100万行),我也用类似的数据测试了Memcached(我使用libmemcached和memcached_get()获取用户数据),在MySQL SQL测试中,我使用了一个传统的SELECT语句:“SELECT user_name, user_email, created FROM user WHERE user_id=?”,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%  
MySQL via HandlerSocket                      
750,000      %us 45%  %sy 53%  

 

  通过HandlerSocket比传统的SQL语句吞吐量要高出7.5倍,这说明了MySQL的SQL层是非常耗资源的,如果能跳过这一层性能肯定会大大提升。有趣的是,MySQL使用HandlerSocket时的速度比使用Memcached快178%,并且Memcached消耗的%system资源也更多,虽然Memcached是一个很好的产品,但仍然有优化的空间。

  下面是oprofile输出内容,是在MySQL HandlerSocket测试期间收集到的,在核心操作,如网络数据包处理,获取数据等的CPU资源消耗(bnx2是一个网络设备驱动程序)。

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

 

  因为HandlerSocket是运行在MySQL内部的,并直接与InnoDB打交道,你可以使用常见的SQL命令,如SHOW GLOBAL STATUS获得统计信息,Innodb_rows_read达到了750000+是值得一看的。

$ mysqladmin extended-status -uroot -i 1 -r | 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     |  ...

 

  测试用机详细规格如下:

  型号:戴尔PowerEdge R710

  CPU:Nehalem 8核,E5540@2.53GHz

  内存:32GB(所有数据都装入缓冲池)

  MySQL版本:5.1.50,InnoDB插件

  Memcached/libmemcached版本:1.4.5(Memcached),0.44(libmemcached)

  网络:Boradcom NetXtreme II BCM5709 1000Base-T(内建四端口,使用了其中三个)

  Memcached和HandlerSocket都做了网络I/O限制,当我测试单个端口时,HandlerSocket的成绩是260000qps,Memcached的成绩是220000qps。 

0
相关文章