From:http://pt.alibaba-inc.com/wp/experience_1224/robustness-of-implement.html
Dubbo作为远程服务暴露、调用和治理的解决方案,是应用运转的经络,其本身实现健壮性的重要程度是不言而喻的。
这里列出一些Dubbo用到的原则和方法。
一、日志
日志是发现问题、查看问题一个最常用的手段。
日志质量往往被忽视,没有日志使用上的明确约定。
重视Log的使用,提高Log的信息浓度。
日志过多、过于混乱,会导致有用的信息被淹没。
要有效利用这个工具要注意:
1. 严格约定WARN、ERROR级别记录的内容
· WARN表示可以恢复的问题,无需人工介入。
· ERROR表示需要人工介入问题。
有了这样的约定,监管系统发现日志文件的中出现ERROR字串就报警,又尽量减少了发生。
过多的报警会让人疲倦,使人对报警失去警惕性,使ERROR日志失去意义。
再辅以人工定期查看WARN级别信息,以评估系统的“亚健康”程度。
2. 日志中,尽量多的收集关键信息
哪些是关键信息呢?
· 出问题时的现场信息,即排查问题要用到的信息。如服务调用失败时,要给出 使用Dubbo的版本、服务提供者的IP、使用的是哪个注册中心;调用的是哪个服务、哪个方法等等。这些信息如果不给出,那么事后人工收集的,问题过后现场可能已经不能复原,加大排查问题的难度。
· 如果可能,给出问题的原因和解决方法。这让维护和问题解决变得简单,而不是寻求精通者(往往是实现者)的帮助。
3. 同一个或是一类问题不要重复记录多次
同一个或是一类异常日志连续出现几十遍的情况,还是常常能看到的。人眼很容易漏掉淹没在其中不一样的重要日志信息。要尽量避免这种情况。在可以预见会出现的情况,有必要加一些逻辑来避免。
如为一个问题准备一个标志,出问题后打日志后设置标志,避免重复打日志。问题恢复后清除标志。
虽然有点麻烦,但是这样做保证日志信息浓度,让监控更有效。
二、界限设置
资源是有限的,CPU、内存、IO等等。不要因为外部的请求、数据不受限的而崩溃。
1. 线程池(ExectorService)的大小和饱和策略
Server端用于处理请求的ExectorService设置上限。
ExecutorService的任务等待队列使用有限队列,避免资源耗尽。
当任务等待队列饱和时,选择一个合适的饱和策略。这样保证平滑劣化。
在Dubbo中,饱和策略是丢弃数据,等待结果也只是请求的超时。
达到饱和时,说明已经达到服务提供方的负荷上限,要在饱和策略的操作中日志记录这个问题,以发出监控警报。
记得注意不要重复多次记录哦。
(注意,缺省的饱和策略不会有这些附加的操作。)
根据警报的频率,已经决定扩容调整等等,避免系统问题被忽略。
2. 集合容量
如果确保进入集合的元素是可控的且是足够少,则可以放心使用。这是大部分的情况。
如果不能保证,则使用有有界的集合。当到达界限时,选择一个合适的丢弃策略。
三、容错-重试-恢复
高可用组件要容忍其依赖组件的失败。
1. Dubbo的服务注册中心
目前服务注册中心使用了数据库来保存服务提供者和消费者的信息;
注册中心集群不同注册中心也通过数据库来之间同步数据,以感知其它注册中心上提供者。
注册中心会内存中保证一份提供者和消费者数据,数据库不可用时,注册中心独立对外正常运转,只是拿不到其它注册中心的数据。
当数据库恢复时,重试逻辑会内存中修改的数据写回数据库,并拿到数据库中新数据。
2. 服务的消费者
服务消息者从注册中心拿到提供者列表后,会保存提供者列表到内存和磁盘文件中。
这样注册中心宕后消费者可以正常运转,甚至可以在注册中心宕机过程中重启消费者。
消费者启动时,发现注册中心不可用,会读取保存在磁盘文件中提供者列表。
重试逻辑保证注册中心恢复后,更新信息。
四、重试延迟策略
上一点的子问题。Dubbo中碰到有两个相关的场景。
1. 数据库上的活锁
注册中心会定时更新数据库一条记录的时间戳,这样集群中其它的注册中心感知它是存活。
过期注册中心和它的相关数据 会被清除。数据库正常时,这个机制运行良好。
但是数据库负荷高时,其上的每个操作都会很慢。这就出现:
· A注册中心认为B过期,删除B的数据。
· B发现自己的数据没有了,重新写入自己的数据。
的反复操作。这些反复的操作又加重了数据库的负荷,恶化问题。
可以使用下面逻辑
当B发现自己数据被删除时(写入失败),选择等待这段时间再重试。
重试时间可以选择指数级增长,如第一次等1分钟,第二次10分钟、第三次100分钟。
这样操作减少后,保证数据库可以冷却(Cool Down)下来。
2. Client重连注册中心
当一个注册中心停机时,其它的Client会同时接收事件,而去重连另一个注册中心。
Client数量相对比较多,会对注册中心造成冲击。
避免方法可以是Client重连时随机延时3分钟,把重连分散开。
Dubbo作为远程服务暴露、调用和治理的解决方案,是应用运转的经络,其本身实现健壮性的重要程度是不言而喻的。
这里列出一些Dubbo用到的原则和方法。
一、日志
日志是发现问题、查看问题一个最常用的手段。
日志质量往往被忽视,没有日志使用上的明确约定。
重视Log的使用,提高Log的信息浓度。
日志过多、过于混乱,会导致有用的信息被淹没。
要有效利用这个工具要注意:
1. 严格约定WARN、ERROR级别记录的内容
· WARN表示可以恢复的问题,无需人工介入。
· ERROR表示需要人工介入问题。
有了这样的约定,监管系统发现日志文件的中出现ERROR字串就报警,又尽量减少了发生。
过多的报警会让人疲倦,使人对报警失去警惕性,使ERROR日志失去意义。
再辅以人工定期查看WARN级别信息,以评估系统的“亚健康”程度。
2. 日志中,尽量多的收集关键信息
哪些是关键信息呢?
· 出问题时的现场信息,即排查问题要用到的信息。如服务调用失败时,要给出 使用Dubbo的版本、服务提供者的IP、使用的是哪个注册中心;调用的是哪个服务、哪个方法等等。这些信息如果不给出,那么事后人工收集的,问题过后现场可能已经不能复原,加大排查问题的难度。
· 如果可能,给出问题的原因和解决方法。这让维护和问题解决变得简单,而不是寻求精通者(往往是实现者)的帮助。
3. 同一个或是一类问题不要重复记录多次
同一个或是一类异常日志连续出现几十遍的情况,还是常常能看到的。人眼很容易漏掉淹没在其中不一样的重要日志信息。要尽量避免这种情况。在可以预见会出现的情况,有必要加一些逻辑来避免。
如为一个问题准备一个标志,出问题后打日志后设置标志,避免重复打日志。问题恢复后清除标志。
虽然有点麻烦,但是这样做保证日志信息浓度,让监控更有效。
二、界限设置
资源是有限的,CPU、内存、IO等等。不要因为外部的请求、数据不受限的而崩溃。
1. 线程池(ExectorService)的大小和饱和策略
Server端用于处理请求的ExectorService设置上限。
ExecutorService的任务等待队列使用有限队列,避免资源耗尽。
当任务等待队列饱和时,选择一个合适的饱和策略。这样保证平滑劣化。
在Dubbo中,饱和策略是丢弃数据,等待结果也只是请求的超时。
达到饱和时,说明已经达到服务提供方的负荷上限,要在饱和策略的操作中日志记录这个问题,以发出监控警报。
记得注意不要重复多次记录哦。
(注意,缺省的饱和策略不会有这些附加的操作。)
根据警报的频率,已经决定扩容调整等等,避免系统问题被忽略。
2. 集合容量
如果确保进入集合的元素是可控的且是足够少,则可以放心使用。这是大部分的情况。
如果不能保证,则使用有有界的集合。当到达界限时,选择一个合适的丢弃策略。
三、容错-重试-恢复
高可用组件要容忍其依赖组件的失败。
1. Dubbo的服务注册中心
目前服务注册中心使用了数据库来保存服务提供者和消费者的信息;
注册中心集群不同注册中心也通过数据库来之间同步数据,以感知其它注册中心上提供者。
注册中心会内存中保证一份提供者和消费者数据,数据库不可用时,注册中心独立对外正常运转,只是拿不到其它注册中心的数据。
当数据库恢复时,重试逻辑会内存中修改的数据写回数据库,并拿到数据库中新数据。
2. 服务的消费者
服务消息者从注册中心拿到提供者列表后,会保存提供者列表到内存和磁盘文件中。
这样注册中心宕后消费者可以正常运转,甚至可以在注册中心宕机过程中重启消费者。
消费者启动时,发现注册中心不可用,会读取保存在磁盘文件中提供者列表。
重试逻辑保证注册中心恢复后,更新信息。
四、重试延迟策略
上一点的子问题。Dubbo中碰到有两个相关的场景。
1. 数据库上的活锁
注册中心会定时更新数据库一条记录的时间戳,这样集群中其它的注册中心感知它是存活。
过期注册中心和它的相关数据 会被清除。数据库正常时,这个机制运行良好。
但是数据库负荷高时,其上的每个操作都会很慢。这就出现:
· A注册中心认为B过期,删除B的数据。
· B发现自己的数据没有了,重新写入自己的数据。
的反复操作。这些反复的操作又加重了数据库的负荷,恶化问题。
可以使用下面逻辑
当B发现自己数据被删除时(写入失败),选择等待这段时间再重试。
重试时间可以选择指数级增长,如第一次等1分钟,第二次10分钟、第三次100分钟。
这样操作减少后,保证数据库可以冷却(Cool Down)下来。
2. Client重连注册中心
当一个注册中心停机时,其它的Client会同时接收事件,而去重连另一个注册中心。
Client数量相对比较多,会对注册中心造成冲击。
避免方法可以是Client重连时随机延时3分钟,把重连分散开。