jjzjj

linux - go1.6 File方法WriteString频繁调用导致系统缓存大

coder 2024-07-10 原文

go1.6 文件方法WriteString频繁调用导致系统缓存很大。

如何解决这个问题。

进入环境:linux amd64。

这是Linux系统的问题吗?

代码:

package main

import (
    "fmt"
    "net/http"
    "os"
    "time"
)

var logCtxCh chan *http.Request
var accessLogFile *os.File

type HandlerHttp struct{}

func (this *HandlerHttp) ServeHTTP(w http.ResponseWriter, req *http.Request) {
    sendAccessLog(req) 
    w.Write([]byte("Hello Word"))
}

func main() {
    s := &http.Server{
        Addr:    ":8012",
        Handler: &HandlerHttp{},
    }
    logCtxCh = make(chan *http.Request, 500)
    go startAcessLog()

   err:= s.ListenAndServe()
   fmt.Println(err.Error())
}

func startAcessLog() {
    for {
        select {
        case ctx := <-logCtxCh:
            handleAccessLog(ctx)
        }
    }
}

func sendAccessLog(req *http.Request) {
    logCtxCh <- req
}

func handleAccessLog(req *http.Request) {
    uri := req.RequestURI
    ip := req.RemoteAddr
    agent := req.UserAgent()
    refer := req.Referer()
    method := req.Method
    now := time.Now().Format("2006-01-02 15:04:05")

    logText := fmt.Sprintf("%s %s %s %s %s %s\n",
        now,
        ip,
        method,
        uri,
        agent,
        refer,
    )

    fileName := fmt.Sprintf("/data/logs/zyapi/access_zyapi%s.log",
        time.Now().Format("2006010215"),
    )
    writeLog(fileName, logText)
}

func writeLog(fileName, logText string) {
    var err error
    var exist = true

    if _, err = os.Stat(fileName); os.IsNotExist(err) {
        exist = false
    }

    if exist == false {
        if accessLogFile != nil {
            accessLogFile.Sync()
            accessLogFile.Close()
        }

        accessLogFile, err = os.OpenFile(fileName, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
        if err == nil {
            _, err = accessLogFile.WriteString(logText)
        }
        if err != nil {
            fmt.Errorf(err.Error())
        }
    } else {
        if accessLogFile == nil {
            accessLogFile, err = os.OpenFile(fileName, os.O_WRONLY|os.O_APPEND, 0666)
            if err != nil {
                fmt.Errorf(err.Error())
                return
            }
        }
        _, err = accessLogFile.WriteString(logText)
        if err != nil {
            fmt.Errorf(err.Error())
        }
    }
}

测试:

ab -n100000 -c10 -k "http://127.0.0.1:8012/"
ab -n100000 -c10 -k "http://127.0.0.1:8012/"
ab -n100000 -c10 -k "http://127.0.0.1:8012/"
ab -n100000 -c10 -k "http://127.0.0.1:8012/"
ab -n100000 -c10 -k "http://127.0.0.1:8012/"

运行几次后系统文件缓存变得很大

CONTAINER    CPU %   MEM USAGE/LIMIT   MEM %     NET I/O   BLOCK I/O

api_8011  38.47%    6.442GB/6.442GB   100.00%    0B/0B     0B/115.4MB 

api_8012  36.90%    6.442GB/6.442GB   99.99%     0B/0B     0B/115.6 MB

最佳答案

发生了很多事情,我无法立即发现错误,但这些事情会有所帮助:

  1. 尝试使用bufio.Writer尽可能多地调用file.WriteString ,否则每次写入都将是系统调用,从而影响性能。

  2. 您不需要使用 select在你里面startAccessLog功能:

    func startAcessLog() { for ctx := <-logCtxCh { handleAccessLog(ctx) } }

  3. 更改您的错误检查:

    if err != nil { fmt.Errorf(err.Error()) }

    到:

    if err != nil { fmt.Println(err) }

    否则你不是打印错误。 fmt.Errorf格式化字符串,如 fmt.Sprintf执行并将其作为错误返回。它根本不打印任何内容。

  4. 你应该守护accessLogsync.Mutex或者通过 channel 写入它。为什么?因为有不止一个 goroutine 试图与 accessLog 一起工作而且您不希望发生数据竞争。
    通过 channel 进行操作会简化您的 writeLog日志功能。目前很难遵循这个逻辑。我最初以为您没有正确关闭文件。

关于linux - go1.6 File方法WriteString频繁调用导致系统缓存大,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38045375/

有关linux - go1.6 File方法WriteString频繁调用导致系统缓存大的更多相关文章

  1. ruby-on-rails - rails : save file from URL and save it to Amazon S3 - 2

    从给定URL下载文件并立即将其上传到AmazonS3的更直接的方法是什么(+将有关文件的一些信息保存到数据库中,例如名称、大小等)?现在,我既不使用Paperclip,也不使用Carrierwave。谢谢 最佳答案 简单明了:require'open-uri'require's3'amazon=S3::Service.new(access_key_id:'KEY',secret_access_key:'KEY')bucket=amazon.buckets.find('image_storage')url='http://www.ex

  2. ruby - 无法让 RSpec 工作—— 'require' : cannot load such file - 2

    我花了三天的时间用头撞墙,试图弄清楚为什么简单的“rake”不能通过我的规范文件。如果您遇到这种情况:任何文件夹路径中都不要有空格!。严重地。事实上,从现在开始,您命名的任何内容都没有空格。这是我的控制台输出:(在/Users/*****/Desktop/LearningRuby/learn_ruby)$rake/Users/*******/Desktop/LearningRuby/learn_ruby/00_hello/hello_spec.rb:116:in`require':cannotloadsuchfile--hello(LoadError) 最佳

  3. ruby CSV : How can I read a tab-delimited file? - 2

    CSV.open(name,"r").eachdo|row|putsrowend我得到以下错误:CSV::MalformedCSVErrorUnquotedfieldsdonotallow\ror\n文件名是一个.txt制表符分隔文件。我是专门做的。我有一个.csv文件,我转到excel,并将文件保存为.txt制表符分隔的文件。所以它是制表符分隔的。CSV.open不应该能够读取制表符分隔的文件吗? 最佳答案 尝试像这样指定字段分隔符:CSV.open("name","r",{:col_sep=>"\t"}).eachdo|row|

  4. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

    我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

  5. ruby - __FILE__ == $PROGRAM_NAME 在 ruby​​ 中是什么意思? - 2

    这个问题在这里已经有了答案:Whatdoes`if__FILE__==$0`meaninRuby(6个答案)关闭6年前。我在审查Ruby代码时偶然发现了这个语法。代码是:if__FILE__==$PROGRAM_NAME#somecode...end我想__FILE__是一个变量,可以让我获取我所在文件的名称?但是$PROGRAM_NAME简化了什么?另外,为什么这个if语句是必需的,因为程序可以使用或不使用它?

  6. ruby - File.read ("| echo mystring") 是如何工作的? - 2

    我在我正在处理的一些代码中发现了这一点。它旨在解决从磁盘读取key文件的要求。在生产环境中,key文件的内容位于环境变量中。旧代码:key=File.read('path/to/key.pem')新代码:key=File.read('|echo$KEY_VARIABLE')这是如何工作的? 最佳答案 来自IOdocs:Astringstartingwith“|”indicatesasubprocess.Theremainderofthestringfollowingthe“|”isinvokedasaprocesswithappro

  7. ruby - 如何通过 Rubocop 指示打开 & :read as argument to File. - 2

    我有这个代码File.open(file_name,'r'){|file|file.read}但是Rubocop发出警告:Offenses:Style/SymbolProc:Pass&:readasargumenttoopeninsteadofablock.你是怎么做到的? 最佳答案 我刚刚创建了一个名为“t.txt”的文件,其中包含“Hello,World\n”。我们可以按如下方式阅读。File.open('t.txt','r',&:read)#=>"Hello,World\n"顺便说一下,由于第二个参数的默认值是'r',所以这样

  8. ruby - Chef : Read variable from file and use it in one converge - 2

    我有以下代码,它下载一个文件,然后将文件的内容读入一个变量。使用该变量,它执行一个命令。这个配方不会收敛,因为/root/foo在编译阶段不存在。我可以通过多个聚合和一个来解决这个问题ifFile.exist但我想用一个收敛来完成它。关于如何做到这一点有什么想法吗?execute'download_joiner'docommand"awss3cps3://bucket/foo/root/foo"not_if{::File.exist?('/root/foo')}endpassword=::File.read('/root/foo').chompexecute'join_domain'd

  9. ruby-on-rails - Rails 2.3.5 : How does one access code inside of lib/directory/file. rb? - 2

    我创建了一个文件,这样我就可以在lib/foo/bar_woo.rb中的许多模型之间共享一个方法。在bar_woo.rb中,我定义了以下内容:moduleBarWoodefhelloputs"hello"endend然后在我的模型中我正在做类似的事情:defMyModel解释器提示它期望bar_woo.rb定义Foo::BarWoo。《使用Rails进行敏捷Web开发》一书指出,如果文件包含类或模块,并且文件使用类或模块名称的小写形式命名,那么Rails将自动加载文件。因此我不需要它。定义代码的正确方法是什么,在我的模型中调用代码的正确方法是什么? 最佳答案

  10. ruby - 使用 File.open 从 ruby​​ 中的目录打开文件 - 2

    我是Ruby的新手,我正在尝试以如下方式打开文件:#!/usr/bin/envrubydata_file='~/path/to/file.txt'file=File.open(data_file,'r')但是我得到“没有这样的文件或目录”(该文件确实存在于该目录中)。如果我将该文件路径作为命令行参数,它会起作用,例如:#!/usr/bin/envrubyfile=File.open(ARGV[0],'r')然后从命令行运行,如:rubyscript.cgi~/path/to/file.txt关于如何让它以第一种方式工作的任何想法? 最佳答案

随机推荐