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

xprotocol协议代理出现了serverCallbacks为空的panic问题 #2338

Open
zzqCh opened this issue Aug 15, 2023 · 35 comments
Open

xprotocol协议代理出现了serverCallbacks为空的panic问题 #2338

zzqCh opened this issue Aug 15, 2023 · 35 comments

Comments

@zzqCh
Copy link

zzqCh commented Aug 15, 2023

Your question

MOSN的config文件如下:

{
	"disable_upgrade": true,
	"servers":[
		{
			"default_log_path":"stdout",
			"default_log_level": "TRACE",
			"routers":[
				{
					"router_config_name":"server_router",
					"virtual_hosts":[{
						"name":"serverHost",
						"domains": ["*"],
						"routers": [
							{
								"route":{"cluster_name":"serverCluster"}
							}
						]
					}]
				}
			],
			"listeners": [
				{
					"name":"serverListener",
					"address": "0.0.0.0:2048",
					"bind_port": true,
					"filter_chains": [{
						"filters": [
							{
								"type": "proxy",
								"config": {
									"downstream_protocol": "protocolA",
									"upstream_protocol": "protocolA",
									"router_config_name":"server_router"
								}
							}
						]
					}]
				}
			]
		}
	],
	"cluster_manager":{
		"clusters":[
			{
				"name":"serverCluster",
				"type": "SIMPLE",
				"lb_type": "LB_RANDOM",
				"max_request_per_conn": 2048,
				"conn_buffer_limit_bytes":32768,
				"cluster_pool_enable": true,
				"circuit_breakers": [
					{
						"max_connections": 100000,
						"max_pending_requests": 1000000000,
						"max_requests": 1000000000,
						"max_retries": 2
					}
				],
				"hosts":[
					{"address":"168.1.1.1:9999"}
				]
			}
		]
	},
	"admin": {
		"address": {
			"socket_address": {
				"address": "0.0.0.0",
				"port_value": 34923
			}
		}
	},
	"pprof": {
		"debug": true,
		"port_value": 34922
	}
}

访问运行出现了panic,问题截图:

image

跟踪代码发现:
image
image

image

Environment

  • MOSN Version
    master分支,最新版本

Logs

  • Paste the logs you see.
    请问这个是mosn自身的问题还是我这边配置的问题?
@taoyuanyuan
Copy link
Contributor

protocolA 你自己实现的协议吗

@zzqCh
Copy link
Author

zzqCh commented Aug 15, 2023

protocolA 你自己实现的协议吗

是的。是在xrpotcol的框架下实现的

@taoyuanyuan
Copy link
Contributor

https://github.com/mosn/mosn/blob/07be2d0d6b9cee511262f85132277fcf937be23b/pkg/stream/xprotocol/conn.go#L254C11-L254C19
看你的流程,应该是返回response,你这儿返回了request,走入了错误的流程

@zzqCh
Copy link
Author

zzqCh commented Aug 15, 2023

https://github.com/mosn/mosn/blob/07be2d0d6b9cee511262f85132277fcf937be23b/pkg/stream/xprotocol/conn.go#L254C11-L254C19 看你的流程,应该是返回response,你这儿返回了request,走入了错误的流程

好的。 谢谢您。我再研究研究

@zzqCh
Copy link
Author

zzqCh commented Aug 15, 2023

https://github.com/mosn/mosn/blob/07be2d0d6b9cee511262f85132277fcf937be23b/pkg/stream/xprotocol/conn.go#L254C11-L254C19 看你的流程,应该是返回response,你这儿返回了request,走入了错误的流程

您好,我这边定位到了,发现是协议中没有字段表明是request还是response,因此返回的都是requst,请问有什么好的办法区分么?莫非要加个filter(filter中把mosn自带的direction设置到variable中??)

@taoyuanyuan
Copy link
Contributor

func (proto dubboProtocol) Decode(ctx context.Context, data types.IoBuffer) (interface{}, error) {

你从ctx里面可以感知到时downstream还是upstream,你可以在frame里面直接保存是request,还是response

@zzqCh
Copy link
Author

zzqCh commented Aug 15, 2023

func (proto dubboProtocol) Decode(ctx context.Context, data types.IoBuffer) (interface{}, error) {

你从ctx里面可以感知到时downstream还是upstream,你可以在frame里面直接保存是request,还是response

image

而且我打印了下ctx,发现里面都是 {"context":{"context":{"context":0}}}

@taoyuanyuan
Copy link
Contributor

这儿你可以不根据协议(你的协议没有字段判断),你可以根据你现在是downstream和upstream的连接来判断,downstream是request,upstream是reponse。
ctx不可能为空吧?日志打出来看看呢

@zzqCh
Copy link
Author

zzqCh commented Aug 15, 2023

这儿你可以不根据协议(你的协议没有字段判断),你可以根据你现在是downstream和upstream的连接来判断,downstream是request,upstream是reponse。 ctx不可能为空吧?日志打出来看看呢

2023-08-15 13:58:04,410 [DEBUG] [network] [server idle checker] connection have read/write data before this read timeout: 308, 314, 0, 0
-------------------->>>>>>context信息>>>>>>>>> {"Context":{"Context":{"Context":0}}}
-------------------->>>>>>context信息>>>>>>>>> {"Context":{"Context":{"Context":0}}}
2023-08-15 13:58:12,427 [DEBUG] [2,-,-] [stream] [xprotocol] new stream detect, requestId = 0
2023-08-15 13:58:12,427 [DEBUG] [2,-,-] [proxy] [downstream] new stream, proxyId = 2 , requestId =0, oneway=false
2023-08-15 13:58:12,427 [DEBUG] [2,-,-] [proxy] [downstream] OnReceive
2023-08-15 13:58:12,427 [TRACE] [2,-,-] [proxy] [downstream] OnReceive

中间省略
中间省略
中间省略
中间省略
中间省略

下面是接收到返回后,打印的日志
2023-08-15 13:58:12,431 [DEBUG] [2,4,-] [stream] [xprotocol] appendData, direction = 0, requestId = 1
2023-08-15 13:58:12,431 [DEBUG] [2,4,-] [stream] [xprotocol] connection 4 endStream, direction = 0, requestId = 1
2023-08-15 13:58:14,108 [DEBUG] [2,4,-] [proxy] [downstream] enter phase WaitNotify[11], proxyId = 2
2023-08-15 13:58:14,108 [DEBUG] [2,4,-] [proxy] [downstream] waitNotify begin 0xc0001e9340, proxyId = 2
-------------------->>>>>>context信息>>>>>>>>> {"Context":{"Context":0}}
-------------------->>>>>>context信息>>>>>>>>> {"Context":{"Context":0}}
2023-08-15 13:58:20,159 [DEBUG] [-,-,-] [stream] [xprotocol] new stream detect, requestId = 0
2023-08-15 13:58:20,161 goroutine panic: runtime error: invalid memory address or nil pointer dereference

@taoyuanyuan
Copy link
Contributor

你用的什么connpool?方便看看你的代码吗

@zzqCh
Copy link
Author

zzqCh commented Aug 15, 2023

你用的什么connpool?方便看看你的代码吗

connpool_multiplex.go. 使用的是这个,具体是哪块的代码呢?我打印context是在decode中的开头,也是看的example中的方法
image

image

@taoyuanyuan
Copy link
Contributor

直接 %+v 打印 ctx 看看

@zzqCh
Copy link
Author

zzqCh commented Aug 15, 2023

直接 %+v 打印 ctx 看看

这么确实打印出来了,但是好像根本看不懂的呢。
&{0xc0006dc540 [0xc0006c1800 [{false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {true 0} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>} {false <nil>}]]}

另外,您能告诉下为啥会替换requestId的么?

image image

我理解的流程如下:
image

image

@taoyuanyuan
Copy link
Contributor

因为client是有多个, 如果这儿不换成新的唯一id,发送给服务端的时候会有冲突。
比如两个client都同时发送了200的id到mosn,mosn不替换的话,会给服务端发送两个200的请求。
你的协议里面有唯一的id标识吗?

@taoyuanyuan
Copy link
Contributor

如果你的协议不支持多路复用,可以选择pingpong的connpool,类似http1.

@zzqCh
Copy link
Author

zzqCh commented Aug 15, 2023

因为client是有多个, 如果这儿不换成新的唯一id,发送给服务端的时候会有冲突。 比如两个client都同时发送了200的id到mosn,mosn不替换的话,会给服务端发送两个200的请求。 你的协议里面有唯一的id标识吗?

有唯一id的。
这个怎么确认协议是否是支持多路复用的呢?我理解实现requestid的两个接口就能多路复用的吧?
http1.1的坏处就是client-->proxy和proxy-->server的连接数是一对一的,这样server也需要部署好多机器,比较浪费资源,如果能够多路复用,那么proxy--->server的连接就会很少。

目前发现收到服务端的响应后,因为找不到clientStream,导致mosn终止了给客户端的响应,您知道是哪块的问题么?

@taoyuanyuan
Copy link
Contributor

  1. 能不能支持多路复用还是要看你的协议以及服务端的实现哟,比如dubbo,http2就是支持多路复用的,http1就不支持,只能pingpong,一来一回的。
  2. http1虽然是pingpong的,但是proxy-server的连接是可以复用的哈,一个请求结束了,就是放入连接池,下次请求来了继续用。
  3. 找不到clientstream,是不是id替换不对呀,你server返回的id和你替换的id一样吗?

@zzqCh zzqCh closed this as completed Aug 15, 2023
@taoyuanyuan
Copy link
Contributor

那是不是你实现的setrequestid方法不对?

@zzqCh
Copy link
Author

zzqCh commented Aug 15, 2023

那是不是你实现的setrequestid方法不对?

是的,我修改了该方法,处理response的时候设置成发送时候的Requestid,非常感谢您的耐心指导。

对了,顺便问下您,您知道取ctx中的哪个key是代表direction的么?我目前没发现,因此自己手动设置了下。

@taoyuanyuan
Copy link
Contributor

你暂时用 types.VariableListenerName 试试,能获取到这个变量就是downstream,后面可以搞个通用的变量。
variable.Get(ctx, types.VariableListenerName)

@taoyuanyuan taoyuanyuan reopened this Aug 15, 2023
@zzqCh
Copy link
Author

zzqCh commented Aug 16, 2023

你暂时用 types.VariableListenerName 试试,能获取到这个变量就是downstream,后面可以搞个通用的变量。 variable.Get(ctx, types.VariableListenerName)

好的,谢谢您。

@zzqCh
Copy link
Author

zzqCh commented Aug 25, 2023

您好,请问下,今天压测过程中发现数据出现了交叉,只有在压测过程中才会出现数据交叉的情况,请问能从哪几个方面去查询的呢?
场景:
一、sever端是一个echo服务,即返回内容就是客户端的请求内容
二、压测客户端client1发送数据到server,比如发送的是aaacccddd
三、此时,重新启动一个客户端client2,发送数据到server,发现接收到的数据错乱了,接收到的数据是client2发送的部分数据和client1发送的部分数据。

@taoyuanyuan
Copy link
Contributor

意思就是server收到了client1和client2的部分数据,就是不完整的请求吗?
你们是支持多路复用的吗?也就是server可以并发处理多个请求?

@zzqCh
Copy link
Author

zzqCh commented Aug 25, 2023

意思就是server收到了client1和client2的部分数据,就是不完整的请求吗? 你们是支持多路复用的吗?也就是server可以并发处理多个请求?

是多路复用,而且xprotocol只支持多路复用的吧?之前改成pingpong的时候服务起不来。server是可以支持多路复用的呢,因为server端每接收到一个请求,就会启动一个协程。
目前从表现上看是client收到了错乱的数据,但不清楚是哪块的问题。

@taoyuanyuan
Copy link
Contributor

你可以打一个debug日志出来看看,有tracelog,能关联出来的,是不是id错乱了

@zzqCh
Copy link
Author

zzqCh commented Aug 25, 2023

你可以打一个debug日志出来看看,有tracelog,能关联出来的,是不是id错乱了

image

这个哪个字段是关联的呢?日志有点多的呢。

@zzqCh
Copy link
Author

zzqCh commented Aug 29, 2023

你可以打一个debug日志出来看看,有tracelog,能关联出来的,是不是id错乱了

您好,请问client到mosn发现有请求id为空,我这边写的请求id为空,那么setRequestID默认是0,是不是这个会导致数据错乱?如果是的话,怎么避免的呢?

@taoyuanyuan
Copy link
Contributor

那肯定有问题,你发送id为空的两个请求,没办法判断回包是属于那个请求啊

@taoyuanyuan
Copy link
Contributor

你如果请求id为空,就证明你不支持多路复用啊,只支持pingpong模型了,或者pipeline。

@zzqCh
Copy link
Author

zzqCh commented Aug 29, 2023

你如果请求id为空,就证明你不支持多路复用啊,只支持pingpong模型了,或者pipeline。

好的。谢谢您,目前定位到确实也是这个问题

@taoyuanyuan
Copy link
Contributor

那你可以用pingpong的connpool试试,串行的,就不会乱了

@zzqCh
Copy link
Author

zzqCh commented Aug 31, 2023

那你可以用pingpong的connpool试试,串行的,就不会乱了

您好,这里我还有个问题,我发现错乱的场景是这样的:
场景:
1)客户端:有三个客户端,其中一个客户端发送的请求中有uuid(我们命名为客户端A),但是另外两个发送的请求中无uuid(命名为客户端B和客户端C),即可认为requestid是0
2)服务端:简单的echo服务,即响应内容就是客户端的请求内容

测试方式:
1.客户端A,一直发送数据,比如发送的数据{"data":"test","iphone":"13pro","time":"123"}
2.客户端B开始发送数据,要求服务端延迟3秒,比如发送的数据{"name":"a","code":"b"}
3.客户端C开始发送数据,要求服务端延迟10秒,比如发送的数据{"name":"a","code":"b"}
4.客户端B开始发送数据,要求服务端延迟3秒,比如发送的数据{"name":"a","code":"b"}

在这个场景下,客户端B和客户端C接收到的数据中会夹杂着客户端A发送的数据,比如可能接收到的是{"name":"a","iphone":"13pro"}或者是{"nameipho":"13a"}(只是为了说明数据错乱了,而且无规则)
但是按照我对mosn的理解,无论客户端B和客户端C怎么发送数据,数据错乱也只会影响到客户端B和客户端C的吧?也就是说客户端B和客户端C收到的数据中不应该存在客户端A收到的数据,但是目前看到客户端B或者C中却存在了客户端A的响应数据。

请求无uuid的情况下,这个case是合理的么?

@taoyuanyuan
Copy link
Contributor

这儿的uuid是协议的唯一id吗
你们server端会返回这个uuid吗
最好有一个出问题的debug日志

@zzqCh
Copy link
Author

zzqCh commented Aug 31, 2023

这儿的uuid是协议的唯一id吗 你们server端会返回这个uuid吗 最好有一个出问题的debug日志

uuid是协议的唯一id,server端也会返回的这个唯一id的呢。

按理来说客户端B和C不会出现客户端A中的数据吧?

@taoyuanyuan
Copy link
Contributor

那其实server收到的请求都是有uuid的钱,因为mosn会生成的,有没有可能server端有问题?最好有个debug日志

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

2 participants