当前位置: 首页 > 科技观察

分布式区域问题,让我们战300回合

时间:2023-03-14 16:28:21 科技观察

本文转载自微信公众号《苏三说科技》,作者苏三说科技。转载本文请联系苏三硕科技公众号。前言我最近参与了公司的一个新项目,需要将接入方的数据,如:企业、订单、合同、物流等,通过openapi接口同步到我们平台,然后我们平台提供他们有经济能力。由于我方与对方不在同一个城市,为提高工作效率,双方进行了多次在线视频交流。一开始还比较顺利。没想到在与企业信息上传接口通信时,接口文档中出现了一个非常不起眼的企业注册地址id字段,让我们一下子进入了僵局。这是怎么回事?1.地区问题在我们平台的企业表中,有一个企业注册id字段,这个字段是必填的。用户需要在企业注册页面选择一个区域作为企业的注册所在地。上面的数据库保存了地区的id。如果企业注册成功,地区名称将显示在企业详情页面上。当然我们系统的后台逻辑是先通过regionid到region表中找出region名称,然后显示在用户界面上。为了和企业表保持一致,我们在定义接口文档的时候,把企业注册的id字段也做成了必填项。当时的情况是这样的:我们的地区表有id、地区名称、国标代码、等级等字段,但是这里的id是我们数据库的主键,在对接方系统中肯定是不存在的。伙伴系统也有一套地区表,不过id是他们的数据库id,他们的表也有地区名、国标代码、等级等字段。所以他们需要在系统内部经过一些转换,才能把我们需要的regionid传递给我们。1.1持久化本地表其实我是中途加入这个项目的。我之前在处理其他事情。我加入的时候,接口文档已经定义好了。我方与对方第二次在线沟通时,双方一起过一遍接口文档的细节,包括:接口的作用,各个参数的含义,是否有传过来的值等,其中,在通过企业信息上传接口时,接口文档中有一个企业注册的id字段,对方无法传值。为了解决这个问题,我们第一个版本的方案是:对接方调用我们的区域查询接口,通过多次分页查询,最终可以获取到我们所有的区域数据,存储到他们本地的区域表中。他们在调用我们的企业信息上传接口之前,先查询本地的region表,转换成我们需要的regionid。在讨论中,对接方觉得自己也是平台,不应该做这些额外的事情。因此,在那次会议上,双方在这个问题上都无法说服对方,最终未能达成共识。后来想了想,确实这个方案太理想化了,没有真正站在用户的角度去思考,忽略了很多细节。可能与文档设计者对区域表不熟悉有关。1.2按名称调用区域查询接口会上,我们这边的几位同事进行了简短的讨论。由于对接方不愿意接受他们本地的区域表持久化,所以我们会退而求其次,不要求他们持久化。这时,我们的一个同事提出,改用名称调用地区查询接口,查询地区id。具体解决方案如下:这个方案表面上好像没什么问题,但是我之前负责过region相关的功能,我知道,恐怕会出现下面的情况:如果region的名字对接方上传不完整,例如:原上传成都,实际上传成都。这样我们就需要做模糊匹配来查询我们所在地区的接口。如果接口被并发调用,可能会影响接口的性能。如果输入关键字北京,可以在我们的地区表中找到两条数据,一条是省级的,一条是市级的。对应的是哪条数据?所以我当时就提出了这两个问题,不建议使用地域名查询。1.3听同事按照国标代码调用地域查询接口后,也觉得用地域名查询有点不靠谱。他立即修改了方案,改为使用所在地区的国标码查询地区id。具体方案如下:由于当时讨论的时间很短,没有时间想太多,所以暂时打算采用这个方案。1.4过了一会儿,企业上传接口进入参数传递国标码,双方继续通过接口文档重新讨论企业信息中企业注册id字段值传递问题上传界面。在调整企业信息上传接口之前,他们首先调整了我们的地区查询接口,找出地区id,输入参数是国标代码。然后在企业信息上传接口中传入地域id。对方仔细听了我们的方案,犹豫了一下。他们觉得没必要再对地域查询界面进行调整。双方用国标码不就行了吗?他们的想法是:在企业信息上传界面中,将企业注册的locationid改为企业注册地的国家标准代码。由于国标代码是国家唯一统一的代码,双方必须相同,这样才能保证数据的一致性。2.我想到了一个问题。说实话,如果没有接触过区域功能,可能大部分人都认同这个方案。不过比较巧合的是,之前正好接触过类似的功能。当时突然想到一个问题:如何保证双方数据的一致性?我们都知道,由于国家的发展,有些城市可能会更名,例如:襄樊改名另外,有时多个地级市合并为一个城市,所以国标代码也会发生变化,所以国家统计网每年都会对地区名称和国家标准代码进行调整。我们的region表是两年前创建的,从数据初始化开始就更新过。对接方不会和我们同时初始化数据,他们会定时更新区域数据,导致双方数据不一致。如果在对接方的业务表单中使用了新添加的城市名称和国家标准代码,但是这些信息不在我们的地区表中,我们无法查询到我们需要的地区ID。遇到这种情况怎么办?2.1双方同时更新region表显然上面的问题是一个难度很大的问题。这时候可能有朋友会说:双方同时使用job更新region表,问题不就解决了吗?我不赞成这个解决方案。主要原因如下:我们只和这个对接方有一个同步的job,没问题。但如果有其他对接方,也需要调用企业信息上传接口。是不是一定要完成一个工作,要求大家同时执行,耦合度太高。如果我方和对接方同时执行作业,但是任何一方执行失败,也会造成数据不一致。如果此时对接方调用的是企业信息上传接口,会不会有问题?2.2以一方地区数据为准?上面这种双方同时更新region表的方案确实有点不靠谱,但是有读者可能会问,基于一方的region数据,另一方同步数据还不够吗?具体方案如下:这个方案其实和我们之前给的第一个方案很像,已经被对方否决了。在他们看来,确实没有必要因为上传企业信息而保存我们的区域数据。说实话,即使他们同意了,这种跨公司、跨系统的数据一致性问题也不好保证,因为如果对接方没有调用我们的区域接口,这时候恰好是上传企业信息,有问题吗??3。其他解决方案其实为了解决问题,我们也穿插讨论了这些解决方案。3.1将上传的数据保存为快照我当时提出,既然是保存对接方的数据,为什么不保存快照呢?我们可以将数据写入mongodb,数据格式为json,简单高效。我的方案是:我们自己的业务数据存放在mysql业务表中,而对接方的数据存在mongodb中,互不干扰。好像没什么问题。但是产品当时说:银行规定在审核数据的时候只看我们的mysql业务表,其他数据源不看。好吧,我不得不承认银行负担不起。3.2手动更新数据另一个同事的想法是让他们先调用企业信息上传接口,如果地区有问题,我们再给他们手动调整地区表中的数据。具体方案如下:调用企业信息上传接口时,如果地区不存在,则向指定人员发送告警邮件。然后,指定人员手动添加或修改相关区域数据。这个方案看似没问题,但是有一个棘手的地方。怕下班或者周末有问题。无论如何,我都不愿意这样做。你想要_____吗?3.3提供更新接口。另外,我们也涉及到这套方案:对接方在调整我们的企业信息上传接口之前,先调整我们的区域查询接口,检查数据是否存在。如果不存在,则保存区域界面(保存包括:添加和修改),如果存在,则正常上传数据。具体方案如下:这个方案还可以简化:查询和保存区域的逻辑可以放在企业信息上传界面,这样对接方一定很开心,对他们来说是透明的,区域问题不存在。但是,产品认为该区域是我们的基础数据。为了安全起见,我们不能提供入口让他们修改,否则以后可能会乱七八糟。这个不行,那个也不行。我们一下子陷入了进退两难的境地,但是为了不影响整体进度,只能先把问题记录下来,然后跳过这个问题继续讨论其他领域。4.如何解决这个问题?那天晚上想了很久,第二天早上发现和我们老板的想法不谋而合。结论是,既然有差异化,就没有办法避免,必须从制度设计上接受差异化。在企业信息上传界面增加两个字段:企业注册地国家标准代码和地区名称,对接方将其更改为传入这两个字段。具体方案如下:在我们的enterprise表中增加regionname字段,是否必填,将之前的regionid字段改为optional。对接方在调用我们的企业信息上传接口时,还会传入所在地区的国家标准代码和地区名称。在我们的企业信息上传界面判断,如果能通过国标码查到regionid,则将regionid写入db,如果不能,则将regionname写入db。我们评估了影响范围。enterprise表中的region字段只是为了显示,没有修改条目,所以上面的方案是可行的。后来在网上再次和对方沟通的时候,把我们的方案告诉了他们,他们也很认同。5小结虽然这个区域性问题在众多技术问题中并不值得一提。但仔细想想,还是有一些宝贵的经验值得总结,给有需要的朋友参考。5.1从用户的角度设计界面在设计界面文档时,要真正从用户的角度出发。特别是对于这种openapi接口,定义的参数尽量选择通用的、公认的参数,避免我们自定义的参数,比如:regionid。尽量减少用户的复杂性,让他们更容易调用接口。5.2技术方案要有包容性技术方案要有包容性,不能非黑即白,需要灵活的思维。在分布式环境中,如果一味追求数据的强一致性,是不会得到很好的结果的。就像高并发下的产品秒杀系统,如果非要用同步的方案来实现,系统最终可能会挂掉。更好的方案是改成异步队列处理。我们这边和对接方都有region表,很难保证数据完全一致。不能为了一致而一致,那样会适得其反。为了使工作顺利进行,必须有一方妥协。我的建议是在openapi接口上妥协。该技术方案具有足够的通用性。5.3没有最好的方案,只有最合适的方案。我们最后的方案并没有完全解决找不到regionid的问题,但是从业务的角度来说,即使没有regionid,有regionname也是一样的。显然,最终的解决方案非常适合我们的实际业务场景。所以没有最好的方案,只有最适合业务场景的方案。5.4进行有效的沟通与合作伙伴在线沟通时,不要因为某个问题而卡壳,保持僵持状态。如果当时没有很好的技术方案,可以选择暂时跳过这个问题,交流其他内容。之后我们会在私底下单独抽出时间,认真思考一下当时的问题,这样才能想出更合理的解决方案。5.5技术为业务服务本文这块区域乍一看比较简单。仔细想想,你会发现这里面有些东西。再加上各种外部因素的限制,你会发现在分布式环境下保证区域数据一致性并不是那么容易实现的。整个过程中,我们提出了很多技术方案,有的看似完美解决了问题,但都被我们的实际业务场景否决了。技术为企业服务。技术虽然很重要,但如果离开了业务,那就只是纸上谈兵了。