zl程序教程

您现在的位置是:首页 >  其他

当前栏目

MySQLHandlerSocket插件安装配置教程

2023-06-13 09:15:24 时间

一、HandlerSocket是什么?
HandlerSocket是akirahiguchi写的一个MySQL的插件。以MySQLDaemonPlugin的形式提供类似NoSQL的网络服务,通过这个插件,你可以直接跟MySQL后端的存储引擎做key-value式的交互,省去了MySQL上层的SQL解释、打开关闭表、创建查询计划等CPU开销。

目前使用MySQL的网站,多半同时使用Memcache作为键值缓存。虽然这样的架构极其流行,有众多成功的案例,但过于依赖Memcache,无形中让Memcache成为故障的根源:
Memcache数据一致性的问题:当MySQL数据变化后,如果不能及时有效的清理掉过期的数据,就会造成数据不一致。这在强调即时性的Web2.0时代,不可取。
Memcache崩溃后的雪崩效应:作为缓存的Memcache一旦崩溃,MySQL很可能在短时间内承受高负载而宕机。

注:关于清理过期数据的问题,可以在程序架构上想办法,如果数据操作有统一DAO封装的话,可以利用Observer模式来清理过期数据,非主题内容,资料自查。

面对以上问题,HandlerSocket项目是个不错的解决方案,它通过插件的方式赋予MySQL完整的NoSQL功能,从原理上讲,它跳过MySQL中最耗时的语法解析,查询计划等步骤,直接读取数据,如果内存够大,能装下索引,MySQL的查询效率能提高若干倍!
HandlerSocket:https://github.com/ahiguti/HandlerSocket-Plugin-for-MySQL
php-handlersocket:http://code.google.com/p/php-handlersocket/

系统信息约定:
系统版本:CentOS6.3X86
PHP安装目录:/usr/local/webserver/php5318
MySQL安装目录:/usr/local/webserver/mysql5520
HandlerSocket安装路径:/usr/local/webserver/handlersocket

二、安装配置HandlerSocket

安装之前建议你先安装相关支持及需要的组件包:

复制代码代码如下:
yuminstallgccgcc-c++libtoolmakeopenssl-develperl-DBIperl-DBD-MySQL
yuminstallrpm-buildgperfreadline-develncurses-develtimeperl-Time-HiRes

1.安装
如果使用PerconaServer版本的MySQL就简单了,因为它已经内置了HandlerSocket支持,不过考虑到其内置的版本不够新,存在一些早已修复的BUG,所以最好采用源代码编译。HandlerSocket是基于MySQL数据库的,因此在安装HanderSocket前需要先按照常规方式部署MySQL服务,同时需注意HandlerSocket时需要MySQL的源码,因此还需要MySQL源码编译方式安装。

复制代码代码如下:


[root@iredmailopt]#gitclonehttps://github.com/ahiguti/HandlerSocket-Plugin-for-MySQL.git
[root@iredmailopt]#cdHandlerSocket-Plugin-for-MySQL
[root@iredmailHandlerSocket-Plugin-for-MySQL]#./autogen.sh
[root@iredmailHandlerSocket-Plugin-for-MySQL]#./configure--prefix=/usr/local/webserver/handlersocket--with-mysql-source=/opt/mysql-5.5.20--with-mysql-bindir=/usr/local/webserver/mysql5520/bin--with-mysql-plugindir=/usr/local/webserver/mysql5520/lib/mysql/plugin

Tips:
--with-mysql-source指定MySQL源码所在目录
--with-mysql-bindir表示MySQL二进制可执行文件目录
--with-mysql-plugindir指定MySQL插件的存储路径,如果不清楚这个目录在哪,可以按如下方法查询:

复制代码代码如下:mysql>showvariableslike"plugin%";
+---------------+-------------------------------------------+
|Variable_name|Value                                    |
+---------------+-------------------------------------------+
|plugin_dir   |/usr/local/webserver/mysql5520/lib/plugin|
+---------------+-------------------------------------------+
1rowinset(0.00sec)
[root@iredmailHandlerSocket-Plugin-for-MySQL]#make

常见错误:

复制代码代码如下:libtool:link:onlyabsoluterun-pathsareallowed
make[2]:***[handlersocket.la]Error1
make[2]:Leavingdirectory`/opt/HandlerSocket-Plugin-for-MySQL/handlersocket"
make[1]:***[all-recursive]Error1
make[1]:Leavingdirectory`/opt/HandlerSocket-Plugin-for-MySQL"
make:***[all]Error2
解决方法:
[root@iredmailHandlerSocket-Plugin-for-MySQL]#vihandlersocket/Makefile
line301:
$(handlersocket_la_LINK)-rpath$(pkgplugindir)$(handlersocket_la_OBJECTS)$(handlersocket_la_LIBADD)$(LIBS)
-->
$(handlersocket_la_LINK)-rpath/opt/HandlerSocket-Plugin-for-MySQL/handlersocket$(handlersocket_la_OBJECTS)$(handlersocket_la_LIBADD)$(LIBS)

[root@iredmailHandlerSocket-Plugin-for-MySQL]#makeinstall


完成后,mysql-plugindir目录下应有handlersocket相关文件

2、配置MySQL:

修改my.cnf配置文件:

复制代码代码如下:[root@iredmailHandlerSocket-Plugin-for-MySQL]#vi/etc/my.cnf
[mysqld]
plugin-load=handlersocket.so(plugin-load可略过不配)
loose_handlersocket_port=9998#指定读请求端口号
#theportnumbertobindto(forreadrequests)
loose_handlersocket_port_wr=9999#指定写请求端口号
#theportnumbertobindto(forwriterequests)
loose_handlersocket_threads=16#指定读线程数目
#thenumberofworkerthreads(forreadrequests)
loose_handlersocket_threads_wr=1#指定写线程数目
#thenumberofworkerthreads(forwriterequests)
open_files_limit=65535
#toallowhandlersocketacceptmanyconcurrenconnections,makeopen_files_limitaslargeaspossible.

Tips:InnoDB的innodb_buffer_pool_size,或MyISAM的key_buffy_size等关系到缓存索引的选项尽可能设置大一些,这样才能发挥HandlerSocket的潜力。

登陆MySQL并激活HandlerSocket插件:

复制代码代码如下:[root@iredmailHandlerSocket-Plugin-for-MySQL]#mysql-uroot-p
mysql>installpluginhandlersocketsoname"handlersocket.so";
ERROR1126(HY000):Can"topensharedlibrary"/usr/local/webserver/mysql5520/lib/plugin/handlersocket.so"(errno:2cannotopensharedobjectfile:Nosuchfileordirectory)
说明:这里提示没有找到handlersocket.so扩展文件,请查看扩展文件是否存在。
mysql>installpluginhandlersocketsoname"handlersocket.so";
QueryOK,0rowsaffected(0.00sec)

mysql>quit;


至此,HandlerSocket插件安装完毕。

重启mysql服务:

复制代码代码如下:[root@iredmailHandlerSocket-Plugin-for-MySQL]#servicemysqldrestart

3、HandlerSocket状态测试:

   

也可以通过查询刚配置的端口是否已经被MySQL占用来确认是否安装成功:
复制代码代码如下:[root@iredmailHandlerSocket-Plugin-for-MySQL]#lsof-i-P|grepmysqld
mysqld   26871mysql  11u IPv4 72467     0t0 TCP*:9998(LISTEN)
mysqld   26871mysql  29u IPv4 72469     0t0 TCP*:9999(LISTEN)
mysqld   26871mysql  31u IPv4 72474     0t0 TCP*:3306(LISTEN)

Tips:Ifports9998and9999don"tshowup. MakesureSELinuxisnotrunning.

三、安装配置php-handlersocket扩展模块:

1、安装php-handlersocket扩展

复制代码代码如下:[root@iredmailopt]#wgethttp://php-handlersocket.googlecode.com/files/php-handlersocket-0.3.1.tar.gz
[root@iredmailopt]#tar-zxvfphp-handlersocket-0.3.1.tar.gz
[root@iredmailopt]#cdhandlersocket/
[root@iredmailhandlersocket]#/usr/local/webserver/php5318/bin/phpize
[root@iredmailhandlersocket]#./configure--with-php-config=/usr/local/webserver/php5318/bin/php-config
./configure可加参数:

 Tips:Ifyougeterror:
configure:error:Can"tfindhsclient headers,pleaseinstalllibhsclientfirst,Or./configure--disable-handlersocket-hsclient--with-php-config=/usr/local/webserver/php5318/bin/php-configusenativetype.
复制代码代码如下:[root@iredmailhandlersocket]#make&&makeinstall
Asuccessfulinstallwillhavecreatedhandlersocket.soandputitintothePHPextensionsdirectory.You"llneedtoandadjustphp.iniandaddanextension=handlersocket.solinebeforeyoucanusetheextension.
复制代码代码如下:[root@iredmailhandlersocket]#vi/usr/local/webserver/php5318/etc/php.ini
extension=handlersocket.so

至此php扩展安装完成,放问php.info页面,我们可以看到已经成功加载了handlersocket扩展

 2、php-handlersocket使用示例:
复制代码代码如下:
/*
 *String  $host:MySQLip;
 *String  $port:handlersocket插件的监听端口,它有两个端口可选:一个用于读、一个用于写
 */
$hs=newHandlerSocket($host,$port);
打开一个数据表:
/*
 *Int      $index:这个数字相当于文件操作里的句柄,HandlerSocket的所有其他方法都会依据这个数字来操作由这个   openIndex打开的表,
 *String  $dbname:库名
 *String  $table:表名
 *String  $key:表的“主键”(HandlerSocket::PRIMARY)或“索引名”作为搜索关键字段,这就是说表必须有主键或索引
 *                个人理解:要被当做where条件的key字段,这样可以认为handlersocket只有一个where条件
 *String  $column:"column1,column2"所打开表的字段(以逗号隔开),就是说$table表的其他字段不会被操作
 */
$hs->openIndex($index,$dbname,$table,$key,$column);
查询:
/*
 *Int    $index:openIndex()所用的$index
 *String  $operation:openIndex方法中指定的$key字段所用的操作符,目前支持"=",">=","<=",">",and"<";可以理解为where条件
 *Array  $value
 *Int      $number(默认是1):获取结果的最大条数;相当于SQL中limit的第二个参数
 *Int    $skip(默认是0):跳过去几条;相当于SQL中limit的第一个参数
 */
$retval=$hs->executeSingle($index,$operation,$value,$number,$skip);
插入(注意:此处的openIndex要用$port_wr,即读写端口):
/*
 *Int    $index:openIndex()所用的$index
 *Array  $arr:数字元素数与openIndex的$column相同
 */
$retval=$hs->executeInsert($index,$arr);
删除(注意:此处的openIndex要用$port_wr,即读写端口):
/*
 *Int    $index:openIndex()所用的$index
 *String  $operation:openIndex方法中指定的$key字段所用的操作符,目前支持"=",">=","<=",">",and"<";可以理解为where条件
 *Array  $value
 *Int    $number(默认是1):获取结果的最大条数;相当于SQL中limit的第二个参数
 *Int    $skip(默认是0):跳过去几条;相当于SQL中limit的第一个参数
 */
$retval=$hs->executeDelete($index,$operation,$value,$number,$skip);
更新(注意:此处的openIndex要用$port_wr,即读写端口):
/*
 *Int    $index:openIndex()所用的$index
 *String  $operation:openIndex方法中指定的$key字段所用的操作符,目前支持"=",">=","<=",">",and"<";可以理解为where条件
 *Array  $value
 *Int      $number(默认是1):获取结果的最大条数;相当于SQL中limit的第二个参数
 *Int    $skip(默认是0):跳过去几条;相当于SQL中limit的第一个参数
 */
$retval=$hs->executeUpdate($index,$operation,$value,$number,$skip);

Example:
测试库hstestdb,测试表hstesttbl:

复制代码代码如下:CREATETABLE`hstesttbl`(
 `id`int(11)NOTNULLAUTO_INCREMENT,
 `k`char(6)DEFAULTNULL,
 `v`char(6)DEFAULTNULL,
 PRIMARYKEY(`id`),
 KEY`idx_hstesttbl_k`(`k`)
)ENGINE=InnoDBAUTO_INCREMENT=7DEFAULTCHARSET=utf8;

PHPTestCode:

复制代码代码如下:
$host      ="localhost";
$port      =9998;
$port_wr    =9999;
$dbname    ="hstestdb";
$table      ="hstesttbl";

//GET
$hs=newHandlerSocket($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=newHandlerSocket($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)===false){
    echo$hs->getError(),PHP_EOL;
    die();
}

unset($hs);

//INSERT
$hs=newHandlerSocket($host,$port_wr);
if(!($hs->openIndex(3,$dbname,$table,"","k,v"))){
    echo$hs->getError(),PHP_EOL;
    die();
}

if($hs->executeInsert(3,array("k2","v2"))===false){
    echo$hs->getError(),PHP_EOL;
}
if($hs->executeInsert(3,array("k3","v3"))===false){
    echo"A",$hs->getError(),PHP_EOL;
}
if($hs->executeInsert(3,array("k4","v4"))===false){
    echo"B",$hs->getError(),PHP_EOL;
}

unset($hs);

//DELETE
$hs=newHandlerSocket($host,$port_wr);
if(!($hs->openIndex(4,$dbname,$table,"",""))){
    echo$hs->getError(),PHP_EOL;
    die();
}

if($hs->executeDelete(4,"=",array("k2"))===false){
    echo$hs->getError(),PHP_EOL;
    die();
}
?>

Tips:理论上HandlerSocket支持MyISAM,InnoDB等各种引擎,不过推荐使用InnoDB。
Tips:Toavoidtheinserterror,Pleaseremembersetstorageengine:InnoDB.
Tips:对HandlerSocket一个常见的误解是只能执行PRIMARY类型的KV查询,实际上只要支持索引,一般的简单查询它都能胜任,这里就不多说了,官方文档里有介绍。

HandlerSocket的缺陷:

(1)写操作并没有淘汰查询缓存——如果执行了写操作通过HandlerSocket,由于没有失效查询缓存,那么你可能从MySQL读到旧的数据;
(2)不支持自动递增——插入时无法从自增列上自动获得增量值。
鉴于以上问题,扬长避短,使用其合并查询操作,发挥其NoSQL性能获取MySQL的InnoDB类型表数据,具体操作如下:

复制代码代码如下:
<?php  
//通过handlersocket获取数据  
$hs=newHandlerSocket(HS_HOST,HS_PORT);  
if(!($hs->openIndex(1,"dbname","table",HandlerSocket::PRIMARY,"id,content,create_uid,create_user,created,state"))){  
  echo$hs->getError(),PHP_EOL;  
  die();  
}  
$dataList=array();  
foreach($idsas$id){
  $dataList[]=array(1,"=",array($id));  
}  
$data=$hs->executeMulti($dataList);  

写在最后的:
MySQL5.6提供原生的MemcachedAPI,实际就是KV型NoSQL了,但HandlerSocket并不局限于KV形式,所以仍然有生存空间。