Rpc异步日志模块

news2024/11/23 22:21:54

Rpc异步日志模块作用

在一个大型分布式系统中,任何部署的分布式节点都可能发生崩溃,试想如果用普通的办法,即先排查哪个节点down掉了,找到down掉的节点后采取调试工具gdb调试该节点,进而排查宕机的原因。这中排查方法对于人力物力都是无法接受的。
那么由此记录日志就变得至关重要,分布式RPC框架必定存在一个异步日志模块,用于记录所有分布式站点的调试信息。通过日志分析就能很容易排查出哪个节点出了问题

Rpc异步日志模块实现思路

一个日志模块必须是异步的,不能影响主程序的运行,例如在RPC框架中显然不能阻塞了RPCProvider(服务提供者)和RPCConsumer(服务调用者)的运行
RPCProvider是一个能接受高并发rpc请求的高性能服务器(epoll+多线程),那么存在多个线程同时写日志的情况,这里的“写日志”并不是真正意义上的写磁盘文件的操作,因为磁盘IO会严重拖累该线程原本执行的其他任务。所以这里的写日志 只是多个线程将日志写入一个异步缓冲队列(这个操作是在内存进行的非常快),并且这个队列必须是线程安全的。
此外,应该另起一个线程来读取队列里面的日志数据进行真正的磁盘写文件操作,这样写日志线程是单独工作的,它只是依赖于异步缓冲队列里面的数据,不会影响RPC服务线程和其他IO线程。
在这里插入图片描述

Rpc异步日志模块实现

下面提供一个简单版本的实现
异步缓冲队列类:

#pragma once

#include <queue>
#include <thread>
#include <mutex>
#include <condition_variable>

//异步写日志的日志队列
template<typename T>
class LockQueue
{

public:
    //多个work线程都会写日志queue
    void Push(const T& data)
    {
        std::lock_guard<std::mutex> lock(m_mutex);
        m_queue.push(data);
        m_condvariable.notify_one();
    }
    //一个线程读日志queue,写日志文件
    T Pop()
    {
        std::unique_lock<std::mutex> lock(m_mutex);
        while(m_queue .empty())
        {
            //日志队列为空, 线程进入wait状态
            m_condvariable.wait(lock);
        }

        T data = m_queue.front();
        m_queue.pop();
        return data;
    }
private:
    std::queue<T> m_queue;
    std::mutex m_mutex;
    std::condition_variable m_condvariable;

};

Logger.h类:

#pragma once

#include "lockqueue.h"
#include <utility>

//日志级别
enum LogLevel{
    INFO = 1, //普通信息
    ERROR  //错误信息
};

//Mprpc框架提供的日志系统
class Logger
{
public:
    //获取日志的单例
    static Logger& GetInstance();
    //写日志
    void Log(std::pair<LogLevel,std::string> msg);

private:
    LockQueue<std::pair<LogLevel,std::string>> m_lckQue; //日志缓冲队列

    Logger();
    Logger(const Logger&) = delete;
    Logger(Logger&& ) = delete;
    Logger& operator=(const Logger&) = delete;
};

//定义宏  LOG_XXX("xxx %d %s", 20, "sdasd");
#define LOG_INFO(logmsgformat, ...) \
    do \
    { \
        Logger &logger = Logger::GetInstance(); \
        char c[1024] = {0};           \
        snprintf(c, 1024, logmsgformat, ##__VA_ARGS__); \
        std::pair<LogLevel,std::string> pr = std::make_pair(INFO, std::string(c)); \
        logger.Log(pr); \
    } while (0);

#define LOG_ERR(logmsgformat, ...) \
do \
{ \
    Logger &logger = Logger::GetInstance(); \
    char c[1024] = {0};           \
    snprintf(c, 1024, logmsgformat, ##__VA_ARGS__); \
    std::pair<LogLevel,std::string> pr = std::make_pair(ERROR, std::string(c)); \
    logger.Log(pr); \
} while (0);
    

Logger.cc

#include "logger.h"
#include <time.h>
#include <iostream>

//获取日志的单例
Logger& Logger::GetInstance()
{
    static Logger logger;
    return logger;
}

Logger::Logger()
{
    //启动专门的写日志线程
    std::thread writeLogTask([&](){
        for(;;)
        {
            //获取当前的日期,然后取日志信息,写入相应的日志文件当中 a+
            time_t now = time(nullptr);
            tm *nowtm = localtime(&now);

            char file_name[128];
            sprintf(file_name, "%d-%d-%d-log.txt", nowtm->tm_year + 1900, nowtm->tm_mon + 1, nowtm->tm_mday);

            FILE* pf = fopen(file_name, "a+");
            if(pf == nullptr)
            {
                std::cout<<"logger file:" << file_name <<"open error" << std::endl;
                exit(EXIT_FAILURE);
            }

            std::pair<LogLevel,std::string> msg = m_lckQue.Pop();

            char time_buf[128] = {0};
            sprintf(time_buf, "%d-%d-%d => [%s]", 
                                    nowtm->tm_hour, 
                                    nowtm->tm_min, 
                                    nowtm->tm_sec,
                                    (msg.first == INFO ? "info" : "error"));
            msg.second.insert(0, time_buf);
            msg.second.append("\n");
            fputs(msg.second.c_str(), pf);
            fclose(pf); 
        }
    });

    //设置分离线程, 守护线程
    writeLogTask.detach();

}

//写日志,把日志信息写入到lockqueue缓冲区当中
void Logger::Log(std::pair<LogLevel,std::string> msg)
{
    m_lckQue.Push(msg);
}

使用:

...
LOG_INFO("NotifyService UserService success");
LOG_ERR("eeeeeerrror%d", 9999999);
LOG_INFO("NotifyService GetFriendListService success");
...

查看日志文件:cat 2023-8-2-log.txt 
21-35-26 => [info]NotifyService UserService success
21-35-26 => [error]eeeeeerrror9999999
21-35-26 => [info]NotifyService GetFriendListService success

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/828423.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Redis的缓存、消息队列、计数器应用

目录 一、redis的应用场景 二、redis如何用于缓存 三、redis如何用于消息队列 四、redis如何用于计数器 一、redis的应用场景 Redis在实际应用中有广泛的应用场景&#xff0c;以下是一些常见的Redis应用场景&#xff1a; 缓存&#xff1a;Redis可以用作缓存层&#xff0c;…

高性能远程通信框架grpc基本使用

文章目录 一、了解grpc二、关于protobuf三、试玩grpc3.1整个工程目录3.2 proto文件编写3.3 使用maven protobuf插件转换.proto文件3.4 Grpc服务端业务实现类3.5 pom参考3.6 grpc client调用 一、了解grpc 谷歌开源远程进程调用框架&#xff0c;支持多语言系统间通信&#xff0…

百分点科技跻身中国智慧应急人工智能解决方案市场前三

近日&#xff0c; 全球领先的IT市场研究和咨询公司IDC发布了《中国智慧应急解决方案市场份额&#xff0c;2022》报告&#xff0c;数据显示&#xff0c;2022年中国智慧应急整体市场为104亿元人民币。其中&#xff0c;智慧应急人工智能解决方案子市场备受关注&#xff0c;百分点科…

小主机折腾记16

7月折腾了 1.2500s&#xff0c;2550k&#xff0c;e3 1225的性能测试 结果如下图 总结如下&#xff1a; a.2500s e3 1225 2390t 差别不大 b.1333频率相对1066频率内存提升12%左右 c.为什么少了2550k&#xff0c;因为装上去风扇尬转&#xff0c;没画面&#xff0c;我猜是因为…

Shell脚本学习-Shell函数

函数的作用就是将程序里多次被调用的相同代码组合起来&#xff08;函数体&#xff09;&#xff0c;并为其取一个名字&#xff0c;即函数名。其他所有想重复调用这部分代码的地方都只需要调用这个名字就可以了。当需要修改这部分代码时候&#xff0c;只需要修改函数体内的这部分…

【网络编程】select

主旨思想 首先要构造一个关于文件描述符的列表&#xff0c;将要监听的文件描述符添加到该列表中 调用一个系统函数(select)&#xff0c;监听该列表中的文件描述符&#xff0c;直到这些描述符中的一个或者多个进行I/O操作时&#xff0c;该函数才返回 这个函数是阻塞函数对文件描…

vue 图片回显标签

第一种 <el-form-item label"打款银行回单"><image-preview :src"form.bankreceiptUrl" :width"120" :height"120"/></el-form-item>// 值为 https://t11.baidu.com/it/app106&fJPEG&fm30&fmtauto&…

一篇五分生信临床模型预测文章代码复现——Figure 10.机制及肿瘤免疫浸润(二)

之前讲过临床模型预测的专栏,但那只是基础版本,下面我们以自噬相关基因为例子,模仿一篇五分文章,将图和代码复现出来,学会本专栏课程,可以具备发一篇五分左右文章的水平: 本专栏目录如下: Figure 1:差异表达基因及预后基因筛选(图片仅供参考) Figure 2. 生存分析,…

语音合成是什么?如何进行语音合成TTS数据采集?

我们在上一篇讲到语音数据采集分为常见的两种语音数据采集类型&#xff0c;一个是语音识别数据&#xff08;ASR&#xff09;&#xff0c;另一个是语音合成&#xff08;TTS&#xff09;。这一期中&#xff0c;我们将介绍语音合成技术是什么&#xff0c;如何采集语音合成数据和制…

【有趣的设计模式】23 种设计模式详解和场景分析

前言 七大设计原则 1、单一原则&#xff1a;一个类只负责一个职责 2、开闭原则&#xff1a;对修改关闭&#xff0c;对扩展开放 3、里氏替换原则&#xff1a;不要破坏继承关系 4、接口隔离原则&#xff1a;暴露最小接口&#xff0c;避免接口过于臃肿 5、依赖倒置原则&#xff1…

完美解决ubuntu系统QtCreator无法输入中文

在Ubuntu18 上安装搜狗输入法&#xff0c;启用fcitx输入系统之后Qt Creator 无法输入中文&#xff0c;原因是缺少fcitx的支持库libfcitxplatforminputcontextplugin.so。解决办法 1 查找是否安装相关库 $ dpkg -L fcitx-frontend-qt5 | grep .so /usr/lib/x86_64-linux-gnu/qt…

语义检索系统【二】:基于无监督训练SimCSE+In-batch Negatives策略有监督训练的语义索引召回

搜索推荐系统专栏简介:搜索推荐全流程讲解(召回粗排精排重排混排)、系统架构、常见问题、算法项目实战总结、技术细节以及项目实战(含码源) 专栏详细介绍:搜索推荐系统专栏简介:搜索推荐全流程讲解(召回粗排精排重排混排)、系统架构、常见问题、算法项目实战总结、技术…

//编写程序数一下 1到 100 的所有整数中出现多少个数字9

//编写程序数一下 1到 100 的所有整数中出现多少个数字9 int main() {int i;int count 0;//用来计数for (int i 1; i < 100; i) {if (i % 10 9 || i / 10 9)count;}printf("1到 100 的所有整数中出现%d个数字9\n", count);

[openCV]基于拟合中线的智能车巡线方案V1

import cv2 as cv import os import numpy as np# 遍历文件夹函数 def getFileList(dir, Filelist, extNone):"""获取文件夹及其子文件夹中文件列表输入 dir&#xff1a;文件夹根目录输入 ext: 扩展名返回&#xff1a; 文件路径列表"""newDir d…

Day10-NodeJS和NPM配置

Day10-NodeJS和NPM 一 Nodejs 1 简介 Nodejs学习中文网:https://www.nodeapp.cn/synopsis.html Nodejs的官网:https://nodejs.org/ 概念:Nodejs是JavaScript的服务端运行环境.Nodejs不是框架,也不是编程语言,就是一个运行环境. Nodejs是基于chrome V8引擎开发的一套js代码…

mac电脑访问windows共享文件夹连接不上(设置445端口)

前提&#xff1a;首先需要保证mac和windows都在同一局域网内&#xff0c;如果不在肯定是连不上的&#xff0c;就不用往下看了。 事情是这样的&#xff0c;公司入职发了mac电脑&#xff0c;但是我是window重度用户&#xff0c;在折腾mac的过程中&#xff0c;有许多文件需要从wi…

当系统接口要加入新方法时,我真后悔没有早点学学Java设计模式

假设系统中有一个接口&#xff0c;这个接口已经被10个实现类实现了&#xff0c;突然有一天&#xff0c;新的需求来了&#xff0c;其中5个实现类需要实现同一个方法。然后你就在接口中添加了这个方法的定义&#xff0c;想着一切都很完美。 当你在接口和其中5个实现类中加完这个…

java(Collection类)

文章目录 Collection接口继承树Collection接口及方法判断删除其它 Iterator(迭代器)接口迭代器的执行原理 foreach循环Collection子接口1&#xff1a;ListList接口特点List接口方法List接口主要实现类&#xff1a;ArrayListList的实现类之二&#xff1a;LinkedListList的实现类…

【python】我用python写了一个可以批量查询文章质量分的小项目(纯python、flask+html、打包成exe文件)

web 效果预览&#xff1a; 文章目录 一、API 分析1.1 质量分查询1.2 文章url获取 二、代码实现2.1 Python2.11 分步实现2.12 一步完成2.13 完整代码 2.2 python html2.21 在本地运行2.22 打打包成exe文件2.23 部署到服务器 一、API 分析 1.1 质量分查询 先去质量查询地址&a…

处理nacos、tomcat、nginx日志增长过快问题

1.nacos日志清理 修改nacos-logback.xml 将日志级别改为error级&#xff0c;减少info级日志产生量 将<maxHistory>调整为2以下&#xff0c;将 <totalSizeCap>调整为2GB左右 比如&#xff1a; [rootiZ0jlapur4hqjezy8waee0Z logs]# ll -h total 2.1G -rw-r--r-…