本系列故事的所有案例和解决方案只是笔者以前在互联网工作期间的一些事例,仅供大家参考,实际操作应该根据业务和项目情况设计,欢迎大家留言提出宝贵的意见
小王和小明分别维护分布式系统中a、b两个服务,有一个场景是 a服务会向b服务通过mq发送事件并且推送用户信息,然后b服务保存用户信息。
有一天,小王和小明因为一件事讨论得热火朝天、互不相让,事情由来如下:
这时候,在一旁扫地的清洁工老梁过来调解,并帮忙排查分析,导致这个问题的主要原因如下:
伪代码如下:
@rabbithandler public void handle(byte[] message) { try { t = parsebody(messagestr); } catch (exception e) { log.error("消费消息失败", e.getcause()); } } private void handlemessage(t t) throws mqhandleexception { //唯一标识 string key = t.getlockedid(); //获取锁 distributedlock lock = distributedlockfactory.getlock(key); try { // 解决分布式服务提交相同资料并发问题 lock.lock(cacheconstants.lock_wait_time, cacheconstants.lock_lease_time, cacheconstants.default_cache_unit); // 处理业务逻辑 handlebusinesslogic(t); } catch (lockexception e) { throw new mqhandleexception(e); } finally { // 释放锁 lock.unlock(); } }
频繁redis超时是因为a、b服务共用一个redis,a服务key太多把redis内存资源占满了(也可能连接占满),导致了b服务经常出现连接超时(该故障不是本章主要关注目标)
b服务在已经成功接受到消息后,没有把消息先保存起来,所以也导致了自身并没有能力重跑
清洁工老梁跟小王和小明进行一番详谈后,了解到他们主要需求有两个:
经过上面的分析,老梁的解题思路主要分为两个方向:
一般来说,常见的微服务架构实现最终一致性有三种模式:可靠事件模式、业务补偿模式、tcc模式。这里ab服务是通过业务补偿模式实现最终一致性,但这里又跟我们一般的分布式架构的事务问题不同,这里我们只需要保证b服务能最终把正常消息事件消费成功即可。
实现思路:
针对于b服务,对于收到的mq信息没有进行有效的记录,而且mq信息处理之后,存在修改错误,没法进行对应信息补充修复的功能,增加通用消息处理层,进行消息体的记录和回溯。 在获取消息之后进行一次记录,进行幂等操作和对应的状态更新, 消息状态在业务相关操作完成后,标记为处理完成,认为对应消息状态结束。
这里hash_value是对请求体进行hash计算得出来的一个值,例如:md5、sha-2,保证每个不同请求的hash码不一样,相同的请求hash码相同,可以用于幂等控制。
表大致操作流程:
异常消息有4个状态
待处理
处理中
处理完成
异常
,等待后期人工重跑失败事件队列在这里是采用数据库表代替
因为并非所有的异常都能重跑就能解决问题,我们只能针对可以修复的异常进行重试,这里把异常分为两大类:
最后小明负责的b服务按照老梁的思路,重新调整了代码,异常处理流程如下:
如对本文有疑问, 点击进行留言回复!!
Java面向对象中:方法重载和方法重写以及区别、 this关键字和super关键字以及区别
【开源】使用Angular9和TypeScript开发RPG游戏(补充了Buffer技能)
网友评论