将MySQL数据映射到Memcached中

    技术2025-01-19  8

     

    测试环境在Linux下进行,版本系统为CentOS5.以下为相关软件,包括其版本和下载地址:

    mysql-5.1.30 下载memcached-1.2.6 下载libevent-1.4.7-stable 下载memcached_functions_mysql-1.1 下载libmemcached-0.26 下载

    编译安装MySQL,安装因个人细好而定,省略许多与测试无关的编译细节及参数。

    [root@localhost ~]#tar xzf mysql-5.1.30.tar_001.gz [root@localhost ~]#cd mysql-5.1.30 [root@localhost ~]#./configure --prefix=/usr/local/mysql51 [root@localhost ~]#make [root@localhost ~]#make install [root@localhost ~]#./scripts/mysql_install_db --user=mysql --skip-name-resolve [root@localhost ~]#/usr/local/mysql51/bin/mysqld_safe

    省略列出安装memcached和libevent的相关命令,具体可按照实际情况安装,测试时我将libevent默认安装,memcached安装于/usr/local/memcached目录下。启动memcached.

    /usr/local/memcached/bin/memcached -d -m 50 -u root -p 11211

    编译安装libmemcache.

    [root@localhost ~]#tar xzf libmemcached-0.26.tar.gz [root@localhost ~]#cd libmemcached-0.26 [root@localhost ~]#./configure --with-memcached=/usr/local/memcached/bin/memcached [root@localhost ~]# make && make install

    编译安装Memcache UDFs for MySQL.

    [root@localhost ~]# tar xzf memcached_functions_mysql-1.1.tar.gz [root@localhost ~]# cd memcached_functions_mysql-1.1 [root@localhost ~]# ./configure --with-mysql-config=/usr/local/mysql51/bin/mysql_config [root@localhost ~]# make && make install

    编译完成后将编译好的库文件复制到mysql的插件目录下,以便于加载使用。

    cp /usr/local/lib/libmemcached_functions_mysql* /usr/local/mysql51/lib/mysql/plugin/

    进入memcached_functions_mysql的源码目录,在目录下有相关添加UDF的SQL文件用于初始化。

    在mysql的shell中执行memcached_functions_mysql源码目录下的sql/install_functions.sql或者运行memcached_functions_mysql源码目录下utils/install.pl这个perl脚本,把memcache function作为UDF加入mysql。

     

    [root@localhost ~]# mysql <sql/install_functions.sql

    检查安装是否成功

    mysql> select name,dl from mysql.func;

    二. 测试用例设计情况:

    (1).新建两张表:urls和results,用来更新urls表里面的内容,让系统自动更新memcached的内容。results用来记录更新memcached失败的记录。sql语句如下:use tests;drop table if exists urls;CREATE TABLE `urls` (  `id` int(10) NOT NULL,  `url` varchar(255) NOT NULL DEFAULT '',  PRIMARY KEY (`id`));

    drop table if exists results;CREATE TABLE `results` (  `id` int(10) NOT NULL,  `result` varchar(255) NOT NULL DEFAULT 'error',  `time` timestamp NULL DEFAULT CURRENT_TIMESTAMP,  PRIMARY KEY (`id`));

    (2). 建立三个trigger.

    当向urls表里面插入数据时,对memcached执行set操作,trigger如下:DELIMITER //DROP TRIGGER IF EXISTS url_mem_insert;CREATE TRIGGER url_mem_insertBEFORE INSERT ON urlsFOR EACH ROW BEGIN    set @mm = memc_set(NEW.id, NEW.url);    if @mm <> 0 then    insert into results(id) values(NEW.id);    end if;

    END //DELIMITER ;

    当对urls表里面的数据进行更新时,对memcached执行replace操作,trigger如下:

    DELIMITER //DROP TRIGGER IF EXISTS url_mem_update;CREATE TRIGGER url_mem_updateBEFORE UPDATE ON urlsFOR EACH ROW BEGIN    set @mm = memc_replace(OLD.id,NEW.url);    if @mm <> 0 then    insert into results(id) values(OLD.id);    end if;

    END //DELIMITER ;

    当对urls表里面的数据进行删除操作时,对memcached执行delete操作,trigger如下:

    DELIMITER //DROP TRIGGER IF EXISTS url_mem_delete;CREATE TRIGGER url_mem_deleteBEFORE DELETE ON urlsFOR EACH ROW BEGIN    set @mm = memc_delete(OLD.ID);    if @mm <> 0 then    insert into results(id) values(OLD.id);    end if;

    END //DELIMITER ;

    (3). 设置memcached相关参数

    设置同时UDF操作的memcaced的机器IP和端口:

    mysql> SELECT memc_servers_set('192.168.3.184:11900');+---------------------------------------+| memc_servers_set('192.168.3.184:11900') |+---------------------------------------+|                                     0 |+---------------------------------------+1 row in set (0.00 sec)

    mysql> select memc_server_count();+---------------------+| memc_server_count() |+---------------------+|                   1 |+---------------------+1 row in set (0.00 sec)

    在mysql命令行列出可以修改memcached参数的行为:mysql> select memc_list_behaviors()/G*************************** 1. row ***************************memc_list_behaviors():MEMCACHED SERVER BEHAVIORSMEMCACHED_BEHAVIOR_SUPPORT_CASMEMCACHED_BEHAVIOR_NO_BLOCKMEMCACHED_BEHAVIOR_TCP_NODELAYMEMCACHED_BEHAVIOR_HASHMEMCACHED_BEHAVIOR_CACHE_LOOKUPSMEMCACHED_BEHAVIOR_SOCKET_SEND_SIZEMEMCACHED_BEHAVIOR_SOCKET_RECV_SIZEMEMCACHED_BEHAVIOR_BUFFER_REQUESTSMEMCACHED_BEHAVIOR_KETAMAMEMCACHED_BEHAVIOR_POLL_TIMEOUTMEMCACHED_BEHAVIOR_RETRY_TIMEOUTMEMCACHED_BEHAVIOR_DISTRIBUTIONMEMCACHED_BEHAVIOR_BUFFER_REQUESTSMEMCACHED_BEHAVIOR_USER_DATAMEMCACHED_BEHAVIOR_SORT_HOSTSMEMCACHED_BEHAVIOR_VERIFY_KEYMEMCACHED_BEHAVIOR_CONNECT_TIMEOUTMEMCACHED_BEHAVIOR_KETAMA_WEIGHTEDMEMCACHED_BEHAVIOR_KETAMA_HASHMEMCACHED_BEHAVIOR_BINARY_PROTOCOLMEMCACHED_BEHAVIOR_SND_TIMEOUTMEMCACHED_BEHAVIOR_RCV_TIMEOUTMEMCACHED_BEHAVIOR_SERVER_FAILURE_LIMITMEMCACHED_BEHAVIOR_IO_MSG_WATERMARKMEMCACHED_BEHAVIOR_IO_BYTES_WATERMARK

    1 row in set (0.00 sec)

    设置MEMCACHED_BEHAVIOR_NO_BLOCK为打开状态,这样在memcached出现问题时(不能连接时)数据继续插入到mysql中,报错提示,如果不设置此值,如果memcached失败,mysql需要等到timeout才可以插入到表中。mysql> select memc_servers_behavior_set('MEMCACHED_BEHAVIOR_NO_BLOCK','1');+--------------------------------------------------------------+| memc_servers_behavior_set('MEMCACHED_BEHAVIOR_NO_BLOCK','1') |+--------------------------------------------------------------+|                                                            0 |+--------------------------------------------------------------+1 row in set (0.00 sec)

     

    mysql> select memc_servers_behavior_set('MEMCACHED_BEHAVIOR_TCP_NODELAY','1');+-----------------------------------------------------------------+| memc_servers_behavior_set('MEMCACHED_BEHAVIOR_TCP_NODELAY','1') |+-----------------------------------------------------------------+|                                                               0 |+-----------------------------------------------------------------+1 row in set (0.00 sec)

     

    三. 简单的功能测试:

    1. 向表urls里面插入数据,然后查memcached是否也set进数据:

    mysql> insert into urls (id,url) values (1, 'http://www.sina.com.cn');Query OK, 1 row affected, 1 warning (0.00 sec)

    mysql> select memc_get('1');  +------------------------+| memc_get('1')          |+------------------------+| http://www.sina.com.cn |+------------------------+1 row in set (0.00 sec)

    1> telnet 192.168.3.184 11900Trying 192.168.3.184...Connected to 192.168.3.184 (192.168.3.184).Escape character is '^]'.get 1VALUE 1 0 22http://www.sina.com.cnEND

    2.更新表urls里面的数据,然后查询memcached里面是否也更新:mysql> update test.urls set url='http://blog.sina.com.cn' where id=1;Query OK, 1 row affected, 1 warning (0.00 sec)Rows matched: 1  Changed: 1  Warnings: 0

    mysql> select memc_replace('1','http://blog.sina.com.cn'); +---------------------------------------------+| memc_replace('1','http://blog.sina.com.cn') |+---------------------------------------------+|                                           0 |+---------------------------------------------+1 row in set (0.00 sec)

    mysql> select memc_get('1');  +-------------------------+| memc_get('1')           |+-------------------------+| http://blog.sina.com.cn |+-------------------------+1 row in set (0.00 sec)

    1> telnet 192.168.3.184 11900Trying 192.168.3.184...Connected to 192.168.3.184 (192.168.3.184).Escape character is '^]'.get 1VALUE 1 0 23http://blog.sina.com.cnEND

    3.删除表urls里面的数据,然后查memcached是否也删除:mysql> delete from test.urls where id=1;Query OK, 1 row affected, 1 warning (0.00 sec)Rows matched: 1  Changed: 1  Warnings: 0

    mysql> select memc_get('1');  +---------------+| memc_get('1') |+---------------+| NULL          |+---------------+1 row in set (0.00 sec)

    1> telnet 192.168.3.184 11900Trying 192.168.3.184...Connected to 192.168.3.184 (192.168.3.184).Escape character is '^]'.get 1END

     

     

    四. 利用php脚本insert, update,delete表urls里面的数据,进行测试。

    每条记录的平均长度是:17K

    单独向表urls里面插入10万条记录需要的时间为:75秒单独对表urls里面更新10万条记录需要的时间为:70秒单独对表urls里面删除10万条记录需要的时间为:105秒

    同时进行30万数据的insert,update, delete操作需要时间为:241秒

    上面操作都没有memcached失败情况:mysql> select * from results;Empty set (0.00 sec)

    测试脚本如下:

    插入脚本:0> more a.php<?php

    $conn = mysql_connect("192.168.1.61","test","test") or die(mysql_error());

    mysql_select_db("test",$conn) or die(mysql_error());

    //$sql = "show tables";

    echo date("Y-m-d H:i:s");//mysql_query($sql) or die(mysql_error()); 

    for ($i=1; $i<=100000; $i++) {$sql="insert into urls (id,url) values ($i, 'http://$i$i$i$i$i$i$i$i$i$i$i$i$i$i$i$i$i$i$i$i$i$i$i$i$i.com');";mysql_query($sql) or die(mysql_error()); }

    echo "/n";echo date("Y-m-d H:i:s");

    ?>

    更新脚本:0> more b.php<?php

    $conn = mysql_connect("192.168.1.61","test","test") or die(mysql_error());

    mysql_select_db("test",$conn) or die(mysql_error());

    //$sql = "show tables";

    echo date("Y-m-d H:i:s");//mysql_query($sql) or die(mysql_error()); 

    for ($i=1; $i<=100000; $i++) {$sql="update test.urls set url='http://xxxx.$i$i$i$i$i$i$i$i$i$i$i$i$i$i$i$i$i$i$i$i$i$i$i$i$i$i$i.com' where id=$i;";mysql_query($sql) or die(mysql_error()); }

    echo "/n";echo date("Y-m-d H:i:s");

    ?>

    删除脚本:0> more c.php<?php

    $conn = mysql_connect("192.168.1.61","test","test") or die(mysql_error());

    mysql_select_db("test",$conn) or die(mysql_error());

    //$sql = "show tables";

    echo date("Y-m-d H:i:s");//mysql_query($sql) or die(mysql_error()); 

    for ($i=1; $i<=100000; $i++) {$sql="delete from test.urls where id=$i;";mysql_query($sql) or die(mysql_error()); }

    echo "/n";echo date("Y-m-d H:i:s");

    ?>

     

    五. 结论:测试依赖的环境比较多,可能数据会不准确。整体来看速度还不错。适合项目应用相对比较小的场合。

    优点:触发器中使用 UDFs 直接更新 Memcached 的内容,减轻了应用程序设计和编写的复杂性。

    缺点:1. 如果出现mysql服务重启,需要重新设置连接memcached关系(SELECT memc_servers_set('192.168.3.184:11900'))2. 有可能存在bug问题,导致mysql的crash(测试时没遇到:)).

    真正的线上环境比这个复杂很多。我想到的需要考虑的问题:1. 网络因素,mysql和memcached是否放在同一IDC,他们之间的网络性能是否很好。网络性能越好,速度肯定越快,如果使用本机的memcached能适当的减少网络开销。2. 插入的数据量,向mysql插入每条记录的size,以及向memcached里面更新的数据size大小。更新mysql,memcached的数据size越大,更新的速度越慢。所以前期规划好,在memcached里面存那两列(key-value)是关键。3. 延时问题需要考虑,mysql所在机器如果资源使用比较狠,会导致更新memcached慢(出现类似m/s的延时问题)。4. 考虑容灾问题,如果两者中有down出现时,需要考虑怎么恢复,当前的测试是这样考虑的:建一张错误表,如果在出现更新mc出现问题时,自动把更新错误的记录插到一张表里面,通过查这张表,可以知道哪些数据在什么时间更新错误,如果应用于生产环境,需要考虑监控和出现问题时恢复工作(写好脚本完善这个工作)。5. mysql自身因素,例如执行的mysql语句效率,以及连接mysql的client程序(php)的连接开销等等。

     

    参考

    http://blog.sina.com.cn/s/blog_499740cb0100g45p.html

    http://www.libing.name/2009/02/06/mysql-map-data-to-memcached.html

    最新回复(0)