免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: joepayne

[C++] Boost asio 连接池问题 [复制链接]

论坛徽章:
0
发表于 2017-11-17 23:17 |显示全部楼层
回复 30# yulihua49

楼主的情况看起来不像有这种需求,他是一个客户端跑k个线程,没说有大量客户端。所以我觉得处理他的问题用越简单的方式越好,他这种问题网络很少会成为瓶颈。
用全异步架构当然好,但这很多情况下都不是必须的。

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
发表于 2017-11-17 23:25 |显示全部楼层
本帖最后由 yulihua49 于 2017-11-18 10:55 编辑
Fixend 发表于 2017-11-17 23:17
回复 30# yulihua49

楼主的情况看起来不像有这种需求,他是一个客户端跑k个线程,没说有大量客户端。所 ...

我有点跑题了。
他这个“有K级别的并发线程”比较恐怖。他主要是想搞连接池。
跟我们的交易管理器有点像,我们是K级别的前端连接,但是没有K级别的线程,只有几个到几十个线程,然后有几十个后端连接(服务器),构成连接池。线程就像是接线员,不断在前端和后端之间转发信息。
前端的客户端作业,看起来是同步的,但是这个转发器内部工作完全是异步的。


这里实现了M:N:L的方式,M个客户端连接,N个线程,L个服务器连接。
M大约是12800,N16,L:后方10台服务器,每台32连接共计320连接。

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
发表于 2017-11-18 10:58 |显示全部楼层
本帖最后由 yulihua49 于 2017-11-18 11:52 编辑
yulihua49 发表于 2017-11-17 23:25
我有点跑题了。
他这个“有K级别的并发线程”比较恐怖。他主要是想搞连接池。
跟我们的交 ...

我们知道后台服务器处理能力是有限的,那个L数就等于服务器的线程数,就代表了系统最大处理能力。过多或过少的连接都不能充分发挥系统能力。
而前方的客户端数是不断发展的。大量客户端使用有限的服务器能力,这个矛盾就由交易管理器来平衡。连接池就是一个可伸缩的节点,根据需要配重后台服务器的数量和各自的连接数。连接池要负责:维持资源数量,保证他们健康,实现容错,进行负载均衡,无缝的,快速交换资源使用。对于临时拥塞提供缓冲队列。
如果服务器总处理能力大于信息平均到达量,系统就不会长期的拥塞,但是短时间拥塞还是难以避免的。

客户端(context)池,线程池,协程,连接池的关系,初看起来错综复杂,实际上各自独立互相配合。
我们先做的客户端池和线程池,后做的连接池,最后加入了协程。

论坛徽章:
3
亥猪
日期:2013-08-28 12:50:23白羊座
日期:2013-11-25 12:55:50酉鸡
日期:2014-02-12 10:46:13
发表于 2017-11-20 16:39 |显示全部楼层
本帖最后由 joepayne 于 2017-11-20 16:42 编辑

回复 32# yulihua49

他这个“有K级别的并发线程”比较恐怖。他主要是想搞连接池。
跟我们的交易管理器有点像,我们是K级别的前端连接,但是没有K级别的线程,只有几个到几十个线程,然后有几十个后端连接(服务器),构成连接池。线程就像是接线员,不断在前端和后端之间转发信息。
前端的客户端作业,看起来是同步的,但是这个转发器内部工作完全是异步的。


这里实现了M:N:L的方式,M个客户端连接,N个线程,L个服务器连接。
M大约是12800,N16,L:后方10台服务器,每台32连接共计320连接。

华哥好,

其实这里的『K级别的线程』可能并没有描述准确,这里我只是想模拟你所说的并发的客户端(一个线程代表一个客户端),这些客户端独自发请求,每个客户端的生命周期内可能会有多个请求。

一个baseline的版本就是,每个线程(客户端)在发送请求前建立与服务端的连接,然后通信直至结束,断开连接;

然后,一个优化的出发点是,为了节省建立与断开连接的时间,开辟一个共享的连接池,所有客户端共享这些连接,需要的时候就从池子中拿一个出来用,用完放回去,当然它们连接的是同一个end point(IP/PORT),我们唯一需要做的只是保证连接是激活状态,客户端连接上后,服务端也要保证它是活的,只有出现异常或者客户端主动发起关闭请求时才断开连接。这也许就是华哥提到的M:N规则,用来缓冲用户的连接压力

客户端是同步的请求,发送请求与接收响应之间不能被『中断』;服务端本身处理每个请求也是有较大的时间损耗的,大概10ms左右。所以基于此,就想设计一套服务端异步,期望其吞吐量尽可能大,客户端同步(必须)的通信模式。

至于客户端每个机子开的线程资源量是多少,确实都会约束,一般不会为某一个服务去开K级别的线程,会根据对端(服务端)的处理能力来进行合理的配置,这也许就是华哥提到的N:L规则,这里用来缓冲服务端的压力

论坛徽章:
3
亥猪
日期:2013-08-28 12:50:23白羊座
日期:2013-11-25 12:55:50酉鸡
日期:2014-02-12 10:46:13
发表于 2017-11-20 17:08 |显示全部楼层
回复 31# Fixend


描述确实有些不到位,我上面提到的『多线程』只是想模拟并发的客户端,因为我的这个服务本身对高并发的性能确有一定需求,而且最好具备纵向scale的能力,所以这里就把线程量放到K级别了,

另外,不知道大哥们在部署自己的服务时有没有直接用thrift这种跨语言跨平台的第三方网络通信工具呢?据我的测试,其性能的折损率较高

比方说,单次请求的处理时间是10ms,加上这个框架后,测试发现客户端有大量的请求(10%)处理时间已经起过100ms,在资源配置上也做了大量的优化了。



想听听业内大咖们对这种场景需求有什么比较好的意见    @华哥@聪哥

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
发表于 2017-11-20 23:13 |显示全部楼层
本帖最后由 yulihua49 于 2017-11-20 23:19 编辑

我们做的工作正是如此。只是没有用boost。是C而不是C++(可以支持C++调用)。所以,在boost方面帮不了你,只能讨论下应该做什么,怎么做。

我们是万级别的客户端,业务响应时间在百毫秒级,吞吐量每秒60000级别的系统。
在客户端和服务器之间插入一个交易管理器,完成你说的功能。
它承担大量客户端接入,管理一个二维连接池,服务器数,连接数。管理连接的健康,在服务器间进行负载均衡和容错。对超出服务器能力的请求进行排队缓冲。

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
发表于 2017-11-21 08:17 |显示全部楼层
本帖最后由 yulihua49 于 2017-11-21 09:13 编辑
yulihua49 发表于 2017-11-20 23:13
我们做的工作正是如此。只是没有用boost。是C而不是C++(可以支持C++调用)。所以,在boost方面帮不了你 ...

连接健康管理,一般是“保活”,但是服务器是否真的死了是无法探测的(探测不到不等于死了)。总是探测,开销不小,而且为了与正常运用互不干扰,过程也是很复杂。
我们是“保死”策略,置于死地而后生。实践证明此法简单高效而可靠。
具体办法是:
1:连接池初始化后,所有连接处于不连接态,置于空闲队列。
2:一个连接启用时,发现无连接就进行连接。连接成功提交用户使用。失败则对该服务器进行权重标记封锁之。该连接归还空闲队列队尾。
3:任务使用连接完毕,应用程序应对这个连接进行评价,有致命故障要标记。连接池收到归还的连接,无致命故障的回到空闲队列头,其他先关闭连接,然后回到队尾,对该服务器进行权重标记封锁之。
4:必须安排一个线程定时检测各服务器所有空闲队列,发现长时间(300秒)未使用的打开连接,关闭之。这一步很重要,是保证所有连接健康的关键。5:安排超时机制,可以与4安排在同一个线程。所有超时的连接按照致命错误,调用应用程序安排的回调函数。激活应用程序,实现致命错误返回。

这个方案的优点是:
1.对服务器负担小,空闲时没有连接。使用时也是最少连接。比如你配置了100个连接,你经常使用2个连接那么也只存活2个连接,对服务器来说只有2个线程活动。如果按保活方案就会有100个活动线程。你可以想想这个场景:一个服务器突然失效,如果是在空闲时段,过了一段时间维修恢复了,这对于系统没有任何影响。如果期间有连接请求,第一次连接失败,负载均衡器马上安排其他服务器,不会耽误事。在失效期间正在使用的任务会收到操作失败或超时信息,则立即夭折事务,以致命错误归还连接。2.逻辑简单,只检查空闲队列,与正常使用互不干扰。
3.配合负载均衡,容错机制。




论坛徽章:
3
亥猪
日期:2013-08-28 12:50:23白羊座
日期:2013-11-25 12:55:50酉鸡
日期:2014-02-12 10:46:13
发表于 2017-11-21 15:37 |显示全部楼层
回复 37# yulihua49

感谢华哥分享你的连接的健康管理器。
我们系统性能优化的目标跟你做的差不多,只是当下刚起步在尝试各种可行的解决方案。之前写过一段时间Unix C的网络编程,有些基础,当下也在重新学习,也想尝试把这些东西捡起来。

当下我们的整个后台系统业务比较繁琐,所以把一些功能模块全都服务化了,我这边的功能是离线完成的,线上的服务对接及部署由我这边另外独立完成,对外提供接口,并保证我这边的服务能达到一定的吞吐量。鉴于整个业务后台要求具备可移植性,所以想选取一种可行的网络框架,同时得考虑开发成本、性能、稳定性、资源损耗等

听华哥的介绍,感觉你的系统集成性比较强,各模块联系很紧密,似乎最终也是性能至上,而且你的这整套网络层是纯Unix C写的,开发成本应该不低,你们当时没有考虑过采用第三方的网络框架吗?比如thrift/grpc,或者说在其基础之上进行优化什么的。毕竟这些东西比较上层,可移植性强,也屏弊各种底层东西,各种语言都能使,开发成本自然也低,就是性能方面可能不能完全保证

另外,关于华哥的这个连接健康管理器,它是跟负载均衡器集成在一起的吗?还是负载均衡器是单独开发的?

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
发表于 2017-11-21 20:13 |显示全部楼层
本帖最后由 yulihua49 于 2017-11-21 20:18 编辑
joepayne 发表于 2017-11-21 15:37
回复 37# yulihua49

感谢华哥分享你的连接的健康管理器。

是一起的,均衡器、连接池是一体的。
这些工作已经在8年前完成。当时没有采用什么框架,只用了epoll,ucontext(协程工具),eventfd等,可以百度到。
这些东西形成了一套中间件工具包,开发了很多生产项目。这些可能帮不了你,只是交流下思想,供参考。

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
发表于 2017-11-21 20:27 |显示全部楼层
本帖最后由 yulihua49 于 2017-11-21 20:50 编辑
joepayne 发表于 2017-11-21 15:37
回复 37# yulihua49

感谢华哥分享你的连接的健康管理器。

我们的连接池是3维的,你的情况只需要二维。所以我就以二维为例:
一个服务器层的结构,包括一个连接池数组,里边若干连接结构(数组)。一个空闲队列。一个权重值。最高权重标记为512(100%)。权重为空闲连接数与总连接数之比。不用百分比,用512分比,便于计算。如果这个服务器失效了,权重被标为-1。
常规的取连接调用就是负载均衡器人口,在服务器组里找到最高权重的那个服务器,从这个服务器取连接(底层调用),如果成功修改权重,返回连接句柄。如果全忙或失败,就在权重-1的服务器里找,看看有没有能激活的。能激活就把激活的服务器权重修改正常。如果不行,看请求标志,重试次数,6秒一次。0代表不重试,-1代表死等。重试次数完结返回错误。

这个权重算法比LVS好。LVS不知道服务器能力,只按照你配的权重值进行计算,难免那个服务器过载那个空转。我们这个策略能保证忙时所有服务器满载均衡运行。

当管理器取不到连接时,就把任务CONTEXT丢到排队机,然后放弃这个任务干别的去了。排队机有一个线程专门负责读队列,取连接,并丢回任务线程池(像极了医院的号贩子)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP