高并发
小到门户网站的并发阅读、在线聊天,大到春运期间12306官网的并发售票、双十一、618等电商大促的时候并发的交易量、电商活动秒杀系统、微信红包等的并发量。这些都体现了高并发技术的刚性需求。
在双十一等电商大促活动,屡次刷新最高交易额。另一个十分抢眼的看点就是各个平台在峰值是的处理并发量。很明显,对于高并发的掌控,在一定程度上反映了一个电商平台的技术水平。也会经常性的看到一些国内外的互联网企业频繁的推出各种高并发方面的新的技术框架,可见,高并发也是很多互联网大厂不断挑战、并且乐此不疲的研究方向。实际上,从软件诞生之初开发人员就在不断的探索和钻研高并发的技术,例如Java语言在高并发场景中的支持发展路线。一直不间断的迭代。
“高并发技术”是一个广泛的概念,是指一种高效的实现并发需求的解决方案, 是技术领域的名称,可以包含架构设计、面向服务架构SOA、分布式、微服务、数据处理、多线程等众多的知识体系的集合。
电商平台的秒杀活动会带来很大的高并发请求,为了避免超高频的高并发请求冲击电商的服务器,就需要对所有的并发请求进行处理。一般的就是通过验证码机制和IP限制等手段进行拦截非法请求,然后就是搭建服务器集群,将合法的并发请求进行分流。之后还可以在服务器内部设置最大连接数、最大并发数等服务参数,并且通过消息队列对海量的并发请求进行削峰处理。为了让数据库能稳定的处理高并发的请求,还通过缓存技术减少数据库的请求量,通过服务降级等策略减轻高并发峰值期间对系统的访问压力。最后,为了保证在极端情况下仍然能保证数据安全性,还需要搭建数据库集群并且设置合理的隔离机制。由此,高并发技术其实是贯穿在项目设计的方方面面,从网关到服务器,到数据库设计这些都要考虑到高并发情况下的应对策略。
如何从全局掌控一个大型系统
在开发大型系统的时候,除了根据业务需求实现对应的功能以外,还需要从高性能和高可用等多个维度对系统进行设计。下面就来从高并发、容错性和可扩展等多个方面来对大型开发系统的原则进行阐述。
高并发原则
高并发每个大型项目都无法回避的问题,如何保证项目在高并发环境下能正常运行呢?简单的,可以通过垂直扩展和水平扩展的方式来实现。
垂直扩展:通过软件技术或者升级硬件来提高单机的性能,这就像是一个小马无法能拉动货物的时候,换一匹健壮的大马来拉动货物。
水平扩展:通过增加服务器的节点个数来横向扩展系统性能,也就是说一匹马拉不动的情况下,可以多找几批相同的马,把货物拆分成多个小的块再去拉。
很明显,采用垂直化的方式来是最快的,只需要购买性能强大的硬件来支持,就可以快速的提升性能。但是单机的性能是有限的,就像是一匹马无论多厉害都无法拉动一座山。所以大厂都是通过水平扩展的方式,多少几匹马,然后把山切成小块。进行移山。
具体到技术层面,可以使用缓存减少数据库的访问,用熔断或者降级提高响应速度,通过流量削峰等手段在入口的地方进行限流操作。先拆分项目或者使用微服务的手段快速构建模块。然后使用统一服务治理来进行管理这些模块,通过中间件搭建基于读写分离的高可用数据库集群等等。
衡量高并发的常见指标就是响应时间、吞吐量或者是QPS、并发用户数等。
容错原则
如果高并发技术使用不当,不但无法提高系统的性能,而且会造成系统性能下降,导致各种逻辑混乱,造成出现无法预估的风险。因此就需要对潜在的问题进行预案,确保系统能有一定的容错性。例如,使用Spring Boot+Redis实现分布式缓存,使用MQ实现分布式场景下的事务一致性,使用MQ、PRG模式、Token等解决重复提交的问题,使用“去重表”实现操作的幂等性,使用集群或者Zookeeper解决失败迁移的问题。
在分布式系统中,网络延迟等问题也是不可避免的。一般来讲,可以在长连接的环境下通过“心跳检测机制”来处理。例如,在正常的网络环境下,当用户点击手机上某个APP的退出按钮之后,就会调用服务端的exit()方法等待退出,从而注销用户状态。如果用户的手机网络出现问题,那么如何来判断用户的状态呢?除了通过Session有效时长进行判断之外,还可以采用的就是心跳检测机制。每隔一段时间进行一次心跳检测,如果服务端收到了,则说明用户状态是正常的,如果没有收到那么等待下一个检测周期,如果连续几次都无法进行连接的话就说明此客户端已经下线。
为了提高容错性,可以先采用隔离的手段,例如,对秒杀系统等可预知时间的流量暴增,就可以提前将秒杀系统隔离成一个独立的服务,防止秒杀带来的流量问题可能会影响到系统中其他服务,当然,如果预计流量的增加不多的情况下,也可以使用多级缓存来解决高并发问题。
CAP原则
分布式系统包含了多个节点,多个节点之间的数据应该如何同步?在数据同步的时候又要注意那些因素?CAP原则就给出了这些问题的答案。CAP原则是理解及设计分布式系统的基础,包括Consistency一致性、Availability,可用性、Partition tolerance,分区容错性。
- 一致性 C:在同一时刻,所有节点中的数据都是相同的。
- 可用性 A:在合理的时间范围内,系统能够提供正常的服务。
- 分区容错性 P: 当分布式系统中的一个或多个节点发生网络故障,从而脱离整个系统的网络环境时,系统仍然能够提供可靠的服务,也就是说,当部分节点故障时,系统还能够正常运行。
如图,客户端发出的写请求,成功更新了A服务,由于网络的故障没有更新到B服务,下次客户端访问的时候,就会导致A服务和B服务的数据不一致,牺牲数据的一致性;要么在设计阶段,就要严格要求服务A和服务B中的数据必须是一致的,当向任何一个服务中写失败的时候,就要撤销所有的写操作。也就是牺牲了可用性。
因此,在任何的一个分布式系统中,CAP三者是不可兼得的,最多只能满足两个,一般而言,分布式必然会遇到网络问题,分区容错性是基本的要求,所以在设计的时候只能考虑CP或者AP。
幂等性原则
分布式系统提供的各个模块是通过网络进行交互的,而网络的问题会对用户请求服务的次数造成影响。例如再分布式系统中如果商品模块已经成功调用了支付服务,但是由于网络的问题造成支付模块在返回的时候出错了,就可能导致用户因为无法感知商品服务是否执行成功,从而主动的执行商品服务重复执行。也就是说用户收不到支付成功的消息,一直在点击支付按钮。实际上系统在第一次点击的时候就已经成功了,只不过是在返回的时候出错了。
实际上,在使用消息队列和异步调用的时候,都需要考虑触发的动作是否会被重复执行,为了避免这种重复执行的问题,就可以使用幂等性原则。
幂等性原则是对调用服务次数的一种限制,即无论对某个服务提供的接口调用多次或者一次,其结果是一样的。
对于分布式或者是微服务来说,为了实现幂等性,可以在写操作之前先通过执行读操作来实现,例如,在商品服务调用支付接口的时候,只需要按照如下的步骤就能实现幂等性。
- 1、读操作:查询支付服务中的支付状态。
- 2、写操作:若已经支付,直接返回结果;若未支付,先执行支付操作,再返回支付结果。
对于分布式、微服务或单系统等各种系统,还可以使用更加通用的“去重表”方式来实现幂等性,具体操作如下。
- (1)每个操作在第一次执行时,会生成一个全局唯一的ID,例如订单ID。
- (2)在“去重表”中查询“1”中的ID是否存在
- (3)如果存在,直接返回结果;如果不存在,再执行核心操作,并将“1”中的ID存入“去重表”中,最后返回结果。