Rpc异步日志模块

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线程都会写日志queuevoid 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.hqwc.cn/news/60125.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JavaWeb 手写Tomcat底层机制

目录 一、Tomcat底层整体架构 1.简介 : 2.分析图 : 3.基于Socket开发服务端的流程 : 4.打通服务器端和客户端的数据通道 : 二、多线程模型的实现 1.思路分析 : 2.处理HTTP请求 : 3.自定义Tomcat : 三、自定义Servlet规范 1. HTTP请求和响应 : 1 CyanServletRequest …

多用户跨境电商商品库系统快速搭建(全开源)

搭建一个多用户跨境电商商品库系统需要以下步骤&#xff1a; 1. 确定系统需求&#xff1a;首先&#xff0c;需要明确系统的功能需求&#xff0c;包括商品管理、订单管理、用户管理、支付管理等。根据具体需求确定系统的功能和界面设计。 2. 确定技术栈&#xff1a;选择合适的…

Maven: No compiler is provided in this environment.

在Eclipse中运行Maven项目&#xff0c;报错&#xff1a; No compiler is provided in this environment. Perhaps you are running on a JRE rather than a JDK? 解决方法&#xff1a; Windows > Preferences > Java > Installed JREs > Add > Standard VM,…

python——案例14:斐波那契数列

兔子生殖为例子而引入&#xff0c;故又称“兔子数列”&#xff0c; 其数值为&#xff1a;1、1、2、3、5、8、13、21、34……在数学上&#xff0c; 这一数列以如下递推的方法定义&#xff1a; F(0)1&#xff0c;F(1)1, F(n)F(n - 1)F(n - 2)&#xff08;n ≥ 2&#xff0c;n ∈ …

Android 内存泄漏

名词解释 内存泄漏:即memory leak。是指内存空间使用完毕后无法被释放的现象&#xff0c;虽然Java有垃圾回收机制&#xff08;GC&#xff09;&#xff0c;但是对于还保持着引用&#xff0c; 该内存不能再被分配使用&#xff0c;逻辑上却已经不会再用到的对象&#xff0c;垃圾回…

研发工程师玩转Kubernetes——PVC通过storageClassName进行延迟绑定

不同的PV可以使用相同的StorageClass&#xff0c;它们是一对多的关系。 PV可以设置节点亲和性。比如下图&#xff0c;local-storage-class-waitforfirstconsumer-pv-ubuntuc只能在节点ubuntuc上&#xff1b;local-storage-class-waitforfirstconsumer-pv-ubuntud只能在节点ubu…

MySQL不知道密码,直接修改密码

很简单&#xff0c;我们跳过验证&#xff0c;直接进去修改就好 修改配置文件 vim /etc/my.cnf在[mysqld]下直接添加配置 skip-grant-tables如图&#xff1a; 保存&#xff0c;退出即可。 重启服务 service mysqld restart进入MySQL #(直接点击回车&#xff0c;密码为空)…

Fast Tone Mapping for High Dynamic Range Images

Abstract 我们提出了一种快速、有效、灵活的色调再现方法&#xff0c;在低动态范围再现设备中保留了高动态范围场景的可视性和对比度印象。 一个单一的参数控制能见度和对比度在一个简单和优雅的方式和互动速度。 新方法使用简单&#xff0c;计算效率高。 实验表明&#xff0c…

Git详解及使用

Git简介 Git 是一种分布式版本控制系统&#xff0c;它可以不受网络连接的限制&#xff0c;加上其它众多优点&#xff0c;目前已经成为程序开发人员做项目版本管理时的首选&#xff0c;非开发人员也可以用 Git 来做自己的文档版本管理工具。 大概是大二的时候开始接触和使用Gi…

CRM系统哪些功能可以个性化定制?

不同的企业有着不同的业务流程和需求&#xff0c;因此在选型时就需要一款可以个性化定制的CRM系统。下面说说可以个性化定制的CRM系统的功能和优势。 如何实现个性化定制&#xff1f; Zoho CRM支持个性化定制&#xff0c;您可以创建自定义功能模块、字段以及业务流程&#xf…

资深媒体人宋繁银加入《数据猿》任总编辑,全面负责公司整体内容工作

大数据产业创新服务媒体 ——聚焦数据 改变商业 2023年7月北京&#xff0c;《数据猿》宣布正式任命宋繁银为总编辑&#xff0c;全面负责公司整体内容工作。此次重要的人事任命标志着《数据猿》的发展迈上了一个新的台阶&#xff0c;对于《数据猿》团队而言&#xff0c;不仅是一…