# 单体架构实现

一般而言产品初版为业务试错版本，要求包含核心功能、快速实现，尽早交由市场检验、收集问题待后续完善。我们也遵循这个方式，初版实现只包含贷款申请的核心流程。

## 系统架构

![单体架构组件设计](https://raw.githubusercontent.com/gudaoxuri/Microservices-Architecture/master/resources/images/cdt-monolithic-component.png)

此版本架构相当简单，使用单体架构，包含了提供贷款流程支撑的贷款管理功能、数据化风险控制的风控能力、用于第三方数据服务接入的三方服务管理以及基础的用户权限管理。

服务端与终端统一通过Rest API交互。

![单体架构部署设计](https://raw.githubusercontent.com/gudaoxuri/Microservices-Architecture/master/resources/images/cdt-monolithic-deploy.png)

由于是单体架构，部署上也很简单，启用多个功能相同的节点，使用Nginx或云厂商的SLB服务做负载均衡即可。

## 技术成果

由于使用了最简单的单体架构，又为试错版本，架构设计上只需要关注业务与代码的映射，一定灵活度的表结构设计即可，对高可用、性能、架构可扩展性等要求可暂不考虑。我们研发团队用了5个人，1个技术负责人、2个服务端开发、1个大前端、1个测试，没有运维，在1个月内完成架构、开发、测试到上线1.0-beta版本。上线之后随即投入业务试点，收到大量的反馈及业务流程优化建议，研发又用了1个月左右去适配业务的变更并完成1.0-GA版本。

## 问题初现

上述架构虽然看起来很简陋，但实用性强，对于POC或快速试错时非常有效。当然大家都明白，对于成熟的系统这样的设计必定会出问题，车贷通在市场验证时收集了很多的改进建议及使用过程中也发现了一些Bug，同时市场部也根据这一阶段的表现做了业务预期调整，总结关键变更如下（为实战需要，部分为杜撰需求）：

* 【目标】年内覆盖全国100个地市，实现60亿的贷款额（客单价10w，共6w笔合同），吸收1w名销售顾问使用车贷通APP，逐渐形成独立生态
* 【需求】贷款申请细节及风控逻辑有很多调整，并且会随着运营数据报告而不断修改，要求技术可以快速响应变更
* 【需求】同步已贷车辆的GPS信息做为贷后监控的重要指标
* 【需求】为增强销售顾问的粘性，增加社区功能，并有每天定时红包雨活动
* 【需求】将财务结算由线下手工操作改为系统内自动化处理
* 【Bug】目前接入的短信服务商及三要素验证供应商响应速度太慢且不稳定，需要更换或者优化
* 【Bug】有重复提交申请的情况发生
* ……

以上摘录的几点看似简单，但分析下后可以发现对现有系统架构都有冲击，转服务化架构虽是我们既定的方案，但在服务化版本上线前，目前的单体架构还需要迭代一段时间。

在此期间，单体架构的问题已逐渐暴露：

* 扩展性差，一个功能点的变更需要整体部署，比如前期时常优化的贷款流程，往往一个返回字段变更就需要对整个系统重新打包部署，这过程还可能会需要做回归测试，严重影响发布效率
* 无法实现复杂业务，在一个JVM容器中实现所功能，服务间高度耦合，虽然可以通过合理的命名空间划分来管理不同模块，但很难杜绝开发人员擅自调用三方模块的内部方法，比如贷款模块有一个身份证校验的功能，之后风控模块也需要这个功能，但你无法阻止风控开发人员直接调用贷款模块的身份证校验

> ❓ 笔者实践中发现随着项目版本的迭代、团队成员的变动，规范性的约束往往越来越发挥不了作用，当有“捷径”可走时总有一两个开发人员会带头无视规范，如不制止很快所有成员都会被同化，从而导致项目整体失控。

* 系统性能低下，所有功能都在同一个JVM中运行，稍有不慎就可能会因为某一个接口的问题导致系统整体不可用。比如车贷通维护了一个通用车型库，对外提供了 车辆品牌-型号-车款 的三级联动的接口，由于没有加校验，被某第三方频繁调用，导致了有段时间车贷通的贷款申请接口响应超时。再比如车贷通的敏感数据使用bcrypt加密，加密时会非常占CPU，在渠道推送用户注册时（我们有一些来自三方渠道的用户会批量注册）往往会导致其它模块响应变慢
* 技术升级困难，技术更新很快，为我们带来了更好的解决方案，开发人员也都有尝试新技术的愿望，从项目稳定性上考量肯定希望先拿部分业务试点，成熟后再推广，但单体架构牵一发而动全身，无法模块化地实现技术框架升级。笔者在电信行业从业多年，很多核心系统都是10多年前的单体架构，电信、金融等传统业务给人们技术保守的印象不是它们不知道不想改，而是真心改不动，架构的限制导致重构不如重做
* 开发效率低，这主要有三点：1）达到一定代码量后编译、部署耗时高；2）每个成员都需要有完整的环境依赖，新人上手困难；3）多版本并行开发问题频现，对Git版本管理的要求高企
* 不利于安全管理，站在开发者角度分析看得越全越有全局观就越能全面考虑手头的需求，但让所有开发人员都拥有全量代码，这对成熟项目而言可能未必是件好事

> ❓ 新项目架构是先单体再转微服务还是直接微服务？
>
> 这个问题是笔者被问得比较多的，总的来说要从团队、业务、工期等几点分析：
>
> * 团队配置中有没有了解微服务的架构师及开发人员，如果没有只能从单体或传统SOA做起，这是一刀切的条件
> * 有没有一定的服务积累（比如一些公共的登录鉴权、消息发送、服务注册、统一配置等），项目工期是否允许做服务化架构，如果工期紧手头又没有现成的服务可用，那采用微服务会比较冒进，微服务的架构设计往往会比开发更花时间与精力
> * 业务形态是否稳定，短期内是否会有大的变更，如果是的话也要慎重使用微服务，因为服务的边界与业务关系很大，业务模式的变更会严重影响服务划分
> * 当下及中长期规划的业务是否简单，如果足够简单可能一直使用单体或传统SOA就可以了

车贷通一开始的划分就是先上单体试错，如项目可行则逐步转向微服务，相信这不少研发团队的选择，但如果采用这一演进方案一定要与管理层明确：产品技术一定要重构，当前的架构看似上线很快用的人也很少，但这不足以支撑业务的发展，重构是业务上看不到效果但必须花时间精力做的。如果这点上达不成一致就会像笔者所见的一些项目一样在单体架构上修修补补并且越来越难维护，开发被业务追着走，不断地背锅，士气低下，毫无成就感，进而导致人心涣散项目崩盘。

> ❓ 架构设计绝不仅仅是只对技术与业务的考量，它更是与研发团队、管理团队紧密相关。
>
> 研发人员要懂得保护自己，架构设计时要向管理层说明利害，尤其是可能的风险及应对的措施，
>
> 管理层要理解架构设计中所反馈的风险点，了解软件研发的客观规律，明白适当的重构（笔者并不认为重构就一定是对的）是为了让产品走得很远。
>
> 好的架构设计既能满足产品的预期又可让研发人员做得开心，有成就感，同时也能很到管理层的认可。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://gudaoxuri.gitbook.io/microservices-architecture/xiang-mu-jie-shao/monolithic-architecture-version.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
