忘记密码   免费注册 查看新帖 | 论坛精华区

ChinaUnix.net

  平台 论坛 博客 认证专区 大话IT HPC论坛 徽章 文库 沙龙 自测 下载 频道自动化运维 虚拟化 储存备份 C/C++ PHP MySQL 嵌入式 Linux系统
最近访问板块 发新帖
楼主: 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
发表于 2016-05-13 10:40 |显示全部楼层
本帖最后由 wlmqgzm 于 2016-05-13 10:43 编辑

不积跬步,无以致千里.

初步决定, Memcached的接口一定要做, 只有先做了简单的接口, 测试实践积累经验后, 才能做成更多更好的事情.  好代码都是熬出来的.

用户接口层 与 存储层 之间的接口问题 开始考虑中............

初步的思路是: 双异步策略, 这样可以提供最大化的并发, 并且希望对象之间的耦合比较少. 那么可行的一个技术路径就是: 队列.
分为四类队列, 存储层查询队列, 存储层更新队列, 网络层接收查询结果队列, 网络层接收更新结果队列.

File_mapping 目前遇到的难题是: 层层封装之后, 高层代码对底层隔离了, 但是底层File存在需要动态扩展大小, 然后再ReMapping的问题, 以及写mapping在大小超过4G以后,淘汰前一个Mapping, 创建新文件和新Mapping,  层层传递失败返回结果的模式, 比较土,效率不高.
目前, 正在调整class的关系, 初步的思路是: 高性能代码要减少层级, 正在压缩中......   
昨天在考虑 存储层对象的智慧化, 还在考虑还有没有其他解决办法...................................

思考中:  mapping_region的shared_ptr 能否帮助实现更自动化的管理, 如何设计这部分代码流程......

论坛徽章:
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-05-13 10:56 |显示全部楼层
本帖最后由 wlmqgzm 于 2016-05-13 10:59 编辑

先上点干货,  谈几句时间的问题:

高性能的代码测试, 离不开高性能的时间函数. 以下代码都是本人亲自开发, 亲自调试过的东西. 都是现有的库,
前一段代码是Boost的库, 后一段代码是std的库
几乎同样字节数的代码, 性能差距超过20倍

先上一组 取时间的函数

//  性能太差了, 执行大约要16微秒
unsigned long long now_utc_useconds( void )
{
  return ( boost::posix_time::microsec_clock::universal_time() - ptiime_epoch ).total_microseconds();
}

//  性能太差了, 执行大约要16微秒
unsigned long long now_local_useconds( void )
{
  return ( boost::posix_time::microsec_clock::local_time() - ptiime_epoch ).total_microseconds();
}

//  性能太差了, 执行超过17微秒
void now_local_str( std::string &str_datetime )
{
  boost::posix_time::ptime ptime1 = boost::posix_time::second_clock::local_time();
  str_datetime =  boost::posix_time::to_iso_extended_string( ptime1 );
  return;
}

//  性能太差了, 执行超过17微秒
void now_utc_str( std::string &str_datetime )
{
  boost::posix_time::ptime ptime1 = boost::posix_time::second_clock::universal_time();
  str_datetime =  boost::posix_time::to_iso_extended_string( ptime1 );
  return;
}

再上一组高性能高精度的,
//  高性能, 高精度, 执行低于1微秒
unsigned long long now_utc_microseconds(void)
{
  std::chrono::time_point<std::chrono::system_clock> now1 = std::chrono::system_clock::now();
  unsigned long long  time_microseconds = std::chrono::duration_cast<std::chrono::microseconds>( now1.time_since_epoch() ).count();
  return time_microseconds;
}

//  高性能,高精度, 执行低于1微秒
unsigned long long now_utc_nanoseconds(void)
{
  std::chrono::time_point<std::chrono::system_clock> now1 = std::chrono::system_clock::now();
  unsigned long long  time_nanoseconds = std::chrono::duration_cast<std::chrono::nanoseconds>( now1.time_since_epoch() ).count();
  return time_nanoseconds;
}

论坛徽章:
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-05-13 13:17 |显示全部楼层
本帖最后由 wlmqgzm 于 2016-05-16 00:50 编辑

上传一个 自己的网络库 制作的ECHO SERVER    echo_server_v1.01_linux (1.74 MB, 下载次数: 19)

论坛徽章:
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-05-16 22:23 |显示全部楼层
高性能存储层的代码, 主要困难在:
1) 多线程下编程的复杂性, 涉及到锁, PV等, 也涉及到随之带来的锁冲突.
2) 高性能编程的各类新技术的消化.
3) 尽可能取舍, 在一些情况下尽量用单线程来代替锁.

因此, 这部分代码编写比较慢, 修改也频繁, 明天开始写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
发表于 2016-05-18 16:33 |显示全部楼层
本帖最后由 wlmqgzm 于 2016-05-19 22:33 编辑

存储层的Mapping写线程自动扩展文件大小, 进行写入, 不需要线程间同步的情况下, 读线程高效自动跟随扩展是如何实现的?

前面比较困扰的 mapping文件自动扩展大小后, 采用传统方案, re maping地址大小等参数全部要变化, 层层通知高层代码带来代码复杂化, 低效化, 多线程互相通知同步等等问题, 以及随之带来的可能线程进程冲突的问题.
全新的解决办法:  废弃掉老代码, 实现底层代码智能化的解决方案, 轻松搞定.
现在由于采用了底层代码智能化的方式, 稳定平滑, 不需要通知高层代码, 对高层代码透明, 对多线程透明

关键实现:
在检测到 底层读请求超边界后调用, ,
生成新内存对象, 用第2组虚地址 +前一组老的虚地址  共同指向同一个物理地址,保证平滑扩展, 旧内存对象保护起来, 等以后第2次扩展的时候释放, 保护其他多线程的操作,  这部分是虚内存, 不是物理内存, 因此不用马上释放, 也不能马上释放.
利用原子量计数保护, 实现 扩展函数 线程可再入, 还是没有使用锁.

所有的Mapping代码全部是全新的高性能无锁设计, 支持 多线程 高效并发.

读线程  扩展跟随  功能代码通过 "原子量+3组写内存屏障" 的新技术方案,
// 原子量计数保护, 实现 扩展函数 线程可再入
//  先  生成新内存对象 写屏障保证顺序
/ 再切换地址, 写屏障保证顺序
// 最后切换文件长度,  写屏障保证顺序
实现了稳定平滑文件扩展,   不需要线程间通知, 不需要层层代码通知, 无锁设计, 代码 线程安全, 线程可再入

论坛徽章:
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-05-19 22:05 |显示全部楼层
本帖最后由 wlmqgzm 于 2016-05-19 22:35 编辑

这2天把File_Mapping的代码理了一遍, 实现的机制上, 分为Mapping_read和Mapping_write 这2个对象,  读对象是多线程安全的, 可以并发读, 写对象是单线程驱动的.
分离的设计, 读对象可以无锁设计, 写对象单线程驱动, 也不用锁, 写对象更新数据后, 利用多组内存写屏障技术+offset隔离技术, 保证读对象读到的所有数据都是最新的.
读写分离的机制, 无锁的设计, 这些全新的设计理念, 为上层代码 有望提供非常好的性能.

后续准备再分离出第3个File_mapping对象, Mapping_lz4_write对象, 由于设计中, lz4_commpressHC消耗的资源还是比较大的, 把这部分设计单独拿出来, 用单独的线程驱动,
目前File_mapping的设计, 兼容linux和Windows, 关键的原因在于使用了 boost::interprocess::file_mapping 这个库, 比较简洁的实现了核心代码.

File_mapping层代码的实现上, 实现了无锁设计, 读Mapping所有需要锁的地方, 全部使用 内存写屏障 和 原子量 的办法解决了, 写Mapping是单线程,  因此, 预计File_Mapping层的代码 并发能力超强.
File_Mapping层的上层代码是Block层,  还在设计整理中, 有可能部分代码功能下推到File_Mapping, 部分上移到更高层, 最终彻底减少这个层次, 减少一个调用层级,  

论坛徽章:
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-05-20 21:46 |显示全部楼层
本帖最后由 wlmqgzm 于 2016-05-22 11:33 编辑

重新设计文件序列号,  分为主文件序列号和次序列号, 次序列号作为文件后缀, 从.000--.999,  一共1000组来表示同一个主文件.

修改的这部分设计, 主要是为了实现磁盘空间的多重备份, 数据可以有2个正在使用中的,
1个可用的文件主序列号(做文件名), 有000-999共1000个 次序列号循环使用(做后缀名) , 可实现有效数据至少有2个拷贝可读, 另外, 在虚拟地址空间给预留了2倍的地址(按照次序列号的奇偶区分), 保证可以地址不冲突.
旧的文件自动转移到备份目录中, 实现了动态自动备份的功能.

采用多重备份以后, 单一的文件损坏, 可以重新拷贝回来, 在重新启动后就会自动恢复, 不会造成数据丢失, 这个设计主要是在不增加额外IO的情况下, 增加一些代码将准备丢弃的旧文件作为备份数据, 可实现自动备份, 还是值得在早期的设计中预留这样的空间.
另外, lz4压缩由Mapping层, 直接修改为高层代码执行, 这样CPU的压力可以分摊到每个CPU上, 代码已经变更完毕.

Mapping层增加写文件结束标志, 就是在文件的末位写入 特殊构造的数据, 表示, 该文件已经写完, 后续空间为空, 写入已经切换到新的文件中继续. 也用于重启动后数据校验.
这个标志, 目前的设计方案就是一个空数据构造, 这部分代码已经完成.

论坛徽章:
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-05-22 12:49 |显示全部楼层

通用高性能无锁无等待队列---高并发高性能程序开发的关键技术

本帖最后由 wlmqgzm 于 2016-05-26 00:42 编辑

谈点高性能编程领域的一个关键技术:  

任意对象的无锁无等待队列.  一般线程间通讯采用 队列+锁的方式, 在高并发下, 锁成为瓶颈.  在实践中, 无锁无等待队列可解决这个瓶颈, 彻底提高性能

封装了2个 大对象的无锁/无等待队列,  实际实现就是std::shared_ptr 无锁/无等待队列(lock_free/ wait_free queue)的设计,  以便简化多线程编程中的线程通讯机制.

实际上现有的开放编程库中, 并不存在这样的工具. 所有这样的工具, 都是 关注高性能计算领域的公司 自己开发, 自己内部使用的核心代码, 不会公开.
自己重写了一遍.

在File_Mapping的底层代码上, File_Mapping_write 采用了std::shared_ptr无锁/无等待队列技术, 作为写请求的输入端,  单线程执行写,  准备将CPU的潜力发挥到极致.

下面是自己实现的其中1个高性能高并发队列2次封装

template<typename T, unsigned int N=WAIT_FREE_SPSC_QUEUE_DEFAULT_SIZE>
class  Wait_free_spsc_queue
{
  public:
     Wait_free_spsc_queue( void );
     bool push( std::shared_ptr<T>  sp_in );
     T*  pop(  void );
     unsigned int size( void );
     bool  empty( void );
     bool  full( void );
     bool is_lock_free( void );

  private:
.........................
};

论坛徽章:
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-05-23 09:21 |显示全部楼层
本帖最后由 wlmqgzm 于 2016-05-23 11:21 编辑

第1次做存储层的代码, 难度系数高, 并且希望实现最大的并发, 采用了各类所有能够采用的新技术, 花了大量时间在新技术的探索上,
本来这个帖子就是一个学习帖, 因此, 追求各类新技术到极致.

目前已有代码线程间的通讯已经彻底更换为无等待队列(Wait_free_queue),
包括(Wait_free_spsc_queue)单生产者单消费者 任意对象的Wait_free队列
包括(Wait_free_mpsc_queue)多生产者单消费者 任意对象的Wait_free队列
包括(Wait_free_spmc_queue)单生产者多消费者 任意对象的Wait_free队列
包括(Lock_free_mpmc_queue) 多生产者多消费者 任意对象的Lock_free队列

等等, 这些只在传说中存在的队列, 都被一一实现了,  Wait_free队列应该会比无锁(lock_free)队列有更高的并发, 无锁还是有等待状态的, Wait_free队列彻底没有等待了, 是目前世界上最先进的队列结构.
因此最近一段时间的开发, 反复修改的地方很多, 很多设计是改了又改, 代码废弃的数量也多.

基础的存储结构也反复修改, 目前最新的底层磁盘落地结构, 各类头尾以前大约是30多字节, 目前版本修改到18字节, 在最大限度的实现最优的解决方案.

论坛徽章:
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-05-23 18:48 |显示全部楼层
这个帖子最近都没有什么人来指导一下吗?  是不是很少有人做 存储层的 原因,  
您需要登录后才可以回帖 登录 | 注册

本版积分规则

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号 北京市公安局海淀分局网监中心备案编号:11010802020122
广播电视节目制作经营许可证(京) 字第1234号 中国互联网协会会员  联系我们:
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP