V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
• 请不要在回答技术问题时复制粘贴 AI 生成的内容
leeqingshui
V2EX  ›  程序员

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

  •  
  •   leeqingshui · 2022-09-23 10:18:22 +08:00 · 2191 次点击
    这是一个创建于 818 天前的主题,其中的信息可能已经有所发展或是发生改变。

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

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

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

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

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

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

    27 条回复    2022-10-08 09:41:44 +08:00
    wolfie
        1
    wolfie  
       2022-09-23 10:26:48 +08:00
    对外接口补偿为什么要涉及到 class method 。

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

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

    那么为什么不直接用请求失败的 url 和内容判断?
    因为这些请求内容有可能太长,导致查数据库速度会很慢
    Gmzx
        3
    Gmzx  
       2022-09-23 10:54:21 +08:00
    Hash 的算法,目前来说本来就是抗碰撞的,你那么多参数,不太需要考虑碰撞的问题。
    wolfie
        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 大小没区别。


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

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

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

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

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

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

    就是把多接口改成了多方法的模式。
    leeqingshui
        16
    leeqingshui  
    OP
       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
        17
    zmal  
       2022-09-23 14:54:34 +08:00
    “这严格意义上来讲是错的,所以对此抱有怀疑态度(dog)”
    没什么好怀疑的,在这种场景下 hash 碰撞的概率几乎没有。如果还有疑虑,可以用两个不同的摘要算法。
    lmshl
        18
    lmshl  
       2022-09-23 15:17:01 +08:00
    我是业务消息序列化后存入数据库,要求客户回调地址幂等实现,我只需要实现增时重试

    数据库里也记录了事件生成时间,已经重试次数,另一个纤程每 5 秒扫一次表看哪些事件没投送成功,然后计算下次什么时候重试,加入到 scheduler 中等待
    msg7086
        19
    msg7086  
       2022-09-23 15:21:31 +08:00
    一个良好的 Hash 算法的碰撞可能性比你整个服务器机房起火上云的可能性都要低。
    leonshaw
        20
    leonshaw  
       2022-09-23 15:35:09 +08:00
    一定要正确性的话,hash 字段不要 unique ,遇到碰撞比原始数据去重。
    leeqingshui
        21
    leeqingshui  
    OP
       2022-09-23 15:56:36 +08:00
    @zmal 嗯嗯,好哒~
    leeqingshui
        22
    leeqingshui  
    OP
       2022-09-23 15:57:23 +08:00
    @msg7086 😂
    leeqingshui
        23
    leeqingshui  
    OP
       2022-09-23 16:04:11 +08:00
    @lmshl 嗷,会考虑一部分逻辑使用这种实现~
    securityCoding
        24
    securityCoding  
       2022-09-24 01:36:07 +08:00 via Android
    老哥你都要补偿了,还反重有啥用,业务幂等就行
    wolfie
        25
    wolfie  
       2022-09-26 10:21:28 +08:00
    @leeqingshui
    根据 method 入参找文件,在将文件转 base64 作为请求参数。
    我还是会出一个接口,作为补偿入口。因为反射不好管理。

    这个是我写的基于 http 的补偿。
    /t/882939
    leeqingshui
        26
    leeqingshui  
    OP
       2022-09-26 11:07:32 +08:00
    @wolfie 嗯呢,我看到了,我这边也写了 80%,这周有空完善下,国庆我会把代码放出来,B 站再录个视频说明下~
    leeqingshui
        27
    leeqingshui  
    OP
       2022-10-08 09:41:44 +08:00
    @wolfie 这块国庆抽时间弄了下~
    视频地址:aHR0cHM6Ly9zcGFjZS5iaWxpYmlsaS5jb20vMjAzNTE2NzkzL3ZpZGVv
    代码地址:aHR0cHM6Ly9naXRodWIuY29tL0Nocmlzc3NXb25nL2ludm9rZS1jb21wZW5zYXRpb24=

    后面的优化下周会弄下~
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3179 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 00:40 · PVG 08:40 · LAX 16:40 · JFK 19:40
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.