秒杀活动可以说在互联网上随处可见,从12306抢票,到聚划算抢购,我们生活的方方面面都可以看到秒杀的身影。秒杀的架构设计也是对于一个架构师架构设计能力的一次考验。本文的目的并不在于提供一个可以直接落地的设计方案,而是意在提供一个简单的方法,一个思路,使大家能够对于秒杀背后的一些设计有更感性的认识, 并且可以自己亲自动手实践一下。所有的配置及源码都在本文最后的GitHub repository中可以找到,或者点击阅读原文链接。

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

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

Seckill Service:基于Node.js使用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:基于Node.js的Kafka consumer,会从Kafka中去获取秒杀成功的消息,处理并且存储到MySQL中

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

环境搭建

安装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。

安装Redis、Kafka、ZooKeeper和MySQL

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

代码片段

Seckill Service

第1-8行,引入了程序需要用到的对象,Node.js的MVC框架Express、Redis、Kafka等。

第10行,利用Express提供的方法暴露出一个path为/seckill的POST方法。

第12行,定义了一个方法,在54行会调用。

第13-22行,新建了一个redis client并且禁用词语error事件。

第23行,这行代码非常关键,它的作用是让redis client监视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.EⅩEc()中的这个回调方法。在前面我们已经使用watch对counter进行了监视。如果在事务提交过程中有其它client修改了counter值的话,回调方法中的replies参数就会是null,可以看到第29-31行,程序会打印“可能有冲突”并且再次调用fn方法重试。

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

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条记录,没有发生超卖或者少卖的情况。当然在实际生产环境场景中,还有许多其它需要考虑的地方,希望此文可以起到一个抛砖引玉的作用,帮助大家更好的理解秒杀场景。

项目GitHub地址点击阅读原文链接,或者浏览器输入:https://github.com/geshenyi/MockSecKill

本文转载于微信公众号: Docker(dockerone),更多微信文章请扫描关注公众号:

Tag标签:

kafka mysql秒杀框架_一次模拟简单秒杀场景的实践 Docker Node.js Kafka Redis MySQL...相关推荐

  1. node.js结合redis+mysql

    mysql大家都知道是什么,数据库,就不怎么简介了,redis当你的服务器访问量比较大的时候或者说想让你的速度访问更快的时候,你就要用到redis进行缓存,好处就是别人请求的都是你缓存的数据,你只需要 ...

  2. node在linux无法连接mysql,无法连接到Node.js上的MySQL数据库

    我仍然无法弄清楚为什么我在尝试连接到Node.js上的MYSQL服务器时仍然收到此错误消息 – 错误 – Error: ER_ACCESS_DENIED_ERROR: Access denied fo ...

  3. node.js + sequelize 操作 MySQL 数据库

    Node.js + Sequelize 操作 MySQL 数据库 一. Sequelize 简介 二. 基本操作 1. 连接数据库 2. 创建一张表 3. 对数据表操作 3.1 插入操作 3.2 读取 ...

  4. mysql 分库 框架_数据库水平分库框架设计

    1水平分库 最近在做一个IM系统,之前的旧系统没有考虑到用户量会增长得这么庞大,导致现在数据库性能瓶颈非常严重,迫切需要分库,用于减少每个库的用户数量,进而分摊负载,最终达到数据库横向扩展的目的. 数 ...

  5. python实现秒杀系统_如何设计一个秒杀系统

    前言 最近在部门内部分享了原来在电商业务做秒杀活动的整体思路,大家对这次分享反馈还不错,所以我就简单整理了一下,分享给大家参考参考. 业务介绍 什么是秒杀?通俗一点讲就是网络商家为促销等目的组织的网上 ...

  6. docker mysql开发环境_跟我一步一步用Docker搭建Beimi游戏服务端开发环境

    跟我一步一步用Docker搭建Beimi游戏服务端开发环境 Stone 摘要 本文为java 0基础的小伙伴介绍如何用Docker搭建开发环境.如果不关心过程直接可 跳到本文最后取代码. 关键步骤为: ...

  7. Node.js系列-----数据库MySQL

    一.数据库MySQL 1.1. 为什么要使用数据库 任何的软件系统都需要存放大量的数据,这些数据通常是非常复杂和庞大的: 比如用户信息包括姓名.年龄.性别.地址.身份证号.出生日期等等: 比如商品信息 ...

  8. node.js中对 mysql 进行增删改查等操作和async,await处理

    要对mysql进行操作,我们需要安装一个mysql的库. 一.安装mysql库 npm install mysql --save 二.对mysql进行简单查询操作 const mysql = requ ...

  9. html js不触发_「万字整理 」这里有一份Node.js入门指南和实践,请注意查收 ??

    前言 什么是 Node.js 呢 ? JS 是脚本语言,脚本语言都需要一个解析器才能运行.对于写在 HTML 页面里的 JS,浏览器充当了解析器的角色.而对于需要独立运行的 JS,NodeJS 就是一 ...

最新文章

  1. 设计模式之外观模式(Facade)摘录
  2. crosstab交叉表_透视图和交叉表
  3. 2020\Simulation_1\2.约数个数
  4. springmvc如何使用视图解析器_SpringMVC工作原理
  5. java ref 应用类型_Java四种引用类型
  6. linux dd 重装系统,发现用dd装系统真是简单快捷通用
  7. c++ cdi+示例_C ++“或”关键字示例
  8. 简单的中文分词加上kmean聚类 (c++)
  9. IntelliJ IDEA功能和惊喜赠品
  10. matlab 求极小值 一维优化,MATLABoptimization
  11. CentOS8-linux安装 tailf命令
  12. 下载Google瓦片地图并在Unity中作为场景底图
  13. linux ubuntu 18.04无法输入中文、安装中文拼音输入法
  14. 12月15日(第12天)
  15. android 快速关闭键盘的方法,安卓永久关闭键盘灯的方法
  16. 海康硬盘录像机无法通过rtsp协议连接到EasyNVR的Web页面如何处理?
  17. 计算机中pdf怎么预览,如何在浏览器中开启PDF时默认显示Adobe Reader XI工具栏
  18. idea同时打胖包和瘦包的方法
  19. 【C语言】C语言操作符的分类及应用【超详细讲解】
  20. Taylor formulation

热门文章

  1. 大学计算机课实验,大学计算机课程实验教学平台的设计与实现
  2. pyecharts与mysql_pyecharts画图总结
  3. Prezi如何输入中文
  4. MBus协议详解(二)
  5. MT4如何使用软件开展自动交易详细步骤
  6. 河南科技学院计算机专业代码,河南科技学院专业代码
  7. 工欲善其事必先利其器之浏览器篇
  8. 数据库——SQL语句与数据库设计
  9. c函数memcpy实现
  10. 全面解读第四代基因测序技术Oxford Nanopore--转载