等待事件:reliable message

本文解析了Oracle RAC环境中出现的可靠消息(reliablemessage)等待事件,该事件表明跨实例消息发送过程中,发送方未能及时从接收方获得确认,从而导致性能问题。通常这反映了节点间通信异常或网络负载过高的情况。

author:skate
time:2011/05/03


 

等待事件:reliable message

 

在metalink中的解释如下:

 

 

    When you send a message using the 'KSR' intra-instance broadcast
    service, the message publisher waits on this wait-event until
    all subscribers have consumed the 'reliable message' just sent.
    The publisher waits on this wait-event for three seconds and
    then re-tests if all subscribers have consumed the message, or
    until posted.

 

也就是说当跨实例发送消息时,发送者期望收到订阅者的回复信息,如果得不到可信回复,
就会一直处于等待。等待以3秒为周期进行反复尝试,直到收到所有订阅者的回复或者被唤醒。

 

在RAC环境中如果此等待事件出现在top5中,那就说明在节点间的通讯已经出现问题,一个节点得不到
另外一个节点的可信回复,这个等待事件已经严重影响了性能,这个时候就要检查节点间的通信是否
正常,是否网络负载过大等。

 

 

 

 

 

 

---------end------------

 

 

 

 

 

 

 

 

 

BLE Mesh 消息可靠传输实现指南 根据您提供的文档信息,我来详细解释如何实现消息不丢包和如何发送无应答消息。 1. 实现消息传输不丢包(有应答消息) 要实现可靠传输不丢包,需要使用有应答的消息机制。以下是具体实现方法: 1.1 配置超时时间 首先在 menuconfig 中配置默认超时时间: ``` Component config → Bluetooth Mesh → Client model message timeout (seconds) ``` 或者直接修改 sdkconfig: ```c CONFIG_BLE_MESH_CLIENT_MSG_TIMEOUT=10 # 设置为10秒超时 ``` 1.2 发送有应答消息 ```c /** * @brief 发送有应答的厂商消息(确保可靠传输) * * @param server_addr 目标地址 * @param data 发送数据 * @param length 数据长度 * @param opcode 操作码 * @param timeout_ms 自定义超时时间(毫秒),0表示使用默认值 * @return esp_err_t 发送结果 */ esp_err_t example_ble_mesh_send_reliable_message(uint16_t server_addr, uint8_t *data, uint16_t length, uint32_t opcode, uint32_t timeout_ms) { esp_ble_mesh_msg_ctx_t ctx = {0}; esp_err_t err; // 设置消息上下文 ctx.net_idx = gStore.net_idx; ctx.app_idx = gStore.app_idx; ctx.addr = server_addr; ctx.send_ttl = MSG_SEND_TTL; ctx.send_rel = true; // 要求可靠传输 if (opcode == 0) { opcode = ESP_BLE_MESH_VND_MODEL_OP_SEND; } // 转换超时时间(毫秒到毫秒,但API可能需要不同的单位) int msg_timeout = (timeout_ms > 0) ? (timeout_ms / 1000) : 0; ESP_LOGI(BLE_MESH, "Sending reliable message to 0x%04x, timeout: %d ms", server_addr, (timeout_ms > 0) ? timeout_ms : CONFIG_BLE_MESH_CLIENT_MSG_TIMEOUT * 1000); // 发送有应答的消息(need_rsp = true) err = esp_ble_mesh_client_model_send_msg(vendor_client.model, &ctx, opcode, length, data, msg_timeout, // 超时时间 true, // need_rsp = true 要求应答 MSG_ROLE); if (err != ESP_OK) { ESP_LOGE(BLE_MESH, "Failed to send reliable message: %s", esp_err_to_name(err)); } return err; } ``` 1.3 处理应答和超时事件 需要在Mesh事件回调中处理应答和超时: ```c static void mesh_event_cb(esp_ble_mesh_cb_event_t event, esp_ble_mesh_cb_param_t *param) { switch (event) { case ESP_BLE_MESH_CLIENT_MODEL_SEND_TIMEOUT_EVT: // 消息发送超时处理 ESP_LOGE(BLE_MESH, "Message timeout, opcode: 0x%06x, addr: 0x%04x", param->client_recv_timeout.opcode, param->client_recv_timeout.ctx->addr); // 这里可以触发重试机制 break; case ESP_BLE_MESH_CLIENT_MODEL_RECV_RSP_EVT: // 收到应答处理 ESP_LOGI(BLE_MESH, "Received response, opcode: 0x%06x, addr: 0x%04x", param->client_recv_rsp.opcode, param->client_recv_rsp.ctx->addr); // 处理应答数据 ESP_LOG_BUFFER_HEX_LEVEL(BLE_MESH, param->client_recv_rsp.params, param->client_recv_rsp.length, ESP_LOG_DEBUG); break; // 其他事件处理... } } ``` 1.4 带自动重试的可靠发送函数 ```c /** * @brief 带自动重试的可靠消息发送 */ esp_err_t example_ble_mesh_send_with_retry(uint16_t server_addr, uint8_t *data, uint16_t length, uint32_t opcode, uint8_t max_retries, uint32_t retry_delay_ms) { esp_err_t err; uint8_t retry_count = 0; do { err = example_ble_mesh_send_reliable_message(server_addr, data, length, opcode, 5000); if (err == ESP_OK) { // 发送成功,等待应答或超时事件 // 这里需要实现一个等待机制,比如使用信号量或消息队列 // 等待 ESP_BLE_MESH_CLIENT_MODEL_RECV_RSP_EVT 事件 ESP_LOGI(BLE_MESH, "Message sent successfully, waiting for response..."); return ESP_OK; } retry_count++; if (retry_count <= max_retries) { ESP_LOGW(BLE_MESH, "Send failed, retry %d/%d after %d ms", retry_count, max_retries, retry_delay_ms); vTaskDelay(pdMS_TO_TICKS(retry_delay_ms)); } } while (retry_count <= max_retries); ESP_LOGE(BLE_MESH, "All retries failed for message to 0x%04x", server_addr); return err; } ``` 1. 发送无应答的消息 2.1 客户端模型发送无应答消息 ```c /** * @brief 发送无应答的厂商消息(快速,不保证可靠) * * @param server_addr 目标地址 * @param data 发送数据 * @param length 数据长度 * @param opcode 操作码 * @return esp_err_t 发送结果 */ esp_err_t example_ble_mesh_send_unreliable_message(uint16_t server_addr, uint8_t *data, uint16_t length, uint32_t opcode) { esp_ble_mesh_msg_ctx_t ctx = {0}; esp_err_t err; // 设置消息上下文 ctx.net_idx = gStore.net_idx; ctx.app_idx = gStore.app_idx; ctx.addr = server_addr; ctx.send_ttl = MSG_SEND_TTL; ctx.send_rel = false; // 不要求可靠传输 if (opcode == 0) { opcode = ESP_BLE_MESH_VND_MODEL_OP_SEND; } ESP_LOGI(BLE_MESH, "Sending unreliable message to 0x%04x", server_addr); // 发送无应答的消息(need_rsp = false) err = esp_ble_mesh_client_model_send_msg(vendor_client.model, &ctx, opcode, length, data, 0, // 超时时间设为0 false, // need_rsp = false 不要求应答 MSG_ROLE); if (err != ESP_OK) { ESP_LOGE(BLE_MESH, "Failed to send unreliable message: %s", esp_err_to_name(err)); } else { ESP_LOGD(BLE_MESH, "Unreliable message sent successfully"); } return err; } ``` 2.2 服务器模型发送消息(总是无应答) ```c /** * @brief 服务器模型发送消息(总是无应答) * * 服务器模型发送的消息总是无应答的,适用于状态通知等场景 * * @param model 服务器模型指针 * @param ctx 消息上下文 * @param opcode 操作码 * @param data 发送数据 * @param length 数据长度 * @return esp_err_t 发送结果 */ esp_err_t example_ble_mesh_server_send_message(esp_ble_mesh_model_t *model, esp_ble_mesh_msg_ctx_t *ctx, uint32_t opcode, uint8_t *data, uint16_t length) { esp_err_t err; if (model == NULL || ctx == NULL || data == NULL || length == 0) { return ESP_ERR_INVALID_ARG; } ESP_LOGI(BLE_MESH, "Server sending message to 0x%04x", ctx->addr); // 服务器模型发送消息(总是无应答) err = esp_ble_mesh_server_model_send_msg(model, ctx, opcode, length, data); if (err != ESP_OK) { ESP_LOGE(BLE_MESH, "Server failed to send message: %s", esp_err_to_name(err)); } else { ESP_LOGD(BLE_MESH, "Server message sent successfully"); } return err; } ``` 1. 完整的使用示例 ```c // 初始化Mesh回调 esp_ble_mesh_register_prov_callback(mesh_event_cb); // 发送有应答的可靠消息(不丢包) uint8_t important_data[] = {0x01, 0x02, 0x03}; esp_err_t err = example_ble_mesh_send_reliable_message(0x1001, important_data, sizeof(important_data), 0, 5000); if (err == ESP_OK) { ESP_LOGI(BLE_MESH, "Reliable message sent, waiting for response..."); } // 发送无应答的快速消息 uint8_t status_data[] = {0xAA, 0xBB}; err = example_ble_mesh_send_unreliable_message(0x1002, status_data, sizeof(status_data), 0); if (err == ESP_OK) { ESP_LOGI(BLE_MESH, "Unreliable message sent successfully"); } // 服务器发送状态通知 esp_ble_mesh_msg_ctx_t ctx = { .net_idx = gStore.net_idx, .app_idx = gStore.app_idx, .addr = 0xFFFF, // 广播地址 .send_ttl = 3, .send_rel = false }; uint8_t notification_data[] = {0x55, 0x66}; err = example_ble_mesh_server_send_message(vendor_server_model, &ctx, 0x2001, notification_data, sizeof(notification_data)); ``` 1. 选择策略建议 2. 使用有应答消息的场景: · 关键控制指令(开关、调节等) · 需要确认执行结果的操作 · 数据传输完整性要求高的场景 3. 使用无应答消息的场景: · 状态通知和心跳包 · 实时传感器数据(可以容忍偶尔丢失) · 广播消息和多播消息 · 对延迟敏感的应用 4. 超时时间设置建议: · 局域网内:2-5秒 · 多跳网络:5-10秒 · 高延迟网络:10-30秒 这样的实现可以确保在需要可靠性的场景下不丢包,同时在追求效率的场景下快速发送消息。 能够解决节点“ignoring old seqauth" 指南中api貌似不支持序列号持久化管理
最新发布
09-02
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值