业务系统与多个第三方系统进行对接时,需要调用外部系统接口进行数据的交换,如果在接口请求的过程中发生了网络抖动或其他问题,会导致接口调用失败; 对于此类问题,需要一个接口重新调用补偿机制,在发生网络抖动时可以进行自动或手动地补偿调用
搜寻资料时发下有人给过一个对应的方案,方案网址: https://cache.one/read/4640698
此解决方案是会对接口调用的数据进行记录,然后存到一个补偿表中,但上述方案的补偿表设计是否有问题?
其中定义了一个数据防重字段:unique_hash_code Unique_key Hash(class_name+method_name+method_param_values)
即根据方法类名加方法名及方法参数生成一个 hash 值,这个 hash 值会出现碰撞吧?
所以,针对于这个字段大佬你们是怎么设计的?增加字段再 hash 处理嘛?或者有啥其他更优的处理方案( doge )
1
wolfie 2022-09-23 10:26:48 +08:00
对外接口补偿为什么要涉及到 class method 。
这玩意重复怎么判断,相同的 url + body 不能同时重复吗。 |
2
leeqingshui OP @wolfie 对外接口补偿为什么要涉及到 class method 。我觉得加入这个应当是为了降低生成的 hash 值碰撞可能
相同的 url + body 不能同时重复吗? 不太理解这句话的意思,现在的问题是一个三方接口多次调用出错了,需要存到补偿表,但只有第一次出错存入补偿表,第二次是不进入补偿表的,第二次是否存入补偿表需要判断这个数据是否存入补偿表了,这个需要相关字段判断 那么为什么不直接用请求失败的 url 和内容判断? 因为这些请求内容有可能太长,导致查数据库速度会很慢 |
3
Gmzx 2022-09-23 10:54:21 +08:00
Hash 的算法,目前来说本来就是抗碰撞的,你那么多参数,不太需要考虑碰撞的问题。
|
4
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 大小没区别。 最近正好在做这个。 写完了给你发一下。 |
5
Jooooooooo 2022-09-23 11:14:54 +08:00
你得遇上又出错需要补偿, 又 hash 碰撞的场景, 真不用考虑这个.
不放心的话后面再拼一下 url, 再花精力在几乎不可能出现的场景下就得不偿失了, 考虑一下所做方案的 roi |
6
leeqingshui OP @Gmzx emmm ,但碰撞可能性还是存在的,看网上很多方案都是准备用这些参数生成一个摘要值,认为这个摘要值是唯一的,B 站上有视频也是按照这种方案处理的,这严格意义上来讲是错的,所以对此抱有怀疑态度(dog)
|
7
lonenol 2022-09-23 11:21:57 +08:00
这么做的前提是对方一定是幂等的,所以并不需要去重。。
一定要去重就定义一个业务标识 + 业务唯一键,让接入的业务(或者方法接口)自己去处理。。 你做 hash 去重只有负收益(不同的请求可能被判定为重复)。。而没有正收益(节省资源??) |
8
leeqingshui OP @Jooooooooo 嗯嗯,好的好的,有时候想思考的全面一点,有点完美主义了......
|
9
leeqingshui OP @wolfie 会有异步三方文件调用的接口(这边业务代码设计的不合理 doge~),文件的 Base 64 串会很长哒
|
10
dzdh 2022-09-23 11:26:04 +08:00
业务没有编号的吗
我们所有业务无论大小、场景。跨业务、服务交互都必须带请求号。根据请求号排重 |
11
leeqingshui OP @dzdh 没有,有的话就好搞了 doge~
|
12
matzoh 2022-09-23 12:06:21 +08:00
你是怕重复补偿吗?
重要业务场景,双方都应该做幂等处理的,不重要的其实也就不重要了。 最简单的就是加个 request_id ( nonce )。如果有扩展参数的话,就加一个,没有的话看看能不能塞一个。 没有的话,把失败的放入队列里,也能避免很多因为分布式造成重复补偿的问题。 |
13
xuanbg 2022-09-23 13:32:50 +08:00
用队列去请求数据,失败后放延时队列,延时队列会在到达延时时间后自动进入任务队列。
|
14
leeqingshui OP |
15
xiang0818 2022-09-23 14:22:06 +08:00
上面的同学没有接触过使用同一个接口,通过不同 method 的方法区分的通用三方接口么。
这么设计的是给到外部的(一个业务方 /一个系统 /...) url ,然后通过 method 来判断具体的调用的哪个方法。 就是把多接口改成了多方法的模式。 |
16
leeqingshui OP @xiang0818 是的,这种对接方我遇到过,对接方只提供一个 url ,内部通过请求体的某个字段去调自己内部的方法
比如说,客户只对外提供一个 url: http://v2ex.com/testService 申请接口的请求报文用: ```json { "request": { "head": { "funcode": "apply" }, "body": { } } } ``` 上传文件接口的请求报文则用: ```json { "request": { "head": { "funcode": "upload" }, "body": { } } } ``` 即用 funcode 进行判断自己内部调用哪个方法 doge ~ |
17
zmal 2022-09-23 14:54:34 +08:00
“这严格意义上来讲是错的,所以对此抱有怀疑态度(dog)”
没什么好怀疑的,在这种场景下 hash 碰撞的概率几乎没有。如果还有疑虑,可以用两个不同的摘要算法。 |
18
lmshl 2022-09-23 15:17:01 +08:00
我是业务消息序列化后存入数据库,要求客户回调地址幂等实现,我只需要实现增时重试
数据库里也记录了事件生成时间,已经重试次数,另一个纤程每 5 秒扫一次表看哪些事件没投送成功,然后计算下次什么时候重试,加入到 scheduler 中等待 |
19
msg7086 2022-09-23 15:21:31 +08:00
一个良好的 Hash 算法的碰撞可能性比你整个服务器机房起火上云的可能性都要低。
|
20
leonshaw 2022-09-23 15:35:09 +08:00
一定要正确性的话,hash 字段不要 unique ,遇到碰撞比原始数据去重。
|
21
leeqingshui OP @zmal 嗯嗯,好哒~
|
22
leeqingshui OP @msg7086 😂
|
23
leeqingshui OP @lmshl 嗷,会考虑一部分逻辑使用这种实现~
|
24
securityCoding 2022-09-24 01:36:07 +08:00 via Android
老哥你都要补偿了,还反重有啥用,业务幂等就行
|
25
wolfie 2022-09-26 10:21:28 +08:00
@leeqingshui
根据 method 入参找文件,在将文件转 base64 作为请求参数。 我还是会出一个接口,作为补偿入口。因为反射不好管理。 这个是我写的基于 http 的补偿。 /t/882939 |
26
leeqingshui OP @wolfie 嗯呢,我看到了,我这边也写了 80%,这周有空完善下,国庆我会把代码放出来,B 站再录个视频说明下~
|
27
leeqingshui OP @wolfie 这块国庆抽时间弄了下~
视频地址:aHR0cHM6Ly9zcGFjZS5iaWxpYmlsaS5jb20vMjAzNTE2NzkzL3ZpZGVv 代码地址:aHR0cHM6Ly9naXRodWIuY29tL0Nocmlzc3NXb25nL2ludm9rZS1jb21wZW5zYXRpb24= 后面的优化下周会弄下~ |