免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: wlmqgzm
打印 上一主题 下一主题

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

论坛徽章:
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
111 [报告]
发表于 2015-11-01 14:40 |只看该作者
4核心测试, 小字节数据包收发流量每秒100Mbyte, 已经可以把一个千兆网络占满了,
目前的测试, 测试软件基本上占了一半的CPU使用率, 对真实测试结果有影响. 估计, 目前, 4核心CPU的真实处理能力已经超过100万QPS ECHO,
如果另外找一台机器来做测试, 如果期望有超过82万QPS ECHO的性能, 那么,至少要绑定2个千兆网卡或者使用万兆网络, 才能得到理想的结果,   

暂时没有机器, 可以拿来做测试, 对网络层的测试暂时告一段落, 后面继续其他工作.  

论坛徽章:
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
112 [报告]
发表于 2015-11-02 00:00 |只看该作者
本帖最后由 wlmqgzm 于 2015-11-02 11:33 编辑

以前没有太多调优, 现在很多底层的东西都要自己测试, 积累经验.

测试mutex的效率,1亿次无锁冲突的lock, 大约1.5秒
测试atomic的效率,1亿次atomic, 大约0.5秒
测试内存屏障 1亿次全屏障, 大约0.41秒
测试循环的效率,1亿次循环加法, 大约0.0秒

guo@guo-desktop:/cpp/echo_server/bin/Release$ ./echo_server
begin test mutex.
100000000
1.503490s wall, 1.500000s user + 0.000000s system = 1.500000s CPU (99.8%)
begin test atomic.
0.509658s wall, 0.500000s user + 0.000000s system = 0.500000s CPU (98.1%)
100000000
begin test loop.
0.000000s wall, 0.000000s user + 0.000000s system = 0.000000s CPU (n/a%)
100000000
begin test fenced_block
0.410092s wall, 0.400000s user + 0.000000s system = 0.400000s CPU (97.5%)
100000000

  1. void  test_mutex( void )
  2. {
  3.   unsigned int i;
  4.   std::mutex  mutex1;
  5.   unsigned int j = 0;
  6.   std::cout << "begin test mutex."<< std::endl;
  7.   boost::timer::auto_cpu_timer   a2;

  8.   for( i=0; i<100000000; ++i ) {
  9.     std::lock_guard<std::mutex>  lock(cout_mutex);
  10.     ++j;
  11.     continue;
  12.     }
  13.   std::cout << j << std::endl;
  14.   return;
  15. }


  16. void  test_atomic( void )
  17. {
  18.   unsigned int i;
  19.   std::atomic<unsigned int>   j(0);
  20.   std::cout << "begin test atomic."<< std::endl;
  21.   {
  22.   boost::timer::auto_cpu_timer   a2;
  23.   for( i=0; i<100000000; ++i ) {
  24.     ++j;
  25.     continue;
  26.     }
  27.   }
  28.   std::cout << j << std::endl;
  29.   return;
  30. }

  31. void  test_loop( void )
  32. {
  33.   unsigned int i;
  34.   unsigned int   j=0;
  35.    std::cout << "begin test loop."<< std::endl;
  36.   {
  37.   boost::timer::auto_cpu_timer   a2;
  38.   for( i=0; i<100000000; ++i ) {
  39.     ++j;
  40.     continue;
  41.     }
  42.   }
  43.   std::cout << j << std::endl;
  44.   return;
  45. }


  46. void  test_fenced_block( void )
  47. {
  48.   unsigned int i;
  49.   unsigned int   j=0;
  50.    std::cout << "begin test fenced_block"<< std::endl;

  51.   {
  52.   boost::timer::auto_cpu_timer   a2;
  53.   for( i=0; i<100000000; ++i ) {
  54.    boost::asio::detail::fenced_block  fb(  boost::asio::detail::fenced_block::full );
  55.     ++j;
  56.     continue;
  57.     }
  58.   }
  59.   std::cout << j << std::endl;
  60.   return;
  61. }
复制代码

论坛徽章:
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
113 [报告]
发表于 2015-11-02 00:04 |只看该作者
本帖最后由 wlmqgzm 于 2015-11-02 11:29 编辑

各类内存池对比,内存申请的测试,基本上还是std默认的性能最优,Boost等都慢多了, 差距非常大,.因此 内存池无法更加优化.

申请32字节大小,1亿次
begin test vector mem 1, std default   .
2.132984s wall, 2.120000s user + 0.000000s system = 2.120000s CPU (99.4%)
100000000
begin test vector mem 2, boost::pool_allocator.
8.729578s wall, 8.720000s user + 0.000000s system = 8.720000s CPU (99.9%)
100000000
begin test vector mem 3.  boost::fast_pool_allocator
8.764987s wall, 8.760000s user + 0.000000s system = 8.760000s CPU (99.9%)
100000000
begin test vector mem 4.  __gnu_cxx::__pool_alloc
4.872141s wall, 4.870000s user + 0.000000s system = 4.870000s CPU (100.0%)
100000000
begin test vector mem 5.  __gnu_cxx::malloc_allocato
2.955835s wall, 2.950000s user + 0.000000s system = 2.950000s CPU (99.8%)
100000000
begin test vector mem 6.  __gnu_cxx::__mt_alloc
3.311399s wall, 3.300000s user + 0.000000s system = 3.300000s CPU (99.7%)
100000000

申请4KByte字节大小,1亿次
begin test vector mem 1, std default   .
6.051421s wall, 6.040000s user + 0.000000s system = 6.040000s CPU (99.8%)
100000000
begin test vector mem 2, boost::pool_allocator.
200.278515s wall, 200.100000s user + 0.000000s system = 200.100000s CPU (99.9%)
100000000
begin test vector mem 3.  boost::fast_pool_allocator
196.984990s wall, 196.820000s user + 0.000000s system = 196.820000s CPU (99.9%)
100000000
begin test vector mem 4.  __gnu_cxx::__pool_alloc
112.791246s wall, 112.680000s user + 0.000000s system = 112.680000s CPU (99.9%)
100000000
begin test vector mem 5.  __gnu_cxx::malloc_allocator
112.410630s wall, 112.310000s user + 0.000000s system = 112.310000s CPU (99.9%)
100000000
begin test vector mem 6.  __gnu_cxx::__mt_alloc
113.117813s wall, 113.020000s user + 0.000000s system = 113.020000s CPU (99.9%)
100000000

  1. void  test_vector_mem1( void )
  2. {
  3.   unsigned int i;
  4.   unsigned int   j=0;
  5.    std::cout << "begin test vector mem 1, std default   ."<< std::endl;
  6.    std::vector<char>  vt0(32);
  7.   {
  8.   boost::timer::auto_cpu_timer   a2;
  9.   for( i=0; i<100000000; ++i ) {
  10.     std::vector<char>  vt1(32);
  11.     ++j;
  12.     continue;
  13.     }
  14.   }
  15.   std::cout << j << std::endl;
  16.   return;
  17. }


  18. void  test_vector_mem2( void )
  19. {
  20.   unsigned int i;
  21.   unsigned int   j=0;
  22.    std::cout << "begin test vector mem 2, boost::pool_allocator."<< std::endl;
  23.    std::vector<char, boost::pool_allocator<char> >  vt0(32);
  24.   {
  25.   boost::timer::auto_cpu_timer   a2;
  26.   for( i=0; i<100000000; ++i ) {
  27.     std::vector<char, boost::pool_allocator<char> >  vt1(32);
  28.     ++j;
  29.     continue;
  30.     }
  31.   }
  32.   std::cout << j << std::endl;
  33.   return;
  34. }


  35. void  test_vector_mem3( void )
  36. {
  37.   unsigned int i;
  38.   unsigned int   j=0;
  39.    std::cout << "begin test vector mem 3.  boost::fast_pool_allocator"<< std::endl;
  40.    std::vector<char, boost::fast_pool_allocator<char> >  vt0(32);
  41.   {
  42.   boost::timer::auto_cpu_timer   a2;
  43.   for( i=0; i<100000000; ++i ) {
  44.     std::vector<char, boost::fast_pool_allocator<char> >  vt1(32);
  45.     ++j;
  46.     continue;
  47.     }
  48.   }
  49.   std::cout << j << std::endl;
  50.   return;
  51. }


  52. void  test_vector_mem4( void )
  53. {
  54.   unsigned int i;
  55.   unsigned int   j=0;
  56.    std::cout << "begin test vector mem 4.  __gnu_cxx::__pool_alloc"<< std::endl;
  57.    std::vector<char, __gnu_cxx::__pool_alloc<char> >  vt0(32);
  58.   {
  59.   boost::timer::auto_cpu_timer   a2;
  60.   for( i=0; i<100000000; ++i ) {
  61.     std::vector<char, __gnu_cxx::__pool_alloc<char> >  vt0(32);
  62.     ++j;
  63.     continue;
  64.     }
  65.   }
  66.   std::cout << j << std::endl;
  67.   return;
  68. }


  69. void  test_vector_mem5( void )
  70. {
  71.   unsigned int i;
  72.   unsigned int   j=0;
  73.    std::cout << "begin test vector mem 5.  __gnu_cxx::malloc_allocato"<< std::endl;
  74.    std::vector<char, __gnu_cxx::malloc_allocator<char> >  vt0(32);
  75.   {
  76.   boost::timer::auto_cpu_timer   a2;
  77.   for( i=0; i<100000000; ++i ) {
  78.     std::vector<char, __gnu_cxx::malloc_allocator<char> >  vt1(32);
  79.     ++j;
  80.     continue;
  81.     }
  82.   }
  83.   std::cout << j << std::endl;
  84.   return;
  85. }


  86. void  test_vector_mem6( void )
  87. {
  88.   unsigned int i;
  89.   unsigned int   j=0;
  90.    std::cout << "begin test vector mem 6.  __gnu_cxx::__mt_alloc"<< std::endl;
  91.    std::vector<char, __gnu_cxx::__mt_alloc<char> >  vt0(32);
  92.   {
  93.   boost::timer::auto_cpu_timer   a2;
  94.   for( i=0; i<100000000; ++i ) {
  95.     std::vector<char, __gnu_cxx::__mt_alloc<char> >  vt1(32);
  96.     ++j;
  97.     continue;
  98.     }
  99.   }
  100.   std::cout << j << std::endl;
  101.   return;
  102. }
复制代码

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
114 [报告]
发表于 2015-11-02 02:16 |只看该作者
本帖最后由 windoze 于 2015-11-02 02:17 编辑

回复 113# wlmqgzm

至少你需要试试tcmalloc,dlmalloc,libumem之类现成的malloc实现,然后再试试自制一个lock free/wait free slab based memory allocator。
光这么一句“std默认的性能最优”说明你完全没搞清这玩意儿里面到底怎么转的。

我才不会告诉你当前Linux GLIBC默认用的是ptmalloc…………

论坛徽章:
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
115 [报告]
发表于 2015-11-02 09:03 |只看该作者
本帖最后由 wlmqgzm 于 2015-11-02 09:06 编辑

回复 114# windoze

谢谢提醒, 多测试一下, 以前用过google-perftools里面带有tcmalloc, 好久不用都忘记了.
只测试了最主流的三种, 默认:ptmalloc, 性能最快的tcmalloc, 号称多线程下有更好表现的jemalloc.  
ptmalloc是dlmalloc的分支, libumem没有找到新的版本, 只有2007年的版本, 就不测试了.
基本上还是tcmalloc性能最快.

另外, 更换内存引擎, Echo server收发包性能无变化, 因为accept时预先分配了12KByte, 单ab测试程序只有100个连接, 后来每个收发包都不涉及内存分配
应该对新建连接性能有影响.

ptmalloc 32Byte
begin test vector mem 1, std default   .
2.132984s wall, 2.120000s user + 0.000000s system = 2.120000s CPU (99.4%)
100000000

jemalloc 32Byte
begin test vector mem 1, std default   .
1.625155s wall, 1.620000s user + 0.000000s system = 1.620000s CPU (99.7%)
100000000

tcmalloc 32Byte
begin test vector mem 1, std default   .
1.210702s wall, 1.210000s user + 0.000000s system = 1.210000s CPU (99.9%)
100000000

===================================================

ptmalloc 4KByte
begin test vector mem 1, std default   .
6.051421s wall, 6.040000s user + 0.000000s system = 6.040000s CPU (99.8%)
100000000

jemalloc4k
begin test vector mem 1, std default   .
5.321043s wall, 5.310000s user + 0.000000s system = 5.310000s CPU (99.8%)
100000000

tcmalloc 4K
begin test vector mem 1, std default   .
4.931310s wall, 4.920000s user + 0.000000s system = 4.920000s CPU (99.8%)
100000000  

论坛徽章:
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
116 [报告]
发表于 2015-11-02 11:04 |只看该作者
本帖最后由 wlmqgzm 于 2015-11-02 11:28 编辑

回复 95# hellioncu

谢谢提醒, 昨天在 服务器代码中又仔细找了一遍可能需要 内存屏障 的地方,  基本上所有的代码都不需要, 因为这些需要线程交换数据的地方, 都调用了io_sevice.post, post内部设置了 内存屏障
只有1个显示统计总计数的函数, 可能会需要.
最终调用这个显示统计总计数函数的地方只有一处, 就是最后退出, 总体析构的时候, 而且析构过程中有至少有1ms sleep保护,最后才调用显示统计总计数, 理论上也不需要  内存屏障
但是考虑以后, 可能要更改代码, 提供随时查看总计数, 在更新计数器的函数中就加上了 sfence.   

boost::asio::detail::fenced_block  fb(  boost::asio::detail::fenced_block::half );

继续进行底层的基本性能测试, 算学习吧, 更精细的了解情况.
测试对比性能, 只使用sfence的代码, 每秒大约可执行6亿次,  比不冲突的锁, 性能要高10倍.  减少锁的使用量, 确实能够提高一点性能.
但是, 非冲突的锁,  单线程下每秒也可以执行6000多万次, 性能也是非常突出的.
所以, 有锁的前提下, 最重要的是减少锁冲突, 代码中有几个锁,如果不冲突的话, 代价并不高.

begin test  half fenced_block(sfence)
0.163584s wall, 0.160000s user + 0.000000s system = 0.160000s CPU (97.8%)
100000000
begin test fenced_block(sfence+lfence)
0.410092s wall, 0.400000s user + 0.000000s system = 0.400000s CPU (97.5%)
100000000
begin test mutex.
100000000
1.503490s wall, 1.500000s user + 0.000000s system = 1.500000s CPU (99.8%)
begin test atomic.
0.509658s wall, 0.500000s user + 0.000000s system = 0.500000s CPU (98.1%)
100000000

  1. void  test_fenced_block( void )
  2. {
  3.   unsigned int i;
  4.   unsigned int   j=0;
  5.    std::cout << "begin test fenced_block"<< std::endl;

  6.   {
  7.   boost::timer::auto_cpu_timer   a2;
  8.   for( i=0; i<100000000; ++i ) {
  9.    boost::asio::detail::fenced_block  fb(  boost::asio::detail::fenced_block::full );
  10.     ++j;
  11.     continue;
  12.     }
  13.   }
  14.   std::cout << j << std::endl;
  15.   return;
  16. }


  17. void  test_half_fenced_block( void )
  18. {
  19.   unsigned int i;
  20.   unsigned int   j=0;
  21.    std::cout << "begin test  half fenced_block"<< std::endl;

  22.   {
  23.   boost::timer::auto_cpu_timer   a2;
  24.   for( i=0; i<100000000; ++i ) {
  25.    boost::asio::detail::fenced_block  fb(  boost::asio::detail::fenced_block::half );
  26.     ++j;
  27.     continue;
  28.     }
  29.   }
  30.   std::cout << j << std::endl;
  31.   return;
  32. }
复制代码

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
117 [报告]
发表于 2015-11-02 12:15 |只看该作者
回复 115# wlmqgzm

I服了you,你就拿你现在100个连接的echo server测32个字节的小包看不出区别了…………

难道说你花这么大力气搞这么一堆东西就打算做一个支持100并发的echo server?再说你现在拿这么个echo server往死了做benchmark有什么意义呢?具体应用中的瓶颈肯定不一样啊

论坛徽章:
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
118 [报告]
发表于 2015-11-02 12:40 |只看该作者
本帖最后由 wlmqgzm 于 2015-11-02 12:42 编辑

回复 117# windoze

你说的对, 这个改进当然还是有必要的, 提高了大并发下新建连接的性能, 并且实际应用中, 性能肯定有所改善.  测试不能全面反映情况.
已经将代码中的内存管理, 换用tcmalloc了, 能简单压出一点性能的地方, 都要用上.  

g++  -o bin/Release/echo_server obj/Release/main.o  -s  -lboost_thread -lboost_system -lboost_timer -ltcmalloc_minimal

论坛徽章:
44
15-16赛季CBA联赛之浙江
日期:2021-10-11 02:03:59程序设计版块每日发帖之星
日期:2016-07-02 06:20:0015-16赛季CBA联赛之新疆
日期:2016-04-25 10:55:452016科比退役纪念章
日期:2016-04-23 00:51:2315-16赛季CBA联赛之山东
日期:2016-04-17 12:00:2815-16赛季CBA联赛之福建
日期:2016-04-12 15:21:2915-16赛季CBA联赛之辽宁
日期:2016-03-24 21:38:2715-16赛季CBA联赛之福建
日期:2016-03-18 12:13:4015-16赛季CBA联赛之佛山
日期:2016-02-05 00:55:2015-16赛季CBA联赛之佛山
日期:2016-02-04 21:11:3615-16赛季CBA联赛之天津
日期:2016-11-02 00:33:1215-16赛季CBA联赛之浙江
日期:2017-01-13 01:31:49
119 [报告]
发表于 2015-11-02 12:44 |只看该作者
回复 118# wlmqgzm

对于框架,我还是觉得自制一个memory pool会比较好,因为框架里的内存分配使用情况基本是已知的,用memory pool可以(几乎)完全消除掉所有的内存分配和释放。

论坛徽章:
0
120 [报告]
发表于 2015-11-02 17:45 |只看该作者
....900的并发  其实你测试的是大块数据的传输, 这根本没什么压力。 把连接数提到100万以后,再来做测试。 你能做到50wqps 都很高了!
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP