首页 > 数据库 >使用Redis来处理高并发问题

使用Redis来处理高并发问题

时间:2024-09-09 18:26:33浏览次数:8  
标签:缓存 请求 处理 系统 数据库 Redis 并发 秒杀

设计理念:

限流:鉴于只有少部分用户能够秒杀成功,所以要限制大部分流量,只允许少部分流量进入服务后端。

削峰:对于秒杀系统瞬时会有大量用户涌入,所以在抢购一开始会有很高的瞬间峰值。高峰值流量是压垮系统很重要的原因,所以如何把瞬间的高流量变成一段时间平稳的流量也是设计秒杀系统很重要的思路。实现削峰的常用的方法有利用缓存和消息中间件等技术。

异步处理:秒杀系统是一个高并发系统,采用异步处理模式可以极大地提高系统并发量,其实异步处理就是削峰的一种实现方式。

内存缓存:秒杀系统最大的瓶颈一般都是数据库读写,由于数据库读写属于磁盘IO,性能很低,如果能够把部分数据或业务逻辑转移到内存缓存,效率会有极大地提升。 可拓展:当然如果我们想支持更多用户,更大的并发,最好就将系统设计成弹性可拓展的,如果流量来了,拓展机器就好了。像淘宝、京东等双十一活动时会增加大量机器应对交易高峰。

通用方案:

设计思路

将请求拦截在系统上游,降低下游压力:秒杀系统特点是并发量极大,但实际秒杀成功的请求数量却很少,所以如果不在前端拦截很可能造成数据库读写锁冲突,甚至导致死锁,最终请求超时。

充分利用缓存:利用缓存可极大提高系统读写速度。

消息队列:消息队列可以削峰,将拦截大量并发请求,这也是一个异步处理过程,后台业务根据自己的处理能力,从消息队列中主动的拉取请求消息进行业务处理。

 

前端方案

浏览器端(js): 页面静态化:将活动页面上的所有可以静态的元素全部静态化,并尽量减少动态元素。通过CDN来抗峰值。

禁止重复提交:用户提交之后按钮置灰,禁止重复提交

用户限流:在某一时间段内只允许用户提交一次请求,比如可以采取IP限流

后端方案

服务端控制器层(网关层)
限制uid(UserID)访问频率:我们上面拦截了浏览器访问的请求,但针对某些恶意攻击或其它插件,在服务端控制层需要针对同一个访问uid,限制访问频率。

 

服务层

上面只拦截了一部分访问请求,当秒杀的用户量很大时,即使每个用户只有一个请求,到服务层的请求数量还是很大。比如我们有100W用户同时抢100台手机,服务层并发请求压力至少为100W。

 

采用消息队列缓存请求:既然服务层知道库存只有100台手机,那完全没有必要把100W个请求都传递到数据库啊,那么可以先把这些请求都写到消息队列缓存一下,数据库层订阅消息减库存,减库存成功的请求返回秒杀成功,失败的返回秒杀结束。

 

利用缓存应对读请求:对类似于12306等购票业务,是典型的读多写少业务,大部分请求是查询请求,所以可以利用缓存分担数据库压力。

 

利用缓存应对写请求:缓存也是可以应对写请求的,比如我们就可以把数据库中的库存数据转移到Redis缓存中,所有减库存操作都在Redis中进行,然后再通过后台进程把Redis中的用户秒杀请求同步到数据库中。

 

 

数据库层

 

数据库层是最脆弱的一层,一般在应用设计时在上游就需要把请求拦截掉,数据库层只承担“能力范围内”的访问请求。所以,上面通过在服务层引入队列和缓存,让最底层的数据库高枕无忧。

Redis是一个分布式缓存系统,支持多种数据结构,我们可以利用Redis轻松实现一个强大的秒杀系统。

 

我们可以采用Redis 最简单的key-value数据结构,用一个原子类型的变量值(AtomicInteger)作为key,把用户id作为value,库存数量便是原子变量的最大值。对于每个用户的秒杀,我们使用 RPUSH key value插入秒杀请求, 当插入的秒杀请求数达到上限时,停止所有后续插入。

 

然后我们可以在台启动多个工作线程,使用 LPOP key 读取秒杀成功者的用户id,然后再操作数据库做最终的下订单减库存操作。

 

当然,上面Redis也可以替换成消息中间件如ActiveMQ、RabbitMQ等,也可以将缓存和消息中间件 组合起来,缓存系统负责接收记录用户请求,消息中间件负责将缓存中的请求同步到数据库。

 

总结:

架构设计

秒杀系统,是典型的短时大量突发访问类问题。对这类问题,有三种优化性能的思路:

写入内存而不是写入硬盘

异步处理而不是同步处理

分布式处理

用上这三招,不论秒杀时负载多大,都能轻松应对。更好的是,Redis能够满足上述三点。因此,用Redis就能轻松实现秒杀系统。

下面介绍一下为什么上述三种性能优化思路能够解决秒杀系统的性能问题:

写入内存而不是写入硬盘

传统硬盘的读写性能是相当差的。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 

1. 插入秒杀请求 当插入的秒杀请求数达到上限时,停止所有后续插入。

后台启动多个工作线程,使用

LPOP key 

1. 读取秒杀成功者的用户id,进行后续处理。

或者使用​​LRANGE key start end​​命令读取秒杀成功者的用户id,

进行后续处理。 每完成一条秒杀记录的处理,就执行INCR key_num。一旦所有库存处理完毕,就结束该商品的本次秒杀,关闭工作线程,也不再接收秒杀请求。

 

标签:缓存,请求,处理,系统,数据库,Redis,并发,秒杀
From: https://www.cnblogs.com/peteremperor/p/18405059

相关文章

  • Java并发编程15
    1、创建线程的有哪些方式继承Thread类创建线程类通过Runnable接口创建线程类通过Callable和Future创建线程通过线程池创建2、创建线程的三种方式的对比1、采用实现Runnable、Callable接口的方式创建多线程。**优势是:**线程类只是实现了Runnable接口或Calla......
  • 《黑神话:悟空》游戏启动时崩溃弹窗“找不到amdvlk64.dll”该怎么办?黑神话悟空游戏闪退
    当《黑神话:悟空》启动时崩溃弹窗提示“找不到amdvlk64.dll”,可以考虑重新安装游戏以找回该文件。也可从可靠来源下载amdvlk64.dll,放置到游戏安装目录下,尝试解决问题让游戏正常启动。本篇将为大家带来《黑神话:悟空》游戏启动时崩溃弹窗“找不到amdvlk64.dll”该怎么办的内容,感兴......
  • EaseUS Video Editor Pro v2激活版下载及详细安装教程 (视频编辑处理)
    安装步骤EaseUSVideoEditor:https://pan.xunlei.com/s/VO6LAsTOYj2vtXprMQ-DMKGZA1?pwd=v2zv#1、点击运行安装2、选择安装路径,将C改成D,建议别安装在C盘,后面两个步骤选择默认即可3、选择取消客户体验改善计划4、安装中...5、安装完成后取消勾选6、返回我们解压的文件,访......
  • SQL SERVER -- JSON处理
    --JSON 字符串转 行记录Declare@JsonStrNvarchar(Max)='[{"State":0,"Name":"语文","ReMark":"了解国学信息","RepDtl":[{"ID":1,"Age":11},{"ID":2,"Age":12},{"ID&quo......
  • FastAPI 深度指南:使用依赖注入处理分页和过滤逻辑
    在FastAPI框架中,Depends是一个关键的功能,它允许开发者通过依赖注入来管理和重用代码。这在处理API的分页和过滤逻辑时尤其有用,因为它可以将这些逻辑抽象化,从而减少冗余代码并提高效率。通过Depends,我们可以定义一个函数,该函数负责获取和验证分页参数(如skip和limit)以及过滤参数(如基......
  • 优雅处理封装返回
    前言大家写代码可能会使用try...catch处理异常,当然springmvc架构中各层会出现大量的try{...}catch{...}finally{...}代码块,不仅有大量的冗余代码,而且还影响代码的可读性。下面推荐大家这样处理,既方便代码也显得更加规范优雅,真的香的不行。推荐理由:代码复制到项目中通过简单......
  • 使用java对栅格数据的处理,对栅格文件进行导入导出
    需求背景:对栅格文件进行导入导出(使用代码的方式,非命令方式);当然也可以使用代码和GDAL的方式进行,但是GDAL配置部署不便捷,故选用GeoTools方式来实现。ps:若是使用命令方式,首先打开PostgreSQL的安装目录【\PostgreSQL\14\bin】,然后使用如下命令即可实现把栅格文件导入到数据库中......
  • PHP错误处理全攻略:掌握函数中的错误处理机制,提升代码健壮性,php显示错误报告方式
    在开发过程中,PHP错误处理是一个非常关键的环节。错误处理不仅关系到程序的稳定性,还直接影响到用户的使用体验。如果代码中存在未处理的错误,轻则导致功能异常,重则可能引发系统崩溃。本文将为大家详细介绍PHP中的错误处理机制,帮助你掌握相关技巧,从而提升代码的健壮性。我们需要了解......
  • redis 常用数据类型和常用命令
    一、数据类型在Redis中命令不区分大小写,但key是区分大小写的,帮助命令如下:helpcommandhelp@group解释:group是指数据类型,比如string、hash,这样就会把关于字符串或者是hash数据类型的所有命令列出来redis有十大数据类型,本文介绍常用的六种。1.1、string在一个字符串中存储......
  • 1 件全新6ES7314-6EH04-0AB0 6ES73146EH040AB0 中央处理单元
    6ES7314-6EH04-0AB06ES73146EH040AB0中央处理单元6ES7314-6EH04-0AB06ES73146EH040AB0中央处理单元6ES7314-6EH04-0AB06ES73146EH040AB0中央处理单元6ES7314-6EH04-0AB06ES73146EH040AB0中央处理单元引脚线6ES7314-6EH04-0AB06ES73146EH040AB0中央处理单元说明书......