来源:blog.thankbabe.com/2016/09/14/high-concurrency-scheme/什么是统一异常处理高并发往往出现在活跃用户数量多、用户聚合度高的业务场景中,比如:秒杀活动、定时领红包等。为了让业务顺利运行,给用户提供良好的交互体验,我们需要根据业务场景的需求等因素,设计出适合自己业务场景的高并发处理方案。估计业务场景实现的并发数。在这几年电子商务相关产品的开发中,有幸遇到过并发带来的各种坑。一路上有很多血和泪。这里总结作为自己的存档记录,分享给大家。每个人。服务器架构业务从发展初期走向逐步成熟,服务器架构也从相对单一的集群发展到分布式服务。一个能够支持高并发的服务,需要一个好的服务器架构,需要负载均衡,数据库主从集群,nosql缓存主从集群,静态文件上传CDN。大部分服务器需要运维人员配合搭建。需要用到的服务器架构大致如下:服务器负载均衡(如:nginx,阿里云SLB)资源监控分布式数据库主从分离,集群DBA表优化,索引优化,其他分布式nosql主从separation,clustermaster-slaveseparation,clustermaster-slaveseparation,clusterredismongodbmemcachecdnhtmlcssjsimageconcurrencytest高并发相关业务,需要进行并发测试,通过大量的数据分析评估整个架构能够支持的并发量。测试高并发,可以使用第三方服务器或者自己的测试服务器,使用测试工具测试并发请求,分析测试数据,得到可以支持的并发请求数的评估。这可以作为预警参考。第三方服务:阿里云性能测试并发测试工具:ApacheJMeterVisualStudio性能负载测试MicrosoftWebApplicationStressTool实用方案总体方案日常用户流量较大,但比较分散,偶尔会出现用户高度集中;场景:用户签到、用户中心、用户下单等服务器架构图:说明:场景中的这些服务基本都是用户进入APP后进行操作。除了活动日(618、双11等),这些服务的用户量不会高聚合。同时,这些业务相关的表都是大数据表,大部分业务都是查询操作,所以我们需要减少用户直接打DB的查询次数;优先查询缓存,如果缓存不存在,则进行DB查询,并缓存查询结果。更新用户相关的缓存需要分布式存储,比如使用用户ID进行hash分组,将用户分布到不同的缓存中。这样的缓存集总量不会很大,不会影响查询效率。比如用户签到获得积分计算用户分布的key,在redishash中找到用户今天的签到信息。如果查询到登录信息,则返回登录信息。签到信息同步redis缓存。如果在DB中没有找到今天的签到记录,执行签到逻辑,操作DB添加今天的签到记录,添加签到点(整个DB操作就是一个事务),缓存签到-in信息到redis,并返回签到信息注意会出现并发情况下的逻辑问题,比如:一天签到多次,给用户签发多个积分。-用户订单这里我们只缓存用户首页的订单信息,每页40条数据,用户一般只读取首页的订单数据。用户访问订单列表。如果是第一页读缓存,如果不是读DB计算用户分布的key,在redishash中找到用户订单信息。如果查询用户订单信息,则返回订单信息。如果不存在,则对第一页的订单数据进行DB查询,然后缓存redis,返回订单信息——用户中心计算的用户分发的key,在redishash中查找用户订单信息.如果查询用户信息,则返回用户信息。如果不存在,则进行用户DB查询,然后缓存redis,返回用户信息。公共缓存数据需要注意一些问题,如下:公共缓存数据需要考虑并发可能导致大量命中DB查询,可以使用管理后台更新缓存,或者锁定DB查询。上面的例子是一个比较简单的高并发架构,在并发量不是很高的时候可以很好的支持。但是随着业务的增长,并发用户数的增加,我们的架构也会不断的优化演进。比如业务的Servitization,每个服务都有自己的并发架构,自己的平衡服务器,分布式数据库,nosql主从集群,比如:用户服务,订单服务;消息队列秒杀、secgrab等主动服务,用户瞬间抢购收益产生的高并发请求场景:定时接收红包,等待服务器架构图:描述:场景中的定时接收是一个高并发业务,例如秒杀活动。一个暴击,如果你扛不住,它就会倒下,进而影响到整个生意;像这种既有查询操作又有高并发插入或更新数据的业务,上面提到的通用方案无法支持。都是直接打DB;在设计这个业务的时候,会用到消息队列。可以将参与用户的信息添加到消息队列中,然后写一个多线程程序消费队列,给队列中的用户分发红包;方案如:定时领红包,一般是在用户参与活动时使用redis列表,将用户参与信息推送到队列中,然后写一个多线程程序弹出数据,分发红包,让用户在high下并发可以正常参与活动,避免数据库服务器宕机的危险另外:很多服务可以通过消息队列来完成。如:定时短信发送服务,使用sset(sortedset),发送时间戳作为排序依据,短信数据队列按照时间排序,然后写一个程序定时循环读取sset队列中的第一项,当前是否timeexceedsthesendingtime时间,如果超过,发送短信。一级缓存高并发请求连接缓存服务器超过服务器可接收的请求连接数,部分用户出现建立连接超时后无法读取数据的问题;因此,需要一种解决方案,可以在高并发高的时候减少对缓存服务器的命中;这时候就有了一级缓存方案。一级缓存是使用站点服务器缓存来存储数据。注意只存储部分请求量大的数据,一定要控制缓存的数据量。它不会受到站点服务器内存过度使用的影响。为了站点应用的正常运行,一级缓存需要设置一个以秒为单位的过期时间。具体时间根据业务场景设置。目的是在不连接缓存的情况下,让数据获取在有高并发请求时命中一级缓存。Nosql数据服务器,减轻nosql数据服务器的压力,比如APP首屏商品数据接口,这些数据是公开的,不会为用户定制,这些数据不会经常更新,这样的接口需要量比较大的请求加入一级缓存;服务器架构图:合理规范使用nosql缓存数据库,根据业务拆分缓存数据库集群,基本可以很好的支撑业务。毕竟一级缓存使用的是站点服务器缓存,所以要好好利用。静态数据高并发请求数据是不会变化的,如果不能请求自己的服务器获取数据,那么可以减少服务器的资源压力。如果更新频率不高,数据可以在短时间内延迟,可以将数据静态转换成JSON、XML、HTML等数据文件上传到CDN。从缓存和数据库中获取。当管理员操作后台编辑数据然后重新生成静态文件上传到CDN,这样在高并发的时候数据获取可以命中到CDN服务器上。CDN节点的同步有一定的延迟,所以找一家靠谱的CDN服务器商也很重要。对于其他方案,对于不经常更新的数据,APP和PC浏览器可以将数据缓存到本地,然后每次请求接口。上传当前缓存数据的版本号时,服务端接收版本号判断版本号是否与最新的数据版本号一致。如果没有,则查询最新的数据,返回最新的数据和最新的版本号。如果相同,则返回状态码通知数据已经是最新的。降低服务器压力:资源、带宽等。分层、分段、分布式的大型网站必须很好地支持高并发,这需要长期的规划和设计。前期需要对系统进行分层,在开发过程中进行核心业务。拆分成模块化单元,按需分布式部署,独立团队维护开发。分层将系统在水平维度上分成几个部分。每个部门负责一个比较简单、比较单一的职责,然后通过上层对下层的依赖和调度,形成一个完整的系统。例如,电子商务系统分为:应用层、服务层、数据层。(具体层数取决于自己的业务场景)应用层:网站首页、用户中心、商品中心、购物车、红包业务、活动中心等,负责具体业务和视图展示服务层:订单服务、用户管理服务、红包服务、商品服务等,为应用层提供服务,支持数据层:关系数据库、nosql数据库等,提供数据存储查询服务分层架构逻辑清晰,可部署物理部署在同一台物理机上,但是随着网站业务的发展,需要将分层的模块分离部署在不同的服务器上,这样网站才能支持更多的用户访问。切分将业务垂直划分,将一个相对复杂的业务划分成不同的模块单元,并打包成高内聚低耦合的模块,不仅有利于软件的开发和维护,也便于不同模块的分布式部署,提高网站的并发处理能力和功能扩展。例如用户中心可以分为:账户信息模块、订单模块、充值模块、提现模块、优惠券模块等-分布式分布式应用和服务,分布式部署分层或拆分业务,独立的应用服务器,数据库,缓存服务器,当业务达到一定用户量时,再均衡服务器负载,数据库,缓存主从集群分布式静态资源,如:上传静态资源到CDN分布式计算,如:利用hadoop进行大数据的分布式计算,分布式数据和存储,例如:各个分布式节点按照hash算法或者其他算法分布式存储数据,网站是分层的——图1来自网络集群。针对用户访问集中的业务,独立部署服务器、应用服务器、数据库、nosql数据库。核心业务基本需要搭建集群,即多台服务器部署同一个应用组成集群,通过负载均衡设备对外提供服务。服务器集群可以为同一个服务提供更多的并发支持,所以当有更多的用户访问时,只需要在集群中添加一台新的机器即可。另外,当其中一台服务器出现故障时,可以通过负载均衡故障转移机制将请求转移到集群中的其他服务器,因此可以提高系统的可用性应用服务器集群nginx反向代理slb……(relational/nosql)数据库集群主从分离,从数据库集群通过反向代理进行负载均衡——图2来自网络异步如果涉及到数据库操作的高并发业务,主要压力在数据库服务器上。虽然采用了主从分离,但是数据库操作都是在主库上进行的。单个数据库服务器连接池允许的最大连接数是有限制的。当连接数达到最大值后,其他需要连接数据操作的Request需要等待空闲连接,这样在高并发时很多请求会出现连接超时。那么对于这样一个高并发的业务我们应该如何设计开发方案来降低数据库服务器的压力呢?如:自动弹窗签到、双11过0:00并发请求签到界面、双11抢红包事件、双11订单入库等——设计思路:逆向思维,压力是在数据库上,则业务接口不会进行数据库操作。无压力。数据持久化是否允许延迟?如何让业务接口不直接操作DB,又让数据持久化?-方案设计:对于这类涉及数据库操作的高并发业务,需要考虑采用异步客户端发起接口请求,服务端快速响应,客户端展示结果给用户。如何通过异步同步实现数据库操作的异步同步?使用消息队列将入库内容入队到消息队列中,业务接口快速响应用户结果(可以温馨提示高峰期延迟到达)然后独立编写程序将数据从消息中出队队列执行入库操作。取库成功后刷新用户相关缓存。如果存储失败,记录日志,方便反馈查询和重新持久化。这样只用一个程序(多线程)完成对数据库的操作,不会给数据带来压力。-补充:消息队列除了用在高并发服务中,其他有相同需求的服务也可以使用,比如:短信发送中间件等高并发异步持久化数据可能会影响用户体验,可以可配置或自动监控资源消耗,用于在实时或异步之间切换,这样在流量正常的情况下,可以使用数据库的实时操作来提高用户体验。异步也可以指编程异步函数、异步线程,有时也可以使用异步操作。把不需要等待结果的操作放到异步中,再继续后面的操作,省去了这部分操作的等待时间。高并发的业务接口大部分是查询业务数据,比如:商品列表、商品信息、用户信息、红包信息等,这些数据不会经常变化,持久化直接连接从库用于数据库中高并发下的查询操作。多个从数据库服务器无法承受如此大量的连接请求(前面说过,单个数据库服务器允许的最大连接数是有限制的)那么我们如何设计这个高并发的业务接口呢?设计思考:还是逆向思维,压力在数据库上,那我们就不会去查询数据库,数据也不会经常变化,为什么还要一直去查询DB呢?数据不会改变。为什么客户端请求服务器返回相同的数据?-方案设计:数据不经常变化,我们可以缓存数据,缓存有很多种方式,一般:应用服务器直接缓存内存,主流:存储在memcache中,redis内存数据库缓存直接存储在应用服务器中,读取速度快,内存数据库服务器允许大量连接,数据存储在内存中,读取速度快,加上主从集群,可以支持大量并发查询.根据业务场景,配合客户使用端到本地的存储,如果我们的数据内容不经常变化,为什么还要不断请求服务器获取相同的数据呢?我们可以匹配数据版本号。如果版本号不同,接口会重新查询缓存,返回数据和版本号。如果它们相同,则不会查询数据。直接响应不仅可以提高界面的响应速度,还可以节省服务器带宽。虽然有些服务器带宽是按流量收费的,但也不是绝对无限的。当服务器带宽高时,服务器带宽也可能造成请求响应慢的问题-补充:缓存也指静态资源客户端缓存CDN缓存,静态资源上传到CDN,CDN节点缓存我们的静态资源,减少服务器pressureService-orientedSOA面向服务的架构设计微服务更细粒度和面向服务,一系列独立的服务组合体系,利用面向服务的思想,将核心业务或通用业务功能分离成服务独立部署,以及提供对外提供功能的接口。最理想的设计是将一个复杂的系统拆分成多个服务。共同构成系统的服务具有松散耦合、高可用性、高扩展性、易维护等优点。通过面向服务的设计,独立的服务器部署,负载均衡,数据库集群,服务可以支持更高的并发业务。示例:用户行为跟踪记录统计-描述:通过上报应用模块、操作事件、事件对象等数据,记录用户的操作行为,如:记录用户在某个产品模块中点击某个产品,或者浏览某种产品。服务的业务也是核心业务的用户行为跟踪,所以请求量非常大,高峰期会产生大量的并发请求。架构:nodejsWEB应用服务器负载均衡redis主从集群mysql主节点nodejs+express+ejs+redis+mysql服务器使用nodejs,nodejs是单进程(pm2根据CPU核数启动多个工作进程),以及采用事件驱动机制。适合I/O密集型业务,处理高并发能力强业务设计:并发量大,不能直接入库,使用:异步数据同步,消息队列请求接口上报数据,接口会推送上报数据到redis的list队列nodejs写库脚本,循环popredislist数据,将数据入库,并进行相关统计更新。没有数据的时候,休眠几秒,因为数据量会比较大。报表数据表按天命名存储接口:报表数据接口统计查询接口-在线跟进:服务业务基本正常,日报表有千万级冗余数据。当高并发业务所在的服务器宕机时,需要有备份服务器来快速替代。在应用服务器压力大的时候,可以快速的向集群中添加机器,所以我们需要有可以随时待命的备用机器。最理想的方式是自动监控服务器资源消耗并发出告警,自动切换降级方案,自动执行服务器更换和添加??操作。自动化可以降低人工操作的成本,可以快速操作,避免人工操作。错误。冗余数据库备份备份服务器自动化自动化监控自动化报警自动化降级通过GitLab事件,我们应该反思备份数据并不代表万无一失。我们需要确保高可用性。首先,备份是否正常,备份数据是否可用,需要我们进行定期检查,或者自动化监控,以及如何避免人为操作失误。(不过gitlab在事件中的开放态度和积极的处理方式还是值得我们学习的。)综上所述,高并发架构是一个不断进化的过程。三尺冰洞非一日之寒,万里长城非一日之功。奠定良好的基础设施以方便未来的扩展是非常重要的。近期热点文章推荐:1.1000+Java面试题及答案(2022最新版)2.厉害了!Java协程来了。..3.SpringBoot2.x教程,太全面了!4、SpringBoot2.6正式发布,一大波新特性。.5.《Java开发手册(嵩山版)》最新发布,赶快下载吧!感觉不错,别忘了点赞+转发!
