【web server】日志系统

简介: 【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日志并进行多维度分析。
相关文章
|
4月前
|
IDE Linux 开发工具
如何在Linux运行RStudio Server并实现Web浏览器远程访问
如何在Linux运行RStudio Server并实现Web浏览器远程访问
81 0
|
4月前
|
存储 运维 应用服务中间件
[运维日志] Web 服务器日志依日期归档(Powershell 实现,附源代码)
[运维日志] Web 服务器日志依日期归档(Powershell 实现,附源代码)
74 0
|
4月前
|
算法 前端开发 JavaScript
什么是 Web 开发的 Server Side Model
什么是 Web 开发的 Server Side Model
26 0
|
3月前
|
应用服务中间件 nginx
【报错】Failed to start A high performance web server and a reverse proxy server.
【报错】Failed to start A high performance web server and a reverse proxy server.
134 2
|
4月前
|
Linux
【web server】基于升序链表的定时器
【web server】基于升序链表的定时器
|
13天前
|
Apache
web服务器(Apache)访问日志(access_log)详细解释
web服务器(Apache)访问日志(access_log)详细解释
|
2月前
|
弹性计算 算法 应用服务中间件
倚天使用|Nginx性能高27%,性价比1.5倍,基于阿里云倚天ECS的Web server实践
倚天710构建的ECS产品,基于云原生独立物理核、大cache,结合CIPU新架构,倚天ECS在Nginx场景下,具备强大的性能优势。相对典型x86,Http长连接场景性能收益27%,开启gzip压缩时性能收益达到74%。 同时阿里云G8y实例售价比G7实例低23%,是Web Server最佳选择。
|
2月前
|
Windows
Windows Server 各版本搭建 Web 服务器实现访问本地 Web 网站(03~19)
Windows Server 各版本搭建 Web 服务器实现访问本地 Web 网站(03~19)
|
3月前
|
JSON 监控 Java
Java Web开发中的异常处理与日志记录最佳实践
Java Web开发中的异常处理与日志记录最佳实践
|
4月前
|
XML C++ 数据格式
C++使用gSoap写Web Server和Web Client
C++使用gSoap写Web Server和Web Client
38 1