关于秒杀

随着双11活动的不断发展,小米饥饿营销模式的兴起,“秒杀”已经成为一个热点词汇。在一些活动中,热销商品会以惊人的速度售罄,比如最近本人在抢购美图M4手机,12点开卖,1分钟之内就被售罄。

秒杀的实现

对于关注数据库的本人来说,更关心的是如何高效的实现秒杀应用。之前淘宝在2013年的数据库大会上分享过他们的秒杀方案,修改MySQL数据库源码来实现高效的秒杀应用。但是,那篇分享过于高大上,没有给出具体的实现过程。另外,从其他渠道打听到的是这个方案并没有在生产环境上线,不知道有没有其他知道内幕的小伙伴,具体来说说淘宝的方案是否有上线。

当然,有多种方法来优化秒杀应用,比如使用memcached的CAS功能,但是这些方法都不能实现事务的特性。对于深受Jim Gray事务处理教育长大的一代,本人觉得任何事情都应该事务的,不支持事务只不过能取得暂时的胜利,整个世界的哲学应该就是事务,即要么全做,要么全不做,不要处于一个中间状态。本人的为人哲学就是,要么不去设定一个目标,否则这个目标一定会去实现。比如,本人决定去读博,那么一定会完成这个学业。

本人感觉虽然淘宝没有给出具体的实现方式,但是抛出了秒杀应用对于数据库压力的问题所在,即大并发量下更新同一行数据的压力。例如并发执行如下的SQL语句模拟秒杀场景:

BEGIN;
INSERT INTO stock_log VALUES
SELECT count FROM stock WHERE id=1 AND count>0 FOR UPDATE;
UPDATE stock SET count = count -1 WHERE id=1 AND count > 0;
COMMIT;

在做秒杀时,最主要是对库存表进行操作,在操作前可能需要插入一些其他操作,比如日志等,然后就是对库存表进行更新。下图显示增大并发量的情况下,事务处理的性能:

显而易见的是随着并发量的增大,事务处理的性能越差。这和淘宝之前分享的数据基本一致。导致其中的原因就是秒杀是对同一件商品进行更新,需要对同一行记录加锁,因此秒杀操作虽然是并行的,但是在数据库层面是串行的。

随着并发的不断增大,不断发生事务的锁等待与唤醒操作,导致性能的急剧下降。如果通过perf工具来观察的话,应该可以观察到类似如下的内容:

#
59.06%  mysqld  mysqld         [.] lock_deadlock_recursive
16.63%  mysqld  libc-2.13.so   [.] 0x115171
3.09%   mysqld  mysqld         [.] lock_rec_get_prev
2.96%   mysqld  mysqld         [.] my_strnncollsp_utf8
...... 可以发现锁的死锁检测占据了大部分的CPU时间,究其原因,就是因为锁等待。

innodb_thread_concurrency

有小伙伴或许会知道可以通过innodb_thread_concurrency参数来控制InnoDB存储引擎层的并发量。的确,通过这个参数可以限制进入InnoDB引擎层的事务数量,对比测试的话,性能上的确会有一定的提升:

可以发现,将innodb_thread_concurrency设置为16,性能的确会有一定的提升。并发线程数在128的时候,TPS从原有的4300提升为了7200,将近有65%的性能提升。但是在256线程之后,性能依旧堪忧。

导致上述的原因是虽然在InnoDB存储引擎层做了“限流”,但是MySQL数据库上层的线程依然需要等待唤醒。

线程池技术

业界提供了很多关于秒杀MySQL的解决方案,然而非常的定制化,并且需要应用修改相信的程序,比如通过在SQL语句中写hint来进行排队,而这种的排队机制在我看来在低并发量下性能反而又会变差。因此,一个通用的解决方案是采用线程池技术。

线程池可以在MySQL上层限制住同时运行的MySQL的事务数,这样就解决了由秒杀而导致的资源竞争问题。例如,通过前面的测试,已经得知并发16线程时,秒杀可以有最好的性能,那么这时用户将线程池的大小设置为16,这样就能获得用户预期想要的性能:

可以发现即使在4096个并发线程下,秒杀依然可以有近10000的TPS。通过线程池技术,秒杀就是这么简单,无需任何应用端的修改。

但是线程池这里有个参数thread_pool_oversubscribe,这个参数其实有点类似云计算中“超售”概念,即MySQL的线程池允许有额外的线程运行。该参数默认是3,之前thread_pool_size设置为16,那么总共允许16*(1+3)=64个线程同时运行。这个参数的默认值本身没有问题,但是对于秒杀应用来说确是不需要的,因为之前已经讨论过,秒杀应用是串行的。所以将参数thread_pool_oversubscribe设置为1,秒杀应用还能有进一步的提升:

可以发现在大并发的线程下,性能还能有10%~30%的提升。

总结

其实秒杀应用的数据库层优化非常简单,各个层面做好排队即可,如:

  • 应用层做好对于单个商品抢购的数量限制

  • MySQL数据库层使用线程池技术来保证大并发量下的性能

  • 调整参数thread_pool_oversubscribe用来进一步提升性能

MySQL企业版提供了线程池插件,但是需要额外的费用。小伙伴们可以使用开源的MySQL版本InnoSQL,其免费提供了线程池,可以保证应用在大并发量下依旧保证应用的稳定性,特别是对于秒杀类的应用。

秒杀应用的MySQL数据库优化的更多相关文章

  1. 关于MySQL数据库优化的部分整理

    在之前我写过一篇关于这个方面的文章 <[原创]为什么使用数据索引能提高效率?(本文针对mysql进行概述)(更新)> 这次,主要侧重点讲下两种常用存储引擎. 我们一般从两个方面进行MySQ ...

  2. 【MySQL】花10分钟阅读下MySQL数据库优化总结

    1.花10分钟阅读下MySQL数据库优化总结http://www.kuqin.com2.扩展阅读:数据库三范式http://www.cnblogs.com3.my.ini--->C:\Progr ...

  3. 30多条mysql数据库优化方法,千万级数据库记录查询轻松解决(转载)

    1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索 ...

  4. 50多条mysql数据库优化建议

    1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 缺省情况下建立的索引是非群集索引,但有时它并不是最佳的.在非群集索引下,数据在物理上随机存 ...

  5. 解开发者之痛:中国移动MySQL数据库优化最佳实践(转)

    开源数据库MySQL比较容易碰到性能瓶颈,为此经常需要对MySQL数据库进行优化,而MySQL数据库优化需要运维DBA与相关开发共同参与,其中MySQL参数及服务器配置优化主要由运维DBA完成,开发则 ...

  6. 30多条mysql数据库优化方法【转】

    1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索 ...

  7. 百万行mysql数据库优化和10G大文件上传方案

    百万行mysql数据库优化和10G大文件上传方案 最近这几天正在忙这个优化的方案,一直没时间耍,忙碌了一段时间终于还是拿下了这个项目?项目中不要每次都把程序上的问题,让mysql数据库来承担,它只是个 ...

  8. 从运维角度来分析mysql数据库优化的一些关键点【转】

    概述 一个成熟的数据库架构并不是一开始设计就具备高可用.高伸缩等特性的,它是随着用户量的增加,基础架构才逐渐完善. 1.数据库表设计 项目立项后,开发部根据产品部需求开发项目,开发工程师工作其中一部分 ...

  9. 关于mysql数据库优化

    关于mysql数据库优化 以我之愚见,数据库的优化在于优化存储和查询速度 目前主要的优化我认为是优化查询速度,查询速度快了,提高了用户的体验 我认为优化主要从两方面进行考虑, 优化数据库对象, 优化s ...

随机推荐

  1. [Python设计模式] 第8章 学习雷锋好榜样——工厂方法模式

    github地址:https://github.com/cheesezh/python_design_patterns 简单工厂模式 v.s. 工厂方法模式 以简单计算器为例,对比一下简单工厂模式和工 ...

  2. 内联汇编中的asm和__asm__

    基本的内联汇编代码: asm格式: asm("assembly code"):   使用替换的关键字: 如果必须的话,可以改变用于标识内联汇编代码段的关键字asm.ANSI C规范 ...

  3. 视觉SLAM中的数学基础 第三篇 李群与李代数

    视觉SLAM中的数学基础 第三篇 李群与李代数 前言 在SLAM中,除了表达3D旋转与位移之外,我们还要对它们进行估计,因为SLAM整个过程就是在不断地估计机器人的位姿与地图.为了做这件事,需要对变换 ...

  4. jQuery实现表格行上移下移和置顶

    jQuery实现表格行上移下移和置顶 我们在操作列表数据的时候,需要将数据行排列顺序进行调整,如上移和下移行,将行数据置顶等,这些操作都可以在前端通过点击按钮来完成,并且伴随着简单的动态效果,轻松实现 ...

  5. js 引擎 和 html 渲染引擎

  6. javascript中的数据结构

    Javascript中的关键字   abstract     continue      finally      instanceof      private       this boolean ...

  7. MySQL8的新特性ROLE

    [MySQL的ROLE解决了什么问题] 假设你是一个职业素养良好的DBA比较同时又比较注重权限管理的话:可能遇到过这样的问题,数据库中有多个开发人员的账号:有一天要建 一个新的schema,如果你希望 ...

  8. Windows 不能复制文件到远程服务器的解决办法

    1.  开始 -> 运行->浏览->C:\Windows\System32\rdpclip.exe->打开. 2. 打开资源管理器的进程可以看到 rdp复制粘贴正在运行,即可.

  9. ECMAScript 6 入门之字符串

    1.新增字符串的方法 1.字符是否存在 console.log("Yo".indexOf("Y")!=-1); console.log("Yo&quo ...

  10. ffmpeg主体架构分析

    [时间:2016-07] [状态:Open] [关键词:ffmpeg,libavcodec,libavformat] FFmpeg接触几年了,用的比较多的是libavcodec和libavformat ...