当前位置: 首页 > news >正文

【同步 / 异步 日志系统】--- 全局接口 性能测试

 Welcome to 9ilk's Code World

       

(๑•́ ₃ •̀๑) 个人主页:        9ilk

(๑•́ ₃ •̀๑) 文章专栏:     项目  


本篇博客主要是对日志系统的收尾,将日志器更好封装供用户使用,同时测试其性能。

全局接口

    到目前为止,用户可以日志器建造者来创建不同的日志器,必要时,还可以使用全局日志器建造者,添加到管理器中管理,方便全局使用。但是在调用等级日志输出接口的时候,需要用户自己输入文件名__FILE__和行号__LINE__,这对用户来说有点不友好,最好封装成跟使用printf一样就好了,同时通过单例对象获取日志器是比较麻烦的。

提供全局接口&宏函数,对日志系统进行使用便捷性优化:

  1. 提供获取指定日志器的全局接口(避免用户自己操作单例对象)
  2. 使用宏函数对日志器的接口进行代理(代理模式
  3. 提供宏函数直接提供默认日志器进行日志的标准输出打印(不用获取日志器了)

获取指定日志器的全局接口:
 

   Logger::ptr getLogger(const string& name){return LoggerManager::getInstance().getLogger(name);}Logger::ptr getrootLogger(){return LoggerManager::getInstance().getrootLogger();}

使用宏函数对日志器的接口进行代理(代理模式):到时日志器调用等级输出接口时就会进行宏替换

 //2.使用宏函数对日志器的接口进行代理#define debug(fmt,...)  debug(__FILE__,__LINE__,fmt,##__VA__ARGS__)#define info(fmt,...)   info(__FILE__,__LINE__,fmt,##__VA__ARGS__)#define warn(fmt,...)   warn(__FILE__,__LINE__,fmt,##__VA__ARGS__)#define error(fmt,...)  error(__FILE__,__LINE__,fmt,##__VA__ARGS__)#define fatal(fmt,...)  fatal(__FILE__,__LINE__,fmt,##__VA__ARGS__)

此时可以简化使用成这样

  Logger::ptr logger = getLogger("async_logger");logger->debug("测试日志"); --> 替换为 logger->debug(__FILE__,__LINE__,"测试日志")logger->info("测试日志");logger->warn("测试日志");logger->error("测试日志");logger->fatal("测试日志");

提供宏函数, 直接通过默认日志器进行日志的标准输出打印(复用上面的即可):

   #define DEBUG(fmt,...)  getrootLogger()->debug(fmt,##__VA_ARGS__)#define INFO(fmt,...)  getrootLogger()->info(fmt,##__VA_ARGS__)#define WARN(fmt,...)  getrootLogger()->warn(fmt,##__VA_ARGS__)#define ERROR(fmt,...)  getrootLogger()->error(fmt,##__VA_ARGS__)#define FATAL(fmt,...)  getrootLogger()->fatal(fmt,##__VA_ARGS__)

日志系统性能测试

     下面对日志系统做一个性能测试,测试一下平均每秒能打印多少条日志消息到文件。

测试环境:

  • CPU:Intel Xeon Platinum 8255C @2.50 GHz 2核心 / 2线程
  • RAM: 2 GB 
  • ROM:50 GB SSD
  • OS:Ubuntu 22.04.5 LTS (云服务器 2核 2GB内存)

主要测试方法:

  • 耗时 = 结束时间 - 开始时间
  • 每秒能打印日志数 = 打印日志条数 /  总的打印日志所消耗时间
  • 每秒输出大小 = (日志数量*单条日志大小)/ 总耗时

主要测试要素:同步/异步 & 单线程/多线程


同步日志器 单/多线程测试:

void bench(const string& logger_name,size_t thread_count,size_t msg_count,size_t msg_len)
{//1.获取日志器Logger::ptr logger = getLogger(logger_name);if(logger.get() == nullptr)return;cout << "测试日志:" << msg_count << "条  " << "总大小:" << (msg_count*msg_len)/1024 << "KB" << endl;//2.组织指定长度的日志消息string msg(msg_len-1,'A'); //少一个字节是为了给末尾到时添加换行//3.创建指定数量的线程vector<thread> threads;vector<double> cost_array(thread_count);size_t msg_per_thread = msg_count / thread_count;//总日志数量 / 线程数量 = 每个线程要输出的日志数量for(int i = 0 ; i < thread_count ; i++){threads.emplace_back([&,i](){//4.线程内部开始计时auto start = std::chrono::high_resolution_clock::now();//5.开始循环写日志for(int j = 0 ; j < msg_per_thread ; j++)logger->fatal("%s",msg.c_str());//6.线程函数内部结束计时auto end = std::chrono::high_resolution_clock::now();std::chrono::duration<double> cost = end - start;cost_array[i] = cost.count();cout << "线程" << i << ": " << "\t输出数量: " << msg_per_thread << ",耗时: " << cost.count() << "s" << endl; });}for(int i = 0 ; i < thread_count ; i++)threads[i].join();//7.计算总耗时:在多线程中每个线程都会耗时,但线程是并发处理的,因此耗时最高的那个才是总时间double max_cost = cost_array[0];for(int i = 0 ; i < thread_count ; i ++)max_cost = max_cost < cost_array[i] ? cost_array[i] : max_cost;size_t msg_per_sec = msg_count / max_cost; //每秒输出日志数量size_t size_per_sec = (msg_count*msg_len) / (max_cost*1024); //每秒输出日志大小,单位KB//8.输出打印cout << "总耗时: " << max_cost << endl;cout << "每秒输出日志数量:" << msg_per_sec <<"条" << endl;cout << "每秒输出日志大小:" << size_per_sec << "KB" << endl;
}void sync_bench()
{unique_ptr<LoggerBuilder> builder(new GlobalLoggerBuilder());builder->bulidLoggerName("sync_logger");builder->buildFormatter("[%d{%H:%M:%S}][%p]%T%m%n");builder->bulidLoggerType(LoggerType::TYPE_SYNC);builder->buildSink<FileLogSink>("./logfile/sync.log");builder->build();std::cout << "------------------- 同步日志器 单线程 ------------------- " << std::endl;bench("sync_logger",1,1000000,100);std::cout << "------------------- 同步日志器 多线程 ------------------- " << std::endl;bench("sync_logger",3,1000000,100);
}

测试结果如下:

我们可以看到多线程的性能反而比单线程低,这是因为同步日志器多线程锁冲突严重,同时我们这里落地方向是写磁盘,磁盘性能已经达到上限了。


异步日志器下安全模式 vs 非安全模式:

void async_bench()
{unique_ptr<LoggerBuilder> builder(new GlobalLoggerBuilder());builder->bulidLoggerName("async_logger");builder->buildFormatter("[%d{%H:%M:%S}][%p]%T%m%n");builder->bulidLoggerType(LoggerType::TYPE_ASYNC);builder->buildSink<FileLogSink>("./logfile/async.log");// builder->buildEnableUnSafeAsync(); 安全模式builder->buildEnableUnSafeAsync(); //非安全模式builder->build();bench("async_logger",1,3000000,100);
}

测试结果如下:

我们可以看到非安全模式性能比安全模式要高,这是因为非安全模式减少了线程阻塞和同步开销,它不需要等待缓冲区的空间,不需要等待业务线程处理完交换有空闲时间再放数据,减少了I/O操作频率,但是会有丢数据的风险。


异步日志器非安全模式下单线程 vs 多线程:

void async_bench()
{unique_ptr<LoggerBuilder> builder(new GlobalLoggerBuilder());builder->bulidLoggerName("async_logger");builder->buildFormatter("[%d{%H:%M:%S}][%p]%T%m%n");builder->bulidLoggerType(LoggerType::TYPE_ASYNC);builder->buildSink<FileLogSink>("./logfile/async.log");builder->buildEnableUnSafeAsync();builder->build();std::cout << "----------------异步日志非安全模式单线程--------------------"<<  std::endl;bench("async_logger",1,1000000,100);std::cout << "----------------异步日志非安全模式多线程--------------------"<<  std::endl;bench("async_logger",3,1000000,100);
}

测试结果如下:

我们可以看到非安全模式下,没有同步和线程阻塞的开销,不会因为异步工作线程没处理完而阻塞,多线程异步只管多个线程往内存放,虽然锁冲突比单线程严重些,但是多线程所以单位时间处理的数据量要大写,因此锁冲突显得没那么严重了,此时更看重CPU和内存性能的上限。

http://www.dtcms.com/a/528389.html

相关文章:

  • GitHub等平台形成的开源文化正在重也有人
  • 03_Pushgateway使用Prometheus的服务发现机制
  • Speckit和Claude 的初体验
  • 当夸克遇上大模型:中国 AI 产品的“第二阶段”来临了
  • AI大模型弹性伸缩实战:自动扩缩容+模型轻量化+Serverless三大技术方案详解
  • 网站怎么做的qq邮件订阅页面设计存在的问题
  • CMP(类ClouderaCDP7.3(404次编译) )完全支持华为鲲鹏Aarch64(ARM),粉丝数超过200就开源下载
  • HeidiSQL的下载安装和使用
  • 线性代数直觉(五):行列式——让空间坍缩
  • word文档模板通过poi-tl导出问题注意点
  • Java在大数据分布式存储中的创新实践
  • ThinkPHP5 RCE+Linux find提权渗透实战:原理+复现(CVE-2018-20062)
  • 昆明网站排名优化电商网站的功能
  • 代码随想录Day59|dijkstra(堆优化版)精讲、Bellman_ford 算法精讲
  • 四川住建厅官方网站的网址教务管理系统学生登录入口
  • [MySQL]数据类型
  • 3w字一文讲透Java IO
  • 多模态学习大纲笔记(未完成)
  • 组织学习障碍:自我证明的陷阱
  • 【数据结构】顺序表的实现
  • 可以做兼职的网站质量好网站建设多少钱
  • 无声的战争:自动驾驶系统中的资源抢占、调度与生存法则
  • 30-机器学习与大模型开发数学教程-3-4 矩阵的逆与伪逆
  • 【大语言模型 104】LLM推理服务架构:从单机到分布式的演进之路
  • Rust所有权机制解析:内存安全的基石与实战指南
  • 个人做商业网站需要什么如何判断网站数据库类型
  • Spring容器进化论:从BeanFactory到ApplicationContext
  • 20.7 零样本多模态实战:CLIP模型如何让ChatPPT图像识别吞吐量飙升406%
  • 可以做平面设计兼职的网站佛山市网站建设分站哪家好
  • win11系统下配置c++机器学习库mlpack