zoukankan      html  css  js  c++  java
  • 如何科学的设置线程池

    线上高并发的服务就像默默的屹立在大江大河旁边的大堤一样,随时准备着应对洪水带来了冲击,线上高并发服务的线程池导致的问题也颇多,例如:线程池涨满、CPU 利用率高、服务线程挂死等,这些都是因为线程池的使用不当,或者没有做好保护、降级的工作而导致的。

    当然,有些小伙伴是有保护线程池的想法的,但是,大家是不是有过这样的经验和印象,线程池的线程有时候设置多了性能低,设置少了还是性能低,到底应该怎么设置线程池呢?

    在经历过这些年对小伙伴的设计评审,得知小伙伴们都是凭经验、凭直觉来设置线程池的线程数的,然后根据线上的情况调整数量多少,最后找到一个最合适的值,这是通过经验的,有时候管用,有时候不管用,有时候虽然管用但是牺牲了很大的代价才找到最佳的设置数量。

    其实,线程池的设置是有据可依的,可以根据理论计算来设置的。

    首先,我们看一下理想的情况,也就是所有要处理的任务都是计算任务,这时,线程数应该等于 CPU 核数,让每个 CPU 运行一个线程,不需要线程切换,效率是最高的,当然这是理想情况。

    这种情况下,如果我们要达到某个数量的 QPS,我们使用如下的计算公式。

    设置的线程数 = 目标 QPS/(1/任务实际处理时间)

    举例说明,假设目标 QPS=100,任务实际处理时间 0.2s,100 * 0.2 = 20个线程,这里的20个线程必须对应物理的20个 CPU 核心,否则将不能达到预估的 QPS 指标。

    但实际上我们的线上服务除了做内存计算,更多的是访问数据库、缓存和外部服务,大部分的时间都是在等待 IO 任务。

    如果 IO 任务较多,我们使用阿姆达尔定律来计算。

    设置的线程数 = CPU 核数 * (1 + io/computing)

    举例说明,假设4核 CPU,每个任务中的 IO 任务占总任务的80%,4 * (1 + 4) = 20个线程,这里的20个线程对应的是4核心的 CPU。

    线程中除了线程数的设置,线程队列大小的设置也很重要,这也是可以通过理论计算得出,规则为按照目标响应时间计算队列大小。

    队列大小 = 线程数 * (目标相应时间/任务实际处理时间)

    举例说明,假设目标相应时间为0.4s,计算阻塞队列的长度为20 * (0.4 / 0.2) = 40。

    另外,在设置线程池数量的时候,我们有如下最佳实践。

    1. 线程池的使用要考虑线程最大数量和最小数最小数量。

    2. 对于单部的服务,线程的最大数量应该等于线程的最小数量,而混布的服务,适当的拉开最大最小数量的差距,能够整体调整 CPU 内核的利用率。

    3. 线程队列大小一定要设置有界队列,否则压力过大就会拖垮整个服务。

    4. 必要时才使用线程池,须进行设计性能评估和压测。

    5. 须考虑线程池的失败策略,失败后的补偿。

    6. 后台批处理服务须与线上面向用户的服务进行分离。

  • 相关阅读:
    python 正则表达式 (重点) re模块
    python 异常处理
    面向对象 反射 特殊方法
    3. 容器备份与迁移
    2. Docker部署tomcat, nginx, redis,及docker私有仓库
    1. Docker快速入门(仓库,镜像,容器)
    Linux部署项目 shell脚本启动 及 Centos7开放指定端口
    nginx快速入门
    linux安装mysql8(完整图文笔记)
    Redis主从架构核心原理
  • 原文地址:https://www.cnblogs.com/lupeng2010/p/12705795.html
Copyright © 2011-2022 走看看