关于网站高可用性问题的总结

本文是工作中遇到的网站高可用问题及相关解决思路和方法的总结,比较零碎,且会在后续工作过程中不停丰富,有不对之处,请指正。

前后端分离

前后端分离后,可以使用更加轻量级的web容器部署静态资源,如nginx等,还可以对静态资源进行cdn加速,同时针对营销或者活动页面,可以使用内容管理平台,实时更改页面,快速迭代。服务端出来后,专注于业务流程,且为后续的服务拆分提供了便利。

按照业务领域拆分服务

随着业务量的增加,单体架构不能再满足高并发场景,按照业务领域将服务端拆分为多个独立的服务。服务拆分后,这些服务独立部署,独立扩展,服务之间完全解耦。

拆分后的服务通常是无状态的,会话管理等通常交给网关层,或者统一的sso服务,业务服务省去了复杂的会话管理,服务效率提高;

拆分后的服务支持分布式多实例部署,从而达到按需扩展的目的,在应对突发的流量暴增时,如营销活动等,可以迅速按需扩展,提高站点的可用性。

集群部署,负载均衡

拆分后的服务支持分布式部署,可以使用集群部署、负载均衡的方式进一步提升网站可用性。集群部署模式下,多台实例分担流量,并能灵活地增减成员实例;负载均衡机制可以确保某些成员实例失效时,能迅速将流量切换到其他正常成员实例上,从而提高站点的可用性。

负载均衡的方式通常有两种:

  • 硬件负载——F5 7层或者4层网络代理
  • 软件负载——nginx反向代理

负载均衡的算法通常有:轮询法、随机法、源地址哈希法、加权轮询法、加权随机法、最小连接数法

可参考:6种负载均衡算法

使用缓存提高查询服务性能

在查多写少的场景,非常适用使用缓存来提升查询服务的性能,减轻对数据库的压力。通常使用redis cluster作为缓存服务器,redis cluseter机制能很大程度上保证缓存服务的高可用性,及时缓存服务故障,还能从数据库获取信息。

spring+mybatis+redis做扩展缓存的具体实践后续给出。

数据库读写分离,分库分表

业务迅猛到后面,当用户在千万级别时,数据库会成为最后的瓶颈,首先可以根据业务场景分析,考虑做读写分离。写到master库,读salve库。如果读写分离也无法满足高并发要求,需要考虑使用分表分库的思路进行横向扩展。数据库只允许单表操作对于分表分库落地非常友好,因此,在开发前期就约定,业务数据库操作必须单表操作。

读写分离,分库分表的技术手段还没有尝试过,但是现在的系统设计之初就是按照单表操作约定的,因此后续进行横向扩展时会比较便利。

orcle不是分布式数据库,但提供了RAC模式。参考:oracle rac和分布式数据库的区别

分库分表的实际落地方案是有一定难度和取舍的,其中最关键点需要考虑到sharding数的扩张,有空研究下。

数据库尽量少使用事务

一般意义上,大家都会使用数据库级别的事务来保证业务操作的原子性和数据一致性,但是数据库事务的使用会带来性能上的损耗,为此,除非非用不可,其他时候尽量少用。实践下来,这一条是可以做到的。

那么什么时候可以不用呢?简单讲前置数据库操作可以重复进行时,就可以不做事务控制。就是比如用户注册场景,会先insert ‘通行证credential’表,再insert ‘用户user’表,不使用事务控制,我们可以将credential的操作放在user表操作前面,即使credential成功,user插入失败,对数据一致性没有影响,因为用户再次注册会重新生成一个userId,能重新insert credential后,再insert user表。对于用户的影响也和加上事务控制的效果一致。不好的影响在于多生成了一条credential记录。这里的insert ‘通行证credential’表操作就是前置数据库操作,但是非关键数据库操作,因为注册的最终效果是必须在user表中插入一条userId,后续登录时会从user表中获取用户信息进行验证。

什么时候非用不可呢?在订单/支付等业务系统时,同一笔订单不允许重复支持这是底线,因此在订单支付场景,需要加上事务控制,避免订单重复支付发生。

异步化非关键业务

非关键业务是指用户不关心的业务环节,比如注册完成后,发送营销短信通知给用户,用户并不关心这个营销短信是否能及时送达。对于此类非关键业务环节,可以在设计上进行异步化处理。

常用的处理方式有:

  • 简单的处理方式——在流业务线程之外,另起线程/线程池来出来这类异步任务;特别需要主要线程池的使用,通常要同时限定thread size和queue size,否则在某些异常情况下,异步线程全部阻塞,导致任务堆积,会影响到主业务线程的执行。
  • 更好的方式——使用queue来作为任务的中转站,有后台job进行任务的离线处理,这样做还能有其他便利之处,比如job作为基础设施存在,能够有效利用计算资源。

异步化需要考虑业务场景是否是关键场景,任务是否可以容忍丢失。如果不容忍丢失,则智能使用queue的方式,且要对消息进行持久化。

使用异步IO

tomcat使用NIO提升服务性能,对提高网站的可用性也是有益的。

NIO vs BIO vs AIO 需要重新研究下,后续补上。

服务降级,服务熔断

网站架构发展到后面,服务之间的调用变得错综复杂,故障发生之后能够清晰知道是那条服务链路出现了问题,并能及时处理变得很重要。因此需要对服务进行治理,提供服务注册、发现机制,在此基础上,当发现某个服务异常时,可以对该服务或者某个调用渠道进行服务降级,或者针对下游某个异常服务进行熔断处理,确保网站其他非异常服务的可用性。

比如:统一登录服务场景,需要根据不同的登陆方式,调用下游不同的账户验证服务,A账户验证服务一旦出现问题不能殃及B账户验证,所以可以在A账户/B账户验证服务的调用上加上熔断机制处理,确保A账户验证服务调用和B账户验证服务调用之间互不影响。

这一点的设计思想是:理性地砍掉腐烂的手,继续前进,是一种舍得精神。

 

TODO......

 

posted @ 2017-05-01 21:24  倒骑的驴  阅读(1505)  评论(1编辑  收藏  举报