三方接口补偿方案时针对重复失败数据入库的摘要处理如何处理哈希碰撞?

2022-09-23 10:18:22 +08:00
 leeqingshui

业务系统与多个第三方系统进行对接时,需要调用外部系统接口进行数据的交换,如果在接口请求的过程中发生了网络抖动或其他问题,会导致接口调用失败; 对于此类问题,需要一个接口重新调用补偿机制,在发生网络抖动时可以进行自动或手动地补偿调用

搜寻资料时发下有人给过一个对应的方案,方案网址: https://cache.one/read/4640698

此解决方案是会对接口调用的数据进行记录,然后存到一个补偿表中,但上述方案的补偿表设计是否有问题?

其中定义了一个数据防重字段:unique_hash_code Unique_key Hash(class_name+method_name+method_param_values)

即根据方法类名加方法名及方法参数生成一个 hash 值,这个 hash 值会出现碰撞吧?

所以,针对于这个字段大佬你们是怎么设计的?增加字段再 hash 处理嘛?或者有啥其他更优的处理方案( doge )

1943 次点击
所在节点    程序员
27 条回复
wolfie
2022-09-23 10:26:48 +08:00
对外接口补偿为什么要涉及到 class method 。

这玩意重复怎么判断,相同的 url + body 不能同时重复吗。
leeqingshui
2022-09-23 10:44:44 +08:00
@wolfie 对外接口补偿为什么要涉及到 class method 。我觉得加入这个应当是为了降低生成的 hash 值碰撞可能

相同的 url + body 不能同时重复吗?
不太理解这句话的意思,现在的问题是一个三方接口多次调用出错了,需要存到补偿表,但只有第一次出错存入补偿表,第二次是不进入补偿表的,第二次是否存入补偿表需要判断这个数据是否存入补偿表了,这个需要相关字段判断

那么为什么不直接用请求失败的 url 和内容判断?
因为这些请求内容有可能太长,导致查数据库速度会很慢
Gmzx
2022-09-23 10:54:21 +08:00
Hash 的算法,目前来说本来就是抗碰撞的,你那么多参数,不太需要考虑碰撞的问题。
wolfie
2022-09-23 11:09:32 +08:00
@leeqingshui
对外接口是基于 http 吧,跟 class 、method 没关系。
即使做重复校验,也应该是用 http 相关。


> url + body 不能重复吗。
例如一个对外接口:`POST xxx.com/add-item?name=itemName`
这个接口相同参数不能多次调用吗(没有补偿参与前提下)


了解补偿时候错误不会重复记录


一个普通的 form-post 、json-post 能有多长。
补偿用的请求上下文,method-param ,跟 http-param 大小没区别。


最近正好在做这个。
写完了给你发一下。
Jooooooooo
2022-09-23 11:14:54 +08:00
你得遇上又出错需要补偿, 又 hash 碰撞的场景, 真不用考虑这个.

不放心的话后面再拼一下 url, 再花精力在几乎不可能出现的场景下就得不偿失了, 考虑一下所做方案的 roi
leeqingshui
2022-09-23 11:19:37 +08:00
@Gmzx emmm ,但碰撞可能性还是存在的,看网上很多方案都是准备用这些参数生成一个摘要值,认为这个摘要值是唯一的,B 站上有视频也是按照这种方案处理的,这严格意义上来讲是错的,所以对此抱有怀疑态度(dog)
lonenol
2022-09-23 11:21:57 +08:00
这么做的前提是对方一定是幂等的,所以并不需要去重。。
一定要去重就定义一个业务标识 + 业务唯一键,让接入的业务(或者方法接口)自己去处理。。
你做 hash 去重只有负收益(不同的请求可能被判定为重复)。。而没有正收益(节省资源??)
leeqingshui
2022-09-23 11:22:19 +08:00
@Jooooooooo 嗯嗯,好的好的,有时候想思考的全面一点,有点完美主义了......
leeqingshui
2022-09-23 11:25:07 +08:00
@wolfie 会有异步三方文件调用的接口(这边业务代码设计的不合理 doge~),文件的 Base 64 串会很长哒
dzdh
2022-09-23 11:26:04 +08:00
业务没有编号的吗

我们所有业务无论大小、场景。跨业务、服务交互都必须带请求号。根据请求号排重
leeqingshui
2022-09-23 11:30:31 +08:00
@dzdh 没有,有的话就好搞了 doge~
matzoh
2022-09-23 12:06:21 +08:00
你是怕重复补偿吗?
重要业务场景,双方都应该做幂等处理的,不重要的其实也就不重要了。

最简单的就是加个 request_id ( nonce )。如果有扩展参数的话,就加一个,没有的话看看能不能塞一个。

没有的话,把失败的放入队列里,也能避免很多因为分布式造成重复补偿的问题。
xuanbg
2022-09-23 13:32:50 +08:00
用队列去请求数据,失败后放延时队列,延时队列会在到达延时时间后自动进入任务队列。
leeqingshui
2022-09-23 14:15:56 +08:00
@matzoh 是的,双方做好幂等处理,重复补偿其实无所谓,只是数据库会存多条数据而已,问题也不大~
@xuanbg
这边应当不会使用队列,因为补偿数据部分情况会涉及到需要修改值的情况,也就是需要人工介入,所以这边补偿方案会设计考虑兼容自动处理和人工处理两种类型,其实也好处理~
xiang0818
2022-09-23 14:22:06 +08:00
上面的同学没有接触过使用同一个接口,通过不同 method 的方法区分的通用三方接口么。

这么设计的是给到外部的(一个业务方 /一个系统 /...) url ,然后通过 method 来判断具体的调用的哪个方法。

就是把多接口改成了多方法的模式。
leeqingshui
2022-09-23 14:32:41 +08:00
@xiang0818 是的,这种对接方我遇到过,对接方只提供一个 url ,内部通过请求体的某个字段去调自己内部的方法
比如说,客户只对外提供一个 url: http://v2ex.com/testService
申请接口的请求报文用:
```json
{
"request": {
"head": {
"funcode": "apply"
},
"body": {
}
}
}
```
上传文件接口的请求报文则用:
```json
{
"request": {
"head": {
"funcode": "upload"
},
"body": {
}
}
}
```
即用 funcode 进行判断自己内部调用哪个方法 doge ~
zmal
2022-09-23 14:54:34 +08:00
“这严格意义上来讲是错的,所以对此抱有怀疑态度(dog)”
没什么好怀疑的,在这种场景下 hash 碰撞的概率几乎没有。如果还有疑虑,可以用两个不同的摘要算法。
lmshl
2022-09-23 15:17:01 +08:00
我是业务消息序列化后存入数据库,要求客户回调地址幂等实现,我只需要实现增时重试

数据库里也记录了事件生成时间,已经重试次数,另一个纤程每 5 秒扫一次表看哪些事件没投送成功,然后计算下次什么时候重试,加入到 scheduler 中等待
msg7086
2022-09-23 15:21:31 +08:00
一个良好的 Hash 算法的碰撞可能性比你整个服务器机房起火上云的可能性都要低。
leonshaw
2022-09-23 15:35:09 +08:00
一定要正确性的话,hash 字段不要 unique ,遇到碰撞比原始数据去重。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/882316

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX