当前位置: 首页 > 科技观察

如何模拟阿里巴巴双11闪购场景的实现?程序员必看的

时间:2023-03-17 01:30:27 科技观察

秒杀活动在网络上随处可见,从12306抢票到聚划算抢购,我们生活的方方面面都可以看到秒杀的身影。秒杀的架构设计也是对一个架构师架构设计能力的考验。本文的目的不是提供一个可以直接实现的设计方案,而是提供一个简单的方法,一个思路,让大家对秒杀背后的一些设计有一个更感性的认识,并可以自己动手实践.所有配置和源代码都可以在本文末尾的GitHub存储库中找到。首先简单介绍下本文涉及的一些组件,如下图所示:JMeter:在秒杀活动中使用JMeter模拟大量并发用户请求秒杀服务:基于Nodejs使用Express实现的秒杀服务,图2、3、4中的步骤是在这个服务中处理的Redis:一个Redisdocker容器,里面存储了一个名为counter的数据,表示当前剩余库存大小Kafka:一个Kafkadocker容器,其实还有一个Zookeeper的docker容器,Kafka使用zookeeper存储一些元数据,程序中没有涉及到,所以不单独列出。秒杀服务更新Redis后,会向Kafka发送消息,表示秒杀成功秒杀KafkaConsumer:基于Nodejs的Kafka消费者会从Kafka获取秒杀成功的消息,处理并存储到MySQLMySQL中:一个MySQL中docker容器,最终成功的秒杀请求会对应数据库表中的一条记录环境搭建1.安装JMeter从官网下载一个JMeter二进制包,在bin目录下执行jmeter启动,新建一个命名为启动后如下图设置为秒杀的ThreadGroup,设置为5s内发起2000个并发请求。在这个ThreadGroup下新建一个HttpRequestSampler,命名为Seckill。如下图配置主机名、端口号、http请求方式和请求路径2。安装Redis、Kafka、Zookeeper和MySQL,方便搭建环境。这些组件将作为docker容器启动。在此之前,需要先到Docker官网下载安装DockerEngine、DockerMachine和DockerCompose。如果是Windows或者Mac,Docker官网提供了DockerForWindows/DockerForMac安装程序,可以轻松安装这三个组件。3、编写DockerCompose文件,创建Seckill项目文件夹,新建docker-compose.yml文件,内容如下:配置文件中一共配置了4个服务,对应4个docker容器,分别是zookeeper、kafka,redis和mysql。这里有两个地方需要设置成你实际环境的值。一种是kafka配置下的KAFKA_ADVERTISED_HOST_NAME字段,需要设置为本机IP。另一个是MYSQL配置下的MYSQL_ROOT_PASSWORD,你可以设置成任何你想要的值。创建这个文件后,可以在命令行项目的根目录下执行docker-composeup,docker引擎会启动上面配置的所有四个组件。注意:启动后,需要在Kafka容器中创建一个名为CAR_NUMBER的topic,在Redis容器中创建一个名为counter的计数器(设置值为100,即库存初始值为100),并在创建MySQL容器一个名为seckill的数据表(包含一个自增id段和时间戳格式的日期字段)。代码片段1、秒杀服务第1-8行介绍了程序需要的对象。nodejsmvc框架express,redis,kafka等第10行使用express提供的方法暴露了一个POST方法,路径为/seckill第12行定义了一个方法。第54行调用第13-22行,创建新的redis客户端,监听错误事件。第23行非常关键。它的作用是让rediscilent监控redis。counter值,之后会启动一个事务,如果其他客户端在事务提交时修改了counter值,则事务将被放弃。第24行,通过redis客户端的异步方法获取计数器值。因为redis的get操作是原子的,所以这里不用担心读写并发的问题。第25-28行,判断返回的库存值是否大于0,如果大于0,则通过client.multi()启动事务,通过decr()方法将计数器值减1,最后通过提交事务exec()方法;如果小于0,则执行第47行,打印soldout并关闭redis客户端。第29-46行,这里我们看multi.exec()中的回调方法。我们之前使用watch来监控计数器。如果其他客户端在事务提交过程中修改了counter的值,回调方法中的replies参数就会为null,可以看到第29-31行,程序会打印“Theremaybeconflicts”并再次调用fn方法尝试再次。如果replies的值不为null,将使用kafka的producer向CAR_NUMBER主题发送消息。2、这里的seckill_kafka_consumer的代码比较简单。它会初始化一个kafkaconsumer来监听CAR_NUMBER主题,并在MySQL秒杀表中为新获取的消息插入一条记录。操作步骤启动docker容器启动Seckill_Service启动seckill_kafka_consumer启动JMeter发送2000个并发请求结果JMeter请求结果Redis计数器字段MySQL秒杀表可以看到redis中的计数器最后变为0,将100条记录插入到秒杀数据表中而不用任何超卖或少卖。当然,在实际的生产环境场景中,需要考虑的还有很多。希望本文能起到一个催化剂的作用,帮助大家更好的理解秒杀场景。