【web server】日志系统

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: 【web server】日志系统

webserver采用异步日志系统:

逻辑:创建一个线程,不断读消息队列(数组实现的循环队列)中的消息,写入日志文件;需要写日志时,将消息放入消息队列中即可。

Log类中维护一个消息队列和互斥锁,当需要写日志时,对消息队列进行加锁解锁操作,避免竞争。

Log类初始化时,创建一个线程,线程循环等待消息队列不为空:

void async_write_log() {
    string log;
    while (!m_log_queue->empty()) {
    m_mutex.lock();
    log = m_log_queue->front();
    m_log_queue->pop();
    //消息取出来之后,即时归还锁,*写文件的过程不要占用锁*
    m_mutex.unlock();
    //写消息
    fwrite((void *)log.c_str(), 1, log.size(), m_fp);
    fflush(m_fp);
  }
}

消息队列中维护一个互斥锁和条件变量,队列不为空,线程不断取日志写日志,当队列为空时empty阻塞等待条件变量,当向队列中push消息时条件变量唤醒,队列不为空empty不再阻塞,线程又开始写日志。

bool empty() {
  m_mutex.lock();
  while (m_cnt == 0) {
    //如果条件变量等待出错了
    if (!m_cond.wait(m_mutex.get())) {
      m_mutex.unlock();
      return true;
    }
    //否则等到了,m_cnt此时一定不为空,便可以退出循环
  }
  m_mutex.unlock();
  return false;
}

向队列中push消息后,条件变量触发,消息队列不为空:

bool push(string str) {
  m_mutex.lock();
  if (str == "" || m_cnt == m_max_size)  {
    m_cond.broadcast();
    m_mutex.unlock();
    return false;
  }
  m_data[m_tail++] = str;
  if (m_tail == m_max_size) m_tail = 0;
  m_cnt++;
  m_cond.broadcast();
  m_mutex.unlock();
  return true;
}

当写日志线程写的比较慢时,日志会不断的累加到消息队列中,写日志线程不断去取任务,做任务。

再来看下循环队列是如何实现的?

一个固定大小的数组m_data,通过headtail变量来实现弹出和弹入队列的操作,维护一个当前size变量m_cnt和最大size变量m_max_size,如果m_cnt == m_max_size说明队列满了,否则说明队列不满。

head指向队首元素

tail指向队尾下一个元素

pop操作时:head++,m_cnt--,如果head超出了数组,就置为0。下次pop时如果队列不为空,直接pop出0号位置。

push操作时:tail++,m_cnt++,如果tail超出了数组,就置为0。下次push时如果队列不满,直接push到0号位置。

来看一个简单的示例:

#include <iostream>
using namespace std;
class XunHuanDuiLie {
public:
  XunHuanDuiLie(int length)
    : m_data(new int(length))
    , m_cnt(0)
    , m_max_cnt(length)
    , head(0)
    , tail(0)
  {
    for (int i = 0; i < m_max_cnt; i++) {
      m_data[i] = -1;
    }
  }
  int top() {
    if (empty()) {
      cout << "queue is empty return -1" << endl;
      return -1;
    }
    return m_data[head];
  }
  void pop() {
    if (empty()) {
      cout << "queue is empty" << endl;
      return;
    }
    head++;
    m_cnt--;
    if (head == m_max_cnt) {
      head = 0;
    }
    return;
  }
  void push(int val) {
    //首先判空
    if (full()) {
      cout << "queue is full" << endl;
      return ;
    }
    //tail代表末尾元素的下一位
    m_data[tail++] = val;
    m_cnt++;
    if (tail == m_max_cnt) {
      //tail到了末尾
      tail = 0;
    }
    return;
  }
  bool full() {
    return m_cnt == m_max_cnt;
  }
  bool empty() {
    return m_cnt == 0;
  }
  int size() {
    return m_cnt;
  }
  void output() {
    cout << "m_cnt: " << m_cnt << endl;
    cout << "head: " << head << endl;
    cout << "tail: " << tail << endl;
    for (int i = 0; i < m_max_cnt; i++) {
      cout << m_data[i] << " ";
    }
    cout << endl;
  }
private:
  int *m_data;
  int m_cnt;
  int m_max_cnt;
  int head;
  int tail;
};
int main() {
  XunHuanDuiLie queue(4);
  //push 了4次
  queue.push(1);
  queue.push(2);
  queue.push(3);
  queue.push(4);
  //pop五次
  cout << queue.top() << endl;
  queue.pop();
  cout << queue.top() << endl;
  queue.pop();
  cout << queue.top() << endl;
  queue.pop();
  cout << queue.top() << endl;
  queue.pop();
  cout << queue.top() << endl;
  queue.pop();
  queue.push(5);
  cout << queue.top() << endl;
  //queue.pop();
  queue.push(6);
  cout << queue.top() << endl;
  queue.pop();
  queue.output();
  system("pause");
  return 0;
}

m_cnt变量至关重要,它记录的是当前元素的个数。元素的出队操作并没有正真删除元素,而是改变了head的指向,入队时覆盖该位置的值即可。

而关于pop操作和push操作是否会影响队列中已存在的元素的困惑,关键点在于:

如果当前队列不为空,就可以出队。

如果当前队列不满,就可以入队。

日志系统中的循环队列也是采用这种方式。

相关实践学习
日志服务之使用Nginx模式采集日志
本文介绍如何通过日志服务控制台创建Nginx模式的Logtail配置快速采集Nginx日志并进行多维度分析。
相关文章
|
11天前
|
存储 消息中间件 缓存
构建互联网高性能WEB系统经验总结
构建互联网高性能WEB系统经验总结
|
3天前
|
存储 Linux Docker
centos系统清理docker日志文件
通过以上方法,可以有效清理和管理CentOS系统中的Docker日志文件,防止日志文件占用过多磁盘空间。选择合适的方法取决于具体的应用场景和需求,可以结合手动清理、logrotate和调整日志驱动等多种方式,确保系统的高效运行。
8 2
|
27天前
|
机器学习/深度学习 数据处理 数据库
基于Django的深度学习视频分类Web系统
基于Django的深度学习视频分类Web系统
50 4
基于Django的深度学习视频分类Web系统
|
8天前
|
负载均衡 监控 算法
论负载均衡技术在Web系统中的应用
【11月更文挑战第4天】在当今高并发的互联网环境中,负载均衡技术已经成为提升Web系统性能不可或缺的一环。通过有效地将请求分发到多个服务器上,负载均衡不仅能够提高系统的响应速度和处理能力,还能增强系统的可扩展性和稳定性。本文将结合我参与的一个实际软件项目,从项目概述、负载均衡算法原理以及实际应用三个方面,深入探讨负载均衡技术在Web系统中的应用。
36 2
|
14天前
|
XML JSON 监控
告别简陋:Java日志系统的最佳实践
【10月更文挑战第19天】 在Java开发中,`System.out.println()` 是最基本的输出方法,但它在实际项目中往往被认为是不专业和不足够的。本文将探讨为什么在现代Java应用中应该避免使用 `System.out.println()`,并介绍几种更先进的日志解决方案。
38 1
|
21天前
|
监控 网络协议 安全
Linux系统日志管理
Linux系统日志管理
37 3
|
27天前
|
机器学习/深度学习 监控 数据挖掘
基于Django和百度飞桨模型的情感识别Web系统
基于Django和百度飞桨模型的情感识别Web系统
32 5
|
27天前
|
监控 应用服务中间件 网络安全
#637481#基于django和neo4j的日志分析系统
#637481#基于django和neo4j的日志分析系统
32 4
|
25天前
|
网络协议 Windows
Windows Server 2019 Web服务器搭建
Windows Server 2019 Web服务器搭建
|
1月前
|
监控 Linux 测试技术
Linux系统命令与网络,磁盘和日志监控总结
Linux系统命令与网络,磁盘和日志监控总结
52 0