使用Redis轻松实现秒杀系统

导论曾经被问过好多次怎样实现秒杀系统的问题 。昨天又在CSDN架构师微信群被问到了 。因此这里把我设想的实现秒杀系统的价格设计分享出来 。供大家参考 。
秒杀系统的架构设计秒杀系统 , 是典型的短时大量突发访问类问题 。对这类问题 , 有三种优化性能的思路: 写入内存而不是写入硬盘 异步处理而不是同步处理 分布式处理 用上这三招 , 不论秒杀时负载多大 , 都能轻松应对 。更好的是 , redis能够满足上述三点 。因此 , 用Redis就能轻松实现秒杀系统 。用我这个方案 , 无论是电商平台特价秒杀 , 12306火车票秒杀 , 都不是事:)
下面介绍一下为什么上述三种性能优化思路能够解决秒杀系统的性能问题:
写入内存而不是写入硬盘传统硬盘的读写性能是相当差的 。SSD硬盘比传统硬盘快100倍 。而内存又比SSD硬盘快10倍以上 。因此 , 写入内存而不是写入硬盘 , 就能使系统的能力提升上千倍 。也就是说 , 原来你的秒杀系统可能需要1000台服务器支撑 , 现在1台服务器就可以扛住了 。你可能会有这样的疑问:写入内存而不是持久化 , 那么如果此时计算机宕机了 , 那么写入的数据不就全部丢失了吗?如果你就这么倒霉碰到服务器宕机 , 那你就没秒到了 , 有什么大不了? 后面真正处理秒杀订单时 , 我们会把信息持久化到硬盘中 。因此不会丢失关键数据 。Redis是一个缓存系统 , 数据写入内存后就返回给客户端了 , 能够支持这个特性 。
异步处理而不是同步处理像秒杀这样短时大并发的系统 , 在性能负载上有一个明显的波峰和长期的波谷 。为了应对相当短时间的大并发而准备大量服务器来应对 , 在经济上是相当不合算的 。因此 , 对付秒杀类需求 , 就应该化同步为异步 。用户请求写入内存后立刻返回 。后台启动多个线程从内存池中异步读取数据 , 进行处理 。如用户请求可能是1秒钟内进入的 , 系统实际处理完成可能花30分钟 。那么一台服务器在异步情况下其处理能力大于同步情况下1800多倍! 异步处理 , 通常用MQ(消息队列)来实现 。Redis可以看作是一个高性能的MQ 。因为它的数据读写都发生在内存中 。
分布式处理好吧 。也许你的客户很多 , 秒杀系统即使用了上面两招 , 还是捉襟见肘 。没关系 , 我们还有大招:分布式处理 。如果一台服务器撑不住秒杀系统 , 那么就多用几台服务器 。10台不行 , 就上100台 。分布式处理 , 就是把海量用户的请求分散到多个服务器上 。一般使用hash实现均匀分布 。这类系统在大数据云计算时代的今天已经有很多了 。无非是用Paxos算法和Hash Ring实现的 。Redis Cluster正是这样一个分布式的产品 。
使用Redis实现描述系统Redis和Redis Cluster(分布式版本) , 是一个分布式缓存系统 。其支持多种数据结构 , 也支持MQ 。Redis在性能上做了大量优化 。因此使用Redis或者Redis Cluster就可以轻松实现一个强大的秒杀系统 。基本上 , 你用Redis的这些命令就可以了 。RPUSH key value 插入秒杀请求
当插入的秒杀请求数达到上限时 , 停止所有后续插入 。后台启动多个工作线程 , 使用 LPOP key 读取秒杀成功者的用户id , 进行后续处理 。或者使用LRANGE key start end命令读取秒杀成功者的用户id , 进行后续处理 。每完成一条秒杀记录的处理 , 就执行INCR key_num 。一旦所有库存处理完毕 , 就结束该商品的本次秒杀 , 关闭工作线程 , 也不再接收秒杀请求 。
要是还撑不住 , 该怎么办也许你会说 , 我们的客户很多 。即使部署了Redis Cluster , 仍然撑不住 。那该怎么办呢? 记得某个伟人曾经说过:办法总比困难多! 下面 , 我们具体分析下 , 还有哪些情况会压垮我们架构在Redis(Cluster)上的秒杀系统 。
脚本攻击如现在有很多抢火车票的软件 。它们会自动发起http请求 。一个客户端一秒会发起很多次请求 。如果有很多用户使用了这样的软件 , 就可能会直接把我们的交换机给压垮了 。这个问题其实属于网络问题的范畴 , 和我们的秒杀系统不在一个层面上 。因此不应该由我们来解决 。很多交换机都有防止一个源IP发起过多请求的功能 。开源软件也有不少能实现这点 。如linux上的TC可以控制 。流行的Web服务器Nginx(它也可以看做是一个七层软交换机)也可以通过配置做到这一点 。一个IP , 一秒钟我就允许你访问我2次 , 其他软件包直接给你丢了 , 你还能压垮我吗?


推荐阅读