Skip to content
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

关于simpleweb #1998

Open
y2jun opened this issue Nov 15, 2024 · 12 comments
Open

关于simpleweb #1998

y2jun opened this issue Nov 15, 2024 · 12 comments

Comments

@y2jun
Copy link

y2jun commented Nov 15, 2024

问题严重性较低, 长时间找不到原因, 还请麻烦提点一下.

背景:
本人按照simpleweb的案例编写了一套适应skynet的web服务功能, 该服务使用仅为http, 非https.

问题1:
背景: 在使用压力测试工具时, 具体数据可以看下面提供的数据.
问题点: 大量的请求处在connection closed before message completed状态.

问题2:
背景: 在使用压力测试工具时, 服务器文件打开数也设置65535, 具体情况可以看下面提供的图片.
问题点:请求过程中一起开始时在一个稳定在一定的并发数, 但是过一段时间后会掉到0, 再过一段时间就会恢复部份并发数, 以此循环.
期间查看了机器状态, cpu和内存在低负载.

题外
由于花了很多时间, 控制变量法测试.
使用远程服务器, SkynetWeb服务,出现问题.
使用远程服务器, 使用Go的Gin框架搭建的服务, 不出现问题.
使用本地服务器, 不出现问题.

Additional context
这里提供了部分测试数据. 这里的设置了文件打开数较低时为了避免长时间的处在问题2中,

PS C:\Users\pfkj_2024> oha -n 20000 -c 3 -p 2 http://xxxxxx:8001/api/test
Summary:
  Success rate: 54.19%
  Total:        54.4785 secs
  Slowest:      1.0172 secs
  Fastest:      0.0064 secs
  Average:      0.0104 secs
  Requests/sec: 283.1024

  Total data:   1.49 MiB
  Size/request: 187 B
  Size/sec:     28.01 KiB

Response time histogram:
  0.006 [1]    |
  0.107 [8344] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
  0.209 [3]    |
  0.310 [0]    |
  0.411 [0]    |
  0.512 [0]    |
  0.613 [0]    |
  0.714 [0]    |
  0.815 [0]    |
  0.916 [0]    |
  1.017 [9]    |

Response time distribution:
  10.00% in 0.0078 secs
  25.00% in 0.0081 secs
  50.00% in 0.0085 secs
  75.00% in 0.0089 secs
  90.00% in 0.0096 secs
  95.00% in 0.0156 secs
  99.00% in 0.0280 secs
  99.90% in 1.0089 secs
  99.99% in 1.0172 secs


Details (average, fastest, slowest):
  DNS+dialup:   0.0007 secs, 0.0001 secs, 0.0257 secs
  DNS-lookup:   0.0000 secs, 0.0000 secs, 0.0013 secs

Status code distribution:
  [200] 8357 responses

Error distribution:
  [5576] connection closed before message completed
  [1466] connection error
  [15] timeout
  [9] operation was canceled
image

Last
由于本人第一次发issue, 格式错误请见谅, 还有数据不足的话, 我尽可能提供.

@cloudwu
Copy link
Owner

cloudwu commented Nov 15, 2024

你可以先调试测试一下,具体的 close 包是哪一行代码什么时机发出的。

@y2jun
Copy link
Author

y2jun commented Nov 15, 2024

你可以先调试测试一下,具体的 close 包是哪一行代码什么时机发出的。

调试不知道从哪里下手

因为我使用的simpleweb这个案例跑服务, 也是这个情况.
如果单从lua代码层来说的话, 按照逻辑是符合在每次response才进行socket.close,
在看完lua-socket.cskynet_socket.csocket_server.c 代码后, 从write执行到close是同步的, 确保不会因为异步执行导致FIN包出现在发送response之前.

我在限制发送100个请求时, 发现日志仅有78条

...
[:00000027] 14.145.211.92:61029 connected, pass it to agent :00000028
[:00000027] 14.145.211.92:61030 connected, pass it to agent :00000029
...

而且刚好错误请求也在22条,

Error distribution:
  [21] connection closed before message completed
  [1] connection error

这里曾经怀疑是否因为socket.lua的原因丢弃了一些请求连接,
我也按照了service_gate.c的服务写了一份专用的web的gate-C服务(backlog控制在128), 还是会继续丢弃请求.

@cloudwu
Copy link
Owner

cloudwu commented Nov 15, 2024

lua 是无法直接调用系统 api 的,所以真正能 close 的地方只有在 C 中。在 C 里加几行 log 就能知道发生了什么。

正常逻辑的 close 只发生在这一行 https://github.com/cloudwu/skynet/blob/master/skynet-src/socket_server.c#L506

这里的实现区分了两种 close 的逻辑:一种是无论有没有未发送完的数据都立刻关闭,一种是必须等所有数据发送完毕。这个可以调试时查看

https://github.com/cloudwu/skynet/blob/master/skynet-src/socket_server.c#L158

这里的 shutdown 字段,看有没有使用错误。

@cloudwu
Copy link
Owner

cloudwu commented Nov 15, 2024

因为所有对 socket 的操作都只在 socket_server.c 中,所以在这个文件中加 log ,就能了解到底 write 了什么数据,什么时候 close 。

我觉得调试还是比较容易的。

@y2jun
Copy link
Author

y2jun commented Nov 16, 2024

因为所有对 socket 的操作都只在 socket_server.c 中,所以在这个文件中加 log ,就能了解到底 write 了什么数据,什么时候 close 。

我觉得调试还是比较容易的。

其实我已经排查了在socket_server.c506行, 更甚在1634行report_accept(...)加上了打点, 也都只有接收到80条左右的请求数量,
(一直都是限定100的请求量)

其实底层估计没问题, 只是奇怪的是为什么会有部份请求丢失, 如果我使用go搭的web服务器却不会丢(怀疑网络问题), 文件打开数了也控制了.

@cloudwu
Copy link
Owner

cloudwu commented Nov 16, 2024

因为所有对 socket 的操作都只在 socket_server.c 中,所以在这个文件中加 log ,就能了解到底 write 了什么数据,什么时候 close 。
我觉得调试还是比较容易的。

其实我已经排查了在socket_server.c506行, 更甚在1634行report_accept(...)加上了打点, 也都只有接收到80条左右的请求数量, (一直都是限定100的请求量)

其实底层估计没问题, 只是奇怪的是为什么会有部份请求丢失, 如果我使用go搭的web服务器却不会丢(怀疑网络问题), 文件打开数了也控制了.

如果 C 层只收到 80 条,那就是 80 。因为 lua 自己无法直接处理 socket 。

如果在 C api 这个层面丢 accept ,你得调大 backlog 。

@y2jun
Copy link
Author

y2jun commented Nov 16, 2024

因为所有对 socket 的操作都只在 socket_server.c 中,所以在这个文件中加 log ,就能了解到底 write 了什么数据,什么时候 close 。
我觉得调试还是比较容易的。

其实我已经排查了在socket_server.c506行, 更甚在1634行report_accept(...)加上了打点, 也都只有接收到80条左右的请求数量, (一直都是限定100的请求量)
其实底层估计没问题, 只是奇怪的是为什么会有部份请求丢失, 如果我使用go搭的web服务器却不会丢(怀疑网络问题), 文件打开数了也控制了.

如果 C 层只收到 80 条,那就是 80 。因为 lua 自己无法直接处理 socket 。

如果在 C api 这个层面丢 accept ,你得调大 backlog 。

我调到512还是不行(设置了仅仅100的请求量)。

@cloudwu
Copy link
Owner

cloudwu commented Nov 17, 2024

你应该很容易确认问题是出在 C API 上,还是对它们的调用上。看看 accept 成功了多少连接,都 write 了多少数据,什么时候 close 的。

@changlongH
Copy link

changlongH commented Nov 19, 2024

你的压测工具是自己写的吗?有可能多次请求使用同一条socket,而服务器这边每次处理完一条之后就会socket.close()

可以简单验证一下,把simpleweb 修改为循环读取socket数据。

while true do
        local code, url, method, header, body = httpd.read_request(socketRead(id), LIMIT_BODY_SIZE)
        if not code then
            break
        end
        --TODO 业务逻辑
end
 socket.close(id)

@y2jun
Copy link
Author

y2jun commented Nov 20, 2024

你的压测工具是自己写的吗?有可能多次请求使用同一条socket,而服务器这边每次处理完一条之后就会socket.close()

可以简单验证一下,把simpleweb 修改为循环读取socket数据。

while true do
        local code, url, method, header, body = httpd.read_request(socketRead(id), LIMIT_BODY_SIZE)
        if not code then
            break
        end
        --TODO 业务逻辑
end
 socket.close(id)

oha开源工具, 我晚点测试下

@changlongH
Copy link

oha -n 20000 -c 3 -p 2 --no-tui http://localhost:8001                                                                                                              ✔ │ 11:20:43 
Summary:
  Success rate:	100.00%
  Total:	0.3703 secs
  Slowest:	0.0008 secs
  Fastest:	0.0000 secs
  Average:	0.0001 secs
  Requests/sec:	54007.5881

  Total data:	3.11 MiB
  Size/request:	163 B
  Size/sec:	8.40 MiB

Response time histogram:
  0.000 [1]     |
  0.000 [19776] |■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■
  0.000 [216]   |
  0.000 [4]     |
  0.000 [0]     |
  0.000 [0]     |
  0.000 [0]     |
  0.001 [0]     |
  0.001 [0]     |
  0.001 [0]     |
  0.001 [3]     |

Response time distribution:
  10.00% in 0.0000 secs
  25.00% in 0.0000 secs
  50.00% in 0.0001 secs
  75.00% in 0.0001 secs
  90.00% in 0.0001 secs
  95.00% in 0.0001 secs
  99.00% in 0.0001 secs
  99.90% in 0.0002 secs
  99.99% in 0.0008 secs


Details (average, fastest, slowest):
  DNS+dialup:	0.0006 secs, 0.0005 secs, 0.0006 secs
  DNS-lookup:	0.0000 secs, 0.0000 secs, 0.0000 secs

Status code distribution:
  [200] 20000 responses

调整simpleweb.lua支持socket链路复用,我Mac上测试的结果。

while true do
       ....
        if url == sockethelper.socket_error then
            skynet.error("socket closed")
            break
        end
end

(不过oha --no-tui http://localhost:8001默认测试用例测试,一直有18个connection error 可能需要看一下测试用例)

@y2jun
Copy link
Author

y2jun commented Nov 21, 2024

...

调整simpleweb.lua支持socket链路复用,我Mac上测试的结果。

while true do
       ....
        if url == sockethelper.socket_error then
            skynet.error("socket closed")
            break
        end
end

(不过oha --no-tui http://localhost:8001默认测试用例测试,一直有18个connection error 可能需要看一下测试用例)

确实是链路复用的问题, 只要开启了--disable-keepalive就可以保证请求数量正确.
还有一件事, 测试服务器请使用远程的服务器, 这样测出来的效果会更明显点.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants