线程优化本来就属于配置优化,把线程进行独立出来为了清楚地说明线程优化的方法。
一、线程池优化
为什么要有线程池?线程池为了减少创建新线程和销毁线程所造成的资源消耗。
系统性能差一般有以下两种明显表现。
1>CPU使用率不高,用户感觉交易响应时间很长。
2>CPU使用率很高,用户感觉到交易时间很长。
第一种情况可能是由于系统的某一部分造成的瓶颈,导致了所有的请求都在等待。例如,线程池的数量太小,没有可用的线程使用,所有的请求都在排队等待进入线程池,导致交易响应时间很长。
第二种情况产生的原因比较复杂,可能是硬件资源不够,也可能是应用系统中产生了较多的大对象,还可能是线程算法等问题。
二、CPU处理能力
线程池的配置数量与CPU处理能力相关。我们知道,单核CPU同一时刻是只能处理一个任务,那么对于一个四核CPU,理论上线程池配置数量是4个。如果一个任务处理只需要100毫秒,单核一秒可以处理10个任务数,四核可以处理四十个任务,那么单核CPU配置40个连接,任务就就可以处理完成了嘛?这就矛盾了,到底配置配置多少呢?
我们可以这样理解,只要你发送的请求更快,四个连接是可以在1秒完成40个任务的处理的(为了方便说明,忽略CPU的中断与切换时间,网络延时等);如果配置了40个连接,请求就会排队,处理不完就过载,CPU还需要花时间接收这些任务,让他们排队或者直接拒绝,反而占用了CPU用来处理任务的时间。对于这个例子来说,最佳的性能就是40TPS(或者QPS),考虑到CPU的中断与切换及网络延迟时,根据实际测试时的连接状态可以再用多加加几个连接,4个只是一个理论参考。
三、内存容量
每一个线程的实例都会占用一定的内存(栈空间)空间,这个值是累加的,我们可以很快计算出服务器到底能支持多少线程。
例如:一个线程如果需要开辟256KB内存(Heap栈的大小)来保存其运行的状态,那么1GB内存就可以支持4096个线程。
也就是说,内存对线程数的影响,我们可以通过加大内存容量及调整JVM堆空间大小来调节,那么为什么会与JVM有关呢?
这是因为JVM内存空间中每开辟一个线程时,操作系统相应地也开辟一个线程与之对应,所以才产生了下边的公式:
Number of threads=(MaxprocessMemory-JVMMemory-ReservedOsMemory)/ThreadStackSize
MaxprocessMemory:系统识别的最大内存,例如32位系统识别2GB内存空间,64位系统识别的内存空间基本无上限。JVMMemory:JVM内存。ReservedOsMemory:保留给操作系统运行内存大小。ThreadStackSize:线程栈的大小,例如JDK 6 默认的线程栈大小为1MB。
四、系统线程数限制
1>Linux下查看线程。
ps -efL | [进程名] | wc -1
2>Linux 下查看系统线程数量限制:
/proc/sys/kernel/pid_max
/proc/sys/kernel/thread-max
max_user_process(uimit-u)
/proc/sys/vm/max_map_count
3>windows下查看线程
最简单的方式就是在任务管理器中查看,注意有一个线程数列。如果无法看到,大家可以到“选择进程页列”中勾选“线程数”选项。也可以用命令行的方式查询,如tasklist(需要下载安装)
4>windows 下查看线程数限制
在注册表中查看TcpNumConnections 这个键(现在的windows 7以上已经没有了限制)
线程数的控制基本就是一个漏斗模型,我们要从漏斗模型中的每一个关节加以分析,上层开口大,下层开口小,当下层有瓶颈而处理不了时就会造成业务阻塞。在经过了上面的各项计算和预想后,我们还要进行实际的测试,以验证线程数是否合适。
如果8个处理器,他们都同时运行,并出现堵塞线程,为了提高效率就要降低线程数。为了使当地提高客户体验,可以容忍部分线程排队,也就是让acceptCount(Tomcat中线程池配置参数)数量的线程排队。
五、性能测试中的线程优化注意事项有哪些?
在性能测试中进行线程优化时,主要目的是为了确保系统能够在高负载下稳定运行,并且能够有效地利用资源。以下是一些关键的注意事项:
确定合适的并发用户数
在进行性能测试前,需要根据实际业务场景估算出合理的并发用户数量。这通常基于历史数据、预期增长和业务目标等因素。过高或过低的并发设置都可能导致测试结果不准确。
逐步增加负载
采用渐进式的方法逐渐增加并发用户的数量,而不是一开始就使用最大负载。这种方法有助于观察系统在不同负载下的表现,识别性能瓶颈所在位置。
监控资源使用情况
在测试过程中密切监控服务器的CPU、内存、磁盘I/O和网络带宽等资源的使用情况。通过分析这些数据,可以发现是否因资源耗尽导致性能下降。
考虑线程的生命周期管理
确保线程池大小适中,既不过大也不过小。太大的线程池可能会导致上下文切换频繁,增加系统开销;而太小则可能无法充分利用系统资源。
合理设置线程的超时时间和回收策略,避免出现僵尸线程或资源泄露。
处理异常和错误
在设计测试脚本时要考虑到可能出现的各种异常情况(如网络延迟、请求失败等),并制定相应的重试机制或错误处理逻辑,以保证测试的连续性和准确性。
使用合适的工具和技术
根据不同的需求选择合适的性能测试工具(如JMeter, LoadRunner等)以及监控工具(如Prometheus, Grafana等)。同时,也可以利用一些高级技术如分布式测试来模拟更大规模的并发访问。
分析和调优
对测试结果进行详细的分析,找出性能瓶颈的具体原因,并针对性地对代码或配置进行调整优化。这可能包括数据库查询优化、缓存策略改进、算法效率提升等方面。
环境一致性
确保测试环境尽可能接近生产环境,包括硬件配置、软件版本、网络条件等,以便获得更准确的测试结果。
遵循上述建议可以帮助你在性能测试过程中更好地进行线程优化,从而确保应用程序在面对大量并发请求时仍能保持良好的响应速度和稳定性。
阅读后若有收获,不吝关注,分享,在看等操作!!!