2. 系统架构优化-从可用性考虑
2.1 网站可用性度量与考核
(1) 可用性度量,一般用多少个9
来度量网站可用性。4
个9
,99.99%
时间网站可用,也就是一年将近53
分钟不可用,就已经算是有自动恢复能力的高可用性了。一般两个9
是基本可用,三个9
是较高可用,五个9
是极高可用。越到后面付出的成本增加越快,还需要运气加持。
(2) 可用性考核
一般的,故障分级如下:
- 网站整体不可用:事故级故障,权重100;
A
类故障:网站核心功能不可用,访问不顺畅,权重20;B
类故障:非核心功能不可用,或者少数用户核心功能不可用,权重5;C
类故障:除以上情况的故障,权重1;
最终按照权重分数分锅。
2.2 高可用的网站架构
目前的大型系统都会把各个模块按照功能职责分层。分层如下:
- 应用层:直接接收处理用户的请求,执行业务逻辑,调用服务层。
- 服务层:多个应用层产品依赖的、可以复用的通用服务设为服务层,如用户登录、注册,
session
服务等。 - 数据层:直接存取数据的服务,如数据库、缓存数据库、搜索服务、文件服务等。
这样最大的好处是可以方便的按照职责建立集群,不同层次的集群采用不同的方法实现高可用:
- 应用层服务集群需要处理用户请求,则在集群入口部署反向代理服务器进行负载均衡实现高可用;
- 服务层一般由本内网的其他服务调用,直接使用
ribbon
或自带ribbon
的feign
进行调用,在软件层面就可以实现负载均衡; - 而数据层集群则可以设置主从结点、数据持久化等手段进行数据冗余、数据备份实现高可用。
2.3 应用层集群的高可用
(1) 负载均衡进行失效转移
当负责负载均衡的反向代理服务器提高心跳检测机制发现集群中某一台服务器失去响应时,则将其移除,将请求转移到其他服务器上,提高了可用性。
(2) 集群的session
管理
集群环境下,session
管理要比单机时难的多,因为要想办法让每台服务器的session
一样。一般有一下几种方法:
session
复制:一台服务器有某个session
,就通过复制让所有服务器都有这个session
。这种方法简单,但是数量大且改动频繁时会占用不少集群的通信资源。session
绑定:通过负载均衡的源地址哈希算法实现,同一台客户机的请求总是落在同一台服务器,这样session
就不需要同步到集群所有机器。但这样可用性低,当这台服务器宕机时,那台客户机的请求将会落到其他服务器,但此时其他服务器没有这客户机相关的session
,一些相关的业务无法进行。这种方法很少用到。cookie
记录状态信息,由客户端发送。这种方法无需session
,自然没有了管理烦恼。但是cookie
的大小受限、用户可能会将其关闭,传输影响性能,不够安全,因此也不能完全替代session
。一般只有状态信息很小,安全性要求不高时用cookie
。- 如果不计较成本,比较好的方式是建立一个专门的
session
服务器,与无状态的应用服务器分离。应用服务器需要状态信息时都去请求这个session
服务器。
2.4 服务层集群的高可用
服务层集群提供基础公共服务,也可以进行负载均衡,除此之外还有:
- 分级管理:核心服务使用更好的硬件运行,在不同的物理机上部署,其使用的数据服务部署在不同地域等。
- 超时设置:超时调用返回异常信息,及时释放资源,调用者可以选择重试或者调用其他服务实例。
- 异步调用:某个调用可以拆成几个独立模块的调用时,则可以分别进行异步调用,防止一个模块的失败或阻塞影响其他模块。
- 服务降级:服务器快崩时可以采用这种办法保证可用性。拒绝低优先级的调用、或者干脆关闭非核心的服务,如双十一的评价功能;还可以采取拒绝服务的策略,随机或者挑选一些用户拒绝掉请求,防止全军覆没的惨剧。
- 幂等性设计:服务调用时有时会发生因为网络原因返回失败,但实际调用请求已经成功处理了的,这时调用方会错误的去重复调用,如果这个调用是转账操作后果则十分严重。我们需要设计的接口具有幂等性,即服务层接口重复调用和调用一次产生的结果相同,一些操作天然就是幂等性如设置用户未男性,一些则不是。所以,需要额外的设计让接口具有幂等性,例如转账操作入参应该加上一个交易单号,只要第一次成功这个单号就设置为已完成,后续进行多少遍都不会出错。
2.5 数据层的高可用性
数据是最宝贵的资产,数据的完整性、正确性是企业生存的命脉。数据库集群不同于无状态的服务层,当一个机器宕机后不能把原本访问它的请求落到其他机器上,因为数据库是有状态的,每台机器上存放的数据都不一样。还要注意数据库集群与分布式数据库的区别,集群是多个独立的数据库系统,分布式数据库则是多个节点组成的一个系统。
(1) 数据持久性
数据持久性除了将数据写入本地磁盘外,还要将数据同步到多个副本存放到不同的物理存储设备上,核心数据还要上传云端或异地设备上持久化存储,确保万无一失。发生灾害或者其他故障时就可以根据持久化的数据进行恢复。
(2) 数据一致性
当整个网站的数据库系统是由多个节点协作组成的(集群、主从、分布式),就有可能发生任意某两个间无法通信的问题,这时数据的一致性就可能被破坏,除非一旦有两个节点失联就停用整个数据库服务。上述问题其实有一个CAP
理论:
- P:分区容忍性,即是否允许节点间某个时间无法通信。
- A:可用性,即保证整个数据库系统不是物理故障等因素都是可以被访问的。
- C:一致性,即各个节点的数据都在正确的状态。
CAP
理论指出,三者不能同时满足,只能满足两者。P
是必然要满足的,因为无法保证节点间的网络用不出错,何况对集群进行伸缩(增删节点)时也会需要暂停一些节点通信。一般大型网站会在C
和A
中选择A
,毕竟一个那么大的集群不能说停就停,优先保证可用性。所以有时会出现数据不一致的情况,如双十一商品超卖,这只能通过非技术手段解决了。
数据强一致:数据库中的数据总是处于一致的状态。数据用户一致:数据库中的数据不一定时刻一致,但是处理用户请求最终返回的数据通过纠错与校验是正确的。数据最终一致:返回给用户的数据也不一定是正确的,数据只是会在一定时间后自动恢复到正确的状态。
(3) 主从备份与失效转移
由于集群中不同节点的数据都不一样,无法进行失效转移,我们可以未每个集群节点(主节点)设置若干个从节点,从节点的数据与主节点同步。这样实现了数据的备份、冗余,读写还可以分离因为读操作可以专门落到从数据库,而主节点发生故障时,由于从节点的数据是一样的,可以将从节点升级为主节点代替,实现失效转移。
2.6 质量保证
在各层服务都优化给力的情况下,还要科学的管理网站保证质量。
(1) 发布
由于发布时服务器会经历停掉原服务,拉取最新代码,重新运行服务。这个过程会导致服务器无法访问,如果我们不希望这期间用户完全无法访问,可以先停掉集群中部分服务,升级完成后再停一部分,逐步完成整个集群的升级。
(2) 自动化测试
发布完成后要进行回归测试,人力测试的话速度慢、成本高、覆盖率低,一般采用脚本或者脚本化工具进行自动测试。
(3) 预发布验证
由于测试环境与生产环境的差别,最好再上线前进行预发布验证。预发布就是将代码发布到与正式环境一样的机器,但是不开放公网访问而是由内部人员内网访问测试。但是注意,预发布时操作的数据库是正式环境的,注意不要搞事情,一切操作都要按正式的来。
(4) 代码版本控制
科学、正确的使用版本控制工具,发布正确的代码版本。
(5) 灰度发布
灰度发布可以随时将运行的代码回滚到之前的某个版本,紧急情况可以直接回退到之前的稳定版本减少损失。
2.7 监控
没有监控,网站运行就像盲人骑瞎马,可用性无从谈起。
(1) 监控数据采集
- 用户行为数据采集:这对网站设计优化、个性化推荐等很重要。可以在后端使用日志记录每个用户做了些什么,比较方便但是数据可能会失真,如
ip
地址可能不是用户的真实地址而是某个代理的,还有访问路径等信息记录不了;前端嵌入js
脚本可以精准的记录用户行为,但是比较麻烦。 - 服务器性能监控:实时监控各硬件的负载情况,发现情况不对则可以将故障扼杀在摇篮里。
- 运行数据报告:这个不同于服务器性能监控,直接反应硬件的情况。运行数据报告要在程序中埋点,进行一些事件的记录,如缓存命中率、响应延迟时间。
(2) 监控管理
收集到各项数据后,就要进行分析,然后做出一些决定。
- 预警:例如监控到服务的慢请求超过预设的阈值,则在钉钉@负责人,或者服务报异常等场景。
- 失效转移:除了在访问服务时失败进行失效转移,还可以由监控系统主动通知进行失效转移。
- 优雅的服务降级:监控到某个服务负载很低,而另一个服务负载很低,就可以卸载一些低负载服务实例,从而多部署一些高负载服务。