免费注册 查看新帖 |

Chinaunix

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

[C++] 读性能超过Memcached 65%, 单核也超过redis, 支持日志支持掉电保护,欢迎试用 [复制链接]

论坛徽章:
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
141 [报告]
发表于 2017-04-21 17:37 |只看该作者
本帖最后由 wlmqgzm 于 2017-07-10 13:46 编辑

提交了正式的 1.0.37版本, 该版本
1)主要是支持了IP V6,
2)使用了更高效率的自主研发的智能指针,
3)使用了自主研发的性能更高的各种锁,
4)使用了线程局部内存,增加了共享指针字符串对象的内存cache机制, 提高了跨线程内存释放的处理效率。
该版本在性能方面比上一个版本有提高, 尤其是set/add/replace/append/prepend/incr/decr这些指令的性能。

公司研发的智能指针haisql::unique_pt,对比 std::unique_ptr  主要的改进是:
1) 去掉了std::unique_ptr中的 deleter字段,认为这个一般都用不上, 节约了8字节,节约了50%内存。由于节约了50%内存, 所以,赋值等操作快了一倍。
2)unique_ptr中的有的语句, 例如:reset(pointer __p = pointer()) noexcept 赋值语句是swap, 我们认为还是直接先释放旧指针,再赋值, 比swap的效率更高。
总之, 无论是占用空间,还是性能方面,公司研发的unique_ptr都有更大的优势。

我们从C/C++最底层开始重新设计研发效率更高的C/C++底层库,随着时间的增加, 我们已经积累了超过1万行的C++库代码,每周我们都有新的库研发出来,
在速度更快,更好的C++内部库的助力下, 我们研发各类数据库产品,每个数据库产品都将受益于这些底层C++库所带来的更高的效率。
目前我公司的动态申请内存,并且使用了层层封装的Boost::asio网络接口的KV数据库, 已经比预申请内存的memcache快了70%, 单核性能也比redis更快,我们的性能还在继续进步中。。。。。。。。

论坛徽章:
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
142 [报告]
发表于 2017-04-21 19:53 |只看该作者
本帖最后由 wlmqgzm 于 2017-04-21 19:54 编辑

目前该KV数据库查询性能已经比 memcache 快70%, 要知道我的网络层是层层封装的Boost:asio,  内存是动态申请的(memcache的内存是预分配的),
单核性能也比Redis单核性能更快。代码全部是C++的,大量使用std::string, std::vector等各种C++对象, 除库代码外,只有5000行代码,性能超越C语言编写的,号称经典的memcache,确实是非常不容易,也说明了C++基础库对于性能和研发的重大影响。

也许有人会说 : C/C++库都是经典, 是不可超越的, 那么, 这里也是一个例子,即使是memcpy这样看上去无法优化的库代码,其实也是有办法优化的。
例如: 怎样写出一个更快的 memset/memcpy ? - 知乎用户的回答 - 知乎   https://www.zhihu.com/question/35172305/answer/61584927

论坛徽章:
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
143 [报告]
发表于 2017-06-12 00:56 |只看该作者
本帖最后由 wlmqgzm 于 2017-06-12 00:57 编辑

继续优化软件中, 为了选择最优的方式, linux下 做了一些测试
做了一个测试, 发现 new/delete 消耗的CPU资源远远大于malloc/free, 另外boost库的pool确实性能很差, 还不如不用.

begin test pool
100000000
0.499390s wall, 0.500000s user + 0.000000s system = 0.500000s CPU (100.1%)

begin test std1 new delete
100000000
2.293141s wall, 2.320000s user + 0.000000s system = 2.320000s CPU (101.2%)

begin test std2 malloc free
100000000
0.000006s wall, 0.000000s user + 0.000000s system = 0.000000s CPU (n/a%)

begin test std3 stack
100000000
0.000006s wall, 0.000000s user + 0.000000s system = 0.000000s CPU (n/a%)

代码如下:

struct Aaa32
{
  public:
    char  aaa[32];
};


void  test_pool( void )
{
  boost::timer::auto_cpu_timer   a2;

   unsigned int   j=0;
   std::cout << "begin test pool"<< std::endl;
   boost::pool<boost::default_user_allocator_malloc_free>   pool1( sizeof( Aaa32 ) );
  {
  for( unsigned long long i=0; i<100000000; ++i ) {
   struct Aaa32   *p_struct1 = reinterpret_cast<struct Aaa32  *>( pool1.malloc() );
   p_struct1->aaa[0] = '\0';
   struct Aaa32   *p_struct2 = reinterpret_cast<struct Aaa32  *>( pool1.malloc() );
   p_struct2->aaa[0] = '\0';
   pool1.free( p_struct1 );
   pool1.free( p_struct2 );
    ++j;
    continue;
    }
  }
  std::cout << j << std::endl;
  return;
}


void  test_std1( void )
{
  boost::timer::auto_cpu_timer   a2;

  unsigned int   j=0;
   std::cout << "begin test std1 new delete"<< std::endl;
  {
  for( unsigned long long i=0; i<100000000; ++i ) {
   struct Aaa32   *p_struct1 = new Aaa32;
   p_struct1->aaa[0] = '\0';
   struct Aaa32   *p_struct2 = new Aaa32;
   p_struct2->aaa[0] = '\0';
   delete  p_struct1 ;
   delete  p_struct2;
    ++j;
    continue;
    }
  }
  std::cout << j << std::endl;
  return;
}

void  test_std2( void )
{
  boost::timer::auto_cpu_timer   a2;

  unsigned int   j=0;
   std::cout << "begin test std2 malloc free"<< std::endl;
  {

  for( unsigned long long i=0; i<100000000; ++i ) {
   struct Aaa32   *p_struct1 = reinterpret_cast<struct Aaa32  *>( malloc( sizeof(  Aaa32 ) ) );
   p_struct1->aaa[0] = '\0';
  struct Aaa32   *p_struct2 = reinterpret_cast<struct Aaa32  *>( malloc( sizeof( Aaa32 ) ) );
  p_struct2->aaa[0] = '\1';
   free( p_struct1 );
    free( p_struct2 );
    ++j;
    continue;
    }
  }
  std::cout << j << std::endl;
  return;
}


void  test_std3( void )
{
  boost::timer::auto_cpu_timer   a2;

  unsigned int   j=0;
   std::cout << "begin test std3 stack"<< std::endl;
  {

  for( unsigned long long i=0; i<100000000; ++i ) {
   struct Aaa32   struct1;
   struct1.aaa[0] = '\0';
  struct Aaa32   struct2;
  struct2.aaa[0] = '\1';
    ++j;
    continue;
    }
  }
  std::cout << j << std::endl;
  return;
}



int main(int argc, char *argv[])
{
  test_pool( );
  test_std1();
  test_std2();  //exit;
  test_std3();  //exit;

论坛徽章:
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
144 [报告]
发表于 2017-06-12 01:31 |只看该作者
本帖最后由 wlmqgzm 于 2017-06-12 01:34 编辑

这几天在测试windows版本, 为了优化性能, 将windows版本的tcmalloc也链接进来, 发现windows下性能反而下降了, 原因不明. 测试是在一台古老的双核机器上, 或者是核心比较少的情况下, tcmalloc并没有优势的原因.

在windows下使用 tcmalloc 库, 需要注意的要点是:
1)用microsoft  vs2015编译 tcmalloc , 默认的是win32模式, 这样编译出来的是32位的链接库dll和lib,  需要自己定义 X64模式, 选择拷贝win32的其他设置, 执行重新生成,  才能编译出64位的链接库dll和lib.
尝试链接的时候, 发现链接格式 不正确的提示, 回过头来检查, 发现是X64/win32 的原因.
2)使用步骤1)的 tcmalloc 库, 我这边是在另外一台机器上, 安装的是windows 下的mingw/gcc, 需要注意的是: 除了要添加上步骤1)编译的链接库外,  需要 指定gcc 链接参数 -u __tcmalloc, 否则, 根本就不会链接上 tcmalloc 库. 这个参数是翻了无数gcc的资料, 一直没有任何资料说明,  试验了多种办法, 最终连猜带蒙弄出来的.

在windwos下折腾使用 jemalloc 库, 编译链接成功, 使用的是静态链接的方式, 然而编译期间告警很多, 都是一堆的重复定义之类的, 运行时出现了 crash 问题, 折腾很久未找到解决办法, 暂时先放弃掉.

抽空学习了operator new/delete 的一些用法, 以及new 的 enplace 模式, 一直在想有没有合适的渠道, 可以用来进一步优化性能.
然后将 boost pool 封装了一下, 实现了 thread_local_memory 的封装, 尝试准备多线程并发, 然而, 单独一测试boost pool, 发现boost pool的性能实在是太烂, 烂泥扶不上墙, 算了吧.
除非自己从头弄一套, 唉.
另外 operator new/delete 本身是static的, 想实现的一些用法, 还各种受限, 尝试了一阵子, 放弃了, 总之, 要简单的实现高效率的内存管理不容易.

测试中还发现一个问题, 就是new/delete 的开销远远大于malloc/free 的开销, 在上面的例子中,相差数千倍, 即使是一个最简单的struct,  
这两天就会提交一个windows的服务 版本, 不过性能比linux慢很多, 按说网络库底层是boost asio 的, 应该没有这么太大差距, 都是一个库.

windows安装程序是用 inno setup实现的, 里面注册服务 是用sc.exe 来实现的, 路径是利用 expand..({app})来获得的, 总之, 测试工程师在开发安装程序这块, 这两个问题一致搞不定, 我找了一些资料, 最终把这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
145 [报告]
发表于 2017-06-15 16:45 |只看该作者
我们的程序单机性能已经无法再提升了

这两天又有一个优化的思路,然后做到程序中, 结果测试发现在 低端双核机器上用memcslap测试, 很明显性能提高了。 在4核8线程机器上测试,发现基本没有变化。
思考之后,才发现,目前的版本已经优化到极限了,原因如下:
memcslap 测试包的大小是4KByte, 目前的性能是38.6万QPS,约等于40万QPS,  每秒传送的数据带宽=4X(10_3)X40X(10_4) = 16X(10_ = 1.6X(10_9) = 1.6GByte,
服务器端和客户端都在本机,刚好把 内存双通道 DDR3_1600 的带宽耗尽。

具体内存带宽的测试, 可以参考  memcpy 的测试,  http://blog.csdn.net/z2007b/article/details/6559457
http://blog.chinaunix.net/uid-22122564-id-3655984.html
基本上这两个测试结果都是 1G Byte memcpy 消耗的时间大约是0.7秒,大约每秒1.3G Byte,应该是DDR3 1333的时代测试的情况。

论坛徽章:
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
146 [报告]
发表于 2017-07-03 16:58 |只看该作者
本帖最后由 wlmqgzm 于 2017-07-10 14:07 编辑

关于硬件内存事务的测试

intel 硬件事务内存,其通过Transactional Synchronization Extensions(TSX)的组件来实现

测试Intel TSX指令集,准备实现一个更高效率的 乐观锁的结构,可以用于多种场合,
我们尤其希望这种指令可以进一步提升 shared_ptr 内部的一个乐观锁的性能,
希望解决乐观锁内部的临界区代码多线程下 已释放free内存 的快速处理,
代码完成后, 测试失败。

主要的原因是: intel 发现了TSX指令集中有BUG, 因此,升级BIOS后,BIOS临时将此指令集屏蔽掉了, 无法使用。
到Intel网站上查询,从2014年发现BUG至今,该TSX BUG一直没有修复。Not fix
https://www.intel.com/content/da ... 0v3-spec-update.pdf
http://www.expreview.com/35322.html

论坛徽章:
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
147 [报告]
发表于 2017-07-06 17:30 |只看该作者
本帖最后由 wlmqgzm 于 2017-07-10 14:21 编辑

关于线程安全的 shared_ptr

最近一段时间在确认 线程安全的共享指针shared_ptr 模型,
目标是:研发下一代智能指针 shared_ptr,保证在只有一个写操作和多个读操作并发下的线程安全
主要的困难在于: 多对象操作的安全保证, 如何实现一写多读的线程安全。

对于 一个简单的赋值语句, shared_ptr A = shared_ptr B, 我们首先要保证 shared_ptr A 只有一个线程在设置它,这个相对比较简单,使用指定特定单线程或者加一把锁都可以解决保证单写,
其次我们要保证 多线程读 shared_ptr B 的安全性,保证读期间的原子性和稳定性, 不能够出现读 shared_ptr B期间,原有内存被释放,也不能出现 shared_ptr B 被修改了一半数据的情况,
这个就比较复杂,读必须是无锁的,(如果采用两把锁的方式,一方面效率低, 另外一方面两把以上的锁很容易产生死锁的情况,死锁解脱代码讲非常复杂,我们不考虑这种方式。)
最终是通过 多个atomic顺序操作,通过软件事务内存解决。。。。
期间还测试了intel 的硬件事务内存 方式, 这种方式可以进一步提高性能, 但是由于intel TSX指令集出现BUG, Intel最新技术手册要求暂时不能使用该指令集, 只好作罢。

总之,使用了大量创新的超前的技术,研发出来下一代的高性能线程安全智能指针,
与现有shared_ptr/ weak_ptr/enable_shared_from_this/make_shared 在写法上完全兼容,可以简单无缝切换 std/boost 库的相关对象。

线程安全的代码非常不容易,每一行都要仔细检查,属于比较容易出错的代码,终于完成了。
新的 shared_ptr 具备单写多读的线程安全特性, 大大方便了多线程程序的开发, 我们只需要保证 最多只有一个线程写这个shared_ptr,就可以保证所有 读操作的安全, 真的太方便了。
我们还可以使用 引用方式 &shared_ptr 来传送数据, 减少调用过程的 increase_count 和 decrease_count,
全新的无锁赋值, 类似  Erlang 的用法, 我们可以使用 创建一个新shared_ptr,赋值给旧的 shared_ptr,  这个过程是无锁的,没有读并发冲突的

关于 std::shared_ptr 是线程不安全的说明,请参见 Google公司 陈硕 的说明===》 文章标题:为什么多线程读写 shared_ptr 要加锁?
http://blog.csdn.net/solstice/article/details/8547547

论坛徽章:
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
148 [报告]
发表于 2017-07-07 17:38 |只看该作者
函数式编程 以前没有什么地位,这两年比以前流行了,
我觉得重要的是思想,这种编程模式 对于编程中遇到的一些并发的问题,锁冲突的问题,分布式的问题,都给出了一些更简单的解决思路,我觉得受益匪浅。还有很多其他思路都很好
总之, 就是提供了另外一种解决方案或者解决思路,

虽然我用C++编程高并发领域,我觉得现在有了更多的工具包,作为备选方案:
1)mutex /spin_lock 之类传统的锁
2)无锁数据队列+多任务队列,解决并发。
3)函数式编程: immutable/ Copy_on_write / 无锁 shared_ptr(自主研发的只有8字节大小的不需要加锁的原子赋值的新型共享智能指针),也可以在很多场合消灭掉 锁 的使用, 提高并发性能。  

函数式编程  主要是解决高并发和分布式方向  的一种优秀思路。
今后更多CPU支持 “ 硬件事务内存”, 可以助推 函数式编程,可以说 函数式编程 目前是热点,也是未来的发展方向之一。

欧洲超算中心的主任, 非常推崇 “函数式编程”, 他认为目前最好的  分布式编程 = 分布式算法 + 异步消息传递 + 纯函数式,
同时指出了其他传统方式的各种缺陷。
可见他对  “函数式编程”的重视程度。
原文参见  分布式系统编程,你到哪一级了  http://blog.jobbole.com/20304/

论坛徽章:
14
水瓶座
日期:2014-06-10 09:51:0215-16赛季CBA联赛之江苏
日期:2017-11-27 11:42:3515-16赛季CBA联赛之八一
日期:2017-04-12 14:26:2815-16赛季CBA联赛之吉林
日期:2016-08-20 10:43:1215-16赛季CBA联赛之广夏
日期:2016-06-23 09:53:58程序设计版块每日发帖之星
日期:2016-02-11 06:20:00程序设计版块每日发帖之星
日期:2016-02-09 06:20:0015-16赛季CBA联赛之上海
日期:2015-12-25 16:40:3515-16赛季CBA联赛之广夏
日期:2015-12-22 09:39:36程序设计版块每日发帖之星
日期:2015-08-24 06:20:002015亚冠之德黑兰石油
日期:2015-08-07 09:57:302015年辞旧岁徽章
日期:2015-03-03 16:54:15
149 [报告]
发表于 2017-07-10 11:06 |只看该作者
回复 144# wlmqgzm

发现 new/delete 消耗的CPU资源远远大于malloc/free
new是operator new + 构造函数,比malloc耗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
150 [报告]
发表于 2017-07-10 14:00 |只看该作者
本帖最后由 wlmqgzm 于 2017-07-10 14:09 编辑
lxyscls 发表于 2017-07-10 11:06
回复 144# wlmqgzm

new是operator new + 构造函数,比malloc耗CPU,很正常吧

你是对的,很正常,
这里 reclaim 阐述这个大家已知的特性, 只是为了说明 我们的一个优化办法:
对于部分简单 struct,  如果内部没有什么特殊的需要 构造或者析构 的内容,那么我们可以采用 malloc/free 来代替 new /delete, 可以提高性能。  

评分

参与人数 1信誉积分 +10 收起 理由
lxyscls + 10 赞一个!

查看全部评分

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

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP