赞
踩
背景
企业云服务,全是企业客户、代账中介客户,生产环境偶发个别容器dubbo线程池爆满,通过研究发现问题发生时会同时伴随数据库性能抖动、容器CPU爆满,通过和业务系统的开发人员了解到,系统中存在重接口和批量接口的情况,这些接口也往往和客户的数据量大小有关,这些存在隐患的接口并没有得到合理的控制,它们和轻量级接口位于同一个微服务中,就可能相互影响。这些重接口可能造成的问题 1、影响数据库的稳定性;2、影响cpu和内存的稳定性;一旦产生影响,往往伴随着轻量级接口不能及时得到响应,dubbo线程池会被逐渐占满,进而报错。
可能有同学会说,dubbo不是会自动隔离故障节点吗?实际上对于彻底死掉没有心跳的节点确实会自动隔离,但是对于半死不活,心跳还在,但压力很大的节点并不会得到隔离,这就需要我们自己来解决这类刺手问题。
解决思路
一方面我们启用了dubbo的重试机制,在发生线程池满错误的情况下能自动容错到其它容器,保证用户侧无感知。
另一方面我们要防患于未然,把危机扼杀在摇篮里,我们对dubbo的线程池活跃线程(active)数量进行了监控,设置了临界值,健康检查线程每间隔30秒进行一次检测,一旦检测到异常,就会触发一系列的防护措施:
1、dubbo服务隔离可以及时引流消费者流量到其它正常的提供者
2、邮件和短信告警可以让架构师和运维人员及时关注问题容器情况,如果无法自愈,需要运维干预下重启容器。
3、cpu、内存和线程栈信息记录日志,有助于业务开发人员解决接口存在的问题
架构图
原理
1、根据dubbo-admin的原理,注册override配置信息到注册中心;
2、消费者通过注册中心收到事件通知,根据规则进行 override url与provider url以及 consumer url 合并过滤操作;
服务隔离部分的实现代码
1、隔离与恢复事件
- @Autowired
- private HealthCheckConfig checkConfig;
- @Autowired
- private RegistryService registryService;
- @Autowired
- private ProtocolConfig protocolConfig;
-
-
- @EventListener
- public void startIsolate(DubboThreadPoolHighEvent event) {
- //开启隔离
- log.error("故障节点隔离开始:" + event.getActiveCount());
- disableProvider(true);
- log.error("故障节点隔离成功");
- }
-
-
- @EventListener
- public void stopIsolate(DubboThreadPoolNormalEvent event) {
- //关闭隔离
- log.error("故障节点取消隔离开始" + event.getActiveCount());
- disableProvider(false);
- log.error("故障节点取消隔离成功");
- }
-
-
- private void disableProvider(boolean disable) {
- try {
- if (!checkConfig.getHealthCheckIsolateEnable()) {
- log.error("未启用健康检查隔离服务");
- return;
- }
- Map<String, Object> beansWithAnnotation = SpringUtil.getApplicationContext().getBeansWithAnnotation(Service.class);
- //override://192.168.2.100:23881/a.b.c.XxxService?
- // category=configurators&disabled=true&dynamic=false&enabled=true
- String ip = NetUtils.getLocalHost();
- Integer port = protocolConfig.getPort();
- //---
- for (Object value : beansWithAnnotation.values()) {
- Class<?>[] itfs = value.getClass().getInterfaces();
- Class<?> itf = itfs[0];
- URL url = new URL(Constants.OVERRIDE_PROTOCOL, ip, port, itf.getCanonicalName());
- url = url.addParameter("category", "configurators");
- url = url.addParameter("disabled", true);
- url = url.addParameter("dynamic", false);
- url = url.addParameter("enabled", true);
- if (disable) {
- registryService.register(url);
- log.error("register:" + url.toString());
- } else {
- registryService.unregister(url);
- log.error("unregister:" + url.toString());
- }
- }
- }catch (Exception e){
- log.error("isolate error ",e);
- }
-
-
- }
2、优雅关机事件
- @EventListener
- public void clearIsolate(AppCloseEvent event) {
- if (event.getIsolateStatus()) {
- log.error("关闭之前取消隔离" + event.getIsolateStatus());
- disableProvider(false);
- log.error("关闭之前取消隔离成功");
- try {
- TimeUnit.SECONDS.sleep(checkConfig.getHealthCheckShutdownHookWaitTime());
- }catch (Exception e){
-
-
- }
- }else{
- log.error("--isolate status:false--");
- }
- }
3、暴力关机情况的处理
- @EventListener
- public void initIsolate(AppOpenEvent event){
- log.error("--init isolate status--");
- disableProvider(false);
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。