[文章作者:张宴 本文版本:v1.1 最后修改:2010.09.03 转载请注明原文链接:http://blog.zyan.cc/tcsql/]

  曾经有人提出,一般数据库缓存分为四种。第一种:单个对象的缓存(一个对象就是数据库一条记录),对于单个对象的临时缓存或永久缓存,用HashMap就可以了,Key-Value方式的Memcached、Memcachedb、Tokyo Tyrant都可以,或者直接对查询数据库的网页采用Squid做缓存,没什么太难的;第二种:列表缓存,就像论坛里帖子的列表;第三种:记录条数的缓存,比如一个论坛板块里有多少个帖子,这样才方便实现分页。第四种:复杂一点的group,sum,count查询,比如一个论坛里按点击数排名的最HOT的帖子列表。第一种比较好实现,后面三种比较困难,虽然可以通过各种方法来解决,但截至目前,似乎还没有使用即简单、并发处理能力又强、实时性又高的解决办法。



  TCSQL为列表页的实时缓存而生,是金山逍遥网技术支持部平台组以Tokyo Cabinet DBM为底层存储与索引,结合类似Memcached的Key-Value内存对象缓存,借鉴SQL语句的SELECT、INSERT、UPDATE、DELETE思想与功能开发的实时列表缓存数据库,能够较好地解决上述前三种类别,特别是第二种、第三种类别的高并发读写问题。

  TCSQL采用HTTP GET/POST协议+JSON数据交换格式在客户端、服务器端之间进行数据交互,支持HTTP协议的任何客户端或语言(例如JavaScript、PHP、JSP、Perl、Python等),都能够连接TCSQL服务器进行操作。这就意味着,一些查询量非常大的应用,甚至可以直接使用运行在用户浏览器端的JavaScript代码访问TCSQL数据库,当然,为了安全起见,你可以在中间用Nginx配以rewrite规则,对TCSQL做个反向代理,限制一下查询权限。

  利用开源的MySQL UDF自定义函数扩展lib_mysqludf_urlencode、lib_mysqludf_urlencode,以及我们平台组周洋同学编写的lib_mysqludf_http_post扩展,配以MySQL触发器,我们可以在MySQL的某张表发生插入、更新、删除操作时,自动将数据同步到TCSQL数据库,使得TCSQL可以当MySQL从库一样使用。

  TCSQL实时列表缓存数据库单机能够支撑1万以上的并发连接,QPS(每秒查询率)能够达到5000~15000次。

点击在新窗口中浏览此图片

  以下是TCSQL在10000并发连接情况下的查询速度(服务器为浪潮NF190服务器,两颗双核Xeon(TM) CPU 2.80GHz、4GB内存、1万转SCSI硬盘。):

  1、第一种类型A:主键查询并取出倒序第1条记录(“=”运算):12155次请求/秒

  查询内容:http://192.168.8.34:3888/?command=select&type=*&where=pkey:NUMEQ:随机数值&order_by=pkey&order_sort=NUMDESC&limit_skip=0&limit_max=1

  测试结果:
引用
Benchmarking: 10000 clients, running 60 sec.

Speed=729324 pages/min, 8031913 bytes/sec.
Requests: 60777 susceed, 0 failed.


  2、第一种类型B:其他索引键查询并取出倒序第1条记录(“=”运算):11897次请求/秒

  查询内容:http://192.168.8.34:3888/?command=select&type=*&where=uid:NUMEQ:随机数值&order_by=pkey&order_sort=NUMDESC&limit_skip=0&limit_max=1

  测试结果:
引用
Benchmarking: 10000 clients, running 60 sec.

Speed=713856 pages/min, 7865884 bytes/sec.
Requests: 59488 susceed, 0 failed.


  3、第二种类型:根据复合条件查询并取出倒序前10条记录:8778次请求/秒(相当于SELECT * FROM table WHERE dateline >= 随机时间戳 AND idtype = '变换的文本' ORDER BY pkey DESC LIMIT 0,10)

  查询内容:http://192.168.8.34:3888/?command=select&type=*&where=dateline:NUMGE:随机时间戳|idtype:STREQ:变换的文本&order_by=pkey&order_sort=NUMDESC&limit_skip=0&limit_max=10

  测试结果:
引用
Benchmarking: 10000 clients, running 60 sec.

Speed=526680 pages/min, 8971878 bytes/sec.
Requests: 43890 susceed, 0 failed.


  4、第三种类型:统计符合查询条件的记录数量:9160次请求/秒(相当于SELECT count(*) FROM table WHERE dateline >= 随机时间戳 AND idtype = '变换的文本')

  查询内容:http://192.168.8.34:3888/?command=select&type=count&where=dateline:NUMGE:随机时间戳|idtype:STREQ:变换的文本

  测试结果:
引用
Benchmarking: 10000 clients, running 5 sec.

Speed=549648 pages/min, 714542 bytes/sec.
Requests: 45804 susceed, 0 failed.





  一、TCSQL数据库编译安装
  1、编译安装TCSQL需要的扩展库
wget http://www.monkey.org/~provos/libevent-1.4.12-stable.tar.gz
tar zxvf libevent-1.4.12-stable.tar.gz
cd libevent-1.4.12-stable/
./configure --prefix=/usr
make && make install
cd ../

wget http://oss.metaparadigm.com/json-c/json-c-0.9.tar.gz
tar zxvf json-c-0.9.tar.gz
cd json-c-0.9/
./configure --prefix=/usr/local/json-c-0.9
make && make install
cd ../

wget http://www.1978th.net/tokyocabinet/tokyocabinet-1.4.33.tar.gz
tar zxvf tokyocabinet-1.4.33.tar.gz
cd tokyocabinet-1.4.33/
./configure --prefix=/usr/local/tokyocabinet-1.4.33
make && make install
cd ../

echo "/usr/local/json-c-0.9/lib/" > /etc/ld.so.conf.d/json-c-0.9.conf
echo "/usr/local/tokyocabinet-1.4.33/lib/" > /etc/ld.so.conf.d/tokyocabinet-1.4.33.conf

/sbin/ldconfig


  2、编译TCSQL数据库
  注:二进制程序及源码目前只对金山公司内部开放。
gcc -o tcsql tcsql.c -levent -ljson -I/usr/local/json-c-0.9/include/json/ -L/usr/local/json-c-0.9/lib/ -ltokyocabinet -lz -lbz2 -lrt -lpthread -lm -lc -I/usr/local/tokyocabinet-1.4.33/include/ -L/usr/local/tokyocabinet-1.4.33/lib/




  二、TCSQL数据库的启动

  点击在新窗口中浏览此图片

  1、以自定义方式,作为守护进程启动:
ulimit -SHn 65535
./tcsql -l 192.168.8.34 -p 3888 -x /data0/tcsql/data -t 3 -d


  2、以默认值,作为守护进程启动:
ulimit -SHn 65535
./tcsql -d


  注:请确保文件描述符数量够用(系统默认值为1024),以便TCSQL承担上万连接数的并发访问。



  三、TCSQL访问协议
  TCSQL采用HTTP GET/POST协议进行查询、插入、更新、删除、设置索引等操作。TCSQL为单表数据库,一个端口的数据库只有一张表。TCSQL表只有两种数据类型,字符型和数值型,其中主键字段的名称固定不可修改,为pkey,数值型索引。对应日期、时间等类型,请使用数值型的UNIX时间戳存放。

  TCSQL无需事先建表,插入第一条记录后,第一条记录拥有的字段即为该表的字段格式。各字段统一按照文本信息存放数据,无需指定数据类型。如果为字段建立数值型索引,Where条件的数值型运算符可以用到索引;如果为字段建立文本型索引,Where条件的文本型运算符可以用到索引。

  1、命令类别:
  查询:http://127.0.0.1:3888/?command=select
  插入:http://127.0.0.1:3888/?command=insert
  更新:http://127.0.0.1:3888/?command=update
  删除:http://127.0.0.1:3888/?command=delete
  设置索引:http://127.0.0.1:3888/?command=setindex



  2、SELECT查询命令:
  ①、完整参数的查询命令示例:
  A、以Linux下的curl命令访问:
curl "http://127.0.0.1:3888/?command=select&type=*&where=pkey:NUMGE:0|title:STRINC:keyword&order_by=pkey&order_sort=NUMDESC&limit_skip=0&limit_max=10"


  B、用PHP访问:
<?php
$result = json_decode(file_get_contents('http://127.0.0.1:3888/?command=select&type=*&where=pkey:NUMGE:0|title:STRINC:keyword&order_by=pkey&order_sort=NUMDESC&limit_skip=0&limit_max=10'), true));
print_r($result);
?>


  ②、相当于MySQL的SQL语句:
SELECT * FROM table WHERE pkey >= 0 AND title LIKE '%keyword%' ORDER BY pkey DESC LIMIT 0,10


  ③、必填参数说明:
引用
command=select
(命令类别为:select)


引用
&type=*
(查询类型为:* 或 count,相当于MySQL的select * 和 select count(*)语句)


  ④、可选参数说明:
引用
&where=pkey:NUMGE:0|title:STRINC:keyword
(where查询条件,格式为“字段名1:运算符:查询值|字段名2:运算符:查询值|...”,多个条件之间以“|”分割)

Where条件运算符:
数值型运算符:

NUMGT:表示比右边的数值要大。
NUMGE:表大于或等于右边的数值。
NUMLT:表示比右边的数值要小。
NUMLE:表示小于或等于右边的数值。
NUMBT:表示其大小处于右边文字段中被逗号分开的两个数值的中间。
NUMOREQ:表示同右边文字段中被逗号分开的两个数值中的其中一个是相同的。

文本型运算符:
STREQ:表示与右边的文字行列完全相同。
STRINC:表示含有右边文字行列的内容。
STRBW:表从右边的文字行列开始。
STREW:表示到右边的文字行列结束。
STRAND:表示包含右边的文字行列中右逗号分开部分的字段的全部。
STROR:表示包含右边文字段中逗号分开部分的其中一部分。
STROREQ:表示与右边文字段中逗号分开部分的其中某部分完全相同。


引用
&order_by=pkey&order_sort=NUMDESC
(排序字段与排序方式,order_by=pkey表示按照字段pkey排序,order_sort=NUMDESC表示排序方式为数值型倒序排序。)

可选的排序类型如下:
STRASC:表示按照文本型字段内的文本内容在字典中排列顺序的升序。
STRDESC:表示按照文本型字段内的文本内容在字典中排列顺序的降序。
STRASC:表示按照数值大小的升序。
STRDESC:表示按照数值大小的降序。


引用
&limit_skip=0&limit_max=10
(显示的偏移量和记录数,相当于SQL语句中的limit 0,10)


  ⑤、查询返回值(JSON输出):
  无数据时:
引用
[]


  有数据时:
引用
[{ "pkey": "3847", "appid": "3", "icon": "friend", "uid": "188", "username": "独孤拔剑", "dateline": "1253858842", "friend": "0", "hash_template": "cb26e9a5a87778b51eb9b36c38f2616b", "hash_data": "ca4a76f8444363e8215e19f8468be415", "title_template": "{actor} 和 {touser} 成为了好友", "title_data": "a:1:{s:6:\"touser\";s:44:\"<a href=\"space.php?uid=395\">江湖粉丝<\/a>\";}", "body_template": "", "body_data": "a:0:{}", "body_general": "", "image_1": "", "image_1_link": "", "image_2": "", "image_2_link": "", "image_3": "", "image_3_link": "", "image_4": "", "image_4_link": "", "target_ids": "", "id": "0", "idtype": "", "hot": "0" },{ "pkey": "3846", "appid": "3", "icon": "profile", "uid": "591", "username": "七~夜~魔~君", "dateline": "1253858783", "friend": "0", "hash_template": "3a7101a64ea7927f0b3f5179b7a457b3", "hash_data": "ec7d775d9211880bca2ba1d401e3bcb9", "title_template": "{actor} 开通了自己的个人主页", "title_data": "a:0:{}", "body_template": "", "body_data": "a:0:{}", "body_general": "", "image_1": "", "image_1_link": "", "image_2": "", "image_2_link": "", "image_3": "", "image_3_link": "", "image_4": "", "image_4_link": "", "target_ids": "", "id": "0", "idtype": "", "hot": "0" },{ "pkey": "3845", "appid": "3", "icon": "comment", "uid": "247", "username": "freespy", "dateline": "1253858601", "friend": "0", "hash_template": "2e512d5ffebbfb6b596df942871e413a", "hash_data": "eae2c0aebf53cebbe3e39a9da1072ddf", "title_template": "{actor} 评论了 {touser} 的图片", "title_data": "a:1:{s:6:\"touser\";s:44:\"<a href=\"space.php?uid=404\">小营居士<\/a>\";}", "body_template": "{pic_title}", "body_data": "a:1:{s:9:\"pic_title\";s:51:\"20090901_024374553bbea77f21199Vx54Z93Nzjd.jpg.thumb\";}", "body_general": "", "image_1": "http:\/\/pic.xoyo.com\/hu\/attachment\/200909\/24\/404_1253763392qQB4.jpg.thumb.jpg", "image_1_link": "space.php?uid=404&do=album&picid=364", "image_2": "", "image_2_link": "", "image_3": "", "image_3_link": "", "image_4": "", "image_4_link": "", "target_ids": "", "id": "0", "idtype": "", "hot": "0" },{ "pkey": "3844", "appid": "3", "icon": "album", "uid": "404", "username": "小营居士", "dateline": "1253763392", "friend": "0", "hash_template": "405cd24a70f8c85bf9f2affd3aadf790", "hash_data": "6c2921a232ef155f1397c93f68ee6e40", "title_template": "{actor} 上传了新图片", "title_data": "N;", "body_template": "{title}", "body_data": "a:1:{s:5:\"title\";s:51:\"20090901_024374553bbea77f21199Vx54Z93Nzjd.jpg.thumb\";}", "body_general": "", "image_1": "http:\/\/pic.xoyo.com\/hu\/attachment\/200909\/24\/404_1253763392qQB4.jpg.thumb.jpg", "image_1_link": "space.php?uid=404&do=album&picid=364", "image_2": "", "image_2_link": "", "image_3": "", "image_3_link": "", "image_4": "", "image_4_link": "", "target_ids": "", "id": "364", "idtype": "picid", "hot": "1" }]


  以上的JSON信息,通过PHP的print_r(json_decode($data, true))函数解码后得到的数组为:
引用
Array
(
    [0] => Array
        (
            [pkey] => 3847
            [appid] => 3
            [icon] => friend
            [uid] => 188
            [username] => 独孤拔剑
            [dateline] => 1253858842
            [friend] => 0
            [hash_template] => cb26e9a5a87778b51eb9b36c38f2616b
            [hash_data] => ca4a76f8444363e8215e19f8468be415
            [title_template] => {actor} 和 {touser} 成为了好友
            [title_data] => a:1:{s:6:"touser";s:44:"江湖粉丝";}
            [body_template] =>
            [body_data] => a:0:{}
            [body_general] =>
            [image_1] =>
            [image_1_link] =>
            [image_2] =>
            [image_2_link] =>
            [image_3] =>
            [image_3_link] =>
            [image_4] =>
            [image_4_link] =>
            [target_ids] =>
            [id] => 0
            [idtype] =>
            [hot] => 0
        )

    [1] => Array
        (
            [pkey] => 3846
            [appid] => 3
            [icon] => profile
            [uid] => 591
            [username] => 七~夜~魔~君
            [dateline] => 1253858783
            [friend] => 0
            [hash_template] => 3a7101a64ea7927f0b3f5179b7a457b3
            [hash_data] => ec7d775d9211880bca2ba1d401e3bcb9
            [title_template] => {actor} 开通了自己的个人主页
            [title_data] => a:0:{}
            [body_template] =>
            [body_data] => a:0:{}
            [body_general] =>
            [image_1] =>
            [image_1_link] =>
            [image_2] =>
            [image_2_link] =>
            [image_3] =>
            [image_3_link] =>
            [image_4] =>
            [image_4_link] =>
            [target_ids] =>
            [id] => 0
            [idtype] =>
            [hot] => 0
        )

    [2] => Array
        (
            [pkey] => 3845
            [appid] => 3
            [icon] => comment
            [uid] => 247
            [username] => freespy
            [dateline] => 1253858601
            [friend] => 0
            [hash_template] => 2e512d5ffebbfb6b596df942871e413a
            [hash_data] => eae2c0aebf53cebbe3e39a9da1072ddf
            [title_template] => {actor} 评论了 {touser} 的图片
            [title_data] => a:1:{s:6:"touser";s:44:"小营居士";}
            [body_template] => {pic_title}
            [body_data] => a:1:{s:9:"pic_title";s:51:"20090901_024374553bbea77f21199Vx54Z93Nzjd.jpg.thumb";}
            [body_general] =>
            [image_1] => http://pic.xoyo.com/hu/attachment/200909/24/404_1253763392qQB4.jpg.thumb.jpg
            [image_1_link] => space.php?uid=404&do=album&picid=364
            [image_2] =>
            [image_2_link] =>
            [image_3] =>
            [image_3_link] =>
            [image_4] =>
            [image_4_link] =>
            [target_ids] =>
            [id] => 0
            [idtype] =>
            [hot] => 0
        )

    [3] => Array
        (
            [pkey] => 3844
            [appid] => 3
            [icon] => album
            [uid] => 404
            [username] => 小营居士
            [dateline] => 1253763392
            [friend] => 0
            [hash_template] => 405cd24a70f8c85bf9f2affd3aadf790
            [hash_data] => 6c2921a232ef155f1397c93f68ee6e40
            [title_template] => {actor} 上传了新图片
            [title_data] => N;
            [body_template] => {title}
            [body_data] => a:1:{s:5:"title";s:51:"20090901_024374553bbea77f21199Vx54Z93Nzjd.jpg.thumb";}
            [body_general] =>
            [image_1] => http://pic.xoyo.com/hu/attachment/200909/24/404_1253763392qQB4.jpg.thumb.jpg
            [image_1_link] => space.php?uid=404&do=album&picid=364
            [image_2] =>
            [image_2_link] =>
            [image_3] =>
            [image_3_link] =>
            [image_4] =>
            [image_4_link] =>
            [target_ids] =>
            [id] => 364
            [idtype] => picid
            [hot] => 1
        )
)




  3、INSERT插入命令
  ①、完整参数的插入命令示例(以Linux下的curl命令访问):
curl -d "urlencode编码后的JSON数据" "http://127.0.0.1:3888/?command=insert"


  一个PHP的一维数组经过json_encode编码后,形成以下JSON数据:
引用
{"pkey":1,"appid":3,"icon":"profile","uid":2,"username":"wangduo","dateline":1251768576,"friend":0,"hash_template":"3a7101a64ea7927f0b3f5179b7a457b3","hash_data":"ec7d775d9211880bca2ba1d401e3bcb9","title_template":"{actor} 开通了自己的个人主页","title_data":"a:0:{}","body_template":"","body_data":"a:0:{}","body_general":"","image_1":"","image_1_link":"","image_2":"","image_2_link":"","image_3":"","image_3_link":"","image_4":"","image_4_link":"","target_ids":"","id":0,"idtype":"","hot":0}


  将以上的JSON数据urlencode后,通过HTTP POST发送到TCSQL(在PHP中不urlencode也行):
引用
%7B%22pkey%22%3A1%2C%22appid%22%3A3%2C%22icon%22%3A%22profile%22%2C%22uid%22%3A2%2C%22username%22%3A%22wangduo%22%2C%22dateline%22%3A1251768576%2C%22friend%22%3A0%2C%22hash_template%22%3A%223a7101a64ea7927f0b3f5179b7a457b3%22%2C%22hash_data%22%3A%22ec7d775d9211880bca2ba1d401e3bcb9%22%2C%22title_template%22%3A%22%7Bactor%7D%20%E5%BC%80%E9%80%9A%E4%BA%86%E8%87%AA%E5%B7%B1%E7%9A%84%E4%B8%AA%E4%BA%BA%E4%B8%BB%E9%A1%B5%22%2C%22title_data%22%3A%22a%3A0%3A%7B%7D%22%2C%22body_template%22%3A%22%22%2C%22body_data%22%3A%22a%3A0%3A%7B%7D%22%2C%22body_general%22%3A%22%22%2C%22image_1%22%3A%22%22%2C%22image_1_link%22%3A%22%22%2C%22image_2%22%3A%22%22%2C%22image_2_link%22%3A%22%22%2C%22image_3%22%3A%22%22%2C%22image_3_link%22%3A%22%22%2C%22image_4%22%3A%22%22%2C%22image_4_link%22%3A%22%22%2C%22target_ids%22%3A%22%22%2C%22id%22%3A0%2C%22idtype%22%3A%22%22%2C%22hot%22%3A0%7D


  注:INSERT插入命令如果遇到数据库中已经重复的主键,将会用新数据替换旧记录的数据,这一点跟MySQL的REPLACE INTO操作类似。



  4、UPDATE更新命令
  ①、完整参数的更新命令示例(以Linux下的curl命令访问):
curl -d "urlencode编码后的JSON数据" "http://127.0.0.1:3888/?command=update&type=*&where=pkey:NUMGT:195"


  一个PHP的一维数组经过json_encode编码后,形成以下JSON数据:
引用
{"pkey":1,"appid":3,"icon":"profile","uid":2,"username":"wangduo","dateline":1251768576,"friend":0,"hash_template":"3a7101a64ea7927f0b3f5179b7a457b3","hash_data":"ec7d775d9211880bca2ba1d401e3bcb9","title_template":"{actor} 开通了自己的个人主页","title_data":"a:0:{}","body_template":"","body_data":"a:0:{}","body_general":"","image_1":"","image_1_link":"","image_2":"","image_2_link":"","image_3":"","image_3_link":"","image_4":"","image_4_link":"","target_ids":"","id":0,"idtype":"","hot":0}


  将以上的JSON数据urlencode后,通过HTTP POST发送到TCSQL:
引用
%7B%22pkey%22%3A1%2C%22appid%22%3A3%2C%22icon%22%3A%22profile%22%2C%22uid%22%3A2%2C%22username%22%3A%22wangduo%22%2C%22dateline%22%3A1251768576%2C%22friend%22%3A0%2C%22hash_template%22%3A%223a7101a64ea7927f0b3f5179b7a457b3%22%2C%22hash_data%22%3A%22ec7d775d9211880bca2ba1d401e3bcb9%22%2C%22title_template%22%3A%22%7Bactor%7D%20%E5%BC%80%E9%80%9A%E4%BA%86%E8%87%AA%E5%B7%B1%E7%9A%84%E4%B8%AA%E4%BA%BA%E4%B8%BB%E9%A1%B5%22%2C%22title_data%22%3A%22a%3A0%3A%7B%7D%22%2C%22body_template%22%3A%22%22%2C%22body_data%22%3A%22a%3A0%3A%7B%7D%22%2C%22body_general%22%3A%22%22%2C%22image_1%22%3A%22%22%2C%22image_1_link%22%3A%22%22%2C%22image_2%22%3A%22%22%2C%22image_2_link%22%3A%22%22%2C%22image_3%22%3A%22%22%2C%22image_3_link%22%3A%22%22%2C%22image_4%22%3A%22%22%2C%22image_4_link%22%3A%22%22%2C%22target_ids%22%3A%22%22%2C%22id%22%3A0%2C%22idtype%22%3A%22%22%2C%22hot%22%3A0%7D


  注:UPDATE更新命令是SELECT查询命令和INSERT插入命令的结合,URL查询部分使用SELECT查询命令的语法,HTTP POST使用INSERT插入命令的语法。



  5、DELETE删除命令
  ①、完整参数的删除命令示例(以Linux下的curl命令访问):
curl "http://127.0.0.1:3888/?command=delete&type=*&where=pkey:NUMGT:195"




  6、SetIndex索引设置命令
  ①、创建文本型字段索引示例(以Linux下的curl命令访问):
curl "http://127.0.0.1:3888/?command=setindex&type=TDBITLEXICAL&field=需要建文本型索引的字段名"


  ②、创建数值型字段索引示例(以Linux下的curl命令访问):
curl "http://127.0.0.1:3888/?command=setindex&type=TDBITDECIMAL&field=需要建数值型索引的字段名"


  ③、优化索引示例(以Linux下的curl命令访问):
curl "http://127.0.0.1:3888/?command=setindex&type=TDBITOPT&field=需要优化索引的字段名"


引用
“type=”可填的参数为:
TDBITLEXICAL:创建文本型索引
TDBITDECIMAL:创建数值型索引
TDBITTOKEN:创建标记倒排索引
TDBITQGRAM:创建q-gram倒排索引
TDBITOPT:优化索引
TDBITVOID:删除索引




  四、让TCSQL从MySQL同步数据
  1、编译安装三个MySQL UDF函数扩展(json、urlencode、http_post)
wget http://mirrors.xoyo.com/xoyo/tcsql/mysql_to_tcsql_udf.tar.gz
tar zxvf mysql_to_tcsql_udf.tar.gz
cd mysql_to_tcsql_udf/lib_mysqludf_json/
make
make install
cd ../lib_mysqludf_urlencode/
echo "/usr/local/webserver/mysql/lib/mysql/" > /etc/ld.so.conf.d/mysql.Conf
/sbin/ldconfig
./configure --prefix=/usr/local/webserver/mysql/lib/mysql/plugin/ --with-mysq=/usr/local/webserver/mysql --with-mysql_config=/usr/local/webserver/mysql/bin/mysql_config --with-mysql-include=/usr/local/webserver/mysql/include
make && make install
cp -f /usr/local/webserver/mysql/lib/mysql/plugin/lib/* /usr/local/webserver/mysql/lib/mysql/plugin/
make
make install

cd ../lib_mysqludf_http_post/
make
make install


  2、通过命令行登入MySQL,执行以下语句创建MySQL自定义函数。
drop function lib_mysqludf_json_info;
drop function json_array;
drop function json_members;
drop function json_object;
drop function json_values;
create function lib_mysqludf_json_info returns string soname 'lib_mysqludf_json.so';
create function json_array returns string soname 'lib_mysqludf_json.so';
create function json_members returns string soname 'lib_mysqludf_json.so';
create function json_object returns string soname 'lib_mysqludf_json.so';
create function json_values returns string soname 'lib_mysqludf_json.so';

drop function http_post;
create function http_post returns string soname 'lib_http_post.so';

drop function urlencode;
create function urlencode returns string soname 'libmysqludf_urlencode.so';


  3、利用触发器自动同步MySQL数据到TCSQL数据库
  示例:通过MySQL命令行连接到MySQL服务器,执行以下SQL,对sns_feed表创建三个MySQL触发器:sns_feed_insert、sns_feed_update、sns_feed_delete,当MySQL的sns_feed表发生增、删、改操作时,自动将修改的记录内容通过HTTP POST到TCSQL数据库(192.168.8.34:3888)。
DELIMITER |
DROP TRIGGER IF EXISTS sns_feed_insert;
CREATE TRIGGER sns_feed_insert
AFTER INSERT ON sns_feed
FOR EACH ROW BEGIN
    SET @tcsql_result_json = (SELECT json_object(feedid as pkey,appid,icon,uid,username,dateline,friend,hash_template,hash_data,title_template,title_data,body_template,body_data,body_general,image_1,image_1_link,image_2,image_2_link,image_3,image_3_link,image_4,image_4_link,target_ids,id,idtype,hot) FROM sns_feed WHERE feedid = NEW.feedid limit 1);
    SET @tcsql_result_eval = (SELECT http_post('192.168.8.34', '3888', 'command=insert', urlencode(@tcsql_result_json)));
END |
DELIMITER ;

DELIMITER |
DROP TRIGGER IF EXISTS sns_feed_update;
CREATE TRIGGER sns_feed_update
AFTER UPDATE ON sns_feed
FOR EACH ROW BEGIN
    SET @tcsql_result_json = (SELECT json_object(feedid as pkey,appid,icon,uid,username,dateline,friend,hash_template,hash_data,title_template,title_data,body_template,body_data,body_general,image_1,image_1_link,image_2,image_2_link,image_3,image_3_link,image_4,image_4_link,target_ids,id,idtype,hot) FROM sns_feed WHERE feedid = OLD.feedid limit 1);
    SET @tcsql_result_eval = (SELECT http_post('192.168.8.34', '3888', 'command=insert', urlencode(@tcsql_result_json)));
END |
DELIMITER ;

DELIMITER |
DROP TRIGGER IF EXISTS sns_feed_delete;
CREATE TRIGGER sns_feed_delete
AFTER DELETE ON sns_feed
FOR EACH ROW BEGIN
    SET @tcsql_result_eval = (SELECT http_post('192.168.8.34', '3888', concat('command=delete&where=pkey:NUMEQ:', OLD.feedid), ''));
END |
DELIMITER ;




  五、TCSQL的PHP客户端Class
下载文件 (已下载 2057 次)


  以下是一段SELECT查询TCSQL,并逐行显示内容的PHP示例程序:
  您也可以参考以下网址,使用JavaScript对TCSQL数据库进行操作:
  http://www.json.org/JSONRequest.html
  http://www.devpro.it/JSON/files/JSONRequest-js.html



  六、TCSQL在实际项目中的应用
  金山游戏官网逍遥网内测中的SNS非实名制垂直类互动游戏社区“逍遥江湖”(相关新闻:http://tech.qq.com/a/20090924/000316.htm),使用TCSQL存放读写非常频繁的、记录用户每一步操作的Feed信息(好友动态、我的动态、热门推荐、全站动态)。

  2009-09-29 补充介绍:
引用
  关于Feed信息,数据写入MySQL主库,同步到N台MySQL从库。在其中的一台无其他查询的备用MySQL从库上,按照第四部分的内容建立了触发器,将数据实时同步到TCSQL。查询部分,直接修改UCH的代码,将原来查询MySQL的SQL语句,改成以下的TCSQL查询语句即可。MySQL单表能实现的大部分功能,TCSQL都能够实现,迁移起来很简单。

  【好友动态】
  TCSQL的查询语句:
  http://192.168.8.34:3888/?command=select&type=*&where=uid:NUMOREQ:0,57,48,60263,43,89163,42,74,91,93,94,105,106,109&order_by=dateline&order_sort=NUMDESC&limit_skip=0&limit_max=100

  等同于原MySQL的SQL查询语句:
  SELECT * FROM sns_feed USE INDEX(dateline) WHERE uid IN ('0',57,48,60263,43,89163,42,74,91,93,94,105,106,109) ORDER BY dateline DESC LIMIT 0,100


  【我的动态】
  TCSQL的查询语句:
  http://192.168.8.34:3888/?command=select&type=*&where=uid:NUMEQ:55&order_by=dateline&order_sort=NUMDESC&limit_skip=0&limit_max=100

  等同于原MySQL的SQL查询语句:
  SELECT * FROM sns_feed WHERE uid='55' ORDER BY dateline DESC LIMIT 0,100


  【热门推荐】
  TCSQL的查询语句:
  http://192.168.8.34:3888/?command=select&type=*&where=hot:NUMGE:3&order_by=dateline&order_sort=NUMDESC&limit_skip=0&limit_max=50

  等同于原MySQL的SQL查询语句:
  SELECT * FROM sns_feed WHERE hot >= '3' ORDER BY dateline DESC LIMIT 0,50


  【全站动态】
  TCSQL的查询语句:
  http://192.168.8.34:3888/?command=select&type=*&where=&order_by=dateline&order_sort=NUMDESC&limit_skip=0&limit_max=100

  等同于原MySQL的SQL查询语句:
  SELECT * FROM sns_feed ORDER BY dateline DESC LIMIT 0,100





技术大类 » 数据库技术 | 评论(112) | 引用(0) | 阅读(119157)
Willko Homepage
2009-9-25 15:40
看上去比较像在tc本身的检索功能上,提供sql适配器。不知道是否理解正确
张宴 回复于 2009-9-25 17:02
检索功能主要依赖TCTABLE。提供类似SQL的关系适配器,实现了一些TC没有的逻辑处理,例如SQL中UPDATE一次修改多条记录的某一字段值的功能,取数据时增加了类似Memcached的Key-Value缓存,采用JSON进行数据交互。
小宝 Email Homepage
2009-9-25 16:57
好文章,学习学习!
nicidoggy Email Homepage
2009-9-25 18:53
好久没更新,一更新就真么长
blue
2009-9-25 19:22
能开源就好了.
airwin
2009-9-25 19:24
这个以后会放出来吗?~grin
jiangjun
2009-9-25 21:02
呵呵,越来越高深了~~~
dengjiuhong
2009-9-25 21:48
tc 很强大,最近开发的项目大量用到。
lnnujxxy
2009-9-25 22:29
希望以后能提供详细的线上的运行数据
k
2009-9-26 21:54
没什么特别的
kgl
2009-9-27 17:32
能否具体说明一下利用key-value建立索引过程和策略,毕竟涉及到客户端查询取值模糊匹配的结果集返回,感觉这个应该是此应用的核心,谢谢!~
dreamfly_1981
2009-9-28 19:44
你好。我的站也是uchome2.0建立的。可以讲一下。你们的feed操作是如何通过TCSQL来实现的。
tcsql是部署在同一台和mysql 相同的服务器还是在不同的服务器。谢谢了
张宴 回复于 2009-9-29 10:09
数据写入MySQL主库,同步到N台MySQL从库,在其中的一台无其他查询的备用MySQL从库上,按照第四部分的内容建立了触发器,将数据实时同步到TCSQL。查询部分,直接修改UCH的代码,将原来查询MySQL的SQL语句,改成TCSQL的查询语句即可。MySQL单表能实现的大部分功能,TCSQL都能够实现,迁移起来很简单。服务器资源充足情况下,MySQL和TCSQL在不同的服务器。

【好友动态】
TCSQL的查询语句:
http://192.168.8.34:3888/?command=select&type=*&where=uid:NUMOREQ:0,57,48,60263,43,89163,42,74,91,93,94,105,106,109&order_filed=dateline&order_sort=NUMDESC&limit_skip=0&limit_max=100

等同于原MySQL的SQL查询语句:
SELECT * FROM sns_feed USE INDEX(dateline) WHERE uid IN ('0',57,48,60263,43,89163,42,74,91,93,94,105,106,109) ORDER BY dateline DESC LIMIT 0,100


【我的动态】
TCSQL的查询语句:
http://192.168.8.34:3888/?command=select&type=*&where=uid:NUMEQ:55&order_filed=dateline&order_sort=NUMDESC&limit_skip=0&limit_max=100

等同于原MySQL的SQL查询语句:
SELECT * FROM sns_feed WHERE uid='55' ORDER BY dateline DESC LIMIT 0,100


【热门推荐】
TCSQL的查询语句:
http://192.168.8.34:3888/?command=select&type=*&where=hot:NUMGE:3&order_filed=dateline&order_sort=NUMDESC&limit_skip=0&limit_max=50

等同于原MySQL的SQL查询语句:
SELECT * FROM sns_feed WHERE hot >= '3' ORDER BY dateline DESC LIMIT 0,50


【全站动态】
TCSQL的查询语句:
http://192.168.8.34:3888/?command=select&type=*&where=&order_filed=dateline&order_sort=NUMDESC&limit_skip=0&limit_max=100

等同于原MySQL的SQL查询语句:
SELECT * FROM sns_feed ORDER BY dateline DESC LIMIT 0,100
最美别墅 Homepage
2009-9-28 21:42
终于看到更新文章了。
不错的优化数据库读写效率的好文章。很多开源的东西如果结合的好,并适当地发挥各自的优点,的确可以事半功倍。感谢张宴的开源共享精神。
kitsudo
2009-9-29 14:45
这个很好很强大
太阳里的雪 Homepage
2009-10-5 13:25
这个用内存数据库(Timesten)等不能够更好的实现?
张宴 回复于 2009-10-5 20:16
timesten的数据全部存放在内存中,没有持久化存储。另外,timesten是商业收费软件,需要1.2万美元/CPU,不适合大规模部署。
crunch Homepage
2009-10-10 08:34
能有python接口就好。
张宴 回复于 2009-10-10 12:47
TCSQL采用HTTP协议,任何支持HTTP的语言都可以直接调用。
mickey
2009-10-10 09:10
我感觉就是TC的table,利用libevent做了一点HTTP的封装。为什么你不直接用tyrant呢?我觉得利用原剩的TC table+Tyrant,然后利用其PHP扩展,再写一个PHP Class封装一下逻辑处理,完全没有必要这么麻烦。你能说一下你为什么这么做吗?另外,TC 的table似乎同时只能用两个索引检索,你是怎么解决这个问题的?
张宴 回复于 2009-10-10 12:46
1、UPDATE操作TC table+Tyrant时,如果只更新一条记录中的某个字段的值,PHP需要先读回TC table+Tyrant中该记录的全部内容到一个PHP数组,再修改该数组中的值,最后再将该数组写回TC table+Tyrant,来回传输速度慢、效率低。TCSQL接收需要修改的“主键”、“字段名称”及“字段内容”,是在TCSQL内部处理完成修改操作的,没有不必要的传输。

2、UPDATE操作TC table+Tyrant时,比如要将hot字段大于3的所有记录的stats字段置为1,在SQL语句中就是UPDATE table SET stats = 1 WHERE hot > 1,原生的TC table只能针对主键做操作,需要先在PHP中search出主键,再用PHP的for/foreach循环去update某些记录,效率较低。TCSQL增加了对这种update操作的处理。

3、原生TC table的根据key取出value的速度只能达到TC hash、TC B+Tree的30%左右,记录中的字段数越多越慢。TCSQL增加了命中率非常高的内存缓存机制,比如按照时间倒叙显示50条记录,第一次查询就会将记录数据缓存在内存中,如果第二次查询时已经新增了3条记录(或者修改了3条记录),第二次查询只会从TC table中取出3条记录,剩余47条从内存缓存中取出,大大加快了读取速度。

4、TCSQL支持了从MySQL实时同步数据

5、TCSQL以JSON交互,可通过将JavaScript+Nginx(rewrite、proxy_pass)+TCSQL结合,抛弃了中间制约性能的PHP,使得运行于浏览器端的JavaScript代码能够直接查询TCSQL数据库,取得数据并在网页显示。单台PHP查询Memcached的简单程序,速度大概在200~1000 request/sec,抛弃中间的PHP后,JavaScript是在用户客户端浏览器执行,性能不用考虑,Nginx(rewrite、proxy_pass)+TCSQL能达到5000~15000 request/sec,处理性能提高了N多倍。
kakashilw Email
2009-10-10 17:13
可惜 tcsql.c  没有公开。。。

不知以后会不会公开。。。

不知发布一个编译过的是否可行。。。

这样我们也可以在自己服务器上测试对比下性能。。。。
lehehe
2009-10-13 13:55
能提供tcsql.c下载吗?
it
2009-10-13 17:04
这排名个根本用不上搞得这么复杂
路人甲
2009-10-22 02:00
有好多知识是从这学习的,真是受教,太感谢啦
分页: 1/6 第一页 1 2 3 4 5 6 下页 最后页
发表评论
表情
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
emotemotemotemotemot
打开HTML
打开UBB
打开表情
隐藏
记住我
昵称   密码   游客无需密码
网址   电邮   [注册]