V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
Tianpu
V2EX  ›  程序员

探讨 - 缓存存储方案:mysql vs memcached

  •  
  •   Tianpu · 2014-01-06 20:16:12 +08:00 · 4596 次点击
    这是一个创建于 3762 天前的主题,其中的信息可能已经有所发展或是发生改变。
    key使用md5特征字符串

    方案一:
    使用mysql:

    CREATE TABLE IF NOT EXISTS `keys` (
    `key` varchar(32) NOT NULL,
    `time` int(12) NOT NULL,
    UNIQUE KEY `key` (`key`),
    KEY `time` (`time`)
    ) ENGINE=MyISAM;

    CREATE TABLE IF NOT EXISTS `tmp0` (
    `key` varchar(32) NOT NULL,
    `value` blob NOT NULL,
    `time` int(12) unsigned NOT NULL,
    KEY `key` (`key`)
    ) ENGINE=MyISAM;

    .... tmp1 -> tmpf;

    一共17个表

    逻辑上这么处理

    key的首字符用来分表到 tmp0 -> tmpf

    添加数据:添加key和有效时间到keys表;添加key value 有效时间到tmp0-f的数据表
    读取数据:根据key直接从tmp*读取数据 做下有效时间判断 过期则删除缓存
    过期处理:使用计划任务从keys表读取过期数据索引 批量删除


    方案二:

    使用memcached

    添加数据:添加key value 过期时间到memcached
    读取数据:根据key从memcached直接读取数据
    过期处理:memcached自动维护


    我想问的是方案一有什么明显的缺陷吗? 跟方案二相比 系统瓶颈在哪里?

    如果1000万数据缓存的话 单挑数据压缩后3K 方案一索引大小是32*10000000/16=20M 也不会卡的 方案二如果有优势在哪里?

    我想到的可能是内存读取速度比硬盘快 那如果SSD做RAID10 使用内存的memcached还有优势吗?

    实际测试中 方案一速度是0.0008 方案二是0.0004

    不考虑非常海量的并发
    24 条回复    1970-01-01 08:00:00 +08:00
    Ever
        1
    Ever  
       2014-01-06 20:41:17 +08:00   ❤️ 2
    方案一表类型改成innodb, innodb文件格式设置成barracuda.

    把表简化成一个, 不用分区或者分表
    key binary(16) primary_key
    time int index
    value blob


    还可以直接通过handlersocket读取数据, 而不是sql.

    以上, 一家之言.
    Actrace
        2
    Actrace  
       2014-01-06 21:08:43 +08:00   ❤️ 1
    1,SSD速度永远赶不上内存...
    2,你若是用MYISAM,那么你的业务基本没有写入和更新咯?MYISAM锁表是很蛋疼的.
    jimrok
        3
    jimrok  
       2014-01-06 21:31:04 +08:00   ❤️ 1
    不明白是做什么用的?
    Maslino
        4
    Maslino  
       2014-01-06 21:34:55 +08:00   ❤️ 1
    我想问问楼主实际是如何做性能测试的?缓存的是什么样的数据,单条压缩后仍然有3KB?
    mahone3297
        5
    mahone3297  
       2014-01-06 21:36:55 +08:00   ❤️ 1
    @Ever innodb文件格式设置成barracuda 这句话没看懂。。
    Tianpu
        6
    Tianpu  
    OP
       2014-01-06 22:10:39 +08:00
    @Maslino ab测试不能说明问题 又没有别的测试 我就贴下吧

    **********************************************************************

    128并发:

    方案一:
    Write errors: 0
    Total transferred: 200530818 bytes
    HTML transferred: 198350958 bytes
    Requests per second: 822.91 [#/sec] (mean)
    Time per request: 155.545 [ms] (mean)
    Time per request: 1.215 [ms] (mean, across all concurrent requests)
    Transfer rate: 15737.46 [Kbytes/sec] received

    Connection Times (ms)
    min mean[+/-sd] median max
    Connect: 0 13 22.8 1 133
    Processing: 10 142 53.2 142 676
    Waiting: 0 131 57.5 137 676
    Total: 11 155 51.1 147 705

    Percentage of the requests served within a certain time (ms)
    50% 147
    66% 161
    75% 173
    80% 181
    90% 209
    95% 237
    98% 279
    99% 318
    100% 705 (longest request)


    方案二:
    Write errors: 0
    Total transferred: 200939520 bytes
    HTML transferred: 198758400 bytes
    Requests per second: 819.24 [#/sec] (mean)
    Time per request: 156.241 [ms] (mean)
    Time per request: 1.221 [ms] (mean, across all concurrent requests)
    Transfer rate: 15699.26 [Kbytes/sec] received

    Connection Times (ms)
    min mean[+/-sd] median max
    Connect: 0 21 27.1 6 137
    Processing: 9 135 51.5 129 445
    Waiting: 1 118 56.1 112 434
    Total: 12 156 51.9 149 445

    Percentage of the requests served within a certain time (ms)
    50% 149
    66% 169
    75% 187
    80% 195
    90% 223
    95% 248
    98% 279
    99% 308
    100% 445 (longest request)

    *********************************************************************


    1024并发:

    方案一:
    Write errors: 0
    Total transferred: 200336198 bytes
    HTML transferred: 198156938 bytes
    Requests per second: 801.65 [#/sec] (mean)
    Time per request: 1277.367 [ms] (mean)
    Time per request: 1.247 [ms] (mean, across all concurrent requests)
    Transfer rate: 15315.95 [Kbytes/sec] received

    Connection Times (ms)
    min mean[+/-sd] median max
    Connect: 0 51 98.1 1 623
    Processing: 32 1191 540.9 1237 3749
    Waiting: 7 1090 471.4 1221 3474
    Total: 96 1241 518.5 1251 4039

    Percentage of the requests served within a certain time (ms)
    50% 1251
    66% 1315
    75% 1355
    80% 1519
    90% 1848
    95% 2017
    98% 2366
    99% 3112
    100% 4039 (longest request)


    方案二:

    Total transferred: 200939520 bytes
    HTML transferred: 198758400 bytes
    Requests per second: 824.39 [#/sec] (mean)
    Time per request: 1242.128 [ms] (mean)
    Time per request: 1.213 [ms] (mean, across all concurrent requests)
    Transfer rate: 15797.89 [Kbytes/sec] received

    Connection Times (ms)
    min mean[+/-sd] median max
    Connect: 0 70 113.6 12 597
    Processing: 14 1131 484.6 1066 2970
    Waiting: 9 1011 461.8 992 2431
    Total: 47 1201 452.1 1176 2970

    Percentage of the requests served within a certain time (ms)
    50% 1176
    66% 1279
    75% 1426
    80% 1532
    90% 1800
    95% 1959
    98% 2328
    99% 2657
    100% 2970 (longest request)


    ************************************************************************

    高并发mysql的确不如memcached 一般并发 mysql劣势不是很明显

    一般情况下,只读是这样子的:

    方案一:

    73dc7f908ca127684c9cb874dbc3392d
    73dc7f908ca127684c9cb874dbc3392d
    73dc7f908ca127684c9cb874dbc3392d
    73dc7f908ca127684c9cb874dbc3392d
    73dc7f908ca127684c9cb874dbc3392d
    73dc7f908ca127684c9cb874dbc3392d
    73dc7f908ca127684c9cb874dbc3392d
    73dc7f908ca127684c9cb874dbc3392d
    73dc7f908ca127684c9cb874dbc3392d

    load in 0.000408888s

    方案二:

    23618634799318c968a5a35c8cac0974
    23618634799318c968a5a35c8cac0974
    23618634799318c968a5a35c8cac0974
    23618634799318c968a5a35c8cac0974
    23618634799318c968a5a35c8cac0974
    23618634799318c968a5a35c8cac0974
    23618634799318c968a5a35c8cac0974
    23618634799318c968a5a35c8cac0974
    23618634799318c968a5a35c8cac0974

    load in 0.000947952s
    9hills
        7
    9hills  
       2014-01-06 22:11:16 +08:00   ❤️ 1
    simple is better,你的方案1也太过度设计了吧
    Tianpu
        8
    Tianpu  
    OP
       2014-01-06 22:12:46 +08:00
    结论似乎是mysql并发不行 貌似就是一般结论了 好处是mysql相对更加持久和不怕重启 哎 我还是改回memcached吧

    多些楼上各位 都送钱了
    Tianpu
        9
    Tianpu  
    OP
       2014-01-06 22:13:54 +08:00
    @9hills 清理缓存方便些 被动过期数据没有触发就麻烦些 多存一份数据 删除过期数据更可控
    9hills
        10
    9hills  
       2014-01-06 22:17:19 +08:00   ❤️ 1
    @Tianpu 持久化看看redis吧
    Tianpu
        11
    Tianpu  
    OP
       2014-01-06 22:18:05 +08:00
    @9hills 不喜欢名字 :)
    jimrok
        12
    jimrok  
       2014-01-07 00:23:31 +08:00   ❤️ 1
    为什么不测试redis呢?
    kindy
        13
    kindy  
       2014-01-07 00:26:47 +08:00 via Android   ❤️ 1
    @Tianpu redis 多好的名字呀
    bakac
        14
    bakac  
       2014-01-07 09:10:33 +08:00   ❤️ 1
    mysql 有内存存储引擎的 如果不需要持久化 可以用这个 如果需要持久化 就还是 innodb
    est
        15
    est  
       2014-01-07 09:25:44 +08:00   ❤️ 1
    @bakac 那个玩意写入数据要锁表。
    bakac
        16
    bakac  
       2014-01-07 09:42:47 +08:00   ❤️ 1
    @est 忘记了( 我只记得他能很快....
    likuku
        17
    likuku  
       2014-01-07 09:59:41 +08:00   ❤️ 1
    memcached 有个日本人作的版本,支持两台memcached双向自动同步,假若一台坏掉,之后恢复运作会自动从活着的那台抓回数据复活。
    Tianpu
        18
    Tianpu  
    OP
       2014-01-07 10:43:55 +08:00
    @bakac 应该不是查询速度的问题 查询速度无论哪种都非常快

    就是高并发下mysql不如memcached
    likuku
        19
    likuku  
       2014-01-07 12:10:28 +08:00   ❤️ 1
    @Tianpu 没考虑过单一web服务器/web前端? 这部分也会造成瓶颈吧。

    只单纯测试 mysql 和 memcached 的话,直接用同一种语言的API来测或许会更公平。
    Maslino
        20
    Maslino  
       2014-01-07 13:05:31 +08:00   ❤️ 1
    @est Innodb引擎的锁机制不一样哦
    lecher
        21
    lecher  
       2014-01-07 13:16:05 +08:00   ❤️ 1
    @likuku
    memcached 有个日本人作的版本,支持两台memcached双向自动同步,假若一台坏掉,之后恢复运作会自动从活着的那台抓回数据复活。

    这个插件有个坑都在网络连接上面:
    一个是网络连接传输过程如果阻塞了,会一直挂起.

    局域网可能不容易被坑到,但是如果服务器负载太高,可能会踩到第一个坑.
    远程的话,要评估一下数据一致性的要求有多高了.
    Tianpu
        22
    Tianpu  
    OP
       2014-01-07 13:26:38 +08:00
    @likuku 负载基本0.01的单机 我就是想页面渲染速度更快点 php脚本都在内存里了 想了想也就数据库读取慢 所以就全部尽量所有进入内存了

    远程的话仅仅持久化一点 就首选Mysql了 redis的持久化貌似容易有坑?比如同步到磁盘的时候是不是会一顿一卡的?

    memcacedb挺好的 就是太持久了 不能自动过期 缓存对象太多 担心性能有下降或者占用磁盘太多

    比较好的方式 觉得是使用memcachedb做持久化,同时维护一个Key表 手工清理过期缓存 这样子坏处是系统太复杂了
    Ever
        23
    Ever  
       2014-01-10 14:58:24 +08:00
    @mahone3297 innodb_file_format=barracuda, 适合有变长大blob字段的row

    @Tianpu 你要带持久化的memcached, 可以用tokyo tyrant或者kyoto cabinet, 都支持memcached协议。
    Tianpu
        24
    Tianpu  
    OP
       2014-01-19 02:04:17 +08:00
    更新下,某个对于时间要求不高的mysql缓存的统计信息,差不多10天了:

    Cache:
    keys 2781521
    tmp0 173826
    tmp1 174125
    tmp2 174395
    tmp3 173631
    tmp4 173336
    tmp5 174308
    tmp6 174062
    tmp7 173443
    tmp8 173672
    tmp9 173556
    tmpa 174011
    tmpb 173744
    tmpc 173170
    tmpd 173886
    tmpe 173940
    tmpf 174416
    offset 0

    缓存失败,如写keys、写缓存、或者两个一起失败,差不多有500来次,比例可以接受

    目前仍旧是飞速,占用数据库7G了,刚把过期时间改成32天,预计最终稳定态是占用20多G数据库,到时候继续更新看看是不是还能稳定运行。

    keys索引有100多M了 的确是个瓶颈 在考虑keys表是不是只做时间的索引 放弃一致性 然后随机读取 随机删除过期的
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   5241 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 37ms · UTC 09:25 · PVG 17:25 · LAX 02:25 · JFK 05:25
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.