暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

系统就是被这样的架构设计一步步毁掉的……

202


架构决策可以成就或毁掉一个软件系统。


我逐渐意识到,做出正确决策不仅需要技术能力,还需要权衡利弊、考虑长期影响,并与团队有效协作。


本文将分享我的软件架构设计方法,以及如何应对艰难的决策场景。




几乎没有完美的答案——只有最适合当前场景的解决方案。




架构始于清晰性


在开始画架构图之前,我强迫自己要彻底理解问题。


清晰定义问题是做出优秀架构决策的前提。


以下是我的方法论:


1、反复追问“为什么?”


当有人说“我们需要微服务”时,我不会直接同意。而是反复追问原因,直到理解真实需求——可能是扩展性、团队分工或快速迭代。


2、明确约束条件


性能、扩展性、团队技能、预算等因素会直接影响架构形态。


3、与利益相关者沟通


包括产品、业务和运维团队。他们可能提出隐藏需求,例如合规要求、成本限制或现有痛点。


4、聚焦核心用例


初期不纠结边缘场景,专注系统必须完美实现的核心功能。试图满足所有需求的架构往往一事无成。


5、用一页纸写清楚


这并非陈词滥调!若无法用一页纸清晰描述问题和约束,说明理解尚不充分。纸上模糊的架构,落地后必然混乱。


一、平衡简单性与灵活性


场景:团队正在开发电商平台。支付成功后需立即通知订单系统和库存系统。


矛盾点:系统需支持秒杀活动的高并发流量,同时保证可靠性。


可选方案:


1、使用REST API同步调用,确保即时响应但增加耦合性。

2、采用事件驱动架构(如Kafka),提升扩展性但引入复杂度。


你会如何选择?


我的决策思路:


当事件简单时,REST API会简单直观,但在高并发场景下可能成为瓶颈。


使用REST API,PaymentService首先调用OrderFulfillmentService,然后调用InventoryService,类似这样:

    POST /confirm-payment
    → call OrderFulfillmentService.confirmOrder(orderId)
    → call InventoryService.deductStock(orderId)
    → return response to client



    REST方案会产生的问题:


    • 任一服务响应延迟会阻塞整个流程

    • 服务宕机导致支付确认完全失败

    • 需处理分布式事务和重试机制


    由此看来,事件驱动架构的优势更显著:


    • 松耦合:支付服务无需感知下游服务

    • 独立扩展:库存服务过载时可单独扩容(例如库存压力大时单独扩展消费者组)

    • 故障隔离:订单服务宕机不影响支付主流程

    • 扩展性:新增功能只需订阅事件,无需修改现有代码


    尽管需处理消息队列监控、重试和去重等问题,但扩展性和可靠性收益远超成本。


    二、自研 vs 采购


    场景: 开发企业级移动应用,需支持MFA、生物识别登录和SSO,同时满足GDPR/HIPAA合规。


    可选方案:


    1、自研认证服务以实现完全控制。

    2、使用Auth0或AWS Cognito等第三方服务快速上线。


    我的决策思路:


    安全功能实现难度高且容错空间小。在此场景下,选择第三方服务更合理:


      • 第三方服务已通过实战检验,内置合规支持并持续更新

      • 自研需投入大量时间成本,并需安全专家、审计和长期维护,分散团队对核心业务的专注力

      • 虽然可能产生额外费用,但自研的隐性成本(如安全漏洞风险)更高


      三、单体 vs 微服务


      场景: 初创公司开发SaaS平台,需快速迭代验证产品市场匹配度(PMF)。


      备选方案:


      1、采用模块化单体架构,后期逐步拆分。

      2、直接采用微服务架构,早期引入复杂度。


      你的决策是哪一个?



      我的决策思路:


      微服务虽酷炫,但初期更适合模块化单体:


        • 初期产品未验证市场时,单体架构便于快速开发和调试,部署维护更简单

        • 明确产品方向后,再逐步拆分出微服务(如 Instagram、Facebook 均采用此路径)

        • 过早使用微服务会引入分布式事务、服务间通信等复杂度,拖慢早期进度


        四、SQL vs NoSQL


        场景: 开发支持动态字段的CRM系统,需平衡灵活性与扩展性。


        备选方案:


        1、使用PostgreSQL的JSON字段支持动态数据。

        2、采用MongoDB等NoSQL数据库原生支持动态模式。



        我的决策思路:


        默认选择关系型数据库(ACID事务和复杂查询优势),但若自定义字段变化频繁,NoSQL 更合适:


          • NoSQL 天然支持动态模式,写入和读取更高效

          • 扩展性更强(尤其水平扩展场景)

          • 若需复杂报表,可结合 SQL 与 NoSQL 混合使用


          五、缓存策略:实时 vs 预计算


          场景: 视频推荐系统面临高并发查询压力,需快速优化性能。


          备选方案:


          1、引入Redis缓存加速重复查询。

          2、异步预计算推荐结果并存储至读优化数据库。


          我的决策思路:



          优先选择Redis缓存:


            • 快速见效:缓存可将查询耗时从 2 秒降至 100 毫秒以内

            • 改动风险低,现有架构影响小

            • 预计算虽更快(<10ms),但需额外存储和计算资源,适合长期稳定负载

            • 紧急情况下,先通过缓存缓解问题,后续再优化为预计算方案


            六、改造遗留系统


            场景: 维护20年老旧单体系统,技术债务高且迭代困难。



            备选方案:


            1、推倒重来,从零构建新系统。

            2、渐进式重构,逐步现代化。


            我的决策思路:


            完全重写风险极高:


            • 周期长,可能中途失去业务支持

            • 新系统可能引入未知缺陷


            渐进式重构更可控:


              • 包装遗留组件:通过接口隔离旧代码,逐步替换内部实现。

              • 逐步抽取服务:从低风险高价值模块开始拆分。

              • 强化测试与 CI/CD:确保重构不影响现有功能。

              • 迭代优化架构:分阶段改进,而非一次性“完美解决”。


              最佳实践总结


              1、以史为鉴:复盘历史项目,分析成功与失败模式。


              2、警惕技术炒作:不盲目跟风,只选适合当前需求的工具。


              3、为变化而设计:通过模块化和松耦合支持架构演进。


              4、小步验证:通过原型验证性能、扩展性等假设。


              5、评估可逆性:优先选择易于回退的决策。


              6、允许纠错:建立持续改进的团队文化。


              7、平衡短期与长期:避免为快速交付牺牲未来可维护性。


              8、消除技术偏见:基于需求而非个人喜好选择工具。


              优秀架构并非一蹴而就,而是通过持续学习、灵活调整和理性决策逐步打磨而成。


              你在架构决策中遇到过哪些挑战?欢迎留言分享!



              作者丨Vinod Pal     编译丨Rio
              来源丨网址:https://medium.com/@vndpal/how-i-make-better-architectural-decisions-as-a-senior-developer-09ab94e0715f
              dbaplus社群欢迎广大技术人员投稿,投稿邮箱:editor@dbaplus.cn

              文章转载自杨建荣的学习笔记,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

              评论