php HandlerSocket的使用


Posted in PHP onMay 02, 2011
  • Memcache数据一致性的问题:当MySQL数据变化后,如果不能及时有效的清理掉过期的数据,就会造成数据不一致。这在强调即时性的Web2.0时代,不可取。
  • Memcache崩溃后的雪崩效应:作为缓存的Memcache一旦崩溃,MySQL很可能在短时间内承受高负载而宕机。据说前段时间新浪微博就遭遇了这样的问题。

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

面对这些问题,HandlerSocket项目是个不错的解决方案,它通过插件的方式赋予MySQL完整的NoSQL功能,从原理上讲,它跳过MySQL中最耗时的语法解析,查询计划等步骤,直接读取数据,如果内存够大,能装下索引,MySQL的查询效率能提高若干倍!

性能测试:Using MySQL as a NoSQL ? A story for exceeding 750,000 qps (F*ck GFW)

因为HandlerSocket的性能足够好,所以就没有必要使用Memcache了,能节省大量的硬件资源,相当低碳!而且HandlerSocket操作的是MySQL放在内存中的索引,没有额外的缓存,所以自然就不存在数据一致性的问题。

安装

如果使用Percona Server版本的MySQL就简单了,因为它已经内置了HandlerSocket支持,不过考虑到其内置的版本不够新,存在一些早已修复的BUG,所以最好采用源代码编译。

注:旧版本HandlerSocket的一些问题可参见:What's up with HandlerSocket?

官方已经有了一份简单的安装文档,但在我实际安装时,遇到了一些其他未说明的问题,所以这里就把相应的安装过程再写一遍。

首先要确保已经安装了MySQL5.1以上的版本,我用的是Ubuntu操作系统,事先已经用apt安装了MySQL5.1.37,同时还需要相应的mysql_config,如果是Ubuntu的话,可以:

shell> aptitude install libmysqld-dev

注:如果你用的MySQL是从源代码编译的或官方提供的二进制版本,可以略过此步。

接着下载一份和系统MySQL版本一致的MySQL源代码和HandlerSocket源代码:

  • mysql-5.1.37.tar.gz
  • ahiguti-HandlerSocket-Plugin-for-MySQL-1.0.6-76-gf5f7443.tar.gz
shell> tar zxf mysql-5.1.37.tar.gz
shell> tar zxf ahiguti-HandlerSocket-Plugin-for-MySQL-1.0.6-76-gf5f7443.tar.gz
shell> cd ahiguti-HandlerSocket-Plugin-for-MySQL-f5f7443
shell> ./autogen.sh
shell> ./configure --with-mysql-source=../mysql-5.1.37 \
          --with-mysql-bindir=/usr/bin \
          --with-mysql-plugindir=/usr/lib/mysql/plugin

其中的参数含义如下:with-mysql-source表示MySQL源代码目录,with-mysql-bindir表示MySQL二进制可执行文件目录(也就是mysql_config所在目录),with-mysql-plugindir表示MySQL插件目录,如果不清楚这个目录在哪,可以按如下方法查询:

mysql> SHOW VARIABLES LIKE 'plugin%';
+---------------+-----------------------+
| Variable_name | Value         |
+---------------+-----------------------+
| plugin_dir  | /usr/lib/mysql/plugin |
+---------------+-----------------------+

运行命令后,如果你使用的是MySQL5.1.37版本的话,会遇到如下错误信息:

MySQL source version does not match MySQL binary version

明明我们的MySQL源代码版本和二进制版本都是5.1.37,为什么还会出现这个错误呢?通过查询HandlerSocket的编译脚本,发现原来它会检索MySQL源代码目录中的VERSION文件,可MySQL5.1.37的源代码目录里不知何故竟然没有这个文件,所以就报错了,既然知道了原因,那我们就照猫画虎做一个VERSION文件放到MySQL源代码目录,内容如下:

MYSQL_VERSION_MAJOR=5
MYSQL_VERSION_MINOR=1
MYSQL_VERSION_PATCH=37
MYSQL_VERSION_EXTRA=

再次运行configure脚本,应该就OK了,把剩下的步骤进行完:

shell> make
shell> make install

接着需要配置一下HandlerSocket,编辑MySQL配置文件,加入如下内容:

[mysqld]
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)
open_files_limit = 65535
# to allow handlersocket accept many concurrent
# connections, make open_files_limit as large as
# possible.

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

注:apt包管理下的配置文件一般是/etc/mysql/my.cnf,否则一般是/etc/my.cnf

最后登陆MySQL并激活HandlerSocket插件:

mysql> INSTALL PLUGIN handlersocket soname 'handlersocket.so';

重启一下MySQL服务,如果没有问题,就能在MySQL里看到HandlerSocket的线程了:

mysql> SHOW PROCESSLIST;

也可以通过查询刚配置的端口是否已经被MySQL占用来确认是否安装成功:

shell> lsof -i :9998
shell> lsof -i :9999

完活儿!现在你的MySQL已经具备NoSQL的能力了!

实战

首先创建一个测试用的表:

CREATE TABLE IF NOT EXISTS `test`.`t` (
 `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
 `a` varchar(10) NOT NULL,
 `b` varchar(10) NOT NULL,
 PRIMARY KEY (`id`),
 KEY `a_b` (`a`,`b`)
) ENGINE=InnoDB;

注:理论上HandlerSocket支持MyISAM,InnoDB等各种引擎,不过推荐使用InnoDB。

HandlerSocket的协议非常简单,指令通过TAB分割,一行就是一个请求。本文用到了:

  • 打开索引:P <索引标识> <数据库> <表> <索引> <字段>
  • 插入数据:<索引标识> ‘+' <参数个数> <参数1> … <参数N>
  • 读取数据:<索引标识> <操作> <参数个数> <参数1> … <参数N> <条数> <偏移>

SQL原型:INSERT INTO test.t (id, a, b) VALUES (1, ‘a1′, ‘b1′), (2, ‘a2′, ‘b2′)

shell> telnet localhost 9999
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
P    1    test  t    PRIMARY id,a,b
0    1
1    +    3    1    a1   b1
0    1    0
1    +    3    2    a2   b2
0    1    0

注:使用HandlerSocket时,因为没有实际运行SQL,所以Binlog记录的是Row格式。

SQL原型:SELECT id, a, b FROM test.t WHERE id = 1 LIMIT 1

shell> telnet localhost 9999
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
P    1    test  t    PRIMARY id,a,b
0    1
1    =    1    1    1    0
0    3    1    a1   b1

SQL原型:SELECT id, a, b FROM test.t WHERE id >=1 LIMIT 2

shell> telnet localhost 9999
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
P    1    test  t    PRIMARY id,a,b
0    1
1    >=   1    1    2    0
0    3    1    a1   b1   2    a2   b2

SQL原型:SELECT id, a, b FROM test.t WHERE a = ‘a1′ AND b = ‘b1′ LIMIT 1

shell> telnet localhost 9999
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
P    1    test  t    a_b   id,a,b
0    1
1    =    2    a1   b1   1    0
0    3    1    a1   b1

对HandlerSocket一个常见的误解是只能执行PRIMARY类型的KV查询,实际上只要支持索引,一般的简单查询它都能胜任,篇幅所限,这里就不多说了,如果你觉得直接操作telnet有些吃力,也可以使用自己熟悉的客户端来测试,官方文档里有介绍。

注:HandlerSocket作者写了一个不错的PPT可以参考:HandlerSocket plugin for MySQL

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

互联网技术发展犹如一列高速运行的火车,下一站:HandlerSocket!大家做好准备吧。

PHP 相关文章推荐
菜鸟学PHP之Smarty入门
Jan 04 PHP
php 文件上传代码(限制jpg文件)
Jan 05 PHP
php学习笔记 [预定义数组(超全局数组)]
Jun 09 PHP
php数组函数序列之ksort()对数组的元素键名进行升序排序,保持索引关系
Nov 02 PHP
比file_get_contents稳定的curl_get_contents分享
Jan 11 PHP
php中使用preg_replace函数匹配图片并加上链接的方法
Feb 06 PHP
php调用nginx的mod_zip模块打包ZIP文件
Jun 11 PHP
php中in_array函数用法探究
Nov 25 PHP
Yii列表定义与使用分页方法小结(3种方法)
Jul 15 PHP
PHP 7.0新增加的特性介绍
Jun 08 PHP
PHP设计模式之工厂模式(Factory Pattern)的讲解
Mar 21 PHP
PHP常用工具函数小结【移除XSS攻击、UTF8与GBK编码转换等】
Apr 27 PHP
深入理解PHP原理之错误抑制与内嵌HTML分析
May 02 #PHP
PHP错误抑制符(@)导致引用传参失败Bug的分析
May 02 #PHP
一些PHP Coding Tips(php小技巧)[2011/04/02最后更新]
May 02 #PHP
PHP中使用gettext来支持多语言的方法
May 02 #PHP
php中神奇的fastcgi_finish_request
May 02 #PHP
PHP开发不能违背的安全规则 过滤用户输入
May 01 #PHP
PHP 调试工具Debug Tools
Apr 30 #PHP
You might like
使用PHP的日期与时间函数技巧
2008/04/24 PHP
php UTF-8、Unicode和BOM问题
2010/05/18 PHP
PHP执行zip与rar解压缩方法实现代码
2010/12/05 PHP
php ci框架中加载css和js文件失败的原因及解决方法
2014/07/29 PHP
PHP从FLV文件获取视频预览图的方法
2015/03/12 PHP
PHP检测用户语言的方法
2015/06/15 PHP
thinkphp实现图片上传功能
2016/01/13 PHP
Yii 2.0实现联表查询加搜索分页的方法示例
2017/08/02 PHP
laravel unique验证、确认密码confirmed验证以及密码修改验证的方法
2019/10/16 PHP
用JavaScript获取网页中的js、css、Flash等文件
2006/12/20 Javascript
js关闭子窗体刷新父窗体实现方法
2012/12/04 Javascript
JS链式调用的实现方法
2013/03/07 Javascript
jQuery文本框(input textare)事件绑定方法教程
2013/04/24 Javascript
js替换字符串的所有示例代码
2013/07/23 Javascript
JavaScript包装对象使用介绍
2013/08/29 Javascript
使用Jquery实现每日签到功能
2015/04/03 Javascript
JS 作用域与作用域链详解
2015/04/07 Javascript
AspNet中使用JQuery上传插件Uploadify详解
2015/05/20 Javascript
AngularJS基础 ng-click 指令示例代码
2016/08/01 Javascript
jQuery插件MovingBoxes实现左右滑动中间放大图片效果
2017/02/28 Javascript
js实现京东轮播图效果
2017/06/30 Javascript
详解jquery插件jquery.viewport.js学习使用方法
2017/09/08 jQuery
浅谈Vue下使用百度地图的简易方法
2018/03/23 Javascript
JavaScript函数式编程(Functional Programming)纯函数用法分析
2019/05/22 Javascript
[59:48]LGD vs IG 2018国际邀请赛小组赛BO2 第一场 8.18
2018/08/19 DOTA
python对excel文档去重及求和的实例
2018/04/18 Python
对Pyhon实现静态变量全局变量的方法详解
2019/01/11 Python
使用虚拟环境打包python为exe 文件的方法
2019/08/29 Python
pip install python 快速安装模块的教程图解
2019/10/08 Python
flask框架自定义过滤器示例【markdown文件读取和展示功能】
2019/11/08 Python
DELPHI面试题研发笔试试卷
2015/11/08 面试题
绘画设计学生的个人自我评价
2013/09/20 职场文书
校长四风对照检查材料
2014/09/27 职场文书
爱国电影观后感
2015/06/19 职场文书
农村老人去世追悼词
2015/06/23 职场文书
如何利用python实现列表嵌套字典取值
2022/06/10 Python