• 怎样高速的把日志输出到磁盘上


        无论是做client业务,还是做服务端业务,日志子系统都是很重要的一个组件。

        日志系统的输出目的地能够是disk,也能够是tty,更能够是network。

        我的日志系统能够输出到tty。不同log level能够有不同的color,这样看日志很的醒目,当然这里着重谈的是怎样高速的把log内容写到磁盘上。

        

        事实上,怎样高速的把log内容写到磁盘上,网上文章已经汗牛充栋。真正高质量的没多少。本篇可能也是狗尾续貂之作。只是。我的log子系统可以达到106M/s的输出速率。

        具体介绍我的log系统之前。推荐大家看看陈硕大牛的《Linux 多线程服务端编程:使用 muduo C++ 网络库》一书中关于muduo log的实现,muduo的log的思路和实现都是非常美丽的。网上还有相关的ppt,这里面有非常多的干货。

        

        log系统怎样高速的把log内容写到磁盘上?其关键就在于写log时要进行顺序写。即每次写log的大小要为4k或者4k的倍数。

        鉴于语言描写叙述非本人强项,以下先呈上关键代码。然后再详述之。

        struct log_t {
            int                            file;
            pthread_mutex_t mutex;
            int                           buf_cursor;
            char                       buf[4 * 1024];
            struct iovec           iovec_[2];
        };
        
        int log_write(log_t* log, char* buf, int len)
        {
            int ret = 0;
        
            pthread_mutex_lock(&log->mutex);
            do  {
                size = log->buf_cursor + len;
                if (size < sizeof(log->buf))  {
                    memcpy(log->buf + log->buf_cursor, buf, len);
                    log->buf_cursor = size;
                    break;
                }
        
                log->iovec_[0].iov_base = log->buf;
                log->iovec_[0].iov_len = log->buf_cursor;
                log->iovec_[1].iov_base = buf;
                log->iovec_[1].iov_len = len;
                ret = (int)writev(log->file, log->iovec_, 2);
                if (ret != size))  {
                    ret = -2;
                }
        
                log->cursor += size;
                log->buf_cursor = 0;
            } while(0);
            pthread_mutex_unlock(&log->mutex);
        
            return ret;
        }
        看上面这段代码的,log有一个4k的buf。假设本次输出的内容可以放到buf里面,那么就把内容拷贝进去,然后退出。否则就调用writev函数把内容写进log文件。

        其思路跟陈硕大牛的muduo的log比起来当然是云泥之别,没那么高大上。

    其方法的关键就是减小锁的粒度、合并多次write为一次write以进行顺序写log内容至磁盘上。

        

        log系统有同步和异步两种差别,上面的实现方式本质是一种同步方式。另外,writev并非一个原子操作,它一次可能并不能把log->iovec中全部的内容都写到磁盘上,所以考虑到其是一种同步实现方式,实际应用中应该通过循环方式保证log->iovec全部的内容都写到磁盘上(这个脏活留给你,天下没有免费的午餐)。

        所谓的异步输出log就是专门启动一个日志线程,它能够有一个log队列。其它线程作为生产者把内容输出至队列,日志线程就作为消费者从队列中取出log内容,然后把它写到磁盘上。

        我近期为公司实现了一种异步log系统。其关键流程当然就是上面一段的思路。可是。只靠上面的这样的方法是无法实现高速地进行异步log输出的。除了log线程的队列外。參考陈硕的muduo log的思路,我还加入了一个log buf(struct log_buf {  int cursor;  char buf[1 * 1024 * 1024];  };),其思路跟同步方式一样,先把log内容放到这个log_buf中。待log_buf快溢出的时候,把log_buf放入队列中。

       因为代码的版权归公司全部。所以这里就不贴代码了。异步log的终于效果能达到140M/s的输出速率。

  • 相关阅读:
    获取spring源码并导入到eclipse
    Android的EditText设置可编辑与不可编辑的方法
    漫谈设计模式笔记:模板模式
    jfreechar中文乱码设置主题样式解决
    FrameLayout布局下让图片居中的方法
    java典型模块实例1:英文,数字,中文混合的验证码
    学习Lucene笔记一:创建索引
    How to Display a PDF File in a HTML Web Page
    NET数据类型及字节数
    2012年1月编程语言排行榜
  • 原文地址:https://www.cnblogs.com/slgkaifa/p/6768291.html
Copyright © 2020-2023  润新知