架构及代码问题思考
1. 对于需求设计的一点思考---最好维护的代码是没有写出来的代码
程序员Q:这个需求这样做很麻烦
项目经理A: 这块可以先不用考虑,这样就简单很多
上边开发过程中可能碰到的场景,最近看到的一句话:
最好维护的代码是没有写出来的代码
很符合这种场景。在扮演不同角色时,我们思考模式也是不同的。有时候站在产品经理或者项目经理的角度想一下需求,让需求稍微妥协一下,代码就会简单很多。
以下是碰到是两个场景
- 关于撤单交易的处理
在针对理财产品的特殊场景,合作方平台用用户的赎回款申购理财产品。在申购交易做撤单时,正常我方会给客户退申购款;但另外一个系统如果未收到我方申购交易,认为申购未成功,也会给用户退赎回款。这样当日撤单可能给客户退款两次从而造成我方短款。
我了解到这个情况时,开发同事正在考虑区分当日撤单和隔日撤单,当日撤单由对方退款。当日还在讨论方案。且预估改造量非常大,开发时间可能要三天。
但是有一种更简单的方案,就是对方不要退款,统一由我方退款。基本无需改造只要我们改下配置,文件中把当日撤单当成功给到对方就可以。但据说是因为一个报反洗钱的要求。随后我拉他们和产品经理和项目经理又讨论了一下,发现这个需求并不重要。对这个设计的推动我感到很有成就了,印证了这句话---最好维护的代码是没有写出来的代码。 - 关于持仓对账不平的问题
对于理财产品,每个交易日我方都要和理财公司做份额对账。部分产品我们目前做实时确认,对于新用户如果交易申请未到下游,则对账会有我方多下游无的差异。当时开发的解决策略是持仓对账时远程调用订单服务,用了一个复杂的sql去查询那些之前没做过交易的新客户,排除这些记录后再对账。这个改造上线后,就经常由于远程服务超时导致批量执行失败。
经过讨论:
1.首先这些差异,可以明显看到差异结果是我方多但金额都是零,对业务无影响。在对账结束只有对这些差异过滤后计算真正的差异即可;2.并且新客户并不会每天有,且记录不是很多,显示差异对业务也无影响;3.最后原先设计也违反了我们的一个服务自治原则,基础服务尽量不要互相调用,这种写法甚至可能会由于慢sql问题导致订单服务出现问题。
最后我们只是对这样的特殊差异简单做了金额是0的判断,报警短信标明,减少了很多代码。
2. 服务划分---架构划分的原则:合适、简单、演化
>问题Q: 目前微服务拆分了有6个,是不是太细了
我目前的答案A:拆分的不太好,之前参考的互联网的做法,单纯从技术角度目前看下来并不太合适。产品交易流水和产品持仓拆分服务引入了分布式事务问题,目前没有非常好的解决方案;对于部分场景一个文件要多个服务处理,增加了很多额外的代码量;目前业务对于性能的要求也并不是很高。
上边是目前我对于我们服务拆分运行一段时候后的思考。下边是我们和其它同业系统的简单对比(同业系统服务明细见最后):
- 目前的划分对比:
- 我方:订单中心、订单工厂服务、资产服务、额度服务、产品服务、理财开户服务、清算服务、前置服务。并独立服务独立数据库
- 同业一:
公共服务和交易服务,数据库也做了隔离。 - 同业二:
数据库未拆分,部分服务间表做了隔离;服务划分了交易服务、产品额度服务、清算服务、综合查询服务。
- 遇到的问题:
- 分布式事务:因为订单服务、资产服务、额度服务都是独立的服务,在交易时需要保证交易成功时支付服务、资产服务、额度服务都处理成功。目前采用的补偿机制,对下游交易也要求要做到幂等。
- 复杂度上升:
- 联机容易出现问题且可能要各个服务去查问题;
- 引入的rabbitMQ,但缺少维护MQ的专业人员;不用MQ处理异常交易如果扫表只是会有时效性的问题;
- 文件的处理,需更新多个服务库的表;
- 拆分了服务,但团队不够清晰,多个团队提交同一个服务的代码,导致测试时版本及生产升级时的版本维护问题
- 数据存在多个服务,设计时设计人员服务边界不清晰、不必要的远程调用(自己服务又可以获取到需要的数据)等,引起奇怪的设计、生产调用超时等问题。
以下是碰到是两个场景
- 处理收益批量时调用开户服务获取开户的账户信息
由于我方和理财子公司交易用的理财交易账户,而和上游合作方(我方产品输出的合作渠道)用不同的账户体系交易。对于收益文件,文件里只有理财交易账户,我们需要查到对应的账户好后续输出给合作方。之前开发设计是到开户服务远程查询对应信息。这些数据,本来持仓表有记录,是可以查询本地库,没有必要发起远程调用的。 - 处理持仓对账时,调用订单服务查询交易时间,引起的超时问题
同上边---持仓对账不平问题。
3. 摘录的别人的架构设计总结以及思考
1. 架构设计的目的
架构设计的主要目的是为了解决软件复杂度带来的问题。
系统复杂度的来源:高性能、高可用、可扩展性、安全性、成本、规模。
思考:针对我们系统复杂度的来源,通过排除法,相对来说系统的复杂度来源在可扩展性,应对各种业务需求及合作方需求的可扩展性,设计的时候需要找到会不断变化的部分,设计为独立服务;
我们做的比较好的地方:例如针对不同合作方的个性化报文要求,拆分了订单中心前置服务做转换;针对不同上游的文件格式,拆分了文件前置服务做配置化的文件转换。
2. 架构划分的原则
合适优于业界领先、简单优于复杂、演化优于一步到位
合适:
1. 没那么多人,却想干那么多活,是失败的第一个主要原因
2. 没那么多积累,却想一步登天,是失败的第二个主要原因
3. 没那么卓越的业务场景,却幻想灵光一闪成为天才,是失败的第三个主要原因
简单:
1. 组件越多,就越有可能其中某个组件出现故障,从而导致系统故障
2. 某个组件改动,会影响关联的所有组件,这些被影响的组件同样会递归影响更多的组件
3. 定位一个复杂系统中的问题总是比简单系统更加困难
演化:
1. 对于建筑来说,永恒是主题;而对于软件来说,变化才是主题
2. 软件架构需要根据业务发展不断变化这个本质特点,软件架构设计其实更加类似于大自然“设计”一个生物,通过演化让生物适应环境,逐步变得更加强大
思考:针对几个原则,针对传统行业,由于没有那个多技术力量,相对保守的设计更加合适;同样,尽量不引入那么多中间件,避免引起的技术复杂度,没有足够专业的技术人员处理;初期没必要服务拆分的太细,应该在不断对接新需求时找到变化的地方进而做抽象、隔离及拆分服务。
我们做的不好的地方:引入的redis、rabbitMQ,做的不太好,对应了一句话手里有一把锤子,看什么都是钉子;
网友评论