Azure IoT Edge自定义模块无法连接Hub,Communication_Error故障求助
Azure IoT Edge自定义模块持续连接中断排查与解决方案
问题描述
自定义IoT Edge模块此前运行正常,近期出现持续连接中断:ConnectionStatusChangeHandler报告状态为ConnectionStatus.Disconnected,原因包含ConnectionStatusChangeReason.Retry_Expired和ConnectionStatusChangeReason.Communication_Error。按最佳实践触发客户端重新初始化后仍无法恢复,无间歇性成功连接,排除临时故障。
检查EdgeHub模块孪生的reported properties,发现clients节点仅列出正常连接的IoTEdgeMetricsCollector模块,自定义模块未被识别:
}, "clients": { "$lastUpdated": "2024-05-22T06:41:40.9107753Z", "deviceId/IoTEdgeMetricsCollector": { "$lastUpdated": "2024-05-22T06:41:40.9107753Z", "status": { "$lastUpdated": "2024-05-22T06:41:40.9107753Z" }, "lastConnectedTimeUtc": { "$lastUpdated": "2024-05-22T06:41:40.9107753Z" } } }
自定义模块可正常部署启动,但无法连接EdgeHub发送遥测,模块内捕获WebSocket异常:
HasStack="True" ThreadID="6,006" ProcessorNumber="0" thisOrContextObject="ErrorDelegatingHandler#34683734" memberName="ExecuteWithErrorHandlingAsync" message="Exception caught: System.Net.WebSockets.WebSocketException (0x80004005): Unable to connect to the remote server ---> System.Net.Http.HttpRequestException: The SSL connection could not be established, see inner exception. ---> System.IO.IOException: Received an unexpected EOF or 0 bytes from the transport stream. at System.Net.Security.SslStream.ReceiveBlobAsync[TIOAdapter](TIOAdapter adapter) at System.Net.Security.SslStream.ForceAuthenticationAsync[TIOAdapter](TIOAdapter adapter, Boolean receiveFirst, Byte[] reAuthenticationData, Boolean isApm) at System.Net.Http.ConnectHelper.EstablishSslConnectionAsync(SslClientAuthenticationOptions sslOptions, HttpRequestMessage request, Boolean async, Stream stream, CancellationToken cancellationToken) --- End of inner exception stack trace --- at System.Net.Http.ConnectHelper.EstablishSslConnectionAsync(SslClientAuthenticationOptions sslOptions, HttpRequestMessage request, Boolean async, Stream stream, CancellationToken cancellationToken) at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken) at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken) at System.Net.Http.HttpConnectionPool.AddHttp11ConnectionAsync(HttpRequestMessage request) at System.Threading.Tasks.TaskCompletionSourceWithCancellation`1.WaitWithCancellationAsync(CancellationToken cancellationToken) at System.Net.Http.HttpConnectionPool.GetHttp11ConnectionAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken) at System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage request, Boolean async, Boolean doRequestAuth, CancellationToken cancellationToken) at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancellationToken) at System.Net.WebSockets.WebSocketHandle.ConnectAsync(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options) at System.Net.WebSockets.WebSocketHandle.ConnectAsync(Uri uri, CancellationToken cancellationToken, ClientWebSocketOptions options) at System.Net.WebSockets.ClientWebSocket.ConnectAsyncCore(Uri uri, CancellationToken cancellationToken) at Microsoft.Azure.Devices.Client.Transport.AmqpIot.AmqpIotTransport.CreateClientWebSocketAsync(Uri websocketUri, CancellationToken cancellationToken) at Microsoft.Azure.Devices.Client.Transport.AmqpIot.AmqpIotTransport.CreateClientWebSocketTransportAsync(CancellationToken cancellationToken) at Microsoft.Azure.Devices.Client.Transport.AmqpIot.AmqpIotTransport.InitializeAsync(CancellationToken cancellationToken) at Microsoft.Azure.Devices.Client.Transport.Amqp.AmqpIotConnector.OpenConnectionAsync(CancellationToken cancellationToken) at Microsoft.Azure.Devices.Client.Transport.Amqp.AmqpConnectionHolder.EnsureConnectionAsync(CancellationToken cancellationToken) at Microsoft.Azure.Devices.Client.Transport.Amqp.AmqpConnectionHolder.OpenSessionAsync(IDeviceIdentity deviceIdentity, CancellationToken cancellationToken) at Microsoft.Azure.Devices.Client.Transport.AmqpIot.AmqpUnit.EnsureSessionIsOpenAsync(CancellationToken cancellationToken) at Microsoft.Azure.Devices.Client.Transport.AmqpIot.AmqpUnit.OpenAsync(CancellationToken cancellationToken) at Microsoft.Azure.Devices.Client.Transport.Amqp.AmqpTransportHandler.OpenAsync(CancellationToken cancellationToken) at Microsoft.Azure.Devices.Client.Transport.ProtocolRoutingDelegatingHandler.OpenAsync(CancellationToken cancellationToken) at Microsoft.Azure.Devices.Client.Transport.ErrorDelegatingHandler.<>c__DisplayClass27_0.<ExecuteWithErrorHandlingAsync>b__0>d.MoveNext() --- End of stack trace from previous location --- at Microsoft.Azure.Devices.Client.Transport.ErrorDelegatingHandler.ExecuteWithErrorHandlingAsync[T](Func`1 asyncOperation)"
环境信息
- 主机:Debian 11,Arm64
- aziot-edged:1.4.27
- Edge Agent:1.4.35
- Edge Hub:1.4.35
- Docker/Moby:24.0.9-1
已尝试操作
- 在Azure门户及分层部署中移除并重新添加自定义模块
- 重启网关、系统模块,执行
iotedge system restart - 部署
SimulatedTemperatureSensor模块,可正常注册到EdgeHub并运行 iotedge check返回全绿,仅少量版本警告- 重启后EdgeHub和EdgeAgent日志无报错
解决方案建议
1. 重置EdgeHub模块孪生配置
推测因意外修改EdgeHub孪生导致模块识别异常,可通过Azure CLI重置EdgeHub的期望属性为默认值:
az iot hub module-twin update --hub-name <你的IoT Hub名称> --device-id <Edge设备ID> --module-name edgeHub --set properties.desired='{}'
执行后等待部署生效,再重新部署自定义模块。
2. 验证自定义模块的连接字符串与SSL证书
- 检查自定义模块的环境变量
EdgeHubConnectionString是否正确,确保使用模块孪生生成的连接字符串 - 验证设备本地IoT Edge根证书有效性:
若证书过期或损坏,重新生成证书:ls /etc/aziot/certs/ openssl x509 -in /etc/aziot/certs/iotedge-device-ca.crt -text -nooutsudo iotedge certgen renew
3. 检查EdgeHub的端口与网络配置
- 执行
docker inspect edgeHub查看Ports字段,确认默认端口(5671、8883、443)映射正常 - 检查主机防火墙规则,确保自定义模块可访问EdgeHub端口:
sudo ufw status sudo iptables -L -n
4. 清理EdgeHub本地状态缓存
EdgeHub本地缓存可能存在异常,清理后重启:
sudo docker stop edgeHub sudo docker rm edgeHub sudo rm -rf /var/lib/aziot/edged/mnt/data/edgeHub sudo iotedge system restart
5. 切换自定义模块的传输协议
当前AMQP over WebSocket连接失败,可尝试切换为MQTT协议,修改模块代码中的客户端初始化逻辑:
var options = new ClientOptions { TransportSettings = new List<ITransportSettings> { new MqttTransportSettings(MqttTransportType.Tcp) } }; var deviceClient = DeviceClient.CreateFromConnectionString(connectionString, options);
内容的提问来源于stack exchange,提问作者user1483086
相关产品推荐
相关产品推荐

