在系统运行期间,有可能硬件的损坏、软件运行中流量激增导致宕机等,导致系统不能正常运行。为了解决这些异常,我们可以从以下几个来考虑。
冗余
比如我们旅游拍了很多照片,放在手机里怕丢怎么办啊,我们会上传到百度网盘,这个就是冗余。
冗余是最简单的办法,同时也要做到故障转移,比如为了保证nginx的高可用,我们会启动两个nginx,一个是主一个是备,还要再弄一个Keepalive,当主挂了,Keepalive会自动切换到备份的nginx。
比如mysql数据库,我们会做主从,slave通过binlog同步master的数据,当master挂了,会切换到slave(由于数据的同步是异步的,此时可能会丢失数据)。
比如redis,我们采用哨兵或者集群的形式,当master挂了自动检测并切换到slave。
比如消息队列,比如hadoop,比如kafka,比如elasticsearch等等,都是通过冗余来保证系统或者副本的高可用性。
如果条件允许,还需要做到多地多活。不然备份同一个机房,机房发生火灾,数据全部丢失,备份同一个地点,发生地震洪水等自然灾害,数据全部丢失。
超时重试
当我们调用第三方接口的时候,或者网关层调用业务逻辑层等,由于网络或者其他问题,导致我们的请求没有得到响应或者很久才得到响应,为了保证我们的服务是高可用的,我们通常会设置重试的次数和超时的时间。
重试的次数不能太大,这样很容易请求流量翻了很多倍,造成被请求服务的雪崩。
超时的时间不能设置的太长,这样很容易让自己一直等待,积压了很多请求,导致自己服务雪崩。也不能太短,还没响应就直接取消了,造成请求成功率下降。
如果A调用B,B调用C,此时A的超时时间应该要长与B调用C的超时时间。比如A->B是100毫秒,B->C是200毫秒,B在150毫秒拿了C的响应,但是A已经过期了,然后A又开始了重试,请求流量又涨涨涨。
我们重试的机制,必须要确定被调用方的接口是幂等性的,不然会造成数据的错乱。
降级熔断
当我们调用第三方接口的时候,第三方响应慢或者没响应,比如宕机或者网络不可用,不断的请求,会占用我们的系统资源,更甚者会导致我们系统的雪崩,所以我们通过降级熔断来避免雪崩情况。
比如我们原先调用第三方获取商品的信息,此时第三方不可用,我们就调用自己的本地缓存、redis缓存或者直接返回空,这个叫降级。如果第三方一直不可用,那我们就不调用第三方,直接自己处理,这个叫熔断。如果熔断了,需要异步调用看第三方服务是否恢复了,如果恢复了,取消熔断。
目前比较火的就是sentine以及hystrix。
幂等设计
当我们提供接口给第三方的时候,由于第三方可能的重试,造成数据的错乱,所以我们要保证我们的系统是幂等的。接口幂等设计
限流
当我们提供接口给第三方的时候,由于第三方可能大规模的调用,流量超过了我们系统的峰值,导致我们系统的不可用。我们可以想直接降级来解决,返回空或者缓存数据,但是有些业务场景,比如秒杀,就不能通过降级来解决,此时就需要限流,让有限的流量进来。常用的限流算法有令牌桶和漏桶两个。有时候也根据计数器,来限制数据库连接池、线程池的并发数。
压测
不管是哪种限流方式,我们都需要知道我们系统的峰值在哪里,所以需要压测,方便扩容和设置限流阈值。
线下压测
包括使用apache ab、apache jmeter、loadrunner、Tcpcopy 这些工具,对接口进行压测,对测试的结果进行性能优化以及确认系统的阈值。压测的时候尽量保证硬件设施和测试数据接近线上,这样才可以保证结果的准确性。
线上压测
当服务器比较少的时候,我们还原线上的环境需要的开销其实不太大,如果服务器很多的时候,那开销就很大了,所以要利用线上的环境来进行压测。
线上压测包括读压测、写压测、读写混合压测。写压测的时候,要注意写的数据和真是数据隔离。
比如我们有100个服务做集群,在凌晨或者流量小的时候,逐步引流到指定的服务,比如从100到90到80,监控各个服务、数据库、第三方中间件等的cpu内存情况。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。