Xray-core icon indicating copy to clipboard operation
Xray-core copied to clipboard

关于传输协议 gRPC 的一些疑惑,望解答。

Open ghost opened this issue 3 years ago • 74 comments

最近看到一个关于主动探测“23 3 3”相关的 issue ,在社区目前还未有结论时,想先暂时切换到 gRPC 模式使用。但现在有几个疑问如下,望大家解惑。

问题 1:gRPC 模式下带宽跑不起来

首先不得不说 gRPC 传输协议相比其他协议,握手响应是真滴快!无论什么多图多元素的页面,基本都是秒开。有时恍惚了还以为在使用 IPLC 节点忘记换了。不过遇到了也是唯一的个问题——带宽跑不起来。

有两条线路,分别是电信 500Mb/30Mb 宽带与移动 200Mb 专线,服务器位于美西电信 CN2 GIA 机房。使用 VLESS+xTLS 、 VLESS+TLS 或 VLESS+TLS+WebSocket 时,均能跑满上下行带宽。但是切换到 gRPC 模式后,下行在 50Mb 左右,上行在 5Mb 左右。虽说日常上网看视频什么的足够了,但是觉得这样的带宽表现肯定是“不正常”的。

服务端的配置试过 Nginx:443 --> Xray(gRPC) --> free ; 也试过配置 Xray:443 --> Nginx --> Xray(gRPC) --> free

但是没什么区别,还是一样的情况。感觉应该是 Nginx 的配置问题(接下来排查的方向)。

问题 2 :~~关于 Nginx 的配置~~(已解决)

如果不使用 Xray-examples gRPC 配置范例中推荐的 Nginx 参数及值(如下),而使用默认值或其他值时,是否会影响到 gRPC 传输协议工作时的带宽表现?

server {
   listen ... so_keepalive=on;

   client_header_timeout 1071906480m;
   keepalive_timeout 1071906480m;

   location /gRPC_name {
        client_max_body_size 0;
        client_body_timeout 1071906480m;
        grpc_read_timeout 1071906480m;
        grpc_pass ...
    }
}

我的 Nginx 服务器预设值

client_header_timeout 10;
keepalive_timeout 65;
client_max_body_size 8M;
client_body_timeout 10;

问题 3 :~~普通模式与 Multi 模式的区别~~(已解决)

官方文档 GRPCObject 里只提到了“Multi 模式”比“普通模式”有一定的性能提升,但没有描述两者工作方式的差异。希望有人能用几句话简单概括下两者工作方式有什么不同,感谢!

官方文档中提到了使用 Nginx 作反向代理时,普通模式与 Multi 模式需要使用不同的 location path 设置: 普通模式:

    location /gRPC_name/Tun {
        grpc_pass ...;
    }

Multi 模式

    location /gRPC_name/TunMulti {
        grpc_pass ...;
    }

但实际使用中发现 location path 设置为 /gRPC_name 也能工作,想知道其中的具体区别。

    location /gRPC_name {
        grpc_pass ...;
    }

另外,还想再确认下:

  • 使用 gRPC 的普通模式时,是否 client.json 中的 "multiMode": false 、 nginx.conf 中的 location /gRPC_name/Tun 、 ~~server.json 中的 "multiMode": false~~ 三者缺一不可?
  • 使用 gRPC 的 Multi 模式时,是否 client.json 中的 "multiMode": true 、 nginx.conf 中的 location /gRPC_name/TunMulti 、 ~~server.json 中的 "multiMode": true~~ 三者缺一不可?

目前的配置

client.json

{
    "outbounds": [
        {
            "protocol": "vless",
            "settings": {
                "vnext": [
                    {
                        "address": "xxx.com",
                        "port": 443,
                        "users": [
                            {
                                "id": "UUID-UUID-UUID-UUID",
                                "encryption": "none"
                            }
                        ]
                    }
                ]
            },
            "streamSettings": {
                "network": "grpc",
                "security": "tls",
                "grpcSettings": {
                    "serviceName": "gRPC_name",
                    "multiMode": true
                }
            }
        }
    ]
}

server.json

{
    "inbounds": [
        {
            "port": 443,
            "protocol": "vless",
            "settings": {
                "clients": [
                    {
                        "id": "UUID-UUID-UUID-UUID"
                    }
                ],
                "decryption": "none",
                "fallbacks": [
                    {
                        "alpn": "h2",
                        "dest": "/.../h2c.sock",
                        "xver": 1
                    },
                    {
                        "dest": "/.../default.sock",
                        "xver": 1
                    }
                ]
            },
            "streamSettings": {
                "network": "tcp",
                "security": "tls",
                "tlsSettings": {
                    "alpn": [
                        "h2",
                        "http/1.1"
                    ],
                    "certificates": [
                        {
                            "certificateFile": "/.../xxx.com.crt",
                            "keyFile": "/.../xxx.com.key"
                        }
                    ]
                }
            }
        },
        {
            "listen": "/.../grpc.sock",
            "protocol": "vless",
            "settings": {
                "clients": [
                    {
                        "id": "UUID-UUID-UUID-UUID"
                    }
                ],
                "decryption": "none"
            },
            "streamSettings": {
                "network": "grpc",
                "grpcSettings": {
                    "serviceName": "gRPC_name",
                    "multiMode": true
                }
            }
        }
    ]
}

nginx.conf

server {
    listen unix:/.../default.sock proxy_protocol;
    listen unix:/.../h2c.sock http2 proxy_protocol;

    server_name xxx.com;

    # reverse proxy for gRPC
    location /gRPC_name/TunMulti {
        grpc_pass unix:/.../grpc.sock;
    }

    ... ...
}

ghost avatar Mar 07 '22 06:03 ghost

client_max_body_size 不设 0 连接会意外关闭。比如 浏览器下载文件

xqzr avatar Mar 07 '22 07:03 xqzr

grpc_read_timeout 不设较大值 Nginx error.log 会有 timeout

xqzr avatar Mar 07 '22 07:03 xqzr

client_header_timeout & keepalive_timeout & client_body_timeout 不设较大值,如果 没有数据传输 连接会在 60/75秒 时关闭,客户端会重新连接,反复。

xqzr avatar Mar 07 '22 07:03 xqzr

关于部分线路 gRPC 过 Nginx 后 降速问题 可能的原因。 可能是因为 Ngimx 不回复 大量的 h2 ping,而 线路差 需要一直调窗口大小,而调 窗口大小 需要 h2 ping。

xqzr avatar Mar 07 '22 08:03 xqzr

location 默认是 模糊匹配。 location = 是全字匹配。

xqzr avatar Mar 07 '22 08:03 xqzr

multiMode 默认是 false 即 普通模式( Tun

xqzr avatar Mar 07 '22 08:03 xqzr

关于部分线路 gRPC 过 Nginx 后 降速问题 可能的原因。 可能是因为 Ngimx 不回复 大量的 h2 ping,而 线路差 需要一直调窗口大小,而调 窗口大小 需要 h2 ping。

可以尝试不经过 Nginx。

xqzr avatar Mar 07 '22 08:03 xqzr

client_header_timeout & keepalive_timeout & client_body_timeout 不设较大值,如果 没有数据传输 连接会在 60/75秒 时关闭,客户端会重新连接,反复。

@xqzr 非常感谢你的回复。 Nginx 服务器有在跑正常 Web 业务,如下的 nginx.conf 参数如果设置为 官方 gRPC 配置范例 中的推荐值 1071906480m ,担心会引起一些不可预知的问题。比如正常的 Web 会话无法及时释放、加重服务器负载之类的。

    client_body_timeout 3600;
    client_header_timeout 3600;
    client_max_body_size 0;
    keepalive_timeout 3600;

考虑到正常 Web 业务与“科学”上网兼顾的话,将超时阈值设置为 1 小时,根据您的经验,这样会不会有改善或者还需要设置更大的值?

location 默认是 模糊匹配。 location = 是全字匹配。

谢谢,明白了。

multiMode 默认是 false 即 普通模式( Tun

gRPC 传输协议要使用性能更好“Multi 模式”,配置是否应该是这样? client.json > "multiMode": true nginx.conf > location /gRPC_name/TunMulti or location = /gRPC_name/TunMulti server.json > "multiMode": true

关于部分线路 gRPC 过 Nginx 后 降速问题 可能的原因。 可能是因为 Ngimx 不回复 大量的 h2 ping,而 线路差 需要一直调窗口大小,而调 窗口大小 需要 h2 ping。

可以尝试不经过 Nginx。

担心 gRPC 服务存在被主动探测的风险。

ghost avatar Mar 07 '22 08:03 ghost

gRPC 传输协议要使用性能更好“Multi 模式”,配置是否应该是这样? client.json > "multiMode": true nginx.conf > location /gRPC_name/TunMulti or location = /gRPC_name/TunMulti server.json > "multiMode": true

location /gRPC_name 即可兼容两种模式

xqzr avatar Mar 07 '22 08:03 xqzr

gRPC 传输协议要使用性能更好“Multi 模式”,配置是否应该是这样? client.json > "multiMode": true nginx.conf > location /gRPC_name/TunMulti or location = /gRPC_name/TunMulti server.json > "multiMode": true

location /gRPC_name 即可兼容两种模式

(๑•̀ㅂ•́)و✧❤

再多问一句,"multiMode": true 是客户端与服务端都需要设置,还是说服务端自适应(可以不用设置)?

ghost avatar Mar 07 '22 08:03 ghost

担心 gRPC 服务存在被主动探测的风险。

临时试一下 ~~没事的吧~~

xqzr avatar Mar 07 '22 08:03 xqzr

@xqzr 非常感谢你的回复。 Nginx 服务器有在跑正常 Web 业务,如下的 nginx.conf 参数如果设置为 官方 gRPC 配置范例 中的推荐值 1071906480m ,担心会引起一些不可预知的问题。比如正常的 Web 会话无法及时释放、加重服务器负载之类的。

    client_body_timeout 3600;
    client_header_timeout 3600;
    client_max_body_size 0;
    keepalive_timeout 3600;

考虑到正常 Web 业务与“科学”上网兼顾的话,将超时阈值设置为 1 小时,根据您的经验,这样会不会有改善或者还需要设置更大的值?

可以尝试新值 https://github.com/XTLS/Xray-examples/blob/97af2eb5ef019b873b899db83ed58f83f8a9796e/VLESS-GRPC/README.md#nginx

xqzr avatar Mar 07 '22 08:03 xqzr

再多问一句,"multiMode": true 是客户端与服务端都需要设置,还是说服务端自适应(可以不用设置)?

仅 客户端

xqzr avatar Mar 07 '22 08:03 xqzr

担心 gRPC 服务存在被主动探测的风险。

临时试一下 ~没事的吧~

刚才试了下服务端不通过 Nginx 反代而直接监听 443 端口,下行带宽没什么变化还是 50Mb 左右。不过上行带宽提高了,也到 50Mb 左右。看来终端到服务器的 CN2 GIA 线路上使用 gRPC 协议也只能这样子了。

再多问一句,"multiMode": true 是客户端与服务端都需要设置,还是说服务端自适应(可以不用设置)?

仅 客户端

明白了,谢谢。

ghost avatar Mar 07 '22 09:03 ghost

听说 client_body_buffer_size 调大 可以提升 上传速率,可以试试 设为 512k https://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size

xqzr avatar Mar 07 '22 09:03 xqzr

听说 client_body_buffer_size 调大 可以提升 上传速率,可以试试 设为 512k https://nginx.org/en/docs/http/ngx_http_core_module.html#client_body_buffer_size

o( ̄▽ ̄)d 上行速度提升到了接近 20Mb,增幅超过 200% !感谢!

@xqzr 另外 nginx.conf 中监听项的 so_keepalive=on 需要保留吗?

server {
   listen ... so_keepalive=on;
   ...
}

ghost avatar Mar 07 '22 09:03 ghost

@xqzr 另外 nginx.conf 中监听项的 so_keepalive=on 需要保留吗?

server {
   listen ... so_keepalive=on;
   ...
}

需要 不然一堆“死连接”

xqzr avatar Mar 07 '22 11:03 xqzr

另外 想了解下 你的 sendfilegrep sendfile /etc/nginx/nginx.conf

xqzr avatar Mar 07 '22 11:03 xqzr

另外 想了解下 你的 sendfilegrep sendfile /etc/nginx/nginx.conf

sendfile on;

刚才又重新测试了几台不同地区不同线路的服务器。发现使用了 client_body_buffer_size 512k; 之后,客户端下行带宽能从原来的总带宽 15% 提升到 60% 左右;客户端上行带宽能从原来的总带宽 15% 提升到 30% 左右。

ghost avatar Mar 07 '22 12:03 ghost

@xqzr 另外 nginx.conf 中监听项的 so_keepalive=on 需要保留吗?

server {
   listen ... so_keepalive=on;
   ...
}

需要 不然一堆“死连接”

因为没有使用端口使用的是 unix domain socket ,也不知道那种用法是对的 -_-''

server {
    listen unix:/dev/shm/h2c.sock http2 so_keepalive=on proxy_protocol;
    ...
}
server {
    listen unix:/dev/shm/h2c.sock http2 proxy_protocol so_keepalive=on;
    ...
}

ghost avatar Mar 07 '22 12:03 ghost

刚才又重新测试了几台不同地区不同线路的服务器。发现使用了 client_body_buffer_size 512k; 之后,客户端下行带宽能从原来的总带宽 15% 提升到 60% 左右;客户端上行带宽能从原来的总带宽 15% 提升到 30% 左右。

thx 想请你帮忙测试一下 把 client_body_buffer_size 替换为 grpc_buffer_size 看看效果

xqzr avatar Mar 07 '22 12:03 xqzr

server {
    listen unix:/dev/shm/h2c.sock http2 so_keepalive=on proxy_protocol;
    ...
}
server {
    listen unix:/dev/shm/h2c.sock http2 proxy_protocol so_keepalive=on;
    ...
}

看漏了...没有监听端口(TCP)的话 不需要 可以去掉

xqzr avatar Mar 07 '22 12:03 xqzr

刚才又重新测试了几台不同地区不同线路的服务器。发现使用了 client_body_buffer_size 512k; 之后,客户端下行带宽能从原来的总带宽 15% 提升到 60% 左右;客户端上行带宽能从原来的总带宽 15% 提升到 30% 左右。

thx 想请你帮忙测试一下 把 client_body_buffer_size 替换为 grpc_buffer_size 看看效果

client_body_buffer_size 512k; 替换成了 grpc_buffer_size 512k; ,测了五、六次,平均算下来上下行带宽跟前面测出来的结果差不多:

刚才又重新测试了几台不同地区不同线路的服务器。发现使用了 client_body_buffer_size 512k; 之后,客户端下行带宽能从原来的总带宽 15% 提升到 60% 左右;客户端上行带宽能从原来的总带宽 15% 提升到 30% 左右。

@xqzr ~~上面是 Win64 的客户端测试结果;但如果是在软路由 Arm64 平台的客户端测试,下行少到只有总带宽的 10% 左右,上行带宽却翻倍了,能到 50~60% 。~~(失误了,忘记监听全端口了,Speedtest 测速使用的是非常规端口 O(∩_∩)O哈哈~ 实测结果与 Windows 客户端一致。)

ghost avatar Mar 07 '22 12:03 ghost

client_body_buffer_size 512k; 替换成了 grpc_buffer_size 512k; ,测了五、六次,平均算下来上下行带宽跟前面测出来的结果差不多:

辛苦 ~~如果都去掉呢?~~ 我自测 加与不加都差不多 Linux amd64(可能我带宽小)

xqzr avatar Mar 07 '22 12:03 xqzr

再多问一句,"multiMode": true 是客户端与服务端都需要设置,还是说服务端自适应(可以不用设置)?

仅 客户端

@xqzr 建议更新官方文档 GRPCObject 文档,为 multiMode 描述添加像 idle_timeout 样的描述文字,如“仅需在客户端配置”。

ghost avatar Mar 08 '22 01:03 ghost

@xqzr 建议更新官方文档 GRPCObject 文档,为 multiMode 描述添加像 idle_timeout 样的描述文字,如“仅需在客户端配置”。

已提交 PR 但目前没人审核

xqzr avatar Mar 08 '22 01:03 xqzr

client_body_buffer_size 512k; grpc_buffer_size 512k; 如果都 加上 效果如何?

xqzr avatar Mar 08 '22 01:03 xqzr

client_body_buffer_size 512k; grpc_buffer_size 512k; 如果都 加上 效果如何?

nginx.conf 添加 client_body_buffer_size 512k; 使用相同测速节点测速三次;(CPU 未满载)

移动 200Mb 专线

  • 168 ms / 114.87 Mb / 46.91 Mb
  • 173 ms / 118.00 Mb / 60.24 Mb
  • 172 ms / 121.60 Mb / 58.99 Mb

电信 500Mb/30Mb 宽带

  • 137 ms / 145.53 Mb / 30.14 Mb
  • 135 ms / 146.81 Mb / 30.01 Mb
  • 138 ms / 139.05 Mb / 29.78 Mb

nginx.conf 添加 client_body_buffer_size 512k;grpc_buffer_size 512k; 使用相同测速节点测速三次。(CPU 未满载)

移动 200Mb 专线(延时变高了,看了下路由,没有直接进到省内的电信 CN2 ,绕路了。)

  • 225 ms / 91.94 Mb / 16.27 Mb
  • 226 ms / 92.85 Mb / 38.09 Mb
  • 226 ms / 95.92 Mb / 58.86 Mb

电信 500Mb/30Mb 宽带

  • 137 ms / 149.41 Mb / 29.47 Mb
  • 137 ms / 136.87 Mb / 30.14 Mb
  • 138 ms / 123.98 Mb / 30.09 Mb

ghost avatar Mar 08 '22 05:03 ghost

nginx.conf 添加 client_body_buffer_size 512k; 使用相同测速节点测速三次;(CPU 未满载)

移动 200Mb 专线

  • 168 ms / 114.87 Mb / 46.91 Mb
  • 173 ms / 118.00 Mb / 60.24 Mb
  • 172 ms / 121.60 Mb / 58.99 Mb

电信 500Mb/30Mb 宽带

  • 137 ms / 145.53 Mb / 30.14 Mb
  • 135 ms / 146.81 Mb / 30.01 Mb
  • 138 ms / 139.05 Mb / 29.78 Mb

nginx.conf 添加 client_body_buffer_size 512k;grpc_buffer_size 512k; 使用相同测速节点测速三次。(CPU 未满载)

移动 200Mb 专线(延时变高了,看了下路由,没有直接进到省内的电信 CN2 ,绕路了。)

  • 225 ms / 91.94 Mb / 16.27 Mb
  • 226 ms / 92.85 Mb / 38.09 Mb
  • 226 ms / 95.92 Mb / 58.86 Mb

电信 500Mb/30Mb 宽带

  • 137 ms / 149.41 Mb / 29.47 Mb
  • 137 ms / 136.87 Mb / 30.14 Mb
  • 138 ms / 123.98 Mb / 30.09 Mb

感谢!看来 client_body_buffer_size 512k; 很重要 有必要添加

xqzr avatar Mar 08 '22 14:03 xqzr

关于部分线路 gRPC 过 Nginx 后 降速问题 可能的原因。 可能是因为 Ngimx 不回复 大量的 h2 ping,而 线路差 需要一直调窗口大小,而调 窗口大小 需要 h2 ping。

可以尝试不经过 Nginx。

@xqzr 你好,想问下目前 Xray 支持设置 window size 吗?

我看软路由 SSR Plus+ 组件设置里有这一项,但是官方文档里没看到有相关的 cvar 介绍。如果支持的话, cvar 是什么?值设置多少合适?

ghost avatar Mar 10 '22 08:03 ghost