Thanks a lot for all your help Marcin! Your expertise makes a total
difference here!

Double-thumbs up!


On Mon, Jun 10, 2019 at 7:46 PM Marcin Romaszewicz <marc...@gmail.com> wrote:
>
> In my example in the previous email, I accidentally used a very old version 
> of echo. If you use the latest ("github.com/labstack/echo/v4"), then it's a 
> lot faster than using simple string splitting, resulting in about 22,000 
> requests per second.
>
> Concurrency Level:      100
> Time taken for tests:   0.443 seconds
> Complete requests:      10000
> Failed requests:        0
> Total transferred:      2160000 bytes
> HTML transferred:       430000 bytes
> Requests per second:    22565.77 [#/sec] (mean)
> Time per request:       4.431 [ms] (mean)
> Time per request:       0.044 [ms] (mean, across all concurrent requests)
> Transfer rate:          4759.97 [Kbytes/sec] received
>
> Connection Times (ms)
>               min  mean[+/-sd] median   max
> Connect:        0    2   0.5      2       9
> Processing:     1    2   0.6      2       9
> Waiting:        0    2   0.6      2       9
> Total:          3    4   0.8      4      11
>
> Percentage of the requests served within a certain time (ms)
>   50%      4
>   66%      4
>   75%      5
>   80%      5
>   90%      5
>   95%      5
>   98%      6
>   99%      6
>  100%     11 (longest request)
>
>
> On Mon, Jun 10, 2019 at 4:12 PM Marcin Romaszewicz <marc...@gmail.com> wrote:
>>
>> One more followup.
>>
>> Here's an example using an HTTP router named Echo, which I use in 
>> production. With proper HTTP parsing and validation, and no regular 
>> expressions involved in routing, it still does about 14,000 requests per 
>> second. I stubbed some of your stuff which doesn't affect the result. This 
>> is a much better implementation than speaking HTTP yourself over sockets and 
>> it's stupendously fast.
>>
>> Concurrency Level:      100
>> Time taken for tests:   0.717 seconds
>> Complete requests:      10000
>> Failed requests:        0
>> Total transferred:      2160000 bytes
>> HTML transferred:       430000 bytes
>> Requests per second:    13940.29 [#/sec] (mean)
>> Time per request:       7.173 [ms] (mean)
>> Time per request:       0.072 [ms] (mean, across all concurrent requests)
>> Transfer rate:          2940.53 [Kbytes/sec] received
>>
>> Connection Times (ms)
>>               min  mean[+/-sd] median   max
>> Connect:        0    3   1.2      3       8
>> Processing:     1    4   1.2      4       9
>> Waiting:        0    3   1.2      3       8
>> Total:          2    7   1.3      7      13
>>
>> Percentage of the requests served within a certain time (ms)
>>   50%      7
>>   66%      7
>>   75%      8
>>   80%      8
>>   90%      9
>>   95%     10
>>   98%     11
>>   99%     11
>>  100%     13 (longest request)
>>
>>
>> package main
>>
>> import (
>>    "flag"
>>    "fmt"
>>    "net/http"
>>    "strconv"
>>
>>    "github.com/labstack/echo"
>> )
>>
>> const pixel = 
>> "\x47\x49\x46\x38\x39\x61\x01\x00\x01\x00\x80\x00\x00\xFF\xFF\xFF\x00\x00\x00\x21\xF9\x04\x01\x00\x00\x00\x00\x2C\x00\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02\x44\x01\x00\x3B"
>>
>> func main() {
>>    var port = flag.Int("port", 8080, "service port")
>>    flag.Parse()
>>
>>    autoProxy := fmt.Sprintf(
>>       "function FindProxyForURL(url, host) { return \"PROXY %s:3128; 
>> DIRECT\"; }",
>>       "stubbed.host")
>>    autoProxyBuf := []byte(autoProxy)
>>
>>    e := echo.New()
>>
>>    serveAutoProxy := func(c echo.Context) error {
>>       response := c.Response()
>>       response.Header().Add("Connection", "close")
>>       return c.Blob(http.StatusOK, "application/octet-stream", autoProxyBuf)
>>    }
>>    e.GET("/proxy.pac", serveAutoProxy)
>>    e.GET("/wpad.dat", serveAutoProxy)
>>
>>    pixelBuf := []byte(pixel)
>>    servePixel := func(c echo.Context) error {
>>       response := c.Response()
>>       response.Header().Add("Connection", "close")
>>       response.Header().Add("ETag", "dbab")
>>       response.Header().Add("Cache-Control", "public, max-age=31536000")
>>       response.Header().Add("Content-length", strconv.Itoa(len(pixelBuf)))
>>       return c.Blob(http.StatusOK, "image/gif", pixelBuf)
>>    }
>>    e.GET("*", servePixel)
>>
>>    // Start server
>>    e.Logger.Fatal(e.Start(fmt.Sprintf("0.0.0.0:%d", *port)))
>> }
>>
>>
>>
>> On Mon, Jun 10, 2019 at 4:07 PM Marcin Romaszewicz <marc...@gmail.com> wrote:
>>>
>>> I think the others were correct in pointing the finger at the RegEx engine 
>>> in Go. It is quite slow. I hacked your inside loop which checks the request 
>>> not to use regular expressions, and it's tons faster. You can't say that 
>>> something can't be responsible for too much slowdown because it "1 line", 
>>> since that one line has a lot of weight behind it. Using regular 
>>> expressions, a benchmark showed 1782 requests per second. Using my simple 
>>> hack, it's 18827 per second. Let's call it 10x faster.
>>>
>>> if strings.Contains(line, "HTTP") {
>>>    parts := strings.Split(line, " ")
>>>    req.Method = strings.ToUpper(strings.TrimSpace(parts[0]))
>>>    req.URL = strings.ToUpper(strings.TrimSpace(parts[1]))
>>>    req.Version = strings.ToUpper(strings.TrimSpace(parts[2]))
>>>    continue
>>> }
>>>
>>>
>>> For this benchmark it behaves correctly, I realize this is fragile. I ran 
>>> `ab -n 10000 -c 100...` to run the tests.
>>>
>>> Benchmarks using regular expressions:
>>> Concurrency Level:      100
>>> Time taken for tests:   5.610 seconds
>>> Complete requests:      10000
>>> Failed requests:        0
>>> Total transferred:      1790000 bytes
>>> HTML transferred:       430000 bytes
>>> Requests per second:    1782.41 [#/sec] (mean)
>>> Time per request:       56.104 [ms] (mean)
>>> Time per request:       0.561 [ms] (mean, across all concurrent requests)
>>> Transfer rate:          311.57 [Kbytes/sec] received
>>>
>>> Connection Times (ms)
>>>               min  mean[+/-sd] median   max
>>> Connect:        0   46 352.7      8    3557
>>> Processing:     0   10  10.6      8     158
>>> Waiting:        0   10  10.6      8     158
>>> Total:          0   56 352.5     21    3565
>>>
>>> Percentage of the requests served within a certain time (ms)
>>>   50%     21
>>>   66%     24
>>>   75%     24
>>>   80%     24
>>>   90%     25
>>>   95%     26
>>>   98%    164
>>>   99%   3549
>>>  100%   3565 (longest request)
>>>
>>> Benchmarks using my hack:
>>>
>>> Concurrency Level:      100
>>> Time taken for tests:   0.531 seconds
>>> Complete requests:      10000
>>> Failed requests:        0
>>> Total transferred:      1790000 bytes
>>> HTML transferred:       430000 bytes
>>> Requests per second:    18827.39 [#/sec] (mean)
>>> Time per request:       5.311 [ms] (mean)
>>> Time per request:       0.053 [ms] (mean, across all concurrent requests)
>>> Transfer rate:          3291.12 [Kbytes/sec] received
>>>
>>> Connection Times (ms)
>>>               min  mean[+/-sd] median   max
>>> Connect:        0    3   0.3      3       4
>>> Processing:     1    3   0.4      3       5
>>> Waiting:        0    3   0.4      3       5
>>> Total:          3    5   0.5      5       8
>>>
>>> Percentage of the requests served within a certain time (ms)
>>>   50%      5
>>>   66%      5
>>>   75%      5
>>>   80%      5
>>>   90%      6
>>>   95%      6
>>>   98%      7
>>>   99%      7
>>>  100%      8 (longest request)
>>>
>>>
>>> On Mon, Jun 10, 2019 at 2:28 PM Tong Sun <suntong...@gmail.com> wrote:
>>>>
>>>> Just to clarify some facts.
>>>>
>>>> On Sun, Jun 9, 2019 at 11:09 AM 'Axel Wagner' wrote:
>>>> >
>>>> > As I've also mentioned: I don't think this test is meaningful.
>>>> >
>>>> > First, as it has been pointed out, your Perl program isn't actually a 
>>>> > web server. It only understands ridiculously simple requests and as such 
>>>> > violates the spec left and right. It's also super naive in how it treats 
>>>> > malformed input or actively malicious clients - all of which are handled 
>>>> > by the Go http package, so of course it's going to have some overhead.
>>>>
>>>> There is a second test well before your this post, which is a direct
>>>> translation of Perl code, that is now reading and writing directly to
>>>> a socket. Hanging on to the first test method and not referring to the
>>>> second test is not a very constructive way of discussion, let alone
>>>> using words like "ridiculously ...".
>>>>
>>>> > In its most generous form, you translate the programs faithfully to do 
>>>> > the same syscalls and implement the same logic - and at that point, you 
>>>> > are essentially benchmarking the Perl regular expression engine against 
>>>> > the Go regular expression engine, as that's the only thing the program 
>>>> > really is doing: Branching on a regexp-match. And the Perl RE-engine is 
>>>> > famously optimized and the Go RE-engine famously is not. In fact, you 
>>>> > aren't even benchmarking Perl against Go, you are benchmarking *C* 
>>>> > against Go, as Perls RE-engine is written in C, AFAIK.
>>>>
>>>> Over 90% of the code are NOT doing regular expression matching.
>>>> Focusing *only* on regular expression, not >90% of the rest, is not
>>>> very convincing but miss the elephant in the room, at least seems to
>>>> me. Many people have given valid inputs as where things might get
>>>> improved, including the one you are quoting.
>>>>
>>>> > Lastly, as I read the results I get with either net/http *or* the naive 
>>>> > regexp-parsing, I just… disagree with your conclusions. All the numbers 
>>>> > I've seen seem to imply that Go responded *on average* a lot faster and 
>>>> > *might* have higher variance and a slightly higher tail latency (though, 
>>>> > FTR, the measurements I got also suggest that the data is mostly noise). 
>>>> > And I'm struggling to find an application, where that would matter a 
>>>> > lot. Like, yeah, tail latency matters, but so does average latency. In 
>>>> > basically all applications I can think of, you a) want tail latencies to 
>>>> > not be catastrophic, especially when considering fan-out, but b) lower 
>>>> > averages are just as important anyway. So, I think you should, for a 
>>>> > decent test, formulate your criteria beforehand. Currently, there seems 
>>>> > to be a lot of reading in tea-leafs involved.
>>>>
>>>> Please don't get personal and emotional over technical discussions,
>>>> and please refrain from using terms like "ridiculously simple" or
>>>> "reading in tea-leafs" in future discussions. It is inappropriately
>>>> condescending, thus not the correct attitude of communication.  It
>>>> does not align with the code of conduct of this mlist, and neither of
>>>> google's, I believe.
>>>>
>>>> If you have test results that contradict with mine, please show me
>>>> yours -- Let's talk the data, and not let the emotion get in the way
>>>> of technical discussion, and fact the fact, whatever it is.
>>>>
>>>> > Anyway, all of that being said: While I don't think the test you devised 
>>>> > allows the broad generalizations you are making, ultimately I don't have 
>>>> > any stakes in this (which is why I haven't responded further on the blog 
>>>> > post). If you like Perl and think it performs good enough or better for 
>>>> > your use case - then go ahead and use Perl. No one here will begrudge 
>>>> > you for it.
>>>>
>>>> As I've comment in the blog many times, I'm not trying to prove Perl
>>>> performs better than Go. On the contrary, I was trying to improve Perl
>>>> performs with Go, that's why the whole thing get started, as I have
>>>> replied to your comment in the blog:"that's why I was rewriting the
>>>> Perl code to Go".
>>>>
>>>> It is still the case, and I want to try out everyone's suggestion to
>>>> see how things can improve.
>>>>
>>>> Moreover, if you have taken a look at my second test, you will
>>>> understand my other goal is to make it clear "who and what to trust".
>>>> Because if you have taken a look at the httperf test result I posted
>>>> to this mlist before you reply, you may have realized that, of all the
>>>> performance testing tools I've used so far, all are suggesting Perl
>>>> performs better than Go, except for httperf. So maybe the performance
>>>> testing tools are biased toward Go, and I made it clear in my second
>>>> blog that I want to get to the bottom of it.
>>>>
>>>> > All of that being said
>>>> >
>>>> > IMO this is just not a meaningful test. Or its results are totally 
>>>> > unsurprising.
>>>>
>>>> Again, I was trying to improve Perl performs with Go. That
>>>> "ridiculously simple" Perl code is the foundation of the Debian dbab
>>>> package, and I was trying to improve it.
>>>>
>>>> It might be meaningless to you but it is perfectly meaningful to me.
>>>> Please don't be so judgmental.
>>>>
>>>> > On Sun, Jun 9, 2019 at 4:54 AM Justin Israel <justinisr...@gmail.com> 
>>>> > wrote:
>>>> >>
>>>> >> I'm wondering about a couple factors in this comparison that seem to 
>>>> >> make a difference in my local test:
>>>> >>
>>>> >> I think perl sockets are write buffered. So would the equivalent be to 
>>>> >> wrap the net.Conn in bufio.NewWriter(c) and flush before the Close?
>>>> >> Since this is a straigh-line test where both servers are not using 
>>>> >> concurrent handling of connections (uncommon for a Go server even on 1 
>>>> >> core), would it not make sense to run the Go server with GOMAXPROCS=1?
>>>> >>
>>>> >> - Justin
>>>> >>
>>>> >> On Saturday, June 8, 2019 at 1:36:49 AM UTC+12, Tong Sun wrote:
>>>> >>>
>>>> >>> I had always believed that the web projects build with Go should be 
>>>> >>> much faster than Perl, since Go is a compiled language.
>>>> >>>
>>>> >>> However that belief was crushed brutally last night, when I did a 
>>>> >>> comparison -- the Go implementation is 8 times worse than the Perl! -- 
>>>> >>> the mean response time jumped from 6ms to 48ms.
>>>> >>>
>>>> >>> I know this is the simplest possible web server, but still, when it 
>>>> >>> comes to simple web servers like this, I have to say that Perl 
>>>> >>> performs much better than Go.
>>>> >>>
>>>> >>> I don't think there is much I can twist on the Go side, since it can't 
>>>> >>> be more simpler than that. However, I also believe it won't hurt to 
>>>> >>> ask and confirm. So,
>>>> >>>
>>>> >>> Have I missed anything? Is it possible for me to make my Go 
>>>> >>> implementation anywhere near the Perl's performance?
>>>> >>>
>>>> >>> Thanks
>>>> >>>
>>>> >>>
>>>> >> --
>>>> >> You received this message because you are subscribed to the Google 
>>>> >> Groups "golang-nuts" group.
>>>> >> To unsubscribe from this group and stop receiving emails from it, send 
>>>> >> an email to golang-nuts+unsubscr...@googlegroups.com.
>>>> >> To view this discussion on the web visit 
>>>> >> https://groups.google.com/d/msgid/golang-nuts/37a1ac7e-85ee-4775-b348-5673c41a162c%40googlegroups.com.
>>>> >> For more options, visit https://groups.google.com/d/optout.
>>>> >
>>>> > --
>>>> > You received this message because you are subscribed to a topic in the 
>>>> > Google Groups "golang-nuts" group.
>>>> > To unsubscribe from this topic, visit 
>>>> > https://groups.google.com/d/topic/golang-nuts/iH2Ck_hpCpI/unsubscribe.
>>>> > To unsubscribe from this group and all its topics, send an email to 
>>>> > golang-nuts+unsubscr...@googlegroups.com.
>>>> > To view this discussion on the web visit 
>>>> > https://groups.google.com/d/msgid/golang-nuts/CAEkBMfF62D5v%2BRiGtAtzuH0wAHzCLqcwNUidC1Oe2KN9DfRv6Q%40mail.gmail.com.
>>>> > For more options, visit https://groups.google.com/d/optout.
>>>>
>>>> --
>>>> You received this message because you are subscribed to the Google Groups 
>>>> "golang-nuts" group.
>>>> To unsubscribe from this group and stop receiving emails from it, send an 
>>>> email to golang-nuts+unsubscr...@googlegroups.com.
>>>> To view this discussion on the web visit 
>>>> https://groups.google.com/d/msgid/golang-nuts/CAMmz1OcefkrZN3_5R7%2BbjuwHjRx%2BLzttaiXmer0ytwmXUjxN_A%40mail.gmail.com.
>>>> For more options, visit https://groups.google.com/d/optout.

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/CAMmz1Oeed76vLx8jC7cqkq00EbHH8LsGwNbnGbqnM5Pko--www%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to