免费注册 查看新帖 |

Chinaunix

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

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

论坛徽章:
36
子鼠
日期:2013-08-28 22:23:29黄金圣斗士
日期:2015-12-01 11:37:51程序设计版块每日发帖之星
日期:2015-12-14 06:20:00CU十四周年纪念徽章
日期:2015-12-22 16:50:40IT运维版块每日发帖之星
日期:2016-01-25 06:20:0015-16赛季CBA联赛之深圳
日期:2016-01-27 10:31:172016猴年福章徽章
日期:2016-02-18 15:30:3415-16赛季CBA联赛之福建
日期:2016-04-07 11:25:2215-16赛季CBA联赛之青岛
日期:2016-04-29 18:02:5915-16赛季CBA联赛之北控
日期:2016-06-20 17:38:50技术图书徽章
日期:2016-07-19 13:54:03程序设计版块每日发帖之星
日期:2016-08-21 06:20:00
91 [报告]
发表于 2016-08-18 10:47 |只看该作者
wlmqgzm 发表于 2016-07-17 10:37
孩子终于出院了, 算捡回了一条命, 感冒病毒感染, 继发细菌感染, 然后各类抗生素无效, 出现败血症, 最后终于 ...


楼主是不是太醉心于代码,对孩子关心太少,才生这么重的病?多陪陪家人,珍惜身边的人一起的时光。

论坛徽章:
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
92 [报告]
发表于 2016-08-29 01:05 |只看该作者
本帖最后由 wlmqgzm 于 2016-08-29 01:17 编辑

上周主要做了一些memcached层的接口代码,目前已经实现了set,get,replace,add等几个基本命令,并且与Key_Value_Table对接成功,少量单线程功能测试基本完成,
现在还有定时清除旧数据的代码没有完成,另外, 还有increase/ decrease 的命令代码没有完成。

由于代码比较复杂,时间有限, 资源有限, 又是多线程高性能并发,为了尽快完成一个可用的版本, 干脆直接设计了一个简化版本,先暂时把落地部分的代码全部屏蔽掉,就只做内存数据库,先不做落地
现在觉得实际做代码以后, 往往出现比自己最早预想的代码要难以调试,只要不断的放弃暂时不需要的功能模块,集中力量于当前重点模块。

最近手上还有优先级比较高的其他项目,家里家外一堆事情, 人生就是不断与命运妥协的过程,。。。。。
这几天做代码不在状态中, 预计在7-14天后可以完成全部功能的代码,就是说基本功能都实现的版本, 一般这种多线程的联合调试和优化查问题,最少要一个月时间, 才能达到比较理想的情况, 这样看的话,10月份希望能够推出一个正式版本的MemCached话,就算很有成就了。

尽管人生总是充满了眼高手低, 但是, 还是充满了希望, 希望自己通过这一段时间的努力, 可以开发出一套世界上最快速的内存数据库。
目前, 设计命令集基本是与Memcached全部兼容。

主要的性能基础是:
1)高性能网络层, 普通4核8线程3.2G CPU单跑Echo_server大约85万QPS
2)  内部划分了256个hash表用于存储Key_value数据, 并且将各个数据平均分摊给每个CPU处理,实现了全并发,并发性能很高。
3)hash计算内部处理优先采用 intel SSE4.2指令集处理,对其他CPU采用Boost Crc算法处理。
期望的性能是比 现有的memcached快一倍。

下周要进行详细性能测试,正在找有关的测试工具。

论坛徽章:
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
93 [报告]
发表于 2016-11-05 17:10 |只看该作者
本帖最后由 wlmqgzm 于 2016-11-06 12:52 编辑

最近比较忙, 一直没有时间更新这个帖子, 目前已经开发完成了一个内存数据库, 与memcache指令集兼容, 与memcached性能基本相当, 目前正在优化中, 最终测试结果要过一段时间

主要优化的方向是两个:
1)hash_map的性能优化, 主要是开发更高效率的hash_map, 有2个方向: 一个是常规有锁hash_map, 一个是无锁hash_map
2)网络层内部写缓冲优化, 目前的结构为std::vector<char>,  计划修改设计输出结构为一个std::queue<std::shared_ptr<std::string> >,这样可以减少一次内存Copy写

近期主要的与此项目相关的技术开发内容是:

1)重新编写了std::unordered_map的代码, 自己开发了新的hash_map,  目前正在测试优化中, 性能测试是:整数key 性能比std::unordered_map提高至少30%,  
delete默认支持自动auto_rehash收缩.   key类型是string,  测试性能提高更大.  目前这部分代码还在测试优化中, 版本代码到目前为止还在每天更新中, 最后的测试结果过一段时间再汇报.

主要的技术改进点是使用了一次性分配的环形队列, 并且引入了hash缓冲, 数据最大查找限制次数等技术. 基本上完全推翻了现有教材中hash_map的vector+list的模型, 算是全新设计的模型吧,
目前还在优化测试中, 版本变化还比较大, 还在寻找更优的方法, 测试改进中.................

2) 同时还在准备编写 对应的无锁hash_map, 目前主要的技术思路是  成熟的无锁设计方法:
大对象用裸指针T* + 对象Copy change + + 内存同步原语 + 更新裸指针T* + 垃圾内存自动回收机制,
小对象有开销更小的办法,
另外还在测试和寻找  总体开销更小的无锁技术方案..................
从开销上看, 无锁hash_map, 单线程必然更慢, 多线程才会快起来.

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

论坛徽章:
2
综合交流区版块每日发帖之星
日期:2016-07-06 06:20:00综合交流区版块每日发帖之星
日期:2016-08-16 06:20:00
94 [报告]
发表于 2016-11-06 12:48 |只看该作者
欢迎继续更新,加油回复 2# wlmqgzm

论坛徽章:
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
95 [报告]
发表于 2016-11-07 22:52 |只看该作者
这两天在测试 自己重写的std::unordered_hash库, 主要的变化有几点:
1)去掉了标准算法容器等效于 vector<list<T>>, 改进后的算法 容器等效于boost::circular_buffer<T>, 由于有更好的cache依存性, 在多数情况下性能会更好
2)算法中容器默认为2的倍数, 每次都按照2的倍数扩展或者减少, 这样去掉了消耗资源多的除法运算, 用&代替, hash值的匹配更快速
3)rehash的改进: 将rehash中copy T过程, 对于旧容器进行依次pop, 及时释放内存, Copy一个释放一个, 而不是一次性释放, 减少了rehash过程中的内存占用.
4)删除中添加检测并 自动rehash, 及时减少内存占用.
5)hash值的缓存, 将每个Key的hash缓存下来,多占用4个字节, 但是rehash的时候就不用重新计算了, 提高了insert性能.

总体上内存占用率下降20%以上, 综合性能提高70%以上.

下为测试情况:

guo@guo-desktop:/mnt/guo/newcpp/hash_map/bin/Release$ ./hash_map
TEST_COUNT=10000000, std::unordered_map<std::string, std::shared_ptr<std::string> >   map1;  // 依次为insert , find , delete的花费时间,

6.076009s wall, 5.880000s user + 0.180000s system = 6.060000s CPU (99.7%)

3.253689s wall, 3.250000s user + 0.000000s system = 3.250000s CPU (99.9%)

4.088779s wall, 4.080000s user + 0.000000s system = 4.080000s CPU (99.8%)

Log: Time=2016-11-06T19:17:10.074099, Line=75, File="/mnt/guo/newcpp/hash_map/main.cpp", Func="test_myhash", Msg="Circular_hash_map    map2"

3.652572s wall, 3.610000s user + 0.050000s system = 3.660000s CPU (100.2%)

2.086055s wall, 2.080000s user + 0.000000s system = 2.080000s CPU (99.7%)

3.389029s wall, 3.360000s user + 0.030000s system = 3.390000s CPU (100.0%)   // 主要是delete中  多次rehash回收了内存, 如果去掉rehash,速度会更快

论坛徽章:
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
96 [报告]
发表于 2016-11-09 11:50 |只看该作者
本帖最后由 wlmqgzm 于 2016-11-09 11:52 编辑

最近又继续优化了wait_free_queue的设计,重新从头开始重写了代码, 彻底抛弃了boost::lock_free库, 完全使用自己的底层lock_free库

这么做的原因是:
(1)boost::lock_free::spsc_queue限制太多, 类型T只支持常规变量,例如整数之类的, 不支持shared_ptr等各类对象,
(2)性能要比自己写的低很多 ,
(3)不支持mpsc/spmc 多生产者或者多消费者 wait_free
(4)功能太少,不支持双向的消息通知, 生产者生产后, 无法通知消费者处理, 消费者处理后不自动通知或者回调生产者
(5)与Boost::asio:io_service没有集成, 无法集中处理CPU资源的申请和释放

下面是最简单的spsc_queue的对比测试情况:测试10亿条数据的push/pop, 只用了不到3秒
TEST_COUNT=1000000000
My Wait_free_spsc_queue<unsigned int>  c1
2.915357s wall, 5.430000s user + 0.340000s system = 5.770000s CPU (197.9%)

boost::lockfree::spsc_queue<unsigned int, boost::lockfree::capacity<4096> >  boost_spsc_queue;
4.840341s wall, 9.430000s user + 0.190000s system = 9.620000s CPU (198.7%)

下面是测试代码:
#define TEST_COUNT   1000000000
Wait_free_spsc_queue<unsigned int>  c1;
boost::lockfree::spsc_queue<unsigned int, boost::lockfree::capacity<4096> >  boost_spsc_queue;

   {
   std::cout << std::endl << "My Wait_free_spsc_queue<unsigned int>  c1" << std::endl;

   boost::timer::auto_cpu_timer   a1;
   std::thread  t1( thread_push_run1 );
   std::thread  t2( thread_pop_run1 );
   t1.join();
   t2.join();
   }

      {
   std::cout << std::endl << "boost::lockfree::spsc_queue<unsigned int, boost::lockfree::capacity<4096> >  boost_spsc_queue;" << std::endl;

   boost::timer::auto_cpu_timer   a1;
   std::thread  t1( thread_push_run_boost );
   std::thread  t2( thread_pop_run_boost );
   t1.join();
   t2.join();
   }

论坛徽章:
0
97 [报告]
发表于 2017-02-06 14:57 |只看该作者
欢迎更新

论坛徽章:
0
98 [报告]
发表于 2017-02-06 14:59 |只看该作者
支持

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

为了测试和验证高性能方向的各种技术模型, 决定将一些先进的C++ class放出来,编写了一个简单的KV内存数据库出来,一方面是为了性能验证,另外一方面,也总算有一个数据库产品面世了。
主要的优点是:性能非常快,支持数据日志,支持数据的掉电保护,性能是常规数据库的10倍。测试 KV 数据大小是4.1K字节.

这个产品的数据结构比较简单,因为是内存数据库,全部数据都在内存中,各类操作简单到了极致,全部都是文本格式,包括日志在内,都一样。
因为是内存数据库不需要读磁盘,这个产品没有使用file_mapping等磁盘读技术,磁盘IO只使用了C++  iofstream。
各种逻辑处理也比较简单,例如:
日常的更新删除插入操作,要写日志,日志内容就是set指令和delete指令。
在正常退出的时候,将全部数据保存(更名数据表为旧,保存数据,保存成功删除旧数据表),如果全部数据表都保存成功,就清空日志。
在启动时,先检查是否存在旧数据表,如果存在,读取旧数据表,再读取日志,否则,直接读取新数据表就可以。。。。。。。

性能比较快,主要快在:
1)一个是有一个快速的网络层,基于Boost::asio基础上二次封装优化改进后的网络库,网络层总行数超过4000行。
2)比std::unordered_map更快,rehash性能抖动小的自主研发的高性能 基于 环形队列 结构的 circular_hash_map 库。环形队列大小自动收缩扩展。
3)log日志单独线程处理,因此, 有更快的速度,有更多的合并写,极大提高了日志的写性能。
4)wait_free_mpsc_queue 多生产者单消费者无等待队列的应用, 极大的提高了多线程的并发性能。 多线程写日志就是通过此队列传递给log单线程 实现。
自主研发的多生产者单消费者无等待队列,性能非常好,比boost库中最快的wait_free_spsc_queue快很多, 时延更小,可以支持任意对象放入到队列中(boost库中的那个只支持普通POD数据,最大长度8字节),支持双向数据传送(boost库只支持单向,我们的版本支持pop处理后的push线程的callback回调数据的传送),支持无任务自动休眠,支持push自动**(10微秒),自动pop处理, 自动调用after_pop_all,自动call_back调用.  内部主要是基于std::atomic和memory_order相关的命令来实现,有一定的技术难度。
使用时,预先设置各function函数,主程序 只要push数据,其他过程都是自动完成的。
5)各种高性能外围库的实现,重写了很多std库。 例如:常用的二进制和十进制互转,常规std库一般是循环将二进制除10来实现的, 我们的库是使用了 5的魔术数字的 乘法+移位来实现的,性能提高了很多。类似std::to_string(T&)之类的库, 性能都有了几倍的提高。
6)各类锁,很多公司和产品都有提供自己写的锁,以便提供比std:;mutex更好的性能,例如:mysql中的自旋锁, 与很多公司此类库直接使用cas指令不同,我们主要是用std::atomic来实现,兼容性更好,参考了C++标准化委员会的建议代码,增加了锁冲突后yield()的机制,无其他任务可执行时候每次spin检查延迟时间只有0.1微秒,有其他任务可执行时将切换线程释放CPU,标准锁class大小只有1个字节, 兼容所有操作系统和所有CPU。
库中已经实现的锁包括:标准锁,读写锁(写优先锁), 读写锁(读优先锁),可重入锁。所有的锁在用法上与std库兼容, 因此,可以直接使用std::lock_guard等各类上锁的标准std操作。

现在将阶段性的技术开发软件,汇总了一个简单的国产高性能数据库出来,放到网站  www.haisql.com 上了,测试版本是免费使用一个月,
性能指标是 在普通4核CPU上 24万QPS,  打开日志功能的插入更新性能是20万TPS,  插入更新每次都刷新日志的性能是16万TPS(64连接下单32G SSD测试,刷新是使用C语言 flush 刷新)

语法是基本上是兼容memcache(各命令和返回结果都一致),因此,直接用memcache的客户端就可以使用了。

论坛徽章:
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
100 [报告]
发表于 2017-02-10 19:28 |只看该作者
本帖最后由 wlmqgzm 于 2017-02-10 19:37 编辑

关于日志的多个写请求的写合并技术介绍如下:

1)不保存日志的情况下,在低端4核CPU下,可以实现24万TPS的更新或者插入性能。

2)保存日志,每秒刷新一次, 或者,空闲时刷新日志, 在低端4核CPU下,可以实现20万TPS的更新或者插入性能。
log日志单独线程处理,因此, 有更快的速度,更多的合并写,提高了日志的写性能。
因为是单线程处理,因此合并多个写日志的操作,非常简单,
默认的工作方式 data_log_work_mode=3 就是 log_thread 先尽量往日志文件中写日志,直到队列中没有数据要写后, 最后再flush刷新日志文件。这样有可能合并几十到几百个写请求。
主要的思路就是尽可能首先去执行写日志,而把刷新放到次要的任务,最大限度合并写请求,实现最高的性能。

3)在打开日志并且每次更新都刷新磁盘的情况下,在低端4核CPU下,可以实现16万TPS的更新或者插入性能。这个性能是常规数据库的100倍以上。
工作方式 data_log_work_mode=4 socket的数据更新操作要等日志刷新到磁盘后,再返回命令执行结果。
内部处理的方式就是:
例如:64个并发连接都在更新数据,服务器接收和处理执行完命令后socket_thread不发送数据, 也不接收数据,直到log_thread处理完log日志队列中的任务(CPU线程 直接处理下一个连接或者任务队列中的任务去了),客户端等待收执行结果中,
日志队列有数据后, log_thread被自动唤 醒后,先尽量往日志文件中写日志,同时保存好回调的socket_data, 直到队列中没有数据要写后, 最后再flush刷新日志文件,所有的日志都被保存到磁盘中了,这样1次磁盘写就合并了最多64个写请求,log_thread再依次按照前面保存的socket_data通知64个并发连接,socket写执行结果数据, 客户端收到执行结果(此时保证数据已经写入日志成功了)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP