C++ 自制Redis数据库(十三) 持久化AOF日志模块测试完毕
2016-02-24 21:33
891 查看
持久化AOF部分测试完毕
废话不多说,一般写日志,很多人就直接write 了,但是效率很低,这里就不详细解释了。
我AOF模块的设计
我是在为我的数据库写这个日志模块所以我需要考虑如下几个指标:1.并发量不敢说很巨大。但是多个线程同时需要写日志这种可能性还是有的,一个连接给一个线程池中的线程干活,当业务很多的时候,好几个线程同时需要写日志是很可能的,所以需要来考虑。
2.吞吐量这个指标对于一个日志自系统来说都是很重要的,我们当然需要尽量利用硬盘的读写速度。
设计模式
我也查了很多的多路缓冲写日志的相关信息,也问了学长@王伟豪@苗帅,然后还是不晓得怎么搞,大概理解就是开辟缓冲区,然后加锁,当缓冲区到达一定程度的时候执行写文件操作。这样,策略很多,我也是眼花缭乱,我突然想起来之前看过Glibc 的malloc的设计,于是结合着我的需求,我这个多路缓冲日志就应运而生啦。思路:
开辟几个缓冲区,每个缓冲区均有自己的锁,然后需要写日志的时候,就获取其中的一个锁,写入缓冲区,如果一个线程发现自己写完日志后,正好这个缓冲区满了,那么它就要负责去抢文件的锁,将整个缓冲区一股脑全写进文件里去。
就是这样,我希望每次来的日志都写进缓冲区去,然后当一个缓冲区满了就去抢写的锁。我们需要尽量将锁的争抢过程放到缓冲区上,文件写锁尽量少发生抢锁的情况,所以我们的缓冲区可以开得大一些。拖延时间,减少文件磁盘IO操作。
下面是一些代码和测试结果
class AOF_FILE{ private: int fd; public: std::mutex mutex_write; AOF_FILE(); }; class AOF_LOG{ private: char (*log_data)[AOF_LOG_MAXSIZE]; AOF_FILE FILE_WRITE; int useful; public: std::mutex mutex_log; AOF_LOG(); ~AOF_LOG(); bool AOF_LOG_ADD(const char *mesg,int flag); bool WRITE(); }; class AOF_LOG_DO{ private: AOF_LOG aof_buffer[AOF_LOG_AREA]; int useful; int resume; public: AOF_LOG_DO(); bool AOF_LOG_add(const char *mesg); bool AOF_LOG_enforce_write(); bool AOF_LOG_READ(char *get); int & AOF_LOG_getresume(); };
AOF_FILE::AOF_FILE(){ fd = 0; } /********************************************************/ AOF_LOG::AOF_LOG(){ /*init one pice of buffer*/ log_data = new char[AOF_LOG_ELEM][AOF_LOG_MAXSIZE]; useful = 0; } AOF_LOG::~AOF_LOG(){ delete [] log_data; } bool AOF_LOG::AOF_LOG_ADD(const char *mesg,int flag){ int length = std::strlen(mesg); if(length != flag){ return false; } bzero(log_data[useful],AOF_LOG_MAXSIZE); memcpy(log_data[useful],mesg,AOF_LOG_MAXSIZE); useful++; if(useful == AOF_LOG_ELEM){ WRITE(); } return true; } bool AOF_LOG::WRITE(){ while(1){ if(FILE_WRITE.mutex_write.try_lock()){ break; } } FILE *fp; //fd = open("LOG_AOF.log",O_RDWR|O_APPEND|O_CREAT,777); fp = fopen("LOG_AOF.log","ab+"); if(!fp){ return false; }else{ for(int i = useful;i > 0;i--){ //write(fd,log_data[i],AOF_LOG_MAXSIZE); fwrite(log_data[i],AOF_LOG_MAXSIZE,1,fp); } useful = 0; fclose(fp); FILE_WRITE.mutex_write.unlock(); return true; } } /*******************************************************/ AOF_LOG_DO::AOF_LOG_DO(){ useful = 0; } bool AOF_LOG_DO::AOF_LOG_add(const char *mesg){ int length = std::strlen(mesg); if(length > AOF_LOG_MAXSIZE){ return false; } int get_mutex = 1; while(get_mutex){ for(int id = 0;id < AOF_LOG_AREA; id++){ if(aof_buffer[id].mutex_log.try_lock()){ aof_buffer[id].AOF_LOG_ADD(mesg,length); aof_buffer[id].mutex_log.unlock(); get_mutex = 0; break; } } } } bool AOF_LOG_DO::AOF_LOG_enforce_write(){ for(int i = 0;i < AOF_LOG_AREA;i++){ while(1){ if(aof_buffer[i].mutex_log.try_lock()){ break; } } aof_buffer[i].WRITE(); aof_buffer[i].mutex_log.unlock(); } return true; } bool AOF_LOG_DO::AOF_LOG_READ(char *get){ FILE *fp; resume = 0; fp = fopen("LOG_AOF.log","rb"); if(!fp){ return false; }else{ while(fread(get,AOF_LOG_MAXSIZE,1,fp)){ resume++; //std::cout << get << std::endl; } } fclose(fp); } int & AOF_LOG_DO::AOF_LOG_getresume(){ return resume; }
测试结果
老实说,我也不知道什么样的效果才能算是称职的日志子系统,大家都看看,提提意见,这肯定不是最优的方法。开4个线程,每个线程写500000(五十万)条日志,总共两百万条日志。
共花费1.9秒,平均每秒100万条日志,100万条日志 大约等于244MB/s.(基本把硬盘都用上了)
以上。
相关文章推荐
- 探究在C++程序并发时保护共享数据的问题
- Nodejs实战心得之eventproxy模块控制并发
- 浅析PHP中Session可能会引起并发问题
- php session的锁和并发
- Oracle 数据库针对表主键列并发导致行级锁简单演示
- MySQL中SELECT+UPDATE处理并发更新问题解决方案分享
- Java并发编程中的生产者与消费者模型简述
- Java中同步与并发用法分析
- Java多线程编程中的两种常用并发容器讲解
- Java实现的并发任务处理实例
- Go语言并发模型的2种编程方案
- Go语言并发技术详解
- JAVA多线程与并发学习总结分析
- JAVA多线程和并发基础面试问答(翻译)
- 在Java内存模型中测试并发程序代码
- 线程池的理解
- Java并发同步工具类之CountDownLatch
- 自旋锁学习系列(3):指数后退技术
- redis并发环境下的使用
- JAVA并发编程