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
最佳答案
发生了很多事情,我无法立即发现错误,但这些事情会有所帮助:
尝试使用bufio.Writer尽可能多地调用
file.WriteString
,否则每次写入都将是系统调用,从而影响性能。您不需要使用
select
在你里面startAccessLog
功能:func startAcessLog() { for ctx := <-logCtxCh { handleAccessLog(ctx) } }
更改您的错误检查:
if err != nil { fmt.Errorf(err.Error()) }
到:
if err != nil { fmt.Println(err) }
否则你不是打印错误。 fmt.Errorf格式化字符串,如
fmt.Sprintf
执行并将其作为错误返回。它根本不打印任何内容。你应该守护
accessLog
用sync.Mutex或者通过 channel 写入它。为什么?因为有不止一个 goroutine 试图与accessLog
一起工作而且您不希望发生数据竞争。
通过 channel 进行操作会简化您的writeLog
日志功能。目前很难遵循这个逻辑。我最初以为您没有正确关闭文件。
关于linux - go1.6 File方法WriteString频繁调用导致系统缓存大,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38045375/