我终于搞懂了微服务,太不容易了...( 六 )


服务提供者如何保障稳定性
①限流
限流就是限制服务请求流量,服务提供者可以根据自身情况(容量)给请求设置一个阈值,当超过这个阈值后就丢弃请求,这样就保证了自身服务的正常运行 。
阈值的设置可以针对两个方面考虑:

  • QPS,即每秒请求数
  • 并发线程数
从实践来看,我们往往会选择后者,因为 QPS 高往往是由于处理能力高,并不能反映出系统"不堪重负" 。
除此之外,我们还有许多针对限流的算法 。例如令牌桶算法以及漏桶算法,主要针对突发流量的状况做了优化 。
第三方的实现中例如 guava rateLimiter 就实现了令牌桶算法 。在此就不就细节展开了 。
②重启与回滚
限流更多的起到一种保障的作用,但如果服务提供者已经出现问题了,这时候该怎么办呢?
这时候就会出现两种状况:一是本身代码有 Bug,这时候一方面需要服务消费者做好熔断降级等操作,一方面服务提供者这边结合 DevOps 需要有快速回滚到上一个正确版本的能力 。
更多的时候,我们可能仅仅碰到了与代码无强关联的单机故障,一个简单粗暴的办法就是自动重启 。
例如观察到某个接口的平均耗时超出了正常范围一定程度,就将该实例进行自动重启 。
当然自动重启需要有很多注意事项,例如重启时间是否放在晚上,以及自动重启引起的与上述节点摘除一样的问题,都需要考虑和处理 。
在事后复盘的时候,如果当时没有保护现场,就很难定位到问题原因 。所以往往在一键回滚或者自动重启之前,我们往往需要进行现场保护 。
现场保护可以是自动的,例如:
  • 一开始就给 jvm 加上打印 gc 日志的参数 -XX:+PrintGCDetails
  • 或者输出 oom 文件 -XX:+HeapDumpOnOutOfMemoryError
  • 也可以配合 DevOps 自动脚本完成,当然手动也可以
一般来说我们会如下操作:
  • 打印堆栈信息,jstak -l 'JAVA进程PID'
  • 打印内存镜像,jmap -dump:format=b,file=hprof 'java进程PID'
  • 保留 gc 日志,保留业务日志
③调度流量
除了以上这些措施,通过调度流量来避免调用到问题节点上也是非常常用的手段 。
当服务提供者中的一台机器出现问题,而其他机器正常时,我们可以结合负载均衡算法迅速调整该机器的权重至 0,避免流量流入,再去机器上进行慢慢排查,而不用着急第一时间重启 。
如果服务提供者分了不同集群/分组,当其中一个集群出现问题时,我们也可以通过路由算法将流量路由到正常的集群中 。这时候一个集群就是一个微服务分组 。
而当机房炸了、光缆被偷了等 IDC 故障时,我们又部署了多 IDC,也可以通过一些方式将流量切换到正常的 IDC,以供服务继续正常运行 。
切换流量同样可以通过微服务的路由实现,但这时候一个 IDC 对应一个微服务分组了 。
除此之外,使用 DNS 解析进行流量切换也是可以的,将对外域名的 VIP 从一个 IDC 切换到另一个 IDC 。
作者:fredalxin
编辑:陶家龙
出处:https://fredal.xin/

【我终于搞懂了微服务,太不容易了...】


推荐阅读