文档章节

高并发接口设计思路

momisabuilder
 momisabuilder
发布于 2018/12/25 14:26
字数 1639
阅读 6057
收藏 206
  • 并发队列的选择

Java的并发包提供了三个常用的并发队列实现,分别是:ArrayBlockingQueue、ConcurrentLinkedQueue 和 LinkedBlockingQueue  。

ArrayBlockingQueue是**初始容量固定**的阻塞队列,我们可以用来作为数据库模块成功竞拍的队列,比如有10个商品,那么我们就设定一个10大小的数组队列。

ConcurrentLinkedQueue使用的是CAS原语无锁队列实现,是一个异步队列入队的速度很快,出队进行了加锁,性能稍慢。

LinkedBlockingQueue也是阻塞的队列,入队和出队都用了加锁,当队空的时候线程会暂时阻塞。

在请求预处理阶段,由于我们的系统入队需求要远大于出队需求,一般不会出现队空的情况,所以我们可以选择ConcurrentLinkedQueue来作为我们的请求队列实现

1. 请求接口的合理设计

一个秒杀或者抢购页面,通常分为2个部分,一个是静态的HTML等内容,另一个就是参与秒杀的Web后台请求接口。

通常静态HTML等内容,是通过CDN的部署,一般压力不大,核心瓶颈实际上在后台请求接口上。这个后端接口,必须能够支持高并发请求,同时,非常重要的一点,必须尽可能“快”,在最短的时间里返回用户的请求结果。为了实现尽可能快这一点,接口的后端存储使用内存级别的操作会更好一点。仍然直接面向MySQL之类的存储是不合适的,如果有这种复杂业务的需求,都建议采用异步写入。

当然,也有一些秒杀和抢购采用“滞后反馈”,就是说秒杀当下不知道结果,一段时间后才可以从页面中看到用户是否秒杀成功。但是,这种属于“偷懒”行为,同时给用户的体验也不好,容易被用户认为是“暗箱操作”。

高并发下的数据安全

我们知道在多线程写入同一个文件的时候,会存现“线程安全”的问题(多个线程同时运行同一段代码,如果每次运行结果和单线程运行的结果是一样的,结果和预期相同,就是线程安全的)。如果是MySQL数据库,可以使用它自带的锁机制很好的解决问题,但是,在大规模并发的场景中,是不推荐使用MySQL的。秒杀和抢购的场景中,还有另外一个问题,就是“超发”,如果在这方面控制不慎,会产生发送过多的情况。我们也曾经听说过,某些电商搞抢购活动,买家成功拍下后,商家却不承认订单有效,拒绝发货。这里的问题,也许并不一定是商家奸诈,而是系统技术层面存在超发风险导致的。

1. 超发的原因

假设某个抢购场景中,我们一共只有100个商品,在最后一刻,我们已经消耗了99个商品,仅剩最后一个。这个时候,系统发来多个并发请求,这批请求读取到的商品余量都是99个,然后都通过了这一个余量判断,最终导致超发。(同文章前面说的场景)

在上面的这个图中,就导致了并发用户B也“抢购成功”,多让一个人获得了商品。这种场景,在高并发的情况下非常容易出现。

2. 悲观锁思路

解决线程安全的思路很多,可以从“悲观锁”的方向开始讨论。

悲观锁,也就是在修改数据的时候,采用锁定状态,排斥外部请求的修改。遇到加锁的状态,就必须等待。

虽然上述的方案的确解决了线程安全的问题,但是,别忘记,我们的场景是“高并发”。也就是说,会很多这样的修改请求,每个请求都需要等待“锁”,某些线程可能永远都没有机会抢到这个“锁”,这种请求就会死在那里。同时,这种请求会很多,瞬间增大系统的平均响应时间,结果是可用连接数被耗尽,系统陷入异常。

3. FIFO队列思路

那好,那么我们稍微修改一下上面的场景,我们直接将请求放入队列中的,采用FIFO(First Input First Output,先进先出),这样的话,我们就不会导致某些请求永远获取不到锁。看到这里,是不是有点强行将多线程变成单线程的感觉哈。

然后,我们现在解决了锁的问题,全部请求采用“先进先出”的队列方式来处理。那么新的问题来了,高并发的场景下,因为请求很多,很可能一瞬间将队列内存“撑爆”,然后系统又陷入到了异常状态。或者设计一个极大的内存队列,也是一种方案,但是,系统处理完一个队列内请求的速度根本无法和疯狂涌入队列中的数目相比。也就是说,队列内的请求会越积累越多,最终Web系统平均响应时候还是会大幅下降,系统还是陷入异常。

4. 乐观锁思路

这个时候,我们就可以讨论一下“乐观锁”的思路了。乐观锁,是相对于“悲观锁”采用更为宽松的加锁机制,大都是采用带版本号(Version)更新。实现就是,这个数据所有请求都有资格去修改,但会获得一个该数据的版本号,只有版本号符合的才能更新成功,其他的返回抢购失败。这样的话,我们就不需要考虑队列的问题,不过,它会增大CPU的计算开销。但是,综合来说,这是一个比较好的解决方案。

有很多软件和服务都“乐观锁”功能的支持,例如Redis中的watch就是其中之一。通过这个实现,我们保证了数据的安全。

本文转载自:https://my.oschina.net/momisabuilder/blog/write/2992962

共有 人打赏支持
momisabuilder

momisabuilder

粉丝 14
博文 66
码字总数 31440
作品 0
西安
程序员
私信 提问
加载中

评论(21)

培风图南

引用来自“名称终被备注代替”的评论

呵呵,乐观锁是真乐观。分分钟被举报暗箱操作,内幕,为什么我比别人早的下单没成功他成功了?这种抢购啊,其实最好的方案还是雷总耍猴的定时到了直接显示余量=0售罄,只是代码啊要注意下别被人拔出来举报了。
雷军一到店,所有的人便都看着他笑,有的叫道,“雷总,听说你要出新手机了!”雷军不回答,对柜台说,“把这个月的业绩报告拿出来给我看看。”。他们又故意的高声嚷道,“你一定又耍猴了!”雷军睁大眼睛说,“你怎么这样凭空污人清白……”“什么清白?新闻都报道了在英国卖手机被抓到在网站后台做手脚!”雷军便涨红了脸,额上的青筋条条绽出,争辩道,“抢购不能叫耍,,,抢购,你们自己要来抢的事,能算耍吗。”接连便是难懂的话,什么“国产良心”,什么“黑科技”之类,引得众人都哄笑起来,店内外充满了快活的空气。
9
92年的java
http://www.jujingyun.com 北京网站建设
http://www.shjuntang.com 上海装潢
javaxiaoz
javaxiaoz
没啦?
名称终被备注代替
名称终被备注代替

引用来自“名称终被备注代替”的评论

呵呵,乐观锁是真乐观。分分钟被举报暗箱操作,内幕,为什么我比别人早的下单没成功他成功了?这种抢购啊,其实最好的方案还是雷总耍猴的定时到了直接显示余量=0售罄,只是代码啊要注意下别被人拔出来举报了。
对应雷总耍猴被抓这种啊,太低级的失误了,后端耍猴就行了,前端还是发请求,后端直接返回失败,这样就抓不到了么。为了偷懒,被抓了吧。
名称终被备注代替
名称终被备注代替
呵呵,乐观锁是真乐观。分分钟被举报暗箱操作,内幕,为什么我比别人早的下单没成功他成功了?这种抢购啊,其实最好的方案还是雷总耍猴的定时到了直接显示余量=0售罄,只是代码啊要注意下别被人拔出来举报了。
momisabuilder
momisabuilder

引用来自“momisabuilder”的评论

作者澄清,不是原创,复制而来,作者澄清,不是原创,复制而来,作者澄清,不是原创,复制而来,

引用来自“酸奶瓶盖儿”的评论

可以重新编辑一下,把原创标签去掉。
已修改,我非常尊重别人的成果😃
momisabuilder
momisabuilder

引用来自“momisabuilder”的评论

作者澄清,不是原创,复制而来,作者澄清,不是原创,复制而来,作者澄清,不是原创,复制而来,

引用来自“慢慢成长”的评论

你可以编辑文章,在文章开头明确标识啊
已修改,我非常尊重别人的成果😃
酸奶瓶盖儿
酸奶瓶盖儿

引用来自“momisabuilder”的评论

作者澄清,不是原创,复制而来,作者澄清,不是原创,复制而来,作者澄清,不是原创,复制而来,
可以重新编辑一下,把原创标签去掉。
酸奶瓶盖儿
酸奶瓶盖儿

引用来自“_永无止境”的评论

不敢苟同,这种高并发的情况用乐观锁不是同一时间段大量返回失败?然后后面一波的可能还能抢到
从使用体验来说,小米貌似就是用的乐观锁,这种方案,并没有什么不妥。谁规定抢购业务只有前面进入的用户才有资格抢购,后面的就不能抢购?所谓的前端限制请求量只是在技术上做了妥协而已。
momisabuilder
momisabuilder

引用来自“开源中国首席技术官”的评论

既然都声明了非原创,那还打上原创标签干嘛。。
绝对不是故意的,那我删了吧,重新来一次。
高并发业务接口开发思路(实战)

高并发业务除了需要有支撑高并发的服务器架构,还需要根据业务需求和架构体系。 . 设计出合理的开发方案,这里根据一个实践过业务场景分析开发思路,罗列出高并发接口需要注意的点,以及设计...

SFLYQ
2017/06/13
0
0
电商那些年,我摸爬打滚出的高并发架构实战精髓(续)

大型网站要很好地支撑高并发,需要长期的规划设计。在初期,需要把系统进行分层,在发展过程中把核心业务进行拆分成模块单元,根据需求进行分布式部署,可以进行独立团队维护开发。 分层: ...

YYQ
2017/03/27
0
0
架构师必备技能之Netty 高并发 UTS 项目实战

一、Netty Netty是由JBOSS提供的一个java开源框架。Netty提供异步的、事件驱动的网络应用程序框架和工具,用以快速开发高性能、高可靠性的网络服务器和客户端程序。 也就是说,Netty 是一个基...

A尚学堂Nancy老师
2018/08/27
0
0
《实战Java高并发程序设计》问答录,看这些问题解决你所有java并行难题

为大家解答关于 Java 的并行程序设计基础、思路、方法和实战 方面的问题。如: 现在的服务器 CPU 可能多达 10 个以上的内核,并发编程市场需求量激增,如何才能将多核 CPU 的性能发挥到极致呢...

吴小编
2016/01/22
308
0
如此牛逼?双11背后的秘密-支付宝app双11最佳实践

近来,FF项目的运营活动越来越多,对于架构设计以及程序研发有了更高的要求,参考国内互联网公司对于营销活动app的设计思路,我们找到了最具有代表性的支付宝双11活动,阐述运营活动类高并发...

丁小晶
2016/04/20
0
0

没有更多内容

加载失败,请刷新页面

加载更多

SQL语句查询

1.1 排序 通过order by语句,可以将查询出的结果进行排序。放置在select语句的最后。 格式: SELECT * FROM 表名 ORDER BY 排序字段ASC|DESC; ASC 升序 (默认) DESC 降序 1.查询所有商品信息,...

stars永恒
37分钟前
2
0
IntelliJ IDEA 第一个 Scala 程序

IntelliJ 安装完成 Scala 插件后,你需要尝试使用 IntelliJ 来创建并且运行第一个程序。 通常这个程序只是简单的输出 Hello World。 创建一个新工程 在文件下面选择新建,然后选择创建工程。...

honeymose
41分钟前
2
0
mysql分表,分区的区别和联系

一,什么是mysql分表,分区 什么是分表,从表面意思上看呢,就是把一张表分成N多个小表,具体请看mysql分表的3种方法 什么是分区,分区呢就是把一张表的数据分成N多个区块,这些区块可以在同...

吴伟祥
44分钟前
1
0
csapp 习题 - 如何实现异或 exclusive-or

阅读 csapp v3 时,练习题 2.13 很有意思。练习题描述如下。 位设置是对于参数 mask 中每一个为 1 的位,那么参数 x 中相应位则被设置为 1 ;位清除是对于参数 mask 中每一个为 1 的位,那么...

ylme
昨天
5
0
Amino——产品迭代

兴趣部落产品迭代 时间 版本号 更新内容 备注 2019年1月2日 v3.1.1 支持定制部落首页的内容tab,酋长可以将精华、相册、分类添加到部落首页啦。 支持申请酋长,酋长可以直接推送优质话题,快...

铸剑为犁413
昨天
3
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部