-
Notifications
You must be signed in to change notification settings - Fork 5.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make accesslogs.logTheRoundTrip async to get lost performance #3152
Make accesslogs.logTheRoundTrip async to get lost performance #3152
Conversation
a175c6c
to
1d77686
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👏
1d77686
to
4712c19
Compare
PR has been rebased. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this PR!
middlewares/accesslog/logger.go
Outdated
close(l.stopCh) | ||
l.wg.Wait() | ||
close(l.logHandlerChan) | ||
l.drainChannel() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of a stopCh
, drainChannel()
and WaitGroup
, WDYT about just create a for/range on the logHandlerChan
and in the Close()
, just close this chan?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That might be a great enhancement! Thanks for that!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -124,6 +124,13 @@ filePath = "/path/to/access.log" | |||
format = "json" | |||
``` | |||
|
|||
To write the logs in async, specify `bufferingSize` as the format (must be >0): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I understand right the code, the buffer size is about the number of lines to bufferize before to write them into the log file.
As usualy the buffer size can concern a number of bytes, I guess it should be nice to precise in the documentation that the buffer size is about a number of access logs and not a number of bytes.
WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's not exactly the number of access logs lines, but the number of access log lines to process in a buffered way. => I will precise it.
docs/configuration/logs.md
Outdated
```toml | ||
[accessLog] | ||
filePath = "/path/to/access.log" | ||
bufferingSize = 262140 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WDYT to use a smaller size in the example (50 or 100)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be better than a random number like i wrote :D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
middlewares/accesslog/logger.go
Outdated
close(l.stopCh) | ||
l.wg.Wait() | ||
close(l.logHandlerChan) | ||
l.drainChannel() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That might be a great enhancement! Thanks for that!
docs/configuration/logs.md
Outdated
```toml | ||
[accessLog] | ||
filePath = "/path/to/access.log" | ||
bufferingSize = 262140 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be better than a random number like i wrote :D
@@ -124,6 +124,13 @@ filePath = "/path/to/access.log" | |||
format = "json" | |||
``` | |||
|
|||
To write the logs in async, specify `bufferingSize` as the format (must be >0): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's not exactly the number of access logs lines, but the number of access log lines to process in a buffered way. => I will precise it.
4712c19
to
5fde503
Compare
@ryarnyah thanks for your work. If you could not rebase and address the review comments in terms of additional commits, this is very useful for us because it facilitates the review. https://github.com/containous/traefik/blob/master/CONTRIBUTING.md#content
|
@ldez That's what i did. I only rebase on master on my last push (sorry for this rebase). I was just asking if i must squash all of them after reviews :D |
@ryarnyah you don't need to rebase or merge master, we have a bot to handle that 🤖 |
middlewares/accesslog/logger.go
Outdated
@@ -83,6 +92,18 @@ func NewLogHandler(config *types.AccessLog) (*LogHandler, error) { | |||
} | |||
} | |||
|
|||
if config.BufferingSize > 0 { | |||
go func() { | |||
for { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WDYT about moving the for/range here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you move it here, don't you need to wait until goroutine end to close file (with WaitGroup per example)?(might already need to)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, you need to add a WaitGroup in order to be sure that Close wait for the drain of logs.
In addition, FYI ok==true
until the chan is empty, so with this code, you will still loop until the chan is empty.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have moved for loop range to goroutine and add sync.WaitGroup to ensure stream is empty before closed file.
middlewares/accesslog/logger.go
Outdated
@@ -83,6 +92,18 @@ func NewLogHandler(config *types.AccessLog) (*LogHandler, error) { | |||
} | |||
} | |||
|
|||
if config.BufferingSize > 0 { | |||
go func() { | |||
for { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right, you need to add a WaitGroup in order to be sure that Close wait for the drain of logs.
In addition, FYI ok==true
until the chan is empty, so with this code, you will still loop until the chan is empty.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👏
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👏 🎉
e53b787
to
69ec30d
Compare
What does this PR do?
Add a async accesslogs.logTheRoundTrip for access logs.
Motivation
On my current project, we use traefik and recently we activate access logs. When i checked the overhead this functionality, i realize that we lost a lot! So i tried to figure why and i found that we use sync io.Writer. So i did that PR #3059 and after some tests i realized that i can do simpler and more effective with this PR(with or without fileFormat per example).
Small benchs:
Base configuration:
Without accesslogs from hey (without json format):
With accesslogs (without json format):
With async accesslogs.logTheRoundTrip (with or without json format and with bufferingSize = 262140):
More
Additional Notes
I think that there is more to do to optimize access logs overhead but it's a first step.
Replace PR #3059.