当前位置:网站首页>日志中打印统计信息的方案
日志中打印统计信息的方案
2022-07-01 13:46:00 【zhanglehes】
概要
目前维护的一套c++服务,在打印日志时会存在锁竞争。先用brpc定位锁竞争的环节,然后提出集中改进方案,以及它们的优缺点。
contention火焰图
使用brpc在压测环境下打印contention火焰图。

左边的圆圈是处理服务的接入数据,会记录接收量,os类型,业务方类型等统计参数;
右边那两个稍小圆圈是两处发送下游,会记录发出量等统计参数;
它们都是用同一把锁,当需要写入统计数据时,会去竞争这把锁;
从连接方框的边旁的数据大小,可以看到主要的锁竞争来自于处理接收数据的业务函数。原因是我们的服务接收数据是逐条接收的,但是发送数据是批量,因此数量是不对等的。
改进方案
每个统计指标对应一把锁
好处:锁的作用域得到最小力度的控制
坏处:当有多处需要写入的统计信息量较大时,这种场景不合适
自旋锁
好处:不会发生cs
坏处:当临界区较长时,对cpu的浪费不能忽视
使用atomic
好处:基础类型在x86架构上是无锁的
坏处:atomic变量虽然比加锁赋值更轻量,但比普通参数复制还是更重一些。当统计参数较多时,这部分时间开销累计起来也是很大的
对比atomic和加锁的时间开销
atomic
#include<iostream>
#include<atomic>
#include<thread>
using namespace std;
atomic<int> a(0);
void sum() {
for(int i=0; i!=10000000; i++) {
a++;
}
}
int main() {
// cout << a.is_lock_free() << endl;
// 启动四个线程
thread t1(sum);
thread t2(sum);
thread t3(sum);
thread t4(sum);
t1.join();
t2.join();
t3.join();
t4.join();
int ret = a.load();
cout << ret << endl;
return 0;
}mutex
#include<iostream>
#include<thread>
#include<mutex>
using namespace std;
mutex m;
int a = 0;
int b = 0;
void sum() {
for(int i=0; i!=10000000; i++) {
m.lock();
a++;
m.unlock();
}
}
int main() {
// 启动四个线程
thread t1(sum);
thread t2(sum);
thread t3(sum);
thread t4(sum);
t1.join();
t2.join();
t3.join();
t4.join();
cout << a << endl;
return 0;
}运行
[email protected] cpptest % time ./atomic
40000000
./atomic 3.41s user 0.01s system 395% cpu 0.865 total
[email protected] cpptest % time ./mutex
40000000
./mutex 2.13s user 4.70s system 317% cpu 2.153 total可见使用atomic后,系统调用的开销显著降低,性能得以提升
双版本切换
该方案的思路是使用双版本保存统计信息。当需要记录统计参数时,先获取当前版本的index,可以获得往哪个版本写。新开一个线程,每隔一个时间间隔切换index,同时打印之前的统计参数
代码
#include<iostream>
#include<atomic>
#include<vector>
#include<thread>
#include<unistd.h>
using namespace std;
struct Info {
int a{0};
void clear() {a=0;}
};
atomic<int> Index(0); // 指向当前的版本
vector<Info*> vec_infos; // 保存双版本的信息
void print_info(int idx) { // 打印idx版本的统计参数
cout << vec_infos.at(idx)->a << endl;
}
void clear_info(int idx) { // 将idx版本的统计参数清零
vec_infos.at(idx)->a = 0;
}
void printInfo() {
int i=0; // 保证函数能退出
int idx=0;
while(i!=10) {
sleep(1);
int next_idx = (idx+1) % 2;
clear_info(next_idx); // 将即将使用的Info清零
Index.store(next_idx); // 切换index,之后的写入的统计数据会放到另一个Info中
print_info(idx); // 打印之前的统计数据
idx = next_idx; // 指向新的index
i++;
}
}
void writeInfo() { // 写入统计参数
while(true) {
int idx = Index.load(); // 获取当前的index
vec_infos.at(idx)->a++;
}
}
int main() {
Info* info1 = new Info();
Info* info2 = new Info();
vec_infos.push_back(info1);
vec_infos.push_back(info2); // 双版本统计参数初始化
thread t1(printInfo); // 启动打印线程
thread t2(writeInfo); // 启动模拟写入统计参数的线程
t1.join();
return 0;
}这份代码其实并不严密,写入统计参数时,可能已经完成打印了,导致数据丢失。首先这种概率并不大,atomic的store操作的时间开销是大于普通变量赋值的;其次是对于统计信息,即使丢少量数据,问题不大;再则我们可以将intervel的时间分成两份,在store操作和print_info之前等待一段时间,确保之前版本的数据都被写入。
边栏推荐
- Word2vec training Chinese word vector
- 盲盒NFT数字藏品平台系统开发(搭建源码)
- 单工,半双工,全双工区别以及TDD和FDD区别
- [sword finger offer] 55 - I. depth of binary tree
- Uni app realizes advertisement scroll bar
- 1.8 new features list
- Station B was scolded on the hot search..
- Enter the top six! Boyun's sales ranking in China's cloud management software market continues to rise
- When you really learn databinding, you will find "this thing is really fragrant"!
- Yarn restart applications record recovery
猜你喜欢

spark源码(五)DAGScheduler TaskScheduler如何配合提交任务,application、job、stage、taskset、task对应关系是什么?
![[anwangbei 2021] Rev WP](/img/98/ea5c241e2b8f3ae4c76e1c75c9e0d1.png)
[anwangbei 2021] Rev WP

队列的基本操作(C语言实现)

Build a vc2010 development environment and create a tutorial of "realizing Tetris game in C language"

App自动化测试开元平台Appium-runner

App automation testing Kaiyuan platform appium runner

QT社团管理系统

Liu Dui (fire line safety) - risk discovery in cloudy environment

Station B was scolded on the hot search..

Etcd 概要 机制 和使用场景
随机推荐
App自动化测试开元平台Appium-runner
Report on the current situation and development trend of bidirectional polypropylene composite film industry in the world and China Ⓟ 2022 ~ 2028
【NLP】预训练模型——GPT1
建立自己的网站(21)
Go整合Logrus实现日志打印
Analysis report on the development prospect and investment strategy of the global and Chinese laser chip industry Ⓑ 2022 ~ 2027
spark源码(五)DAGScheduler TaskScheduler如何配合提交任务,application、job、stage、taskset、task对应关系是什么?
Applet - multiple text line breaks in view
10. Page layout, guess you like it
SAP 智能机器人流程自动化(iRPA)解决方案分享
陈宇(Aqua)-安全-&gt;云安全-&gt;多云安全
【Flask】Flask启程与实现一个基于Flask的最小应用程序
Camp division of common PLC programming software
Investment analysis and prospect prediction report of global and Chinese p-nitrotoluene industry Ⓙ 2022 ~ 2027
JVM有哪些类加载机制?
一文读懂TDengine的窗口查询功能
Dragon lizard community open source coolbpf, BPF program development efficiency increased 100 times
ArrayList capacity expansion mechanism and thread safety
Arthas use
Detailed explanation of leetcode reconstruction binary tree [easy to understand]