性能优化必读 | AntDB-M高性能设计之线程池协程模型

2023-10-29 21:28

本文主要是介绍性能优化必读 | AntDB-M高性能设计之线程池协程模型,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

实际应用场景中,一个AntDB-M节点一般会处理几千个连接,平均每个CPU需处理几百个线程连接,上下文切换频繁;一个进程的线程数太多,会消耗较多的资源,使用Pstack工具检查问题也非常困难,Pstack耗时太久可能导致AntDB-M节点主备切换;对于一些WEB应用或者短连接的使用场景,连接数量能达到几十万级别。

为了提高并发处理性能,AntDB-M除了支持One-Thread-Per-Connection模型,还实现了线程池模型

图1:AntDB-M线程池模型

AntDB-M 线程池模式最佳实践

AntDB-M线程池主要有以下四个特点:

1.平滑创建线程

线程池维护一个与CPU个数相等的Thread Group数组,每个Thread Group单独处理自己的连接, 新连接上来轮询地分配给所有Thread Group,Thread Group客户端发送的请求消息放到一个消息队列。Thread Group创建的工作线程都从这个消息队列中获取任务。

初始化时,Thread Group只有一个线程,可以负责收消息和处理任务,当任务处理不过来时,就会创建一个新的线程。Thread Pool有一个定时器负责周期性检查所有Thread Group是否繁忙,决定是否创建线程,或者唤醒休眠等待任务的线程,一次只会创建/唤醒一个线程。

2.平滑销毁线程

如果有大批业务连接退出,线程池也不会立即将线程销毁,而是等待一段时间。每个线程在等待一段时间之后,如果没有任务可处理,就会退出。在这个过程中,如果有新的消息,线程就会被唤醒。当然,Thread Group会保留最少一个线程来接收新的消息。

3.尽力提高业务处理效率

如果有线程需要去等待某些事件,比如IO、锁,可以认为这个线程不会占用CPU资源,应该开启一个新的线程利用CPU处理任务。Thread Group中的消息队列默认区分高低优先级,对于那些处于事务中的连接发来的消息,放置到高优先级队列。

工作线程处理任务时,优先从高优先级队列中获取消息,然后才处理低优先级队列中的消息。为了防止低优先级队列的消息饿死*[1],线程池的定时器还会定期检查如果有长时间未处理的低优先级消息,把它们移动到高优先级队列中。

*[1]备注:是指采取措施,以确保低优先级的消息在消息队列中也能得到处理,而不会被高优先级消息永远地排挤在后面,导致它们无法被及时处理。

4.系统资源开销限制

每个Thread Group都会有活跃线程上限,整个Thread Pool会有一个总的线程上限,以防止占用资源超出限制。过多的线程并没有优势,因为CPU资源总是有限的。

线程池的缺点:

1.处理任务不够及时

线程池会周期性地检查Thread Group是否过于繁忙,导致有些任务在一段时间内没有处理,然后决定创建新的线程。这段时间的任务,都会延迟一个检查周期时间。

2.没有均衡处理

如果有些Thread Group比较繁忙,有些比较空闲,Thread Group并不会做出调整。

3.不能充分利用CPU资源

虽然线程在等待IO或者临界资源时,会创建新的线程来弥补线程等待时CPU的浪费,但是很多等待事件线程池是无法感知到的,线程池的等待感知完全依赖于代码回调。

为了应对以上问题,AntDB-M同时引入了协程模式。协程模式相对于线程池模式来说,在上下文切换时,不需要内核参与,并且可以由应用层代码自己控制切换的时机。

协程运行时,依托于线程环境,一个线程在一个时刻运行一个协程,可以管理多个协程。从运行和调度的角度考虑,协程对于线程,相当于线程与内核的关系。

  • 在协程运行时,线程将运行环境切换为协程,协程拥有CPU。

  • 当协程运行完成或者主动让出CPU,可以切换到其它协程或者原来的线程环境。

但是线程不能强制切换协程,即没有抢占式调度。这样就不会有多余的上下文切换。

1+1>2 AntDB-M 协程模式

为了同时具备线程池和协程的优点,AntDB-M在线程池基础上实现了协程模型。连接与消息收发,以及线程的创建与销毁,都保持线程池的原有逻辑。对于业务处理,改由协程环境运行。

当一个消息处理完成,或者需要等待时(例如等待行锁或者表锁时),协程会主动让出CPU。当本线程的工作队列为空时,可以去其它线程的工作队列取任务(steal_task)。

图2:AntDB-M协程模型

协程上下文创建与释放

协程上下文使用boost::coroutine接口,make_fcontext创建一个上下文,jump_fcontext执行上下文接口。下面简称boost::coroutine为fcontext。包装fcontext的对象(context_t)需要包含一些基本信息,比如栈地址,为了减少内存分配次数,直接把context_t内存与栈内存放在一起。

协程上下文的切换主要有这几种场景

1.新创建的协程上下文,处理请求,切入;

2.从其它工作线程的队列中获取任务进行处理,切入;

3.请求处理完成,切出到调用线程;

4.处理消息逻辑过程中,需要等待,比如行锁、表锁、临界资源等,需要切出;条件满足(比如其它线程释放行锁)或者等待超时,切入继续处理。

协程模型优势

AntDB-M采用M:N 的协程模型,内置steal_task调度模型来避免长尾效应。协程(用户态线程)切换相比Linux原生内核线程切换,性能提升一个数量级左右;同时steal_task可以实现CPU处理任务时每个核的负载均衡,有利于充分利用CPU资源。

因此,协程模型使得AntDB-M在模型设计上,天然具备高性能、低延迟的特性,以满足复杂的业务应用场景。

关于AntDB数据库

AntDB数据库始于2008年,在运营商的核心系统上,为全国24个省份的10亿多用户提供在线服务,具备高性能、弹性扩展、高可靠等产品特性,峰值每秒可处理百万笔通信核心交易,保障系统持续稳定运行近15年,并在通信、金融、交通、能源、物联网等行业成功商用落地。

这篇关于性能优化必读 | AntDB-M高性能设计之线程池协程模型的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/303440

相关文章

Python实现批量CSV转Excel的高性能处理方案

《Python实现批量CSV转Excel的高性能处理方案》在日常办公中,我们经常需要将CSV格式的数据转换为Excel文件,本文将介绍一个基于Python的高性能解决方案,感兴趣的小伙伴可以跟随小编一... 目录一、场景需求二、技术方案三、核心代码四、批量处理方案五、性能优化六、使用示例完整代码七、小结一、

Java中如何正确的停掉线程

《Java中如何正确的停掉线程》Java通过interrupt()通知线程停止而非强制,确保线程自主处理中断,避免数据损坏,线程池的shutdown()等待任务完成,shutdownNow()强制中断... 目录为什么不强制停止为什么 Java 不提供强制停止线程的能力呢?如何用interrupt停止线程s

从原理到实战解析Java Stream 的并行流性能优化

《从原理到实战解析JavaStream的并行流性能优化》本文给大家介绍JavaStream的并行流性能优化:从原理到实战的全攻略,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的... 目录一、并行流的核心原理与适用场景二、性能优化的核心策略1. 合理设置并行度:打破默认阈值2. 避免装箱

C# LiteDB处理时间序列数据的高性能解决方案

《C#LiteDB处理时间序列数据的高性能解决方案》LiteDB作为.NET生态下的轻量级嵌入式NoSQL数据库,一直是时间序列处理的优选方案,本文将为大家大家简单介绍一下LiteDB处理时间序列数... 目录为什么选择LiteDB处理时间序列数据第一章:LiteDB时间序列数据模型设计1.1 核心设计原则

Python实战之SEO优化自动化工具开发指南

《Python实战之SEO优化自动化工具开发指南》在数字化营销时代,搜索引擎优化(SEO)已成为网站获取流量的重要手段,本文将带您使用Python开发一套完整的SEO自动化工具,需要的可以了解下... 目录前言项目概述技术栈选择核心模块实现1. 关键词研究模块2. 网站技术seo检测模块3. 内容优化分析模

Java实现复杂查询优化的7个技巧小结

《Java实现复杂查询优化的7个技巧小结》在Java项目中,复杂查询是开发者面临的“硬骨头”,本文将通过7个实战技巧,结合代码示例和性能对比,手把手教你如何让复杂查询变得优雅,大家可以根据需求进行选择... 目录一、复杂查询的痛点:为何你的代码“又臭又长”1.1冗余变量与中间状态1.2重复查询与性能陷阱1.

Python内存优化的实战技巧分享

《Python内存优化的实战技巧分享》Python作为一门解释型语言,虽然在开发效率上有着显著优势,但在执行效率方面往往被诟病,然而,通过合理的内存优化策略,我们可以让Python程序的运行速度提升3... 目录前言python内存管理机制引用计数机制垃圾回收机制内存泄漏的常见原因1. 循环引用2. 全局变

深度剖析SpringBoot日志性能提升的原因与解决

《深度剖析SpringBoot日志性能提升的原因与解决》日志记录本该是辅助工具,却为何成了性能瓶颈,SpringBoot如何用代码彻底破解日志导致的高延迟问题,感兴趣的小伙伴可以跟随小编一起学习一下... 目录前言第一章:日志性能陷阱的底层原理1.1 日志级别的“双刃剑”效应1.2 同步日志的“吞吐量杀手”

python 线程池顺序执行的方法实现

《python线程池顺序执行的方法实现》在Python中,线程池默认是并发执行任务的,但若需要实现任务的顺序执行,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋... 目录方案一:强制单线程(伪顺序执行)方案二:按提交顺序获取结果方案三:任务间依赖控制方案四:队列顺序消

Python多线程应用中的卡死问题优化方案指南

《Python多线程应用中的卡死问题优化方案指南》在利用Python语言开发某查询软件时,遇到了点击搜索按钮后软件卡死的问题,本文将简单分析一下出现的原因以及对应的优化方案,希望对大家有所帮助... 目录问题描述优化方案1. 网络请求优化2. 多线程架构优化3. 全局异常处理4. 配置管理优化优化效果1.