修正版 | 面对千万级、亿级流量怎么处理?(一)

wg204wg
发布于 2022-6-9 16:46
浏览
0收藏

 

这是一道很常见的面试题,但是大多数人并不知道怎么回答,这种问题其实可以有很多形式的提问方式,你一定见过而且感觉无从下手:

面对业务急剧增长你怎么处理?

业务量增长10倍、100倍怎么处理?

你们系统怎么支撑高并发的?

怎么设计一个高并发系统?

高并发系统都有什么特点?

... ...

诸如此类,问法很多,但是面试这种类型的问题,看着很难无处下手,但是我们可以有一个常规的思路去回答,就是围绕支撑高并发的业务场景怎么设计系统才合理?如果你能想到这一点,那接下来我们就可以围绕硬件和软件层面怎么支撑高并发这个话题去阐述了。本质上,这个问题就是综合考验你对各个细节是否知道怎么处理,是否有经验处理过而已。

面对超高的并发,首先硬件层面机器要能扛得住,其次架构设计做好微服务的拆分,代码层面各种缓存、削峰、解耦等等问题要处理好,数据库层面做好读写分离、分库分表,稳定性方面要保证有监控,熔断限流降级该有的必须要有,发生问题能及时发现处理。

微服务架构演化
在互联网早期的时候,单体架构就足以支撑起日常的业务需求,大家的所有业务服务都在一个项目里,部署在一台物理机器上。

所有的业务包括你的交易订单、会员、库存、商品、营销等等都夹杂在一起,当流量一旦高起来之后,单体架构的问题就暴露出来了,机器挂了所有的业务全部无法使用了。

 修正版 | 面对千万级、亿级流量怎么处理?(一)-鸿蒙开发者社区
于是,集群架构的架构开始出现,单机无法抗住的压力,最简单的办法就是水平拓展横向扩容。这样,通过负载均衡把压力流量分摊到不同的机器上,暂时是解决了单点导致服务不可用的问题。

 修正版 | 面对千万级、亿级流量怎么处理?(一)-鸿蒙开发者社区
但是随着业务的发展,在一个项目里维护所有的业务场景使开发和代码维护变得越来越困难,一个简单的需求改动都需要发布整个服务,代码的合并冲突也会变得越来越频繁,同时线上故障出现的可能性越大,微服务的架构模式就诞生了。

 修正版 | 面对千万级、亿级流量怎么处理?(一)-鸿蒙开发者社区
把每个独立的业务拆分开独立部署,开发和维护的成本降低,集群能承受的压力也提高了,再也不会出现一个小小的改动点需要牵一发而动全身了。

以上的点从高并发的角度而言,似乎都可以归类为通过服务拆分和集群物理机器的扩展提高了整体的系统抗压能力,那么,随之拆分而带来的问题也就是高并发系统需要解决的问题。

通信
微服务化的拆分带来的好处和便利性是显而易见的,但是与此同时各个微服务之间的通信就需要考虑了。

对于SOA、微服务化的架构而言,就对部署、运维、服务治理、链路追踪等等有了更高的要求。

 修正版 | 面对千万级、亿级流量怎么处理?(一)-鸿蒙开发者社区
基于此,无论选用何种框架Spring Cloud、Spring Cloud Alibaba、Dubbo、Thrift、gRpc其实都一样。

于现在国内的技术栈选择来说,大厂基本都是自研,中小厂更多采用如Dubbo这类框架,现在来说,Spring Cloud Alibaba应该是未来一段时间的主流方向。

但是无论使用何种框架,一些基本原理都是应该了解的。此处以Dubbo举例。

更多请查看:《我想进大厂》之Dubbo普普通通9问

Dubbo工作原理

  1. 服务启动的时候,provider和consumer根据配置信息,连接到注册中心register,分别向注册中心注册和订阅服务
  2. register根据服务订阅关系,返回provider信息到consumer,同时consumer会把provider信息缓存到本地。如果信息有变更,consumer会收到来自register的推送
  3. consumer生成代理对象,同时根据负载均衡策略,选择一台provider,同时定时向monitor记录接口的调用次数和时间信息
  4. 拿到代理对象之后,consumer通过代理对象发起接口调用
  5. provider收到请求后对数据进行反序列化,然后通过代理调用具体的接口实现
     修正版 | 面对千万级、亿级流量怎么处理?(一)-鸿蒙开发者社区

Dubbo负载均衡策略

  1. 加权随机:假设我们有一组服务器 servers = [A, B, C],他们对应的权重为 weights = [5, 3, 2],权重总和为10。现在把这些权重值平铺在一维坐标值上,[0, 5) 区间属于服务器 A,[5, 8) 区间属于服务器 B,[8, 10) 区间属于服务器 C。接下来通过随机数生成器生成一个范围在 [0, 10) 之间的随机数,然后计算这个随机数会落到哪个区间上就可以了。
  2. 最小活跃数:每个服务提供者对应一个活跃数 active,初始情况下,所有服务提供者活跃数均为0。每收到一个请求,活跃数加1,完成请求后则将活跃数减1。在服务运行一段时间后,性能好的服务提供者处理请求的速度更快,因此活跃数下降的也越快,此时这样的服务提供者能够优先获取到新的服务请求。
  3. 一致性hash:通过hash算法,把provider的invoke和随机节点生成hash,并将这个 hash 投射到 [0, 2^32 - 1] 的圆环上,查询的时候根据key进行md5然后进行hash,得到第一个节点的值大于等于当前hash的invoker。

修正版 | 面对千万级、亿级流量怎么处理?(一)-鸿蒙开发者社区

 图片来自dubbo官方

4.加权轮询:比如服务器 A、B、C 权重比为 5:2:1,那么在8次请求中,服务器 A 将收到其中的5次请求,服务器 B 会收到其中的2次请求,服务器 C 则收到其中的1次请求。

集群容错

  1. Failover Cluster失败自动切换:dubbo的默认容错方案,当调用失败时自动切换到其他可用的节点,具体的重试次数和间隔时间可用通过引用服务的时候配置,默认重试次数为1也就是只调用一次。
  2. Failback Cluster失败自动恢复:在调用失败,记录日志和调用信息,然后返回空结果给consumer,并且通过定时任务每隔5秒对失败的调用进行重试
  3. Failfast Cluster快速失败:只会调用一次,失败后立刻抛出异常
  4. Failsafe Cluster失败安全:调用出现异常,记录日志不抛出,返回空结果
  5. Forking Cluster并行调用多个服务提供者:通过线程池创建多个线程,并发调用多个provider,结果保存到阻塞队列,只要有一个provider成功返回了结果,就会立刻返回结果
  6. Broadcast Cluster广播模式:逐个调用每个provider,如果其中一台报错,在循环调用结束后,抛出异常

 

文章转自公众号:艾小仙

分类
标签
已于2022-6-9 16:46:00修改
收藏
回复
举报
回复
    相关推荐