乐趣区

关于微服务:近期业务大量突增微服务性能优化总结4增加对于同步微服务的-HTTP-请求等待队列的监控

最近,业务增长的很迅猛,对于咱们后盾这块也是一个不小的挑战,这次遇到的外围业务接口的性能瓶颈,并不是独自的一个问题导致的,而是几个问题揉在一起:咱们解决一个之后,发上线,之后发现还有另一个的性能瓶颈问题。这也是我经验不足,导致没能一下子定位解决;而我又对咱们后盾整个团队有着执著的自尊,不想通过大量程度扩容这种形式挺过压力顶峰,导致线上间断几晚都呈现了不同水平的问题,必定对于咱们的业务增长是有影响的。这也是我不成熟和要反思的中央。这系列文章次要记录下咱们针对这次业务增长,对于咱们后盾微服务零碎做的通用技术优化,针对业务流程和缓存的优化因为只实用于咱们的业务,这里就不再赘述了。本系列会分为如下几篇:

  1. 改良客户端负载平衡算法
  2. 开发日志输入异样堆栈的过滤插件
  3. 针对 x86 云环境改良异步日志期待策略
  4. 减少对于同步微服务的 HTTP 申请期待队列的监控以及云上部署,须要小心达到实例网络流量下限导致的申请响应迟缓
  5. 针对零碎要害业务减少必要的侵入式监控

减少对于同步微服务的 HTTP 申请期待队列的监控

同步微服务对于申请超时存在的问题

绝对于基于 spring-webflux 的异步微服务,基于 spring-webmvc 的同步微服务没有很好的解决客户端有申请超时配置的状况。当客户端申请超时时,客户端会间接返回超时异样,然而调用的服务端工作,在基于 spring-webmvc 的同步微服务并没有被勾销,基于 spring-webflux 的异步微服务是会被勾销的 目前,还没有很好的方法在同步环境中能够勾销这些曾经超时的工作

咱们的基于 spring-webmvc 的同步微服务,HTTP 容器应用的是 Undertow。在 spring-boot 环境下,咱们能够配置解决 HTTP 申请的线程池大小:

server:
  undertow:
    # 以下的配置会影响 buffer, 这些 buffer 会用于服务器连贯的 IO 操作
    # 如果每次须要 ByteBuffer 的时候都去申请,对于堆内存的 ByteBuffer 须要走 JVM 内存调配流程(TLAB -> 堆),对于间接内存则须要走零碎调用,这样效率是很低下的。# 所以,个别都会引入内存池。在这里就是 `BufferPool`。# 目前,UnderTow 中只有一种 `DefaultByteBufferPool`,其余的实现目前没有用。# 这个 DefaultByteBufferPool 绝对于 netty 的 ByteBufArena 来说,非常简单,相似于 JVM TLAB 的机制
    # 对于 bufferSize,最好和你零碎的 TCP Socket Buffer 配置一样
    # `/proc/sys/net/ipv4/tcp_rmem` (对于读取)
    # `/proc/sys/net/ipv4/tcp_wmem` (对于写入)
    # 在内存大于 128 MB 时,bufferSize 为 16 KB 减去 20 字节,这 20 字节用于协定头
    buffer-size: 16364
    # 是否调配的间接内存(NIO 间接调配的堆外内存),这里开启,所以 java 启动参数须要配置下间接内存大小,缩小不必要的 GC
    # 在内存大于 128 MB 时,默认就是应用间接内存的
    directBuffers: true
    threads:
      # 设置 IO 线程数, 它次要执行非阻塞的工作, 它们会负责多个连贯, 默认设置每个 CPU 外围一个读线程和一个写线程
      io: 4
      # 阻塞工作线程池, 当执行相似 servlet 申请阻塞 IO 操作, undertow 会从这个线程池中获得线程
      # 它的值设置取决于零碎线程执行工作的阻塞系数,默认值是 IO 线程数 *8
      worker: 128

其背地的线程池,是 jboss 的线程池:org.jboss.threads.EnhancedQueueExecutor,spring-boot 目前不能通过配置批改这个线程池的队列大小,默认队列大小是 Integer.MAX

咱们须要监控这个线程池的队列大小,并针对这个指标做一些操作:

  • 当这个工作继续增多的时候,就代表这时候申请解决跟不上申请到来的速率了,须要报警。
  • 当累积到肯定数量时,须要将这个实例临时从注册核心取下,并扩容。
  • 待这个队列生产完之后,从新上线。
  • 当超过肯定工夫还是没有生产完的话,将这个实例重启。

增加同步微服务 HTTP 申请期待队列监控

侥幸的是,org.jboss.threads.EnhancedQueueExecutor 自身通过 JMX 裸露了 HTTP servlet 申请的线程池的各项指标:

咱们的我的项目中,应用两种监控:

  • prometheus + grafana 微服务指标监控,这个次要用于报警以及疾速定位问题本源
  • JFR 监控,这个次要用于具体定位单实例问题

对于 HTTP 申请期待队列监控,咱们应该通过 prometheus 接口向 grafana 裸露,采集指标并欠缺响应操作。

裸露 prometheus 接口指标的代码是:

@Log4j2
@Configuration(proxyBeanMethods = false)
// 须要在引入了 prometheus 并且 actuator 裸露了 prometheus 端口的状况下才加载
@ConditionalOnEnabledMetricsExport("prometheus")
public class UndertowXNIOConfiguration {
    @Autowired
    private ObjectProvider<PrometheusMeterRegistry> meterRegistry;
    // 只初始化一次
    private volatile boolean isInitialized = false;

    // 须要在 ApplicationContext 刷新之后进行注册
    // 在加载 ApplicationContext 之前,日志配置就曾经初始化好了
    // 然而 prometheus 的相干 Bean 加载比较复杂,并且随着版本更迭改变比拟多,所以就间接偷懒,在整个 ApplicationContext 刷新之后再注册
    // ApplicationContext 可能 refresh 屡次,例如调用 /actuator/refresh,还有就是多 ApplicationContext 的场景
    // 这里为了简略,通过一个简略的 isInitialized 判断是否是第一次初始化,保障只初始化一次
    @EventListener(ContextRefreshedEvent.class)
    public synchronized void init() {if (!isInitialized) {Gauge.builder("http_servlet_queue_size", () ->
            {
                try {return (Integer) ManagementFactory.getPlatformMBeanServer()
                            .getAttribute(new ObjectName("org.xnio:type=Xnio,provider=\"nio\",worker=\"XNIO-2\""),"WorkerQueueSize");
                } catch (Exception e) {log.error("get http_servlet_queue_size error", e);
                }
                return -1;
            }).register(meterRegistry.getIfAvailable());
            isInitialized = true;
        }
    }
}

之后,调用 /actuator/prometheus 咱们就能看到对应的指标:

# HELP http_servlet_queue_size  
# TYPE http_servlet_queue_size gauge
http_servlet_queue_size 0.0

当产生队列沉积时,咱们能疾速的报警,并且直观地从 grafana 监控上发现:

对于私有云部署,关注网络限度的监控

当初的私有云,都会针对物理机资源进行虚拟化,对于网络网卡资源,也是会虚拟化的。以 AWS 为例,其网络资源的虚拟化实现即 ENA(Elastic Network Adapter)。它会对以下几个指标进行监控并限度:

  • 带宽 :每个虚拟机实例(AWS 中为每个 EC2 实例),都具备流量出的最大带宽以及流量入的最大带宽。这个统计应用一种网络 I/O 积分机制,依据均匀带宽使用率调配网络带宽,最初的成果是 容许短时间内超过额外带宽,然而不能继续超过。
  • 每秒数据包 (PPS,Packet Per Second) 个数:每个虚拟机实例(AWS 中为每个 EC2 实例)都限度 PPS 大小
  • 连接数:建设连贯的个数是无限的
  • 链接本地服务拜访流量:个别在私有云,每个虚拟机实例(AWS 中为每个 EC2 实例)拜访 DNS,元数据服务器等,都会限度流量

同时,成熟的私有云,这些指标个别都会对用户提供展现剖析界面,例如 AWS 的 CloudWatch 中,就提供了以下几个指标的监控:

在业务流量突增时,咱们通过 JFR 发现拜访 Redis 有性能瓶颈,然而 Redis 自身的监控显示他并没有遇到性能瓶颈。这时候就须要查看是否因为网络流量限度导致其除了问题,在咱们出问题的时间段,咱们发现 NetworkBandwidthOutAllowanceExceeded 事件显著进步了很多:

对于这种问题,就得须要思考 垂直扩容 (晋升实例配置)与 程度扩容 (多实例负载平衡)了,或者缩小 网络流量(减少压缩等)

微信搜寻“我的编程喵”关注公众号,每日一刷,轻松晋升技术,斩获各种 offer

退出移动版