秒杀应用的MySQL数据库优化

其实秒杀应用的数据库层优化非常简单,各个层面做好排队即可,MySQL企业版提供了线程池插件,但是需要额外的费用。

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

关于秒杀

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

秒杀的实现

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

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

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

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

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

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

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

  1. #
  2. 59.06% mysqld mysqld [.] lock_deadlock_recursive
  3. 16.63% mysqld libc-2.13.so [.] 0x115171 3.09% mysqld mysqld [.] lock_rec_get_prev
  4. 2.96% mysqld mysqld [.] my_strnncollsp_utf8
  5. ......

可以发现锁的死锁检测占据了大部分的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,其免费提供了线程池,可以保证应用在大并发量下依旧保证应用的稳定性,特别是对于秒杀类的应用。

原文

时间: 2024-10-10 20:41:12

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

[mysql][【优化集合】mysql数据库优化集合

三个层面: 1.系统层面 2.mysql配置参数 3.sql语句优化 =========================================================== 一.系统层面 =========================================================== 二.mysql参数层面 http://www.oicto.com/mysql-explain-show/ 2.1slowlog 配置slowlog 配置文件: log-slow

中国移动MySQL数据库优化最佳实践

原创 2016-08-12 章颖 DBAplus社群 本文根据DBAplus社群第69期线上分享整理而成,文末还有书送哦~ 讲师介绍章颖 数据研发工程师 现任中国移动杭州研发中心数据研发工程师,擅长MySQL故障诊断,性能调优,MySQL高可用技术,曾任中国电信综合平台开发运营中心DBA 开源数据库MySQL比较容易碰到性能瓶颈,为此经常需要对MySQL数据库进行优化,而MySQL数据库优化需要运维DBA与相关开发共同参与,其中MySQL参数及服务器配置优化主要由运维DBA完成,开发则需要从数据

​Mysql数据库优化总结

Mysql数据库优化总结 -----杜 说明:本文的环境为CENTOS 5.5 64 Bit /Mysql 5.1.50 简介:使用Mysql有一段时间了,期间做了不少关于Mysql优化.设计.维护的工作,这两天有时间做一下简单的总结,方便自己回忆,同时也希望能对大家有点帮助. I            硬件配置优化 CPU选择:多核的CPU,主频高的CPU 内存:更大的内存 磁盘选择:更快的转速.RAID.阵列卡, 网络环境选择:尽量部署在局域网.SCI.光缆.千兆网.双网线提供冗余.0.0.

MySQL数据库优化详解(收藏)

MySQL数据库优化详解 mysql表复制 复制表结构+复制表数据mysql> create table t3 like t1;mysql> insert into t3 select * from t1;mysql索引 ALTER TABLE用来创建普通索引.UNIQUE索引或PRIMARY KEY索引ALTER TABLE table_name ADD INDEX index_name (column_list)ALTER TABLE table_name ADD UNIQUE (colu

Mysql数据库优化技术之配置篇、索引篇 ( 必看 必看 转)

转自:Mysql数据库优化技术之配置篇.索引篇 ( 必看 必看 ) (一)减少数据库访问 对于可以静态化的页面,尽可能静态化 对一个动态页面中可以静态的局部,采用静态化 部分数据可以生成XML,或者文本文件形式保存 使用数据缓存技术,例如: MemCached (二)优化的检测方法 1.用户体验检测 2.Mysql状态检测 在Mysql命令行里面使用show status命令,得到当前mysql状态. 主要关注下列属性: key_read_requests (索引读的请求数)(key_buffe

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

在之前我写过一篇关于这个方面的文章 <[原创]为什么使用数据索引能提高效率?(本文针对mysql进行概述)(更新)> 这次,主要侧重点讲下两种常用存储引擎. 我们一般从两个方面进行MySQL数据库优化: A.SQL语句的优化. 这点,需要我们在写SQL的时候要特别注意,在建表的时候也非常注意. 1 尽量不要在列上进行运算,这样会导致索引失效. 2 使用JOIN时候,应使用小结果集驱动大结果集.把复杂的JOIN拆分成多个QUERY.在多JOIN的时候,最容易导致锁表和堵塞. 3 在使用LIKE进

关于MySQL数据库优化

MySQL数据库优化相关知识: 一.两种常用引擎的选择 1.MyISAM 当MySQL版本小于5.5时的默认引擎 优点:擅长数据处理:高速读写:数据的存储顺序为插入顺序,插入速度快:空间占用量小 特性:全文索引支持(版本大于等于5.6的Innodb也支持),可以利用myisamPack完成数据的压缩功能 缺点:仅支持表级锁定,支持并发插入,写操作中插入操作不会影响其他操作.不支持事务 2.InnoDB 版本大于等于5.5的默认引擎 优点:提供事务,行级锁定,外键约束,注重数据的完整性和安全性 特

mysql数据库优化 开启慢查询

Mysql数据库优化 一.sql及索引优化 如何发现有问题的sql?使用mysql慢查询日志对有效率问题的sql进行监控 //查看是否开启慢查询日志show variables like 'slow_query_log' set global slow_query_log =on;//开启慢查询 //设置保存慢查询日志路径set global slow_query_log_file = '/var/lib/mysql/slow_log.log'; //记录下没有使用索引的query,show v

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

1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的列上建立索引. 2.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索引而进行全表扫描, Sql 代码 : select id from t where num is null; 可以在 num 上设置默认值 0,确保表中 num 列没有 null 值,然后这样查询: Sql 代码 : select id from t where num=0; 3.应尽量避免在 wh