author: selfimpr
date: 2010-07-12
email: [email protected]
blog: http://blog.csdn.net/lgg201
注: 这里会公布所有的测试脚本, 测试脚本有不足指出还请指教学习, 如果有朋友有跑出来新的数据, 烦请发一份给我, 谢谢.
测试脚本共享地址: http://blog.csdn.net/lgg201/archive/2010/07/17/5742763.aspx
测试的要点主要有 :
1. Memcache, TCH, TCB, TCT, Mysql 写入数据的性能对比 .
2. Memcache, TCH, TCB, TCT, Mysql( 根据主键 ) 读取数据的性能对比 .
3. Mysql, TCT 检索数据的性能对比 .
4. 由于网上有人说 TCH 在数据量超过内存后性能会急剧下降 , 而 TCB 性能稳定 , 因此 , 就这个问题也将单独测试 .
all-get-compare.php : 所有 5 种存储产品的根据 key 获取数据的测试 , 此测试输入参数 num, 表示进行 num 次测试 , 输出为对比折线图以及各种存储产品的平均每条耗时 .
all-set-compare.php : 所有 5 种存储产品的数据写入测试 , 此测试输入参数有 num 和 length, num 代表测试的写入次数 , length 代表每次写入的数据大小 (TCT 和 Mysql 的写入略大于此值 ), 输出为 5 种对比折线图及各种存储产品的平均每条耗时 . 另外 , 此脚本可以接受 case 参数 ( 值为 test_tch, test_tcb, test_tct, test_memcache, test_mysql 之一 ), num 和 length 意义同上 , case 参数是为了单独测试某种存储产品的写入耗时 , 另一方面 , 可以用此脚本插入更为合理的测试数据 ( 比存储产品自身的测试数据写入工具慢 ).
autoinsert.php : all-set-compare.php 带 case 参数情况下的原型 .
basic_funcs.php : 基础函数 , 主要包含图表生成函数 , 随机数据生成函数 .
mysql_util.php : 一个简单的 Mysql 封装类 .
search-compare.php : 对搜索的测试 , 两个输入参数 case 和 num, 意义同上 , 其中 case 可选值为 : test_name, test_sex, test_location, 分别是根据名称 , 性别 , 省市搜索 , 此测试只比较 TCT 和 mysql 的性能 . 输出为两者搜索性能的对比图和平均每条耗时 .
tct_setIndex.php : 为 TCT 中的指定列设置索引 .
tt-compare-get.php : 此测试用于 TCT, TCB, TCH 在数据量超出内存后的读取测试 , 两个输入参数 case 和 num, case 可选值为 : test_tch, test_tcb, test_tct. 输出为带内存占用的时间线分析图 .
tt-compare-insert.php : 此测试用于 TCT, TCB, TCH 在数据量超出内存后的写入测试 , 输入参数与 tt-compare-get.php 相同 . 输出也和 tt-compare-get.php 相同 .
concurrent_mysql.php : 此测试用于 Mysql 的并发测试和一次 Mysql 操作各部分用时比例测试 .
注 1: 内存比较图顶端标题有平均每条操作时间
注 2: 多种存储产品比较图各自的标题后有平均每条操作时间
注 3: 本测试中使用的时间单位一律为 e-6 秒 , 即 1/1000000 秒
写入测试
测试脚本 : all-set-compare.php
原始数据 : Memcache 空 , 其余都 2 亿
bnum: 4 亿
输入参数 : num=100000&length=10240
图中红色是 Mysql, 蓝色是 TCB, 黑色是 TCH, 黄色是 TCT, 绿色是 Memcache, 5 种产品平均每条数据写入时间为 :
Mysql |
TCB |
TCT |
TCH |
Memcache |
181e-6 秒 |
324e-6 秒 |
300e-6 秒 |
68e-6 秒 |
39e-6 秒 |
从上面的写入性能来看 , Memcache 最快 , 其次 TCH, 这两个基本在同一数量级 , 而其余三者性能相差比较大 .
读取测试 ( 根据 key)
测试脚本 : all-get-compare.php
原始数据 : Memcache 空 , 其余都 2 亿
bnum: 4 亿
输入参数 : num=100000&length=10240
图中红色是 Mysql, 蓝色是 TCB, 黑色是 TCH, 黄色是 TCT, 绿色是 Memcache, 5 种产品平均每条数据写入时间为 :
Mysql |
TCB |
TCT |
TCH |
Memcache |
90e-6 秒 |
114e-6 秒 |
42e-6 秒 |
34e-6 秒 |
25e-6 秒 |
从上面的读取性能看 , 也是 Memcache 最快 , 其次是 TCH 和 TCT, 另外两种则有较大差距 .
key-value 性能测试结论
根据上面写入和读取的性能测试来看 , Memcache, TCH 在游戏数据的存储方面备选 , 由于在查阅资料的过程中 , 发现有观点认为 TCH 在数据量超出内存后会导致性能下降 , 而 TCB 则性能稳定 , 不受此影响 , 通过下面内存峰值是 TCB 和 TCH 的读取写入性能测试来比较二者 .
TCH 写入
测试脚本 : tt-compare-insert.php
原始数据 : 0
bnum: 400 万
输入参数 : case=test_tch&num=500000&length=10240
从上图对照可以得到结论 : TCH 数据库在数据量超出内存后写入性能会有明显的波动 ( 约 0.6 倍 ).
TCH 读取
测试脚本 : tt-compare-get.php
原始数据 : 0
bnum: 400 万
输入参数 : case=test_tch&num=500000( 内存满负荷 )
输入参数 : case=test_tch&num=500000( 内存空闲 )
对比上面两图顶端标题中的平均耗时 : 内存满负荷 261.4e-6 秒 , 内存空闲 30.05e-6 秒 , 性能差 8 倍左右 , 因此 , 可以得到结论 : TCH 在内存满负荷后性能会下降 8 倍左右 .
TCH 在内存满负荷情况下 , 产生如下性能损耗 : 写入降低为原来的 60% 左右 , 读取性能降低为原来的 12% 左右 .
TCB 写入
测试脚本 : tt-compare-insert.php
原始数据 : 0
bnum: 400 万
输入参数 : case=test_tcb&num=500000&length=10240
从上图可以看出 TCB 的性能比较稳定 , 写入性能与内存消耗几乎无关 .
TCB 读取
测试脚本 : tt-compare-insert.php
原始数据 : 0
bnum: 400 万
输入参数 : case=test_tcb&num=500000( 内存满负荷 )
输入参数 : case=test_tcb&num=500000( 内存空闲 )
对比上面两图顶端标题中的平均耗时 : 内存满负荷 197.22e-6 秒 , 内存空闲 32.25e-6 秒 , 性能差 8 倍左右 , 因此 , 可以得到结论 : TCB 在内存满负荷后性能会下降 8 倍左右 .
TCB 在内存满负荷情况下 , 产生如下性能损耗 : 写入降低为原来的 60% 左右 , 读取性能降低为原来的 12% 左右 .
TCB, TCH 的内存峰值性能测试数据
|
TCH 读取 |
TCH 写入 |
TCB 读取 |
TCB 写入 |
内存满 |
261e-6 |
207e-6 |
197e-6 |
539e-6 |
内存空 |
31e-6 |
32e-6 |
由此表格可以看出 , TCB 在内存满时读取上的平均优势为 60e-6 秒左右 , 而 TCB 的写入性能约为 TCH 的 50%, 由上面图表分析可以证实网上查阅得到的 TCH 在数据量超过内存容量后性能下降 , 但是 , TCB 的读取也会有所下降 , 究其整体运行的性能来看 , TCH 优于 TCB.
因此 , 对于游戏部分的存储 , 在目前的三种备选方案 TCH, TCB, Memcache 中 , 又将 TCB 淘汰出局 .
在仅剩的 TCH 与 Memcache 中 , 但从速度而言 , Memcache 有无可比拟的优势 , 但是 , 从另一个角度来看 , Memcache 作为一个纯粹的缓存产品 , 不能够独立的处理数据存储业务 , 因此 , 如果使用 Memcache 作为 key-value 的存储接口 , 那么为了数据的持久化及其安全性 , 必然要使用某种持久化存储工具去实现 .
如果 Memcache 再套一个持久化存储工具 , 那么这中间必然会带来一定的性能损失 , 从另一方面来讲 , Memcache 外加持久化工具 , 必然要增加编程实现上的难度 , 也就是间接的增大项目风险 .
从安全性方面来讲 , TT 系列的数据库都提供了备份和还原接口 , 能够支持完整备份和增量备份 , 也能够支持指定时间的恢复 , 而 Memcache 在这一方面也要比 TT 弱 .
测试数据量在第一部分讨论过 , 以单表 1.6 亿为准 , 但是 , 由于 Mysql 用来写入测试数据的程序在 7000 万数据以后变得很慢 , 所以 , Mysql 只插入了 7000 万数据 , TCT 使用上面建立的数据库 , 2 亿条初始数据 .
根据名字检索
测试脚本 : search-compare.php
原始数据 : Mysql7000 万 , 其余都 2 亿
bnum: 4 亿
输入参数 : case=test_name&num=20( 由于 Mysql 这里不使用索引 , 性能极低 , 所以使用 20 条检索测试 )
图中蓝色为 Mysql, 黑色为 TCT, 可以看出 , 此时 TCT 的性能远高于 Mysql 并且平稳 , 此时使用的查询条件为 like ‘%%’, Mysql 不使用索引 . 而 TCT 的包含查询仍然能够使用文本索引
图中平均每条搜索时间为 TCT: 22568e-6 秒 , Mysql:5103998e-6 秒
根据性别检索
测试脚本 : search-compare.php
原始数据 : Mysql7000 万 , 其余都 2 亿
bnum: 4 亿
输入参数 : case=test_name&num=20000
图中蓝色为 Mysql, 黑色为 TCT, 此时 , 根据性别检索的条件为 =’’, Mysql 使用索引 , 并且由于是 = 条件 , 所以 Mysql 可以使用常量表优化 , TCT 使用文本索引 , 可以看到 , Mysql 性能优于 TCT.
图中平均检索时间为 TCT: 1456e-6, Mysql: 25e-6.
根据省市查询
测试脚本 : search-compare.php
原始数据 : Mysql7000 万 , 其余都 2 亿
bnum: 4 亿
输入参数 : case=test_location&num=20000
图中 Mysql 是蓝色线 , TCT 是黑色线 , Mysql 性能高于 TCT. 此时 Mysql 是根据情况在 province 和 city 两列上选择索引匹配 , 并且由于 = 存在 , Mysql 可以使用常量表优化 . TCT 使用 province 作为主索引 , city 作为辅助索引检索
图中每条检索平均耗时为 TCT: 189e-6 秒 , Mysql:28e-6 秒
所有条件一起检索
测试脚本 : search-compare.php
原始数据 : Mysql7000 万 , 其余都 2 亿
bnum: 4 亿
输入参数 : case=test_all&num=20000
图中 Mysql 是蓝色线 , TCT 是黑色线 , Mysql 性能高于 TCT. 此时 Mysql 是根据情况在 province 和 city 两列上选择索引匹配 , 并且由于 = 存在 , Mysql 可以使用常量表优化 . 与省市检索一样 , 这里没有用到 sex 索引 .
图中每条检索平均耗时为 TCT: 190e-6 秒 , Mysql:27e-6 秒
关系数据库对比结果
|
TCT |
Mysql |
索引生效 |
190e-6 |
27e-6 |
索引无效 |
22568e-6 |
5103998e-6 |
Mysql 在索引无法使用时 , 表现比 TCT 差 , 但只要能使索引生效 , Mysql 的性能就会高于 TCT, 分析游戏中需要检索排序的数据 :
找人 : 需要对玩家的 name 和 uid 进行 %% 方式的检索 , 在单独使用这两条检索时 , 无法命中索引 , 但是 , 这种检索的数据量为每玩家一条 , 也就是单表 50-100 万条左右 , 根据经验在这个范围内 Mysql 的全表扫描性能也能满足需求 .
日记 , 系统消息等检索 : 这些表数据量会比较大 , 但是这些表中建立索引都是可以命中的 .
寄售商品 : 与日记 , 系统消息相似 , 索引有效 , 并且数据量更小 .
排名 : 数据量与找人相同 , 但索引有效 .
TCT 在这一方面存在的另一个缺陷是只能支持单表 , 这实际上就导致了单表数据量增大 , 即便对于原本小数据量的表 , 在这种情况下 , 也会变成大数据量 .
10 万次操作 , 每次操作包括以下操作 : 连接 ( 打开连接 , 选择数据库 , 设置数据库编码 ), 一条更新 10 行的 update, 一条取前 10 条的全表扫描检索 , 一条 insert 单条的 insert, 关闭连接 .
按照上述分块 , 操作过程中的平均时间为
使用上述测试 Mysql 操作分块的代码 , 利用 apache 的 ab 进行并发连接测试 . 开启 10000 并发做 10000 次请求 , 得到以下结果 :
一万并发 , 一万请求
Server Software: nginx/0.7.62
Server Hostname: localhost
Server Port: 80
Document Path: /end/concurrent_mysql.php?num=1
Document Length: 193 bytes 文档大小
Concurrency Level: 10000 并发连接数
Time taken for tests: 3.384 seconds 所有请求耗时
Complete requests: 10000 完成请求数
Failed requests: 733 失败请求数
(Connect: 0, Receive: 0, Length: 733, Exceptions: 0)
Write errors: 0
Non-2xx responses: 9350 HTTP 响应头非 2xx 的数量
Total transferred: 3525248 bytes 总传输量
HTML transferred: 1900140 bytes HTML 传输量
Requests per second: 2955.47 [#/sec] (mean) 每秒平均请求数
Time per request: 3383.552 [ms] (mean) 平均事务时间 ( 毫秒 )
Time per request: 0.338 [ms] (mean, across all concurrent requests) 平均每条并发请求独立的响应时间 ( 毫秒 )
Transfer rate: 1017.46 [Kbytes/sec] received 传输速度 ( 接收 )
Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 218 706.9 10 3064
Processing: 3 41 100.5 11 973
Waiting: 1 36 100.0 8 971
Total: 6 259 729.2 21 3287
Percentage of the requests served within a certain time (ms)
50% 21 50% 的请求在 21 毫秒内响应
66% 22
75% 26
80% 47 80% 的请求在 47 毫秒内响应
90% 559
95% 3071
98% 3124
99% 3136
100% 3287 (longest request)