秒杀活动可以说在互联网上随处可见,从12306抢票,到聚划算抢购,我们生活的方方面面都可以看到秒杀的身影。

作者:IT技术管理那些事儿

秒杀活动可以说在互联网上随处可见,从12306抢票,到聚划算抢购,我们生活的方方面面都可以看到秒杀的身影。

秒杀的架构设计也是对于一个架构师架构设计能力的一次考验。本文的目的并不在于提供一个可以直接落地的设计方案,而是意在提供一个简单的方法,一个思路,使大家能够对于秒杀背后的一些设计有更感性的认识, 并且可以自己亲自动手实践一下。

所有的配置及源码都在本文最后的GitHub repository中可以找到。

首先,先简单介绍下本文中会涉及到的一些组件,如下图所示:

JMeter:用JMeter来模拟秒杀活动中大量并发的用户请求

Seckill Service:基于Nodejs使用Express实现的秒杀service,图中的步骤2,3,4都是在这个service中处理的

Redis:一个Redis的docker container,在其中保存一个名为counter的数据来表示当前剩余的库存大小

Kafka: 一个Kafka的docker container,其实这里还有一个zookeeper的docker container,Kafka用zookeeper来存放一些元数据,在程序中并没有涉及到,所以也就不单独列出来说了。Seckill service在更新完Redis之后,会发送一条消息给Kafka表示一次成功的秒杀

Seckill Kafka Consumer: 基于Nodejs的Kafka consumer,会从Kafka中去获取秒杀成功的消息,处理并且存储到MySQL中

MySQL:一个MySQL的docker container,最终秒杀成功的请求都会对应着数据库表中的一条记录

环境搭建

1 . 安装JMeter

从官网下载一个JMeter的binary包,执行bin目录下的jmeter即可启动,启动后如下图新建一个名为Seckill的Thread Group,并且设置在5s内发起2000次并发请求。

在这个Thread Group下新建一个Http Request的Sampler并命名为Seckill,按下图配置host name,port number,http request method以及request path

2 . 安装Redis,Kafka, Zookeeper和MySQL

为了方便搭建环境,这几个组件会以docker container的形式启动。在此之前需要去Docker官网下载并安装Docker Engine,Docker Machine和Docker Compose。如果是在Windows或者Mac上,Docker官网提供Docker For Windows/Docker For Mac安装程序,可以很方便的把这3个组件安装好。

3 . 编写Docker Compose文件

创建一个Seckill项目文件夹,新建一个docker-compose.yml文件,内容如下:

配置文件中一共配置了4个services对应4个docker container,分别是zookeeper,kafka,redis以及mysql。这里有两个地方需要设置成你实际环境的值,一个是kafka配置下面的KAFKA_ADVERTISED_HOST_NAME字段,这个需要设置成本地机器的IP。另一个是MYSQL配置下面的MYSQL_ROOT_PASSWORD,你可以设置成你想要的任何值。

创建好这个文件之后,就可以去命令行项目根目录中执行docker-compose up,docker engine就会把上面配置的这4个组件全部启动起来。

注意:在启动完之后,需要去Kafka容器中创建一个名为CAR_NUMBER的topic,去Redis容器中创建一个名为counter的计数器(设置值为100,代表库存初始值为100),去MySQL容器中创建一个名为seckill的数据表(包含一个自增长的id自段和一个timestamp格式的date字段)。

代码片段

1 . Seckill Service

  • 第1-8行,引入了程序需要用到的对象,nodejs的mvc框架express, redis, kafka等
  • 第10行,利用express提供的方法暴露出一个path为/seckill的POST方法
  • 第12行,定义了一个方法,在54行会调用
  • 第13-22行,新建了一个redis client并且监听error事件
  • 第23行,这行代码非常关键,它的作用是让redis cilent监视redis中的counter值,之后会启动一个事务,如果在事务提交的时候发现有其它client修改了counter值的话,就会放弃这个事务。
  • 第24行,通过redis client的异步方法获取counter的值,因为redis的get操作是原子的,所以在这里不用担心有并发读写的问题。
  • 第25-28行,判断返回的库存值是否大于0,如果大于0,通过client.multi()启动一个事务,通过decr()方法将counter值减1,最后通过exec()方法提交事务;如果小于0,则执行第47行,打印卖完了并且关闭redis client。
  • 第29-46行,这里我们看一下multi.exec()中的这个回调方法。在前面我们已经使用watch对counter进行了监视。如果在事务提交过程中有其它client修改了counter值的话,回调方法中的replies参数就会是null,可以看到第29-31行,程序会打印“可能有冲突”并且再次调用fn方法重试。

如果replies的值不为null,就会使用kafka的producer发送一条message到CAR_NUMBER topic。

2 . seckill_kafka_consumer

这里的代码就比较简单了,会初始化一个kafka consumer监听CAR_NUMBER topic,对于新获取的消息会去MySQL的seckill表里插入一条记录。

操作步骤

  • 启动docker container
  • 启动Seckill_Service
  • 启动seckill_kafka_consumer
  • 启动JMeter发送2000个并发请求

结果

JMeter request results

Redis counter field

MySQL seckill table

可以看到,最后redis中的counter变成0,seckill数据表中会插入100条记录,没有发生超卖或者少卖的情况。当然在实际生产环境场景中,还有许多其它需要考虑的地方,希望此文可以起到一个抛砖引玉的作用,帮助大家更好的理解秒杀场景。

阅读目录(置顶)(长期更新计算机领域知识)

阅读目录(置顶)(长期更新计算机领域知识)

阅读目录(置顶)(长期科技领域知识)

歌谣带你看java面试题

第一百三十五期:如何模拟一次阿里双11秒杀场景的实现?程序员必看相关推荐

  1. 第一百二十五期:程序员的自我救赎,使用Python开发性格分析工具

    如此不均衡的贫富差距,各行业的领导者如何能管理好公司,让员工们既努力产出,又能安于现状呢?每个领导者必学的一门课程就是职场心理学.只有你充分了解员工心理与对应的行为表现,才能从容的掌控各类型的人员,从 ...

  2. 第一百三十九期:11月数据库排行:排名前三数据库分数暴跌

    DB-Engines 数据库流行度排行榜 11 月更新已发布,与上期数据相比,这期排行榜最大的亮点就是排名前三数据库那引人注目的"红色"分数. 作者:局长 DB-Engines 数 ...

  3. 第一百三十四期:MySQL分页查询方法及优化

    在MySQL中,分页查询一般都是使用limit子句实现,limit子句声明如下:LIMIT子句可以被用于指定 SELECT 语句返回的记录数. 作者:青芽草  分页查询方法: 在MySQL中,分页查询 ...

  4. nmcli命令详解_【高新课堂】第一百二十五期Liunx必备命令

    点击上方"蓝字"关注我们吧! Liunx系统启动默认为字符界面,一般不会启用图像界面,所以对命令行的熟练程度能更加高效.便捷的管理Liunx服务器. 这节课向读者介绍Liunx系统 ...

  5. 第一百三十八期:37 个MySQL数据库小知识,为面试做准备

    无论是运维.开发.测试,还是架构师,数据库技术是一个必备加薪神器,那么,一直说学习数据库.学MySQL,到底是要学习它的哪些东西呢? 作者:芒果教你学编程 无论是运维.开发.测试,还是架构师,数据库技 ...

  6. 第一百三十六期:详细讲解 Redis 的两种安装部署方式

    Redis 是一款比较常用的 NoSQL 数据库,我们通常使用 Redis 来做缓存,这是一篇关于 Redis 安装的文章,所以不会涉及到 Redis 的高级特性和使用场景,Redis 能够兼容绝大部 ...

  7. sed 第n行后加入_【高新课堂】第一百三十九期Liunx运维17个实用技巧

    来源:高效运维 1.查找前目录下所有以.tar结尾的文件然后移动到指定目录 find . -name "*.tar" -exec mv {}./backup/ ; 注解:find ...

  8. 美学心得(第二百三十五集) 罗国正

    美学心得(第二百三十五集) 罗国正 (2022年3月) 3015.我比较喜欢"破茧化蝶"这个成语,它充满象征意义和美感.其实,人的成长过程,人类的发展就象不断的"破茧化蝶 ...

  9. 第一卷 第一百三十六章 好白菜

    第一卷 第一百三十六章 好白菜 其实我最恨两种人,一种是始乱终弃的小白脸,一种就是生孩子不养活的臭娘们儿.**  提供本书txt电子书下载 **既然你能生就要能养啊,虽然我不知道井里的那个死孩子的母亲 ...

最新文章

  1. cffi java_atomiclong-使用CFFI的原子长类型。-David Reid
  2. .net core 调用c dll_工具:搭建Camp;C,一睹模样
  3. 2016.07.17-18 集合方法
  4. mysql 事务块 sql_Oracle_PL/SQL的基本写法_BEGIN_END块结构及简单的事务实现
  5. feign整合sential,Feign中使用Sentinel熔断器防止服务雪崩
  6. 转一篇关于并发和并行概念的好文,附带大神评论
  7. /var/spool/postfix/maildrop小文件太多造成inode索引使用完解决
  8. java 解析数据包_一种基于Java语言的网络通讯数据包解析方法与流程
  9. 第13章 图像像素采样(《Python趣味创意编程》教学视频)
  10. Linux per-CPU实现分析
  11. Windows勒索病毒补丁下载
  12. android 安装包反编译,Android逆向之反编译APK和安装包漏洞解析
  13. 激光防护屏 激光防护屏
  14. RC时间常数 积分微分 耦合
  15. Activities(活动)
  16. spark JAVA 开发环境搭建及远程调试
  17. android模拟器不玩游戏,安卓模拟器哪个玩游戏最流畅?
  18. 微信公众号开发~有感而发
  19. 谱分析——傅里叶级数(离散谱)
  20. Shell和Jenkins讲解

热门文章

  1. 用cocos2dx实现模态对话框
  2. abap al设置单元格可编辑 oo_excel表格操作: 图形和图表编辑技巧汇总(二)
  3. java 反射机制_基础篇:深入解析JAVA反射机制
  4. 小学三年级上册计算机计划,小学三年级数学上册教学计划
  5. vue 打包路由报错_Vue下路由History模式打包后页面空白的解决方法
  6. 电子商务计算机网络安全技术教案,网络安全技术教案.pdf
  7. php mysql备份还原类_PHP实现MYSQL备份还原
  8. layui内置loading等待加载
  9. PWA(Progressive Web App)入门系列:Sync 后台同步
  10. Java 基础——数组解析