乐趣区

Java 高并发环境下的性能优化,揭秘支付宝技术内幕

前言
高并发经常会发生在有大活跃用户量,用户高聚集的业务场景中,如:秒杀活动,定时领取红包等。
为了让业务可以流畅的运行并且给用户一个好的交互体验,我们需要根据业务场景预估达到的并发量等因素,来设计适合自己业务场景的高并发处理方案。
在电商相关产品开发的这些年,我有幸的遇到了并发下的各种坑,这一路摸爬滚打过来有着不少的血泪史,这里进行的总结,作为自己的归档记录,同时分享给大家。
Java 高并发环境下的性能优化(附高并发视频资料和面试题等),揭秘支付宝技术内幕 私信。
服务器架构

业务从发展的初期到逐渐成熟,服务器架构也是从相对单一到集群,再到分布式服务。
一个可以支持高并发的服务少不了好的服务器架构,需要有均衡负载,数据库需要主从集群,nosql 缓存需要主从集群,静态文件需要上传 cdn,这些都是能让业务程序流畅运行的强大后盾。
服务器这块多是需要运维人员来配合搭建,具体我就不多说了,点到为止。

大致需要用到的服务器架构如下:

服务器
均衡负载 (如:nginx,阿里云 SLB)
资源监控
分布式
数据库
主从分离,集群
DBA 表优化,索引优化,等
分布式
nosql
主从分离,集群
主从分离,集群
主从分离,集群
redis
mongodb
memcache
cdn
html
css
js
image

并发测试

高并发相关的业务,需要进行并发的测试,通过大量的数据分析评估出整个架构可以支撑的并发量。
测试高并发可以使用第三方服务器或者自己测试服务器,利用测试工具进行并发请求测试,分析测试数据得到可以支撑并发数量的评估,这个可以作为一个预警参考,俗话说知己自彼百战不殆。

第三方服务:
阿里云性能测试
并发测试工具:

Apache JMeter
Visual Studio 性能负载测试
Microsoft Web Application Stress Tool

实战方案通用方案
日用户流量大,但是比较分散,偶尔会有用户高聚的情况;场景:用户签到,用户中心,用户订单,等
服务器架构图:

说明:

场景中的这些业务基本是用户进入 APP 后会操作到的,除了活动日 (618, 双 11,等),这些业务的用户量都不会高聚集,同时这些业务相关的表都是大数据表,业务多是查询操作,所以我们需要减少用户直接命中 DB 的查询;优先查询缓存,如果缓存不存在,再进行 DB 查询,将查询结果缓存起来。
更新用户相关缓存需要分布式存储,比如使用用户 ID 进行 hash 分组,把用户分布到不同的缓存中,这样一个缓存集合的总量不会很大,不会影响查询效率。

方案如:

用户签到获取积分
计算出用户分布的 key,redis hash 中查找用户今日签到信息
如果查询到签到信息,返回签到信息
如果没有查询到,DB 查询今日是否签到过,如果有签到过,就把签到信息同步 redis 缓存。
如果 DB 中也没有查询到今日的签到记录,就进行签到逻辑,操作 DB 添加今日签到记录,添加签到积分 (这整个 DB 操作是一个事务)
缓存签到信息到 redis,返回签到信息
注意这里会有并发情况下的逻辑问题,如:一天签到多次,发放多次积分给用户。

用户订单

这里我们只缓存用户第一页的订单信息,一页 40 条数据,用户一般也只会看第一页的订单数据
用户访问订单列表,如果是第一页读缓存,如果不是读 DB
计算出用户分布的 key,redis hash 中查找用户订单信息
如果查询到用户订单信息,返回订单信息
如果不存在就进行 DB 查询第一页的订单数据,然后缓存 redis,返回订单信息

用户中心

计算出用户分布的 key,redis hash 中查找用户订单信息
如果查询到用户信息,返回用户信息
如果不存在进行用户 DB 查询,然后缓存 redis,返回用户信息

其他业务

上面例子多是针对用户存储缓存,如果是公用的缓存数据需要注意一些问题,如下
注意公用的缓存数据需要考虑并发下的可能会导致大量命中 DB 查询,可以使用管理后台更新缓存,或者 DB 查询的锁住操作。

以上例子是一个相对简单的高并发架构,并发量不是很高的情况可以很好的支撑,但是随着业务的壮大,用户并发量增加,我们的架构也会进行不断的优化和演变,比如对业务进行服务化,每个服务有自己的并发架构,自己的均衡服务器,分布式数据库,nosql 主从集群,如:用户服务、订单服务;
消息队列
秒杀、秒抢等活动业务,用户在瞬间涌入产生高并发请求场景:定时领取红包,等
服务器架构图:

一级缓存

高并发请求连接缓存服务器超出服务器能够接收的请求连接量,部分用户出现建立连接超时无法读取到数据的问题;
因此需要有个方案当高并发时候时候可以减少命中缓存服务器;
这时候就出现了一级缓存的方案,一级缓存就是使用站点服务器缓存去存储数据,注意只存储部分请求量大的数据,并且缓存的数据量要控制,不能过分的使用站点服务器的内存而影响了站点应用程序的正常运行,一级缓存需要设置秒单位的过期时间,具体时间根据业务场景设定,目的是当有高并发请求的时候可以让数据的获取命中到一级缓存,而不用连接缓存 nosql 数据服务器,减少 nosql 数据服务器的压力

比如 APP 首屏商品数据接口,这些数据是公共的不会针对用户自定义,而且这些数据不会频繁的更新,像这种接口的请求量比较大就可以加入一级缓存;
服务器架构图:

静态化数据

高并发请求数据不变化的情况下如果可以不请求自己的服务器获取数据那就可以减少服务器的资源压力。
对于更新频繁度不高,并且数据允许短时间内的延迟,可以通过数据静态化成 JSON,XML,HTML 等数据文件上传 CDN,在拉取数据的时候优先到 CDN 拉取,如果没有获取到数据再从缓存,数据库中获取,当管理人员操作后台编辑数据再重新生成静态文件上传同步到 CDN,这样在高并发的时候可以使数据的获取命中在 CDN 服务器上。
CDN 节点同步有一定的延迟性,所以找一个靠谱的 CDN 服务器商也很重要

退出移动版