阿里云Redis读写分离典型场景:如何轻松搭建电商秒杀系统

秒杀活动是绝大部分电商选择的低价促销,推广品牌的方式。不仅可以给平台带来用户量,还可以提高平台知名度。一个好的秒杀系统,可以提高平台系统的稳定性和公平性,获得更好的用户体验,提升平台的口碑,从而提升秒杀活动的最大价值。

本次主要讨论阿里云云数据库Redis缓存设计高并发的秒杀系统。

秒杀的特征

秒杀活动对稀缺或者特价的商品进行定时,定量售卖,吸引成大量的消费者进行抢购,但又只有少部分消费者可以下单成功。因此,秒杀活动将在较短时间内产生比平时大数十倍,上百倍的页面访问流量和下单请求流量。

秒杀活动可以分为3个阶段:

  • 秒杀前:用户不断刷新商品详情页,页面请求达到瞬时峰值。

  • 秒杀开始:用户点击秒杀按钮,下单请求达到瞬时峰值。

  • 秒杀后:一部分成功下单的用户不断刷新订单或者产生退单操作,大部分用户继续刷新商品详情页等待退单机会。

消费者提交订单,一般做法是利用数据库的行级锁。只有抢到锁的请求可以进行库存查询和下单操作。但是在高并发的情况下,数据库无法承担如此大的请求,往往会使整个服务blocked,在消费者看来就是服务器宕机。

秒杀系统

系统架构图

阿里云Redis读写分离典型场景:如何轻松搭建电商秒杀系统

秒杀系统的流量虽然很高,但是实际有效流量是十分有限的。利用系统的层次结构,在每个阶段提前校验,拦截无效流量,可以减少大量无效的流量涌入数据库。

利用浏览器缓存和CDN抗压静态页面流量

秒杀前,用户不断刷新商品详情页,造成大量的页面请求。所以,我们需要把秒杀商品详情页与普通的商品详情页分开。对于秒杀商品详情页尽量将能静态化的元素尽量静态化处理,除了秒杀按钮需要服务端进行动态判断,其他的静态数据可以缓存在浏览器和CDN上。这样,秒杀前刷新页面导致的流量进入服务段的流量只有很小的一部分

利用阿里云读写分离Redis缓存拦截流量

CDN是第一级流量拦截,第二级流量拦截我们使用支持读写分离的阿里云Redis。在这一阶段我们主要读取数据,读写分离Redis能支持高大60万以上qps的,完全可以支持需求。

首先通过数据控制模块,提前将秒杀商品的缓存到阿里云读写分离Redis,并设置秒杀开始标记:

"goodsId_count": 100 //总数"goodsId_start": 0 //开始标记"goodsId_access": 0 //接受下单数

秒杀开始前,服务集群读取goodsId_Start为0,直接返回未开始。

数据控制模块将goodsId_start改为1,标志秒杀开始。

服务集群缓存开始标记位并开始接受请求,并记录到redis中goodsId_access,商品剩余数量为(goodsId_count - goodsId_access)。

当接受下单数达到goodsId_count后,继续拦截所有请求,商品剩余数量为0

可以看出,最后成功参与下单的请求只有少部分可以被接受。在高并发的情况下,允许稍微多的流量进入。因此可以控制接受下单数的比例。

利用阿里云主从版Redis缓存加速库存扣量

成功参与下单,进入下层服务,开始进行订单信息校验,库存扣量。为了避免直接访问数据库,我们使用阿里云主从版Redis来进行库存扣量,阿里云主从版Redis提供10万级别的QPS。我们使用Redis来优化库存查询,提前拦截秒杀失败的请求,将大大提高系统的整体吞吐量。我们也是通过数据控制模块提前将库存存入Redis:

//我们将每个秒杀商品在redis中用一个hash结构表示

"goodsId" : { "Total": 100 "Booked": 100}

扣量时,服务器通过请求Redis获取下单资格,我们通过lua脚本实现,由于Redis时单线程模型,lua可以保证多个命令的原子性:

lua脚本:

local n = tonumber(ARGV[1])if not n or n == 0 then return 0 end local vals = redis.call("HMGET", KEYS[1], "Total", "Booked");local total = tonumber(vals[1])local blocked = tonumber(vals[2])if not total or not blocked then return 0 end if blocked + n <= total then redis.call("HINCRBY", KEYS[1], "Booked", n) return n; end return 0

先使用SCRIPT LOAD将lua脚本提前缓存在Redis,然后调用EVALSHA调用脚本,比直接调用EVAL节省网络带宽:

redis 127.0.0.1:6379>SCRIPT LOAD "lua code""438dd755f3fe0d32771753eb57f075b18fed7716" redis 127.0.0.1:6379>EVAL 438dd755f3fe0d32771753eb57f075b18fed7716 1 goodsId 1

秒杀服务通过判断Redis是否返回抢购个数n,即可知道此次请求是否扣量成功。

使用阿里云主从版Redis实现简单的消息队列异步下单入库

扣量完成后,需要进行订单入库。如果商品数量较少的时候,直接操作数据库即可。如果秒杀的商品是1万,甚至10万级别,那数据库锁冲突将带来很大的性能瓶颈。因此,利用消息队列组件,当秒杀服务将订单信息写入消息队列后,即可认为下单完成,避免直接操作数据库。

消息队列组件依然可以使用Redis实现,在R2中用list数据结构表示:

orderList { [0] = {订单内容} [1] = {订单内容} [2] = {订单内容} ...}

将订单内容写入Redis:

LPUSH orderList {订单内容}

异步下单模块从Redis中顺序获取订单信息,并将订单写入数据库:

BRPOP orderList 0

我们通过使用Redis作为消息队列,异步处理订单入库,有效的提高了用户的下单完成速度。

数据控制模块,管理秒杀数据同步

最开始,我们利用阿里云读写分离Redis进行流量限制,只让部分流量进入下单。对于下单检验失败和退单等情况,我们需要让更多的流量进来。因此,数据控制模块需要定时将数据库中的数据进行一定的计算,同步到主从版Redis,同时再同步到读写分离的Redis,让更多的流量进来。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/473613.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用for语句打印图形

public class Print { public static void main(String[] args) { int num11; //打印上半部分 for(int i0;i { for(int jnum;j>i1;j--) { System.out.print(" "); //打印空格 } for(int j0;j<i;j) { System.out.print("* "); } System.out.println()…

ClickHouse表引擎之Integration系列

​ Integration系统表引擎主要用于将外部数据导入到ClickHouse中&#xff0c;或者在ClickHouse中直接操作外部数据源。 1 Kafka 1.1 Kafka引擎 ​ 将Kafka Topic中的数据直接导入到ClickHouse。 ​ 语法如下&#xff1a; CREATE TABLE [IF NOT EXISTS] [db.]table_name [O…

LeetCode 756. 金字塔转换矩阵(回溯)

文章目录1. 题目2. 解题1. 题目 现在&#xff0c;我们用一些方块来堆砌一个金字塔。 每个方块用仅包含一个字母的字符串表示。 使用三元组表示金字塔的堆砌规则如下&#xff1a; 对于三元组(A, B, C) &#xff0c;“C”为顶层方块&#xff0c;方块“A”、“B”分别作为方块“…

Flask框架项目实例:**租房网站(一)

Flask是一款MVC框架&#xff0c;主要是从模型、视图、模板三个方面对Flask框架有一个全面的认识&#xff0c;通过完成作者-读书功能&#xff0c;先来熟悉Flask框架的完整使用步骤。 操作步骤为&#xff1a; 1.创建项目2.配置数据库3.定义模型类4.定义视图并配置URL 5.定义模板…

mysql中datetime比较大小问题 (转的)

方法一&#xff1a; 你也可以&#xff1a;select * from t1 where unix_timestamp(time1) > unix_timestamp(2011-03-03 17:39:05) and unix_timestamp(time1) < unix_timestamp(2011-03-03 17:39:52);就是用unix_timestamp函数&#xff0c;将字符型的时间&#xff0c;转…

ClickHouse常见问题及其解决方案

1 概述 在对ClickHouse进行分布表复制表zookeeper保证高可用的情况下进行性能测试时遇到如下坑&#xff0c;进行整理 2 分布表join问题Unknown identifier: LO_CUSTKEY, context:… 1.1 问题描述 SQL如下&#xff1a; SELECT count(1) FROM performance.line_all AS c LEFT…

Python中单引号,双引号,3个单引号及3个双引号的区别

单引号和双引号 在Python中我们都知道单引号和双引号都可以用来表示一个字符串&#xff0c;比如 [python] view plaincopy str1 python str2 "python" str1和str2是没有任何区别的。我们知道Python以其易用性而著名&#xff0c;所以刚开始看教程学习看到单引号…

LeetCode 316. 去除重复字母 / 1081. 不同字符的最小子序列(单调栈)

文章目录1. 题目2. 解题1. 题目 LC 316&#xff1a; 给你一个字符串 s &#xff0c;请你去除字符串中重复的字母&#xff0c;使得每个字母只出现一次。需保证 返回结果的字典序最小&#xff08;要求不能打乱其他字符的相对位置&#xff09;。 示例 1&#xff1a; 输入&#…

VSS 请求程序和 SharePoint 2013

Windows Server 中的 VSS 可用于创建可备份和还原 Microsoft SharePoint Foundation 的应用程序。VSS 提供了一个基础结构&#xff0c;使第三方存储管理程序、业务程序&#xff0c;以及硬件提供程序进行合作&#xff0c;以创建和管理卷影副本。基于此基础结构的解决方案可以使用…

Confluent介绍及其使用

1 confluent介绍 Confluent是用来管理和组织不同数据源的流媒体平台&#xff0c;可以实时地把不同源和位置的数据集成到一个中心的事件流平台。并且很可靠、性能很高。 Confluent目前提供了社区版&#xff08;免费&#xff09;和商业版&#xff08;收费&#xff09;两个版本&…

如何使用 Pylint 来规范 Python 代码风格

Pylint 是什么 Pylint 是一个 Python 代码分析工具&#xff0c;它分析 Python 代码中的错误&#xff0c;查找不符合代码风格标准&#xff08;Pylint 默认使用的代码风格是 PEP 8&#xff0c;具体信息&#xff0c;请参阅参考资料&#xff09;和有潜在问题的代码。目前 Pylint 的…

LeetCode 809. 情感丰富的文字

文章目录1. 题目2. 解题1. 题目 有时候人们会用重复写一些字母来表示额外的感受&#xff0c;比如 "hello" -> "heeellooo", "hi" -> "hiii"。 我们将相邻字母都相同的一串字符定义为相同字母组&#xff0c;例如&#xff1a;&qu…

confluent connect写出到ES及ClickHouse

1 连接Elasticsearch测试 1.1 启动confluent /home/kafka/.local/confluent/bin/confluent start This CLI is intended for development only, not for production https://docs.confluent.io/current/cli/index.htmlUsing CONFLUENT_CURRENT: /tmp/confluent.swpIapNw Sta…

tomcat内存溢出问题解决思路

1、修改启动时内存参数、并指定JVM时区 &#xff08;在windows server 2008 下时间少了8个小时&#xff09;在Tomcat上运行j2ee项目代码时&#xff0c;经常会出现内存溢出的情况&#xff0c;解决办法是在系统参数中增加系统参数&#xff1a; window下&#xff0c; 在catalina.b…

网站部署nginx--uwsgi

网站代码写完之后就是项目部署&#xff0c;主要包括两个方面&#xff1a; 1.nginx安装与配置&#xff1a; 1、Nginx 安装 系统平台&#xff1a;CentOS release 6.6 (Final) 64位。 一、安装编译工具及库文件 yum -y install make zlib zlib-devel gcc-c libtool openssl open…

天池 在线编程 滑动数独(滑动窗口)

文章目录1. 题目2. 解题1. 题目 描述 给定一个 3xn的矩阵 number&#xff0c;并且该矩阵只含有1到9的正整数。 考虑有一个大小为 3x3 滑动窗口&#xff0c;从左到右遍历该矩阵 number&#xff0c; 那么该滑动窗口在遍历整个矩阵的过程中会有n-2个。 现在你的任务是找出这些滑…

TIGK监控平台介绍

1 概述 众所周知监控平台对大数据平台是非常重要的&#xff0c;监控是故障诊断和分析的重要辅助利器&#xff0c;在发生事故之前就能预警&#xff0c;最大限度降低系统故障率。   监控系统我们可以分为业务层面&#xff0c;应用层面&#xff0c;系统层面 1.1 业务层面 业务系…

有意思的网站

谱聚类 http://blog.pluskid.org/?p287 Qt Graphics View 框架 http://yleesun.blog.163.com/blog/static/2941340220096110165817/ 谷歌编码规范 http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml 匈牙利命名法 http://blog.csdn.net/buglu/article/details/…

天池 在线编程 队列检查(排序)

文章目录1. 题目2. 解题1. 题目 描述 班上的学生根据他们的年级照片的身高升序排列&#xff0c;确定当前未站在正确位置的学生人数 数组长度 < 10^5示例 输入: heights [1,1,3,3,4,1]输出: 3解释: 经过排序后 heights变成了[1,1,1,3,3,4]&#xff0c;有三个学生不在应在…

celery异步执行任务在Django中的应用实例

1. 创建django项目celery_demo, 创建应用demo: django-admin startproject celery_demo python manage.py startapp demo2.在celery_demo模块中创建celery.py模块, 文件目录为: celery.py模块内容为: from celery import Celery from django.conf import settings import os#…