#7 转载:康威定律

2024-03-04

几乎所有我喜欢的软件架构师,都认同康威定律(Conway Law),认为这个定律非常重要,足以影响到所有系统。而且,你没法与之抗争,想要抗拒康威定律注定要失败。

康威定律的最好表述是:“任何系统的构成,都反映了设计这个系统的组织结构。”

它的出处是 Melvin Conway 在 1968 年写的一篇文章。后来,弗雷德·布鲁克斯(Fred Brooks)在著名的《人月神话》(The Mythical Man-Month)引用了这条定律。

Melvin Conway 观察到,软件系统的架构看起来与构建它的开发团队的组织结构非常相似。

最初的描述是,如果一个团队编写一个编译器,那么它将是一个单通道编译器;但是,如果两个团队共同开发,那么它将是一个双通道编译器。这个描述后来被发现,广泛适用于大量系统。

正如我的同事 Chris Ford 对我说的:“软件耦合是由人类交流促成的。” 如果我可以轻松与代码作者交谈,那么我就更容易对代码有更深入的了解,因此我的代码更容易耦合到该代码。

应对康威定律的第一步是不要与之抗争。我仍然记得一位技术主管,他刚刚被任命为 ​​ 一个大型新项目的架构师,该项目由分布在世界各地不同城市的六个团队组成。“我做出了第一个架构决定”,他告诉我:“就是这个系统将有六个主要的子系统。我不知道它们会是什么子系统,但肯定会有六个。”

为了适应康威定律,现在有一种策略,就是一旦定下软件架构,就相应改变组织结构,让紧密耦合模块的开发者更容易沟通。

#6 异常流量监控

2023-12-09

突然来了大量客户请求,我们无法判断这些请求是正常的,还是客户被攻击所致。为了避免产生严重客损,我们需要识别到这些突然出现的流量高峰,并进行通知以及执行一些处理措施。

客户配置

比如:

request_limit = {
  rate: {
    // 客户配置
    3600: 1000, // 指定 API 1 小时之内的请求量上限
    86400: 8000, // 指定 API 1 天之内的请求量上限
  },
  rate_computed: {
    // 根据之前的请求情况,结合客户配置计算出来的值(不小于客户配置)
    3600: 1000,
    86400: 8000,
  },
  strategy: {
    times_to_notify: 1, // 连续触发几次之后通知
    times_to_suspend: 3, // 连续触发几次之后暂停
    times_to_intercept: 12, // 连续触发几次之后拦截请求
  },
};
  1. 默认给所有客户开启最近 1 小时和最近 24 小时的限制。
  2. 速率控制以小时为单位([1, 24]

定时检查

  1. 定时执行
 5 10 15 20 25 30
35 40 45 50 55  0
  1. 查询过去 1 天有请求的客户清单,根据系统参数(可能还有业务上其他条件)跳过忽略检查客户

  2. 逐个客户查询最近 5 分钟内的请求量,并将 5 分钟数据统计到小时内
    然后逐个时间区间配置,判断总请求量是否超出预设值

end_min = (minute // 5) * 5
start_min = end_minute - 5
  1. 如果流量异常,按照指定策略触发相关事件

客户处理

PS:这个机制的目的是处理异常流量,如果正常的请求量上来了应该调整客户配置。

  1. 警告页面给出客户过去的请求情况,标出告警时间段的数据
  2. 让客户选择处理方案:
  3. 忽略并继续
  4. 清空暂停队列并继续
    可以查看下载受影响的请求信息
  5. 暂不处理
  6. 往后 24 小时之内,下一次触发告警的数量,提供一个默认值(当前请求量的 1.5 倍)
    另一种思路:如果客户选择继续请求,不用填下一次告警的数量,后面计算的时候直接跳过过去一段时间(比如 6 小时)的请求量。

#5 什么是一个设计良好的系统?

2021-08-24

在满足需求、有良好的使用体验(基于真实的用户看法,不是开发者自己觉得)基础上,进一步提更高的要求:

  • 接口响应超时
  • CPU load 升高
  • 内存
  • GC 频繁
  • 死锁
  • 大数据量存储

一、三高(高可用 + 高性能 + 高并发)

1.1 高可用(可用性) Availability

可用性强调的是服务的总体持续时间,比如可用性级别为三个九(99.9%)意味着一年 365 天里总共停止服务 8.76 个小时。

可靠性 Reliability

  • 功能如预期运行(宁可抛出异常,不要默默地给错误运行)
  • 出现故障的频率
  • 出现故障也应该不对系统造成太大的影响
  • 可维修性:故障定位容易、修复步骤简单、修复成本低廉

和高可用的区别:

  1. 大部分时候,这两个指标都是密切相关的
  2. 如果我有一个电视机,每天都准时看儿童频道的《动漫世界》一个小时,然后过去三年也都用得挺好,没有送去修过(导致我看不了),那可以说高可用了(正常运行时间 / 预期运行时间),但是如果这个电视机每次看的时候可能隔一会儿需要拍一巴掌(中间出雪花的时间可以忽略),那这就不能说这个电视机是可靠了。
  3. 又比如说,我又买了另一个电视机,不需要拍巴掌了,我看的挺开心,不过才高兴两年,坏了,看不了了,楼下电器维修店的小哥搞不定,联系厂家售后维修,一下就是两周看不了电视。对于一个家用电器,两年坏一次可以说高可靠,但是可用性就有问题了((365 - 7) / 365 = 98%)。

  4. MTBF Mean Time Between Failure 无故障时间,每隔多久遇到一次故障

  5. MTTR Mean Time To Repair 修复时间,每次遇到故障需要维修多久
  6. MTTF Mean Time To Failure

  7. 根据当前的可用性级别,然后指定合理的可行性目标

  8. 操作规范/最佳实践
  9. 预防性维护 Preventive Maintenance
  10. 合理的 PM 计划:可实施,正确的时机
  11. 重点是影响最大的故障
  12. 不断的改进和优化

稳定性 Stability

  • 系统运行平稳(不一定如预期执行)

连续性 Continuity

故障出现之后的处理能力:故障能否快速修复,能否不影响主要业务的运行。

比如我有两台电视机,坏了一台,我还有另一台可以看,虽然另一台是之前淘汰的一台黑白电视,效果差点,好歹能用啊。
这台电视就是我们常说的灾难备份,或者说容灾备份。

1.2 高性能 HP Performance

  • 处理速度快
  • 资源占用低

1.3 高并发 HC Concurrency

  • 响应时间
  • 吞吐量
  • 并发用户数

二、安全性

  • 基础设施安全:操作系统、网络、数据库
  • 数据安全
  • 脱敏:降低数据泄漏所产生的消极影响

三、易用性

四、其他

3.1 可测试性

3.2 可维护性

运维方便,运营方便,二次开发方便

  • 代码注释与文档
  • 合理的日志
  • 监控与数据统计
  • 误操作发生率低
  • 可理解性:代码可读性,合理的技术框架/系统架构
  • 可拓展性:新增功能不需要修改现有结构的能力。分层,合理的耦合度(尽可能的高内聚、低耦合),合理的功能抽象,数据结构可拓展

3.3 可伸缩性 Scalable/Scalability

在系统不需要修改(顶多改改配置)的前提下,通过增加或减少硬件资源来动态提升或降低系统各项能力。

  1. 通常采用服务器集群的方式。
  2. 集群一上来,就和高可用有很大关联。

3.4 可扩展性 Extensibility

通过合理的设计,使得新增功能时,不需要改动现有功能,或者只需要对现有系统进行少量调整就行。
总之,将新功能对现有业务逻辑的影响降到最低。

3.5 可观测性

能够方便快捷的了解到程序运行情况。
合理的日志,指标数据的暴露(Pull/Push)。

#3 23 种设计模式

2019-05-26

什么是设计模式

https://en.wikipedia.org/wiki/Design_Patterns
https://en.wikipedia.org/wiki/Software_design_pattern

我们说的 23 中设计模式,是来自一本 1994 年出版的书:《Design Patterns: Elements of Reusable Object-Oriented Software》。
这本书的中文名字叫:《设计模式:可复用面向对象软件的基础》。
写这本书的四位作者,被人成为 GoF(Gang of Four),也就是四人帮的意思(因为我们这边的关系,这个词在西方也比较著名,所以...)。

其中定义了设计模式,就是类似的问题的一种解决方案,或者说优秀的设计风格、编码风格,提升代码重用,同时实现高内聚、低耦合,让程序会更加可理解,更加可拓展,更加可维护。

  1. 一般谈到设计模式,都是在面向对象编程。但是我理解这是一种编程思想,和面向对象并不是强绑定关系。这点需要更多的思考和总结。
  2. 这里只研究 GoF 的 23 种设计模式,不是说这就是设计模式的全部,这个可能每个人有不同的看法。
  3. 根据维基百科信息,GoF 后来想重新整理这本书,重新分类,增删一些模式,但是最终没有达成一致。
  4. 根据维基百科信息,有人认为本书提到的设计模式只是语言特性缺失,在其他语言中,部分模式是不需要的。
    1. 就好像我们教材上基于 C 语言的数据结构,有部分在现代语言中是不需要开发者去编码实现一样,编译器做的很好了。

六大原则 SOLID

  1. 单一职责原则(Single Responsibility Principle)
  2. 开闭原则(Open Closed Principle)
  3. 里氏替换原则(Liskov Substitution Principle)
  4. 迪米特法则(Law of Demeter),又叫:最少知识法则(Least Knowledge Principle)
  5. 接口隔离原则(Interface Segregation Principle)
  6. 依赖倒置原则(Dependence Inversion Principle)

有些资料中还加入了一个:合成复用原则 Composite/Aggregate Reuse Principle,减少继承,多用聚合。

  • https://zhuanlan.zhihu.com/p/110130347
  • https://cloud.tencent.com/developer/article/1650116

模式清单

创建型模式 Creational

  1. 工厂模式 Factory Pattern
  2. 问题:
  3. 方案:
  4. 效果:
  5. 抽象工厂模式 Abstract Factory Pattern
  6. 问题:
  7. 方案:
  8. 效果:
  9. 单例模式 Singleton Pattern
  10. 问题:
  11. 方案:
  12. 效果:
  13. 建造者模式 Builder Pattern
  14. 问题:
  15. 方案:
  16. 效果:
  17. 原型模式 Prototype Pattern
  18. 问题:
  19. 方案:
  20. 效果:

结构型模式 Structural

  1. 代理模式 Proxy Pattern
  2. 问题:
  3. 方案:
  4. 效果:
  5. 适配器模式 Adapter Pattern
  6. 问题:
  7. 方案:
  8. 效果:
  9. 桥接模式 Bridge Pattern
  10. 问题:
  11. 方案:
  12. 效果:
  13. 组合模式 Composite Pattern
  14. 问题:
  15. 方案:
  16. 效果:
  17. 装饰器模式 Decorator Pattern
  18. 问题:
  19. 方案:
  20. 效果:
  21. 外观模式 Facade Pattern
  22. 问题:
  23. 方案:
  24. 效果:
  25. 享元模式 Flyweight Pattern
  26. 问题:
  27. 方案:
  28. 效果:

行为型模式 Behavioral

  1. 责任链模式 Chain of Responsibility Pattern
  2. 问题:
  3. 方案:
  4. 效果:
  5. 命令模式 Command Pattern
  6. 问题:
  7. 方案:
  8. 效果:
  9. 解释器模式 Interpreter Pattern
  10. 问题:
  11. 方案:
  12. 效果:
  13. 迭代器模式 Iterator Pattern
  14. 问题:
  15. 方案:
  16. 效果:
  17. 中介者模式 Mediator Pattern
  18. 问题:
  19. 方案:
  20. 效果:
  21. 备忘录模式 Memento Pattern
  22. 问题:
  23. 方案:
  24. 效果:
  25. 观察者模式 Observer Pattern
  26. 问题:
  27. 方案:
  28. 效果:
  29. 状态模式 State Pattern
  30. 问题:
  31. 方案:
  32. 效果:
  33. 策略模式 Strategy Pattern
  34. 问题:
  35. 方案:
  36. 效果:
  37. 模板模式 Template Pattern
    • 问题:
    • 方案:
    • 效果:
  38. 访问者模式 Visitor Pattern
    • 问题:
    • 方案:
    • 效果:

参考资料与拓展阅读