Hyperledger Composer升级后关联资产触发RESOURCE_EXHAUSTED错误求助
错误原因分析
首先,这个RESOURCE_EXHAUSTED: received trailing metadata size exceeds limit错误本质是gRPC层面的限制被触发——事务处理后返回的资产序列化数据体积超过了gRPC的默认大小上限。而在你升级到v0.19.4后的场景里,核心诱因是双向关联资产的循环序列化问题。
看你的资产模型:Order和PackCase是双向关联的,Order持有PackCase的引用,PackCase又包含Order数组。v0.18.1版本的Composer对双向关联的序列化逻辑比较宽松,不会递归序列化整个关联链;但v0.19.x调整了序列化机制,当你更新这两个资产并返回数据时,会递归序列化所有关联对象——也就是说,序列化PackCase时会包含每个Order的完整信息,而每个Order又会引用回PackCase,形成循环嵌套,数据量会随着你添加的订单数量急剧膨胀,连续两次调用后就直接撞破了gRPC的元数据大小限制。
另外,你的事务处理器逻辑也放大了这个问题:每次调用都会同时更新Order和PackCase,并且把新的Order插入PackCase.orders数组,导致PackCase的序列化数据越来越大。
解决方案
针对这个问题,我推荐按优先级尝试以下方法:
1. 给双向关联字段添加序列化注解(最有效)
在你的CTO模型文件中,对双向关联的字段添加@serialized(false)注解,告诉Composer序列化时只保留关联ID,而不递归序列化关联对象的完整数据。修改后的模型如下:
asset Order identified by pullID { o String pullID --> PackCase caseNumber optional @serialized(false) } asset PackCase identified by caseNumber{ o String caseNumber --> Order[] orders optional @serialized(false) }
修改后重新生成业务网络档案(.bna)并部署,这样序列化后的资产数据体积会大幅降低,直接避免触发gRPC的大小限制。
2. 优化事务处理器逻辑
其实你不需要同时更新两个资产的关联关系——Composer的双向关联需要手动维护,但可以调整逻辑减少不必要的全量更新:
- 比如只更新
Order.caseNumber的引用,后续查询PackCase的订单时,通过关联查询(比如自定义selectOrdersByPackCase查询)来获取,而不是每次都修改PackCase.orders数组。 - 另外,把嵌套的Promise改成
async/await语法,既提升可读性,也能避免潜在的回调嵌套问题,示例如下:
async function AssociatePackCaseToOrder(tx) { tx.order.caseNumber = tx.packCase; // 如果不需要实时更新PackCase的orders数组,可以注释掉下面这行 // tx.packCase.orders.push(tx.order); const ordersRegistry = await getAssetRegistry(namespaceAsset+'.Order'); await ordersRegistry.update(tx.order); console.info("Order Updated"); // 如果不需要更新PackCase,这部分也可以省略 const packCaseRegistry = await getAssetRegistry(namespaceAsset+'.PackCase'); await packCaseRegistry.update(tx.packCase); console.info("PackCase Updated"); }
3. 调整gRPC的消息大小限制(治标不治本)
如果前两种方法无法解决,可以尝试增大gRPC的消息大小限制。找到composer-connector-hlfv1的配置文件(通常在node_modules/composer-connector-hlfv1/lib/hlfconnection.js),修改grpc.max_receive_message_length和grpc.max_send_message_length参数,比如设置为64MB(67108864):
// 在创建gRPC客户端的位置添加配置 const client = new grpc.Client(peerUrl, credentials, { 'grpc.max_receive_message_length': 67108864, 'grpc.max_send_message_length': 67108864 });
不过这种方法只是临时绕过限制,随着关联数据增多还是会出问题,所以优先推荐前两种方案。
内容的提问来源于stack exchange,提问作者MrL

