1、消息风暴:1V1时,每10秒发一个消息,那么每秒消息量是0.1。500人群每10秒一个消息,推送消息量是5001/10500=25000。10万人群直播间每10秒一个消息,推送量是1000001/10100000=1000000000=10亿。无论服务器和客户端都无法承载,服务端会限流和选择性丢弃,客户端上限也就是每秒几十条。

2、链路优化:用户发消息后,业务层服务器需要查询接收方的在线状态(链接在哪台服务器上),高并发场景下,这个在线状态服务将会成为瓶颈。 改为:业务层消息入队,接入层的每台网关都订阅这个队列,然后由网关决定给哪个链接推消息。

3、微服务拆分:把打赏、弹幕、点赞、送礼等核心业务 和 直播回放、第三方同步等非核心业务拆分;把容易成为瓶颈的和不容易成为瓶颈的拆分。

4、扩容缩容:指定监控指标,如机器侧的负载、CPU等,和业务侧的同时在线人数、弹幕数、延迟等指标,自动扩容和缩容。

5、负载均衡:扩容后,如果负载均衡策略不变,新链接可能还是均匀的分布给新老机器,导致老机器先到达瓶颈,因为负载均衡器本身也需要扩容,不同的机器可能采用不同了算法,达不到预期。 因此,可以在入口层建立一个调度器,先通过调度器查询可以链接到哪台机器。

1、基础架构:

  • 接入层:连接保持、协议解析、Session 维护(用户和链接的关联关系)、消息推送。

    • 接入层和业务层拆分:消息收发的出入口需要高可用;分开后有助于提升业务开发效率;不需要跟着业务变动频繁发布重启;业务层可以屏蔽协议细节。
  • 业务层:未读数变更、最近联系人等业务场景。
  • 存储层:持久化存储。用于离线消息等。
  • 外部接口:如push等。
    2、特性:
  • 实时性

    • 发:

      • 提供一个http接口,客户端发消息给IM服务器
      • 客户端和IM服务器维持一个TCP长链接,用私有协议封装(如protobuf)。
    • 收:

      • 长链接和push。需要维护一个可靠的长链接:

        • 客户端和服务器精确感知可用性,断线快速重连。
        • 通过这个长链接发送的消息不丢失。
        • TCP协议:Websocket最常见。XMPP(成熟,可扩展,但XML太大),MQTT(推送场景下被广泛使用,但不是很契合IM,不支持群组和离线消息)
      • 轮询:

        • 短轮询:不断的发HTTP请求
        • 长轮询:短轮询的优化,无消息是服务器不立即返回,而是挂起,有新消息或超时后再返回。但是并没有解决大量无效请求,也没有降低QPS(只是入口层降低了,后端还是轮询判断)。
      • 未读数(角标):需要维护一个总未读数,每个会话也需要维护一个未读数。

        • 总未读和每个会话未读,是需要分布式锁/原子操作。
  • 可靠性:不丢消息、不重复消息。

    • 客户端发给服务器丢失:消息加唯一ID,客户端重试+服务器去重。
    • 其他异常:如服务器转给客户端失败,客户端存本地DB失败等,业内一般实现一个业务层的ACK机制。

      • 服务器下发后把ID放入待确认列表,收到客户端ACK后服务器从列表删除。
      • 服务器超时未收到ACK后,会把消息重传,客户端也要进行去重。
      • 特殊情况:服务器下发后未收到ACK时,服务器宕机,客户端重连后并不知道刚才丢了消息,所以客户端上线后拿最新的ID来服务器取大于这个ID的所有消息即可。
      • TCP有ACK为什么业务还要做ACK:

        • 服务器写入TCP缓冲区后,客户端从TCP缓冲区读取后,都可能会失败。而且连接断开时(比如手机crash或没电关机),双方的缓冲区都会直接销毁(即时里面还有未发/未读的数据)。
  • 一致性:顺序保持一致。分布式下,两条消息间肯定会有时间差。

    • 时序基准:全局序号生成器,可以用redis的incr或snowflake算法。但是无法解决同一精度内多个并发消息的排序。
    • 包内整流:多个消息必须要严格顺序时,比如分手+取关,就不能先取关,否则分手发不过去。这时可以以包为单位,packageId+seqId为一条消息,一个包内的消息全部达到后再进行处理,否则丢弃或重试。
  • 安全性:

    • 传输安全:HTTPS/HTTPDNS,明文传输时内容TLS加密。
    • 存储安全:端到端加密,出收发双方,服务器也无法破解。
    • 内容安全:敏感词、图片、语音、外链检测、禁言等。
      3、心跳:除了两端自身问题外,运营商的NAT也会剔除空闲链接以节省资源,这种情况下服务器和客户端均无法感知,只能依赖心跳。
  • TCP keepalive:操作系统实现,默认关闭,三个可配的参数默认值是心跳周期2小时、失败9次、超时75秒。不带数据的心跳包,省带宽,但无法感知如死锁/阻塞等业务异常,也无法动态调整心跳周期。因此只代表网络可用。如WhatApps空闲期10秒一次。
  • 应用层心跳:微博2分半,微信4分半,WhatApps30秒到1分钟。QQ是固定45秒。
    4、推送:
  • 通过中央存储(用户和所在网关的映射关系)进行下推。
  • 推送给所有网关机,有网关机查找链接是否在本机,自行推送。

一、基本思想和模式

  1. 基本思想:拆。按流程、按服务、按功能。按流程拆难理解,固化的内核,移动的数据,如接口层 - 业务层 - 数据层 - 存储层。

  2. 扩展方式:拆了以后修改和扩展不影响其他模块。按流程拆有分层架构、按服务拆有微服务架构和SOA、面向功能拆有微内核架构。

二、分层架构和SOA

  1. 分层架构:如B/S、C/S、MVC、MVP等。

  2. SOA:可以说某企业使用SOA架构了IT系统,而不是某独立系统采用SOA架构。主要对传统企业IT部门。组织架构、员工信息、请假管理等子系统+企业服务总线ESB,组成一个SOA架构的系统。SOA复杂难学,ESB是性能瓶颈。

三、微服务

1、方法:

  1. 关键点:small、lightweight、automated。

  2. 每三个人一个服务,根据团队规模来持续拆,而不是上来就拆的很细  

  3. 拆分方式;按业务拆、按稳定功能和可变功能拆、按可靠性拆(保证核心功能更可靠)、按性能拆(以免血崩)。不是四选一,而是自由组合。

  4. 基础服务完善,包括不限于发现注册、容错、路由第一优先,API网关、接口框架第二优先,自动化测试、部署、配置中心第三优先,监控、跟踪、安全第四优先。技术服务不足,微服务就成了焦油坑。根据团队规模和需要,不一定每一项都有。

2、基础服务:

  1. 自动化测试、自动化部署、配置中心:是为了将放人力。

  2. 接口框架:提供统一http服务和json格式

  3. 接口网关:外部系统不应该调多个服务在组装,而是一个接口搞定。另外权限控制、流量控制、传输加密。

  4. 注册发现:自理式是每个服务统一注册自己做发现。代理式是注册发现有独立服务,但是独立服务需要关注可靠性。

  5. 路由:服务节点的挑选

  6. 容错:故障时剔除节点和服务熔断。

  7. 监控、跟踪:排查方便。

  8. 安全:数据安全、传输安全、接入安全。可继承到配置中心实现。

四、微内核

微内核指插件化架构,分稳定不动的核心模块和跟随业务发展的插件模块。如手淘的atlas。

  1. 设计关键点:插件管理:核心模块可用代码数据库配置中心等配置各插件信息和加载时机。插件链接:插件如何连接到核心模块。插件通信:解耦的插件因业务需要必然会彼此调用。

  2. OSGI:如eclips。

  3. 规则引擎:常见于保险和促销,满多少减多少,打几折各种规则组合。如Drools 


一、架构模版:存储

  1. SQL:最终都会分库分表,避免各业务重复造轮子,会出现独立的中间件,如淘宝TDDL、百度BDProxy,开源方案有Mysql的Mysql route和360的Atlas。当业务继续发展,会出现存储平台,如淘宝UMP系统。

  2. NoSql:集群规模不断增大,假如2000台机器,利用率要提高10%的话可以节省200台机器。集群之后都会出现存储平台。

  3. 小文件:头像照片等小文件,有Hbase等。淘宝有TFS,京东JFS

  4. 大文件:Hadoop、Hbase、hive、storm等

二、架构模版:开发层和服务层

  1. 开发层:优选成熟的框架、成熟的web服务器、docker容器技术。

  2. 服务器技术:配置中心、服务中心。服务中心分为服务名字系统和服务总线系统。

  3. 服务名字系统:服务提供者向服务名字系统注册,调用者向名字系统请求我需要X服务,名字系统返回服务提供者ip port

  4. 服务总线系统:调用者不直接访问服务提供者。调用者访问总线系统,总线系统访问服务提供者,最后逐层返回。

三、架构模板:网络层

    单机的高可用高性能不涉及网络层。但是站在整个全局看,网络层是很关键。

  1. 负载均衡:DNS、HTTP-DNS(自研DNS,解决DNS不实时)、软件七层Nginx、内核四层LVS、硬件四层F5,虽然Nginx便宜,但是F5性能高,当量很大,有上百台Nginx,这时反而一台F5更便宜。

  2. CDN

  3. 多机房:同城多机房、跨城多机房、跨国多机房

  4. 多中心:以多机房为前提,但却是质的飞越,难度复杂度更高。多机房本质是灾备,切换时允许业务中断一定时间,但多中心要求同时对外提供服务,切业务在多中心间切换,关键难点在与数据已执行和数据事务性。

四、架构内功

  1. 先救火(机器扩容、Nginx一键切换等),后优化(组件化、可用性、性能问题等),再重构(单点改为多中心,服务化)。

一、CAP理论

    准确的定义是:在一个分布式系统中(互相连接并共享数据的节点的集合)中,涉及到读写操作时,只能保证一致性C(客户端读保证得到最新的写结果)、可用性A(返回noerror notimeout)、分区容错性P(出现分区后系统可以继续履职)三个中的两个,必须牺牲另一个。在实际中,无论如何都要满足P,因为如果没有P,在网络故障时,要保重C就必须停止写入,但A要求返回noerror和notimeout,所以A也不满足。网络分区错误类似脑裂、数据同步中断,最坏的情况是主从连接断开,各自成为了独立个体。

二、CAP细节:

    1、CAP:

        (1)CAP关注的是数据,而不是整个系统。比如账号信息是CP,而用户资料是AP。

        (2)CAP是忽略网络延迟的。数据复制是有延迟的,即时在内网也有几毫秒,对于金钱和秒杀类的场景,一致性C是无法完美实现的。但并不是说这类业务不能做分布式,可以把同一用户、同一商品放在同一个机器,同一用户做不了分布式,但是整个业务是个做的,比如根据uid分布在不同机器。

        (3)正常情况下,是可以同时满足CAP的。P强调的是网络分区错误时,CA二选一。但是在网络正常情况下,CAP就可以同时满足。分区故障时,选择CP的,节点1可以注册,节点2不可以注册,可以节点1打日志,恢复注册后同步到节点2,CA同时存在。选择AP的,节点1和节点2是用户两次不同的修改,恢复后可以根据时间优先来进行覆盖,最终达到同时满足AP。

    2、ACID:原子性、一致性(食物开始前和结束后,数据库完整性没有被破会)、隔离性(隔离级别)、持久性(事务提交后就是永久的哪怕发生故障)、和CAP中的AC完全不是相同含义,ACID的C是数据库完整性,A是原子性,指事务要么都完成或都回滚;ACD的C是节点数据一致性,A是读写可用性。

    3、BASE:BA(基本可用)和S(软状态)和E(最终一致性)。是对CAP理论的AP的补充。AP分区时放弃的是网络分区这段时间的一致性,但恢复后最终会一致。

        (1)基本可用:允许损失部分可用性,保证核心可用。如可以不注册,但是要保证登陆,否则影响更大。

        (2)软状态:允许出现中间状态,不影响整体可用性。这种中间状态就是CAP理论的数据不一致。

        (3)最终一致性:数据同步一定是有延迟的,只要保证最终一致性即可。如注册后不超过一分钟可以在各个节点登陆。明星发微博后可以三十分钟内同步到所有用户  

    

三、FMEA方法论:故障模式与影响分析

四、高可用存储-双机架构

    1、主备:简单,但是浪费资源,手动扶正。

    2、主从:主挂后可以继续读,但客户端调用时需要知道谁主谁从。故障后需要人工扶正。

    3、双机切换:在主备和主从上加入了切换功能,数据库自己做还是加入第三方、状态如何传递、如何判定故障、自动还是半自动、是否切换角色。

    4、互链式:主备之间除了数据同步,还要状态同步,可以是网络连接和有线连接等VIP自动飘移。但是这个链接管理是难点,可能出现两个都是主。

    5、中介式:引入第三方,弥补互链式缺点。

    6、模拟式:备机当作客户端访问主机。

    7、主主:客户端任写其一,主主互相同步,不做状态和切换。缺点是主键和数据冲突,如用户id商品库存等无法这么做。

五、高可用存储-集群和分区架构

    1、集群:

        (1)、一主多从多备,多备机都要检测主机状态,通常引入第三方如zookeeper,复杂度变高。

        (2)、多主,数据分散写在不同集群,要考虑均衡性、容错性、伸缩性。

    2、分区:分散在地域机房及以上的级别。如果备份要提供服务,则距离不可太远,否则网络不可靠。

        (1)集中式:北京分区上海分区都备份在西安机房。

        (2)互备式:北京备份在上海,上海备份在广州,广州备份在北京

        (3)独立式:各个分区有各自独立的备份机房。

六、高可用计算

    分为主备。主从。集群。集群分为对称和非对称。对称是执行相同任务,非对称则需要区分任务。非对称集群需要处理分发策略和主机选举策略。计算高可用就是通过冗余来解决单点问题,但存储高可用还有数据一致性、对机器之间同步和状态心跳等问题,更为复杂。

七、业务高可用:异地多活

    1、多活复杂度较高,规模以下企业多备即可

    2、方案:

        (1)同城异区主要应对机房故障。

        (2)异地(北京广州)多活复杂度很大,网络延迟,光缆中断等原因导致金钱等敏感业务是做不了多活的。多活为了高可用,但是数据不一致肯定不可用,这是矛盾的。

        (3)跨国多活:通常只有只读业务,和不同地区为不同客户数据不互通。复杂度不高。

八、异地多活技巧

    同城跨区可以将两机房连起来就像内网一样。跨国面向不同用户提供不同服务复杂度不高。这里主要讨论跨城。复杂度来源主要还是网络延迟和机房异常

    1、保证核心业务和高收入业务:比如登陆,核心业务方案简单。而注册是主要任务,同时异地多活复杂度极高。高收入业务会影响财报和广告主口碑等

    2、最终一致性:同步完成之前,B可以路由回A请求。

    3、对手段同步:mysql只有单线程,redis需要全量rdb文件重新做。同步方式有:异步队列、二次读区、存储系统同步、回源读、重新生成等方式。

    4、只保证大部分用户:异地多活方案无法做到100%。

九、接口级故障:限流

    核心思想是保障核心业务和大部分用户。

  1. 降级:指服务内部处理方案,如关闭注册、看帖不能发帖、应用日志接口。有内部提供URL和独立模块实现的方式。

  2. 熔断:指依赖的其他服务异常。实现的机制是要对对方服务采样统计,设计阈值。

  3. 限流:基于流量限流如1分钟超过一万就丢弃;基于资源限流如负载高低和队列容量等。

  4. 排队:借助队列系统。一号店秒杀方案:排队模块,一个商品一个队列;调度模块,业务服务空闲时出队一个交给业务服务处理;业务模块,真正处理业务的。