AlexiaChen / AlexiaChen.github.io

My Blog https://github.com/AlexiaChen/AlexiaChen.github.io/issues
87 stars 11 forks source link

系统架构----高并发 #142

Open AlexiaChen opened 2 years ago

AlexiaChen commented 2 years ago

系统架构之高并发

场景分类

侧重于高并发读的系统

  1. 搜索引擎

拿熟悉的百度举例,在搜索框里面搜索关键词,展示结果网页列表,这个过程中,用户只是浏览,没有修改网页内容。

  1. 电商的商品搜索,描述,价格

与百度搜索之类的类似,发布商品本来频率就更低,搜索浏览淘宝之类的更多。

侧重于高并发写的系统

典型的就是广告计费系统,现在各种App都有广告,点击浏览计费,就会在数据库中扣除广告主的余额。Update很多。相当于就是读多写少的大流量转化成了点击量,最终导致写多。

高并发读写二者兼备的系统

  1. 电商的库存和秒杀系统

库存系统和秒杀系统的一个典型特征是:C端用户要对数据库同时进行高并发读写,我买了这件衣服,那么库存中只能在另一个用户看着一定是少了一件,信息要近乎实时的更新。12306的系统也是这样,春运买火车票,想想都可怕。

  1. 支付系统和微信红包

支付系统也是高并发读写,查询余额和转入转出,并且查询余额也要很实时准确,钱这一类的信息是金融相关的数据,对数据一致性要求很高,也不能延迟。从支付扩展到红包,业务场景会更复杂,一个用户发红包,群里多个人墙。全国那么多群。一个账号发生扣减,多个人的账号加钱,并且这个过程大部分人还会查看哪些人抢到了红包。

  1. IM,微博和朋友圈

QQ,微信消息,微博,朋友圈这些都是,收消息是读,发消息是写,几乎是对半分。用户规模在亿级别,读写处理都需要非常及时。

高并发读

这样的系统在互联网应用中占大部分,大部分的业务系统都是读多写少。大部分数据库的内核设计都是读多写少,尽可能提高查询效率,Google的有个PPT也是说到,写的优化会比读更难。

加缓存,主从,CDN

本质是以空间换时间。

  1. 本地缓存或Redis等这些集中式缓存

这里得小心,能尽量不用缓存就不用缓存,以免增加维护成本。《有些上古程序员一直坚持反对使用Redis怎么办?》

缓存一般是KV结构,更新缓存一般也有两种策略,一种是主动更新(推),当数据库中的数据发生变更时,主动地删除或更新缓存中的数据。另一种是被动更新(拉),当用户的查询请求到来,如果缓存过期,再更新缓存。

对于缓存,需要考虑几个问题:

  1. MySQL的Master/Slave

这样的方式主要是为了分担主库的读压力,加一个或者多个Slave,简单有效。

  1. CDN静态文件加速(动静分离)

图片,HTML,CSS文件这样不变的数据一般用CDN。一个静态文件缓存到了全网的各个节点,当第一个用户访问的时候,离用户最近的节点还没有缓存数据,CDN就会去源系统抓取文件缓存到该节点,等第二个用户访问的时候,只需要从这个节点访问即可。

并发读,串行改并行

  1. 异步RPC

现在的RPC框架基本都支持了异步RPC,对于用户的一个请求,如果需要调用3个RPC接口分别需要耗时T1,T2,T3。如果是同步调用总耗时就是T = T1+T2+T3。如果是异步调用,则所消耗的总时间是T = MAX(T1,T2,T3)。这里有个前提条件就是这三个接口没有耦合关系,不能有结果依赖,需要是可以并行的。

  1. Google的冗余请求(Hedged Request)

Google的顶级基础架构师Jeff Dean在The Tail at Scale的论文中讲过这样一个案例:假设一个用户的请求需要100台服务器同时联合处理,每台服务器有1%的概率发生调用延迟(定义相应时间大于1s为延迟),那么对于C端用户来说,响应时间大于1s的概率是63%。

从这个结果上有点反直觉?但是对于分布式系统,就是这样的,结果是这样计算出来的。假设有100台机器,每一台发生非延迟的调用是99%,因为延迟是1%,如果用户的请求响应时间小于1s,意味着100台机器任何一台都不可以小于1s,这个概率是比较低的也就是99%的100次方。反过来看,用户的请求响应时间大于1s的概率就是:

1 - (99%)^100 = 63%

这个概率是很高的,注意这里是100台联合协同处理,不是负载均衡的那样单独处理,也就是这100台服务器功能独立负责各自的。机器数越多越严重,在分布式系统上,不出问题是不可能的,即使每台的故障率很低。Google的数据中心的规模,据说已经算是无时无刻都有问题故障不断。

怎么解决以上问题?

其中最重要的一个就是服务间调用控制。首先需要说明个前提,在分布式系统中,为了解决数据的可靠性,通常会将数据复制到多台机器上,同时为了实现服务的高可用,又会有多个服务器提供同样的功能,防止部分服务器出现故障。

为了解决响应时间的突刺,调用者需要将请求“同时”发送给多台服务器,并在收到最快的响应后,马上终止其他服务器的处理(或将其他服务器的返回结果直接丢弃,不需要等待)。采用这种方法,可以大大降低某个调用出现的突刺。同时我们也可以看到,这样会让整个系统的请求调用数量(流量)翻几倍。

论文中给出了一个更好的做法:

Google的测试数据表示,,采用这种方案,可以仅用2%的额外请求,将系统的99.9%的请求响应时间从1800ms降低到74ms:

For example, in a Google benchmark that reads the values for 1,000 keys stored in a 
BigTable table distributed across 100 different servers, sending a hedging request after 
a 10ms delay reduces the 99.9th-percentile latency for retrieving all 1,000 values from 
1800ms to 74ms while sending just 2% more requests.

重写轻读

To be continued