免费注册 查看新帖 |

Chinaunix

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

[C++] ASIO,无锁,高并发,高可靠, 统一,网络架构,抗DOS,低端4核心服务器CPU 每秒87万QPS ECHO [复制链接]

论坛徽章:
9
程序设计版块每日发帖之星
日期:2016-02-13 06:20:00数据库技术版块每日发帖之星
日期:2016-06-15 06:20:00数据库技术版块每日发帖之星
日期:2016-06-16 06:20:00数据库技术版块每日发帖之星
日期:2016-06-18 06:20:00程序设计版块每日发帖之星
日期:2016-06-27 06:20:00程序设计版块每日发帖之星
日期:2016-07-09 06:20:00IT运维版块每日发帖之星
日期:2016-07-15 06:20:00IT运维版块每日发帖之星
日期:2016-07-27 06:20:00程序设计版块每日发帖之星
日期:2016-08-18 06:20:00
发表于 2016-09-30 15:13 |显示全部楼层
hanxin83 发表于 2015-10-15 09:57
大猫这算是实力打脸么....

楼主的做法其实还不错的, 不过也不是"无锁"或"少锁"就一定高并发了, 写个echo ...

想问下, linux下ASIO和epoll/poll/select啥区别呢

论坛徽章:
9
程序设计版块每日发帖之星
日期:2015-10-18 06:20:00程序设计版块每日发帖之星
日期:2015-11-01 06:20:00程序设计版块每日发帖之星
日期:2015-11-02 06:20:00每日论坛发贴之星
日期:2015-11-02 06:20:00程序设计版块每日发帖之星
日期:2015-11-03 06:20:00程序设计版块每日发帖之星
日期:2015-11-04 06:20:00程序设计版块每日发帖之星
日期:2015-11-06 06:20:00数据库技术版块每周发帖之星
日期:2015-12-02 15:02:47数据库技术版块每日发帖之星
日期:2015-12-08 06:20:00
发表于 2016-10-11 15:00 |显示全部楼层
回复 160# mordorwww

内部的区别不大,ASIO内部也是使用epoll,只是封装了多组epoll, 对外部来讲使用ASIO库,要考虑的问题比较少, 开发速度比较快, 也不容易出问题, 毕竟封装后减少了大量的代码。



论坛徽章:
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
发表于 2016-10-13 11:55 |显示全部楼层
wlmqgzm 发表于 2015-10-29 22:13
http://bbs.chinaunix.net/thread-4082130-1-2.html
千万级并发实现的秘密:内核不是解决方案,而是问题所 ...

似乎没必要解决C10M问题,可以用多台服务器阵列来解决问题,没必要吊在一台服务器上。

论坛徽章:
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
发表于 2016-10-13 11:58 |显示全部楼层
wlmqgzm 发表于 2016-10-11 15:00
回复 160# mordorwww

内部的区别不大,ASIO内部也是使用epoll,只是封装了多组epoll, 对外部来讲使用ASI ...

多组epoll是正解。单个的epoll15万QPS基本到头了。

论坛徽章:
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
发表于 2016-10-15 16:03 |显示全部楼层
wlmqgzm 发表于 2016-10-11 15:00
回复 160# mordorwww

内部的区别不大,ASIO内部也是使用epoll,只是封装了多组epoll, 对外部来讲使用ASI ...

请教一下如何无锁:
如果生产者没有push,消费者如何pop?不需要等待吗?
如果一个生产者push了,一大堆消费者在pop,那么给谁好呢?

论坛徽章:
9
程序设计版块每日发帖之星
日期:2015-10-18 06:20:00程序设计版块每日发帖之星
日期:2015-11-01 06:20:00程序设计版块每日发帖之星
日期:2015-11-02 06:20:00每日论坛发贴之星
日期:2015-11-02 06:20:00程序设计版块每日发帖之星
日期:2015-11-03 06:20:00程序设计版块每日发帖之星
日期:2015-11-04 06:20:00程序设计版块每日发帖之星
日期:2015-11-06 06:20:00数据库技术版块每周发帖之星
日期:2015-12-02 15:02:47数据库技术版块每日发帖之星
日期:2015-12-08 06:20:00
发表于 2016-11-05 16:16 |显示全部楼层
回复 164# yulihua49

无锁的设计很复杂, 不是一言两语能够说完的, 有好多这方面的长论文, 对于初次的开发无锁产品的人员很容易陷入各类(例如:ABA等)错误中, 还涉及大量的CPU内存同步方面的知识,

最简单的高性能无锁队列是spsc_queue单生产者, 单消费者,

对于单生产者, 单消费者, 无锁主要是利用环形队列实现的, 现成的库中boost::lock_free_spsc_queue是一个典型的实现, 这个代码在Boost库中就有,自己读吧, 很多人第一次都看不懂,   
boost::lock_free_spsc_queue本身代码没有问题, 唯一就是限制了T的类型,只支持常规数据(整数之类的),

前期开发网络层代码的时候,是直接使用boost. 今年重新开发了几个版本, 主要参考了linux系统调用的源代码高性能无锁队列的设计, 另外为了保证兼容性,没有像linux一样直接使用底层函数, 内存同步协议统一使用了C++14版本的std::atomic thread memory control协议(memory acquire/release) , 公司内部开发使用的wait_free_spsc_queue, 性能基本达到了每秒2-5亿队列处理能力(对于T对象是int,性能5亿TPS,对于T对象是shared_ptr,性能2亿TPS), 并发测试性能与单线程读写std::queue的性能基本一致, 达到了理想的性能.  

公司内部库的设计优势是: 去掉了boost::lock_free_spsc_queue中内部的T对象内存释放~T()语句,  去掉了boost库的限制, 兼容性好,内存同步协议统一使用了C++14版本的std::atomic thread memory control协议(memory acquire/release) , 重新编写了内部的T对象内存释放的处理方式.

多生产者, 单消费者队列, 其实也是spsc_queue单生产者单消费者的扩展, 是再次封装wait_free_spsc_queue来实现的
一般工作中使用的无锁队列是wait_free_mpsc_ios_queue, 主要是通过与boost::io_service队列结合, 不需要自己生成thread, 利用boost::io_service在队列无任务的时候挂起的特性, 实现统一的CPU资源调度.


论坛徽章:
9
程序设计版块每日发帖之星
日期:2015-10-18 06:20:00程序设计版块每日发帖之星
日期:2015-11-01 06:20:00程序设计版块每日发帖之星
日期:2015-11-02 06:20:00每日论坛发贴之星
日期:2015-11-02 06:20:00程序设计版块每日发帖之星
日期:2015-11-03 06:20:00程序设计版块每日发帖之星
日期:2015-11-04 06:20:00程序设计版块每日发帖之星
日期:2015-11-06 06:20:00数据库技术版块每周发帖之星
日期:2015-12-02 15:02:47数据库技术版块每日发帖之星
日期:2015-12-08 06:20:00
发表于 2016-11-05 17:19 |显示全部楼层
本帖最后由 wlmqgzm 于 2016-11-05 20:47 编辑

回复 164# yulihua49

近期主要的与 无锁设计相关的技术开发内容是:

在准备编写 对应的无锁hash_map, 目前主要的技术思路是  成熟的通用任意对象 无锁设计方法:

大对象用裸指针T* + 对象Copy change + + 内存同步原语 + 更新裸指针T* + 垃圾内存自动回收机制,
小对象有开销更小的办法,
另外还在测试和寻找  总体开销更小的无锁技术方案..................
从开销上看, 无锁hash_map class, 单线程跑一般没有优势, 多线程才会快起来.

这块目前是C++技术前沿, 还有一个就是: 我自己代码中 垃圾内存自动回收机制 的设计方面, 目前暂时还没有找到一个足够优秀的解决办法, 我自己目前的解决方案比较土, 不满意.

store(memory_order_release) 保证的是在此store之前的store全部执行完毕了,  load(memory_order_acquire)保证的是在此之后的load指令不允许提前执行.

我们利用
memory_orde同步机制实现 无锁设计方法:   memory_order_release/acquire就是对于保证struct数据的完整性, 相当于实现了读写struct的原子性的操作.


写线程A  新生成 一个 对象裸指针T* new,   旧对象Copy change,     store(memory_order_release) 更新裸指针T* ,  保证的是在此store之前的store全部执行完毕了, 保证 struct数据的完整的store了,  
   
读线程B  
load(memory_order_acquire)  获得当前的  对象裸指针T*, 然后开始读T对象,    load(memory_order_acquire)  保证的是取到的数据一定是完整的数据, 避免发生数据乱序执行,( 避免这样的情况: 例如:先读了旧数据,再获得新的对象裸指针T*, 继续读数据, 这样一半新数据, 一半旧数据的情况 )



当然仅仅这样还不够实现无锁并发, 还要
实现一个  垃圾内存自动回收机制, 否则部分线程读旧数据, 部分线程读新数据, 写线程如果直接回收内存, 那么部分读线程可能会崩溃或者出现离奇的错误.

论坛徽章:
0
发表于 2017-09-11 09:38 |显示全部楼层
wlmqgzm 发表于 2015-11-09 22:32
继续改进:

阅读io_service代码, 发现一个问题, 就是linux下, 未定义  detail::signal_init init_,  

请问asio是如何做到的?我向一个已经关闭的socket连续写入,complete handler始终都被传入broken pipe的error参数。按libc的文档,如果没有忽略SIGPIPE,系统不是会raise SIGPIPE吗?asio怎么做到既不raise SIGPIPE又得到EPIPE的errno的?

论坛徽章:
9
程序设计版块每日发帖之星
日期:2015-10-18 06:20:00程序设计版块每日发帖之星
日期:2015-11-01 06:20:00程序设计版块每日发帖之星
日期:2015-11-02 06:20:00每日论坛发贴之星
日期:2015-11-02 06:20:00程序设计版块每日发帖之星
日期:2015-11-03 06:20:00程序设计版块每日发帖之星
日期:2015-11-04 06:20:00程序设计版块每日发帖之星
日期:2015-11-06 06:20:00数据库技术版块每周发帖之星
日期:2015-12-02 15:02:47数据库技术版块每日发帖之星
日期:2015-12-08 06:20:00
发表于 2017-09-11 13:23 |显示全部楼层
本帖最后由 wlmqgzm 于 2017-09-11 13:38 编辑

回复 167# magiceye1

1)我自己的代码里面一直是定义了
    boost::asio::detail::signal_init<>   g_signal_pipe_disable;   // 接管SIGPIPE
然后就没有遇到相关问题,也就没有去深究.


2)发送部分,现在我基本上重写了asio库的整个发送过程,主要的原因是:
A. 测试中发现存在传送1GByte以上数据时,存在断线的概率,断线时TCP/IP底层有检测到错误,
 仔细反复测试,确认TCP/IP在linux的底层实现存在一个小BUG, 是写缓冲区的容量使用方面,实际使用的时候,并不能够长期将写缓冲区用满,否则会出现故障A.目前我们是使用到80%解决.
B. 另外就是Boost库传送一组多个块数据时,存在crush的风险,而成组成批在一条系统调用中发送数据,可以减少系统开销,实现更高的性能.
 这一块现在已经实现了多组数据块一次性打包传送到系统态,大大提高了大量多组数据包的发送效率,减少了系统开销.
 这块性能的提升还是比较明显的. 
C. 参考了DPDK 的实现思路,在一些情况下,使用轮询比epoll的性能高,使用了一个定时器在适当的时候切换到轮询工作模式,实现了更低开销.
D. Boost asio io_service存在一定的效率问题.写了一个类似功能的io_service作为辅助,性能比boost库的实现提升了5倍, std::function的跨线程调度能力超过了每秒1500万次
重写后,解决了boost库的BUG,绕过了TCP/IP的缺陷, 发送性能相比Boost库有大幅度的提升, 开销要小很多.
Boost库的发送部分已被彻底抛弃不用,里面的代码很久没有看过了,都快忘光了.


您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP