MySQL的NoSQL扩展---HandlerSocket插件

MySQL的NoSQL扩展---HandlerSocket插件
一. HandlerSocket 介绍:
2010 11 月日本社交游戏开发公司 DeNA 发布了 MySQL HandlerSocket 插件。 Handlersocket 插件是由日本人 Yoshinori Matsunobu 开发的。传统的关系型数据库在处理每个请求的时候,都需要做 SQL 解析,查询优化,执行,事务管理,锁管理等一系列的开销操作,消耗性能。非关系型数据库( NoSQL )就去掉了这些操作。通过 handlersocket 插件,可以直接跟 MySQL 的存储引擎层做 key-value 式的交互操作,省略了 MySQL SQL 层次的处理,大大的减少了资源的开销。
 
二. HandlerSocket 架构:
HandlerSocket MySQL 内部实现一个 NoSQL 的网络服务,以 mysqld 进程的 daemon 存在,监听特定端口( 9998 9999 )与 client 通过 TCP/IP 接收 NoSQL 的协议和 API ,然后通过 MySQL 存储引擎 API 直接进行 CRUD 相关的操作。同时,还可以通过传统的 MySQL 的方式进行操作。
简单快速的操作通过 handlersocket 来实现。复杂的操作通过传统的 MySQL 方式来实现。
 
HandlerSocket 结构图如下:
1. MySQL Client à MySQL Upper Layer à Storage Engine Layer
使用 MySQL 传统的方式,客户端通过 3306 端口与 Upper 层交互,在 Upper 层进行 SQL 解析,打开表,查询优化,关闭表等等操作,然后再提交到 Storage Engine 层。
2. HandlerSocket Client à HandlerSocket daemon plugin à Storage Engine Layer
使用 HandlerSocket 方式,减少了很多在传统方式下的 SQL 层的操作。使用 9998 端口进行读操作,使用 9999 端口进行写操作。
                    
 
三. HandlerSocket 优缺点:
优点:
1. 省去了 MySQL SQL 层相关的操作,大大的减少了 CPU 的消耗。
2. 采用合并操作的方式,合并多个请求同时执行,减少了 CPU 开销和 IO 操作次数。
3. 基于简单的文本协议,节省网络流量,提高网络吞吐量。
4. 能同时使用传统的 MySQL HandlerSocket 的方式访问 MySQL 数据库,互不冲突。
5. 支持大的并发连接。
6. 可以继续使用 MySQL Replication 等等成熟机制。
7. 避免有双重缓存。
8. 具有较高的读写性能,在 CPU Bound 的场景中,读取性能一般是同等环境下的 MySQL 3-7.5 倍。同时写入性能也能达到 3-5 倍。
不足之处:
1. 由于采用合并操作的方式,响应时间比 MySQL 来说大一些。
2. 没有安全相关的保证,绝大部分 NoSQL 产品都有这样的问题。
3. IO Bound 的场景中,性能的提升可能不是很明显。
4. 目前只支持 MySQL5.1 MySQL5.5 版本的 Innodb 存储引擎。
 
四. HandlerSocket 的安装:
1. 下载安装
# wget  https://download.github.com/ahiguti-HandlerSocket-Plugin-for-MySQL-1.0.6-71-g159ea6d.tar.gz
# tar zxvf ahiguti-HandlerSocket-Plugin-for-MySQL-1.0.6-71-g159ea6d.tar.gz -C ../software/
#  cd ../software/ahiguti-HandlerSocket-Plugin-for-MySQL-159ea6d/
# ./autogen.sh
# ./configure --prefix=/usr/local/handlersocket
--with-mysql-source=/usr/local/src/software/mysql-5.1.36  //mysql 源码目录
 --with-mysql-bindir=/usr/local/mysql-5.1.36/bin //mysql 安装目录可执行目录
 --with-mysql-plugindir=/usr/local/mysql-5.1.36/lib/mysql/plugin //mysql 插件目录
# make
# make install
 
2. 修改配置文件
my.cnf 文件 [mysqld] 下增加以下配置:
loose_handlersocket_port = 9998  // 指定读请求端口号
loose_handlersocket_port_wr = 9999 // 指定写请求端口号
loose_handlersocket_threads = 16 // 指定读线程数目
loose_handlersocket_threads_wr = 1 // 指定写线程数目
 
3. 安装 handlersocket.so
> INSTALL PLUGIN handlersocket SONAME 'handlersocket.so';
 
4. 查看进程状态
# netstat -ntpl
tcp        0      0 0.0.0.0:3306       0.0.0.0:*        LISTEN      31402/mysqld       
tcp        0      0 0.0.0.0:9998       0.0.0.0:*        LISTEN      31402/mysqld       
tcp        0      0 0.0.0.0:9999       0.0.0.0:*        LISTEN      31402/mysqld        
 
5. 常见问题
configure: error: MySQL source version does not match MySQL binary version
解决方法:在 configure.in 文件中首行添加一行 [MySQL Server] 5.1.36
 
五. HandlerSocket 性能测试:
先来看看软件作者的测试结果:
环境: 2.53GHZ 8 CPU 32G 内存的 Nehalem 服务器
结果:
 
六. 安装 PHP 扩展包 php-handlersocket
# wget http://php-handlersocket.googlecode.com/files/php-handlersocket-0.0.7.tar.gz
# tar zxvf php-handlersocket-0.0.7.tar.gz -C ../software/
# /usr/local/php5.2.13/bin/phpize
# ./configure --prefix=/usr/local/php-handlersocket \
--with-php-config=/usr/local/php5.2.13/bin/php-config \
  --with-handlersocket \
  --with-handlersocket-includedir=/usr/local/handlersocket/include/handlersocket
# make
# make install
# vim /usr/local/Zend/etc/php.ini
     添加下面一行
     extension=/usr/local/php5.2.13/lib/php/extensions/no-debug-zts-20060613/handlersocket.so
     查看是否加载成功:
 
常见问题:
cc -shared  .libs/handlersocket.o  -lstdc++ -L/usr/local/handlersocket/include/handlersocket/lib -lhsclient  -Wl,-rpath -Wl,/usr/local/handlersocket/include/handlersocket/lib -Wl,-soname -Wl,handlersocket.so -o .libs/handlersocket.so
/usr/bin/ld: cannot find -lhsclient
collect2: ld returned 1 exit status
make: *** [handlersocket.la] Error 1
解决方法: # cd /usr/local/handlersocket
          # cp -rf lib include/handlersocket/
 
七. 测试:
1. 建立测试表
mysql>  create table `test_hs` (
-> `id` int(10) auto_increment not null,
-> `k` varchar(50) default null,
-> `v` varchar(50) default null,
-> primary key (`id`),
-> key `index_k` (`k`)
    -> )engine=innodb;
 
mysql> insert into test_hs values ('','k1','v1');
mysql> insert into test_hs values ('','k2','v2');
mysql> insert into test_hs values ('','k3','v3');
 
2. PHP 使用实例
<?php
$host = 'localhost';
$port = 9998;
$port_wr = 9999;
$dbname = 'hstestdb';
$table = 'hstesttbl';
 
 
//GET
$hs = new HandlerSocket($host, $port);
if (!($hs->openIndex(1, $dbname, $table, HandlerSocket::PRIMARY, 'k,v')))
{
    echo $hs->getError(), PHP_EOL;
    die();
}
 
$retval = $hs->executeSingle(1, '=', array('k1'), 1, 0);
 
var_dump($retval);
 
$retval = $hs->executeMulti(
    array(array(1, '=', array('k1'), 1, 0),
          array(1, '=', array('k2'), 1, 0)));
 
var_dump($retval);
 
unset($hs);
 
 
//UPDATE
$hs = new HandlerSocket($host, $port_wr);
if (!($hs->openIndex(2, $dbname, $table, '', 'v')))
{
    echo $hs->getError(), PHP_EOL;
    die();
}
 
if (!($hs->executeUpdate(2, '=', array('k1'), array('V1'), 1, 0)))
{
    echo $hs->getError(), PHP_EOL;
    die();
}
 
unset($hs);
 
 
//INSERT
$hs = new HandlerSocket($host, $port_wr);
if (!($hs->openIndex(3, $dbname, $table, '', 'k,v')))
{
    echo $hs->getError(), PHP_EOL;
    die();
}
 
if (!($hs->executeInsert(3, array('k2', 'v2'))))
{
    echo $hs->getError(), PHP_EOL;
}
if (!($hs->executeInsert(3, array('k3', 'v3'))))
{
    echo $hs->getError(), PHP_EOL;
}
if (!($hs->executeInsert(3, array('k4', 'v4'))))
{
    echo $hs->getError(), PHP_EOL;
}
 
unset($hs);
 
 
//DELETE
$hs = new HandlerSocket($host, $port_wr);
if (!($hs->openIndex(4, $dbname, $table, '', '')))
{
    echo $hs->getError(), PHP_EOL;
    die();
}
 
if (!($hs->executeDelete(4, '=', array('k2'))))
{
    echo $hs->getError(), PHP_EOL;
    die();
}
 
3. 方法注释
openIndex(1, $dbname, $table, HandlerSocket::PRIMARY, 'k,v')
打开索引,第一个参数 1 用来在每个 HandlerSocket 对象中唯一标识一个表名; $dbname 表示为数据库名; $table 表示为表名; HandlerSocket::PRIMARY 表示为索引名; 'k,v' 表示为要查询的列名。
executeSingle(1, '=', array('k1'), 1, 0)
执行查询,第一个参数要跟之前的 openIndex 方法中的第一个参数保持一致;第二个参数 ’=’ 表示检索的条件,支持 ’=’,’>=’,’<=’,’>’,’<’ ;第三个参数 array(‘k1’) 表示一个 arrayref ,指定检索的 key ,其长度必须小于或者等于对应索引的列数;第四个和第五个参数指定查询的 limit offset  
executeMulti 可在一次调用中执行多个操作。

你可能感兴趣的:(mysql,NoSQL,插件,handlersocket)