一、架构层面
不同的系统在不同的业务发展阶段,对系统会有不同的考察指标,进行架构设计和技术选型更多是一种权衡和折中的选择,如何进行存储方案选型?是选择Mysql这类OLTP数据库还是MPP型OLAP数据仓库。如何进行消息队列选型?是选择可靠性更强的RabbitMQ还是还是轻松吞吐百万流量的Kafka,这些都是需要根据具体的业务和场景来抉择的。
1.消除单点故障,保障HA
集群化部署
在服务层面,如果是但实例提供服务,在流量过大等异常情况可能造成单点故障,使得服务不可用,这种情况,可以将服务进行集群化部署,当单节点不可时可以及时切换到健康实例。但在进行集群化改造过程中,重点要做的事情是将有原有状态的服务改造成无状态的服务,这样在进行服务被负载到另外的节点也能够正常使用,其中重点需要改造的包括本地缓存、本地锁等。
在存储层面,重点是考虑将数据库服务进行分布式改造,可以将原单机数据库改造成分布式数据库,这样不会因为一个数据库服务不可用影响到整个数据库服务。
2.保障数据一致性
CAP优先项选择
在将系统进行微服务或分布式改造后,由于不同服务的架构设计异构和服务间的通信,可能出现服务异常或者通信异常,最终导致数据不一致的情况。在处理服务异常或数据异常的顶层涉及上,首先需要考虑的是分布式系统固有的CAP特性,即分布式服务在一致性、可用性、分区容错性者三方面只能取其二。对于实时性要求不高的业务系统一般会采用优先保障可用性和分区容错性。
幂等设计
针对SLA要求比较高的服务,在并发量比较大的情况下,可能会涉及到一些幂等性问题,这就需要在进行系统或架构设计的时候进行幂等性设计,幂等性设计的一种思路就是有一个状态值能够表征该次请求是否为重复下发的,这个状态值既能在Mysql数据库中保存,也能在redis缓存中保存,另一种思路是有机制保障重读请求会失败,比如通过mysql数据库的唯一性主键来保障。
分布式事务处理
在分布式环境中,不像本地一样通过本地事务就能保障数据一致,在分布式环境中需要采用分布式事务来实现,一种思路是通过加分布式锁来保障并行事务在竞争锁资源的时候串行化执行,另一种思路是通过类似二阶段提交、三阶段提交、TCC事务这类分布式解决方案来实现。
3.消息队列服务解耦
通过消息队列用来对服务间的依赖进行解耦,同时也能可以用来保障服务间的可靠性通信,比如常见的RabbiMQ在可靠性的保障就非常全面,他既能通过confirm机制保障生产者生产的消息能可靠投送到消息中间件,其本身的持久化机制也能保障中间件宕机数据不丢失,另外也可以通过ACK的机制来保障消费者的数据可靠性消费,但设置为手动ACK时,只有在消费者正常消费后才确认。
二、代码层面
1.设置合理的重试次策略
服务与服务之间的调用可能有失败的可能,比如两个业务服务间,因业务服务和数据库服务间都有可能,所以针对可靠性要求比较高的场景,就需要设置合理的重试机制。
重试机制中最重要的指标包括重试的次数和重试的间隔,这个因为具体的业务场景而异。
设置重试的时候也一定要设置失败策略,就是要设重试失败的次数和重试失败的时间,如果一致重试下去,一方面会影响到正常业务,另一方面也是对下游系统造成一定的压力。
2.合理配置线程池、连接池大小
线程池和连接池是池化技术的具体实现,其作用是为了资源的复用,在针对具体的业务时,需要合理的设置其大小。
3.核心业务和非核心业务区别处理
在进行系统设计的时候,服务间强依赖的服务越少,系统整体基础稳定性就越高。可以这么理解,在进行业务处理过程中,如果不加区分的所有业务在一个方法中执行,那任何一个业务处理出错都会影响主流程的执行,其出错的概率越大。
所以在业务层面可以进行一些梳理,哪些业务是核心业务,是必须要要保障不出错才能正常执行后续业务,哪些业务是非核心业务,及时出错也不会影响后续业务,针对核心业务可以采用重试等策略,针对非核心业务可以才行错误记录、离线补偿、异步处理等方式。
4.限流、排队、熔断、降级
根据墨菲定律,只要事情可能出错,那就一定会出错。一个系统只要有出问题的可能性,那后续运行的过程中肯定是会出问题的,所以这一部分,我们主要探讨的是如果做到事故的时候处理。
稳定性问题一般出现在系统复杂度高、流量大的情况下,针对这样的情况,就需要提前考虑到流控措施,如果流量过大,就需要进行限流,可以将过高的请求保存在阻塞队列中,待流量洪峰过去后在慢慢释放流量。
同样,如果服务确实无法支持那么大的流量,也可以进行熔断和降级,和限流的区别在于,为保障整体服务的不受牵连,目前该服务就暂时不可用。
三、运维层面
1.有完善的日志功能
针对线上系统,如果出现问题,最有效的问题排查方式就是从系统日志中排查出问题故障。针对单体的应用,Java中有非常丰富的比如log4j、logback等日志系统,针对分布式系统,可以采用ELK架构部署。
2.有完善的运维和监控系统
监控告警系统是系统进行稳定性保障最基础的功能,缺少相关功能就如同没有仪表盘的车开在高速路上,根本无法让你人安心行驶。
所以对于要上线生产环境,需要及时获取运行状态和用户问题反馈的话,需要有完善的运维和监控告警功能,相关功能可以分为业务层面和系统层面,业务层面主要监控业务层的告警信息,系统层面主要监控系统运行中比如OS、网络、数据库、MQ等出现的异常。
四、流程和规范层面
1.更新上线有回滚、补偿预案
进行上线之前,需要做好上线的预案,清楚列明更新的哪些功能,哪些业务可能会收到影响。
针对风险较大的操作,更新先需要做好失败回滚和补偿的预案。
参考资料
Java后端稳定性建设最佳实践:https://blog.csdn.net/jack1liu/article/details/112647026
3+1保障:高可用系统稳定性是如何炼成的?:https://developer.aliyun.com/article/781491
稳定性全系列(一):如何做好系统稳定性建设:https://www.infoq.cn/article/z4ssmnks3w4ebbustyo1