工程结构
服务器
【强制】 调用远程操作必须有超时设置。 说明: 类似于HttpClient
的超时设置需要自己明确去设置Timeout
。根据经验表明,无数次的故障都是因为没有设置超时时间。【推荐】 客户端设置远程接口方法的具体超时时间(单位ms),超时设置生效顺序一般为: 1)客户 端Special Method
; 2)客户端接口级别; 3)服务端Special Method
; 4)服务端接口级别。【推荐】 高并发服务器建议调小TCP协议的time_wait
超时时间。 说明: 操作系统默认240
秒后,才会关闭处于time_wait
状态的连接,在高并发访问下,服务器端会因为处于time_wait
的连接数太多,可能无法建立新的连接,所以需要在服务器上调小此等待值。 正例: 在linux服务器上请通过变更/etc/sysctl.conf
文件去修改该缺省值(秒):net.ipv4.tcp_fin_timeout=30
【推荐】 调大服务器所支持的最大文件句柄数(File Descriptor,简写为fd) 说明: 主流操作系统的设计是将TCP/UDP
连接采用与文件一样的方式去管理,即一个连接对应于一个fd
。主流的 linux
服务器默认所支持最大fd
数量为1024
,当并发连接数很大时很容易因为fd
不足而出现“open too many files
”错误,导致新的连接无法建立。建议将linux服务器所支持的最大句柄数调高数倍(与服务器的内存数量相关)。【推荐】 给JVM
环境参数设置-XX:+HeapDumpOnOutOfMemoryError
参数,让JVM
碰到OOM
场景时输出 dump
信息。 说明: OOM
的发生是有概率的,甚至相隔数月才出现一例,出错时的堆内信息对解决问题非常有帮助。【推荐】 在线上生产环境,JVM
的Xms
和Xmx
设置一样大小的内存容量,避免在GC
后调整堆大小带 来的压力。【推荐】 了解每个服务大致的平均耗时,可以通过独立配置线程池,将较慢的服务与主线程池隔离开,免得不同服务的线程同归于尽。【参考】 服务器内部重定向必须使用forward
;外部部重定向地址必须使用URLBroker
生成,否则因线 上采用HTTPS
协议而导致浏览器提示"不安全"。此外,还会带来URL
维护不一致的问题。
设计规约
【推荐】 系统架构设计时明确以下目标: ●确定系统边界。确定系统在技术层面上的做与不做。 ●确定系统内模块之间的关系。确定模块之间的依赖关系及模块的宏观输入与输出。 ●确定指导后续设计与演化的原则。使后续的子系统或模块设计在一个既定的框架内和技术方向上继续演化。 ●确定非功能性需求。非功能性需求是指安全性、可用性、可扩展性等。【推荐】 需求分析与系统设计在考虑主干功能的同时,需要充分评估异常流程与业务边界。【推荐】 类在设计与实现时要符合单一原则。 说明: 单一原则最易理解却是最难实现的一条规则,随着系统演进,很多时候,忘记了类设计的初衷。【推荐】 谨慎使用继承的方式来进行扩展,优先使用聚合/组合的方式来实现。 说明: 不得已使用继承的话,必须符合里氏代换原则,此原则说父类能够出现的地方子类一定能够出现,比如,“把钱交出来",钱的子类美元、欧元、人民币等都可以出现。【推荐】 系统设计阶段,根据依赖倒置原则,尽量依赖抽象类与接口,有利于扩展与维护。 说明: 低层次模块依赖于高层次模块的抽象,方便系统间的解耦。【推荐】 系统设计阶段,注意对扩展开放,对修改闭合。 说明: 极端情况下,交付的代码是不可修改的,同一业务域内的需求变化,通过模块或类的扩展来实现。【推荐】 系统设计阶段,共性业务或公共行为抽取出来公共模块、公共配置、公共类、公共方法等,在 系统中不出现重复代码的情况,即 DRY原则(Don’t Repeat Yourself)。 说明: 随着代码的重复次数不断增加,维护成本指数级上升。随意复制和粘贴代码,必然会导致代码的重复,在维护代码时,需要修改所有的副本,容易遗漏。必要时抽取共性方法,或者抽象公共类,甚至是组件化。 正例: 一个类中有多个 public
方法,都需要进行数行相同的参数校验操作,这个时候请抽取: private boolean checkParam(DTO dto) {…}
【推荐】 避免如下误解:敏捷开发=讲故事+编码+发布。 说明: 敏捷开发是快速交付迭代可用的系统,省略多余的设计方案,摒弃传统的审批流程,但核心关键点上的必要设计和文档沉淀是需要的。 反例: 某团队为了业务快速发展,敏捷成了产品经理催进度的借口,系统中均是勉强能运行但像面条一样的代码,可维护性和可扩展性极差,一年之后,不得不进行大规模重构,得不偿失。【参考】 设计文档的作用是明确需求、理顺逻辑、后期维护,次要目的用于指导编码。 说明: 避免为了设计而设计,系统设计文档有助于后期的系统维护和重构,所以设计结果需要进行分类归档保存。【参考】 可扩展性的本质是找到系统的变化点,并隔离变化点。 说明: 世间众多设计模式其实就是一种设计模式即隔离变化点的模式。 正例: 极致扩展性的标志,就是需求的新增,不会在原有代码交付物上进行任何形式的修改。【参考】 设计的本质就是识别和表达系统难点。 说明: 识别和表达完全是两回事,很多人错误地认为识别到系统难点在哪里,表达只是自然而然的事情,但是大家在设计评审中经常出现语嫣不详,甚至是词不达意的情况。准确地表达系统难点需要具备如下能力:表达规则和表达工具的熟练性。抽象思维和总结能力的局限性。基础知识体系的完备性。深入浅出的生动表达力。【参考】 代码即文档的观点是错误的,清晰的代码只是文档的某个片断,而不是全部。 说明: 代码的深度调用,模块层面上的依赖关系网,业务场景逻辑,非功能性需求等问题要相应的文档来完整地呈现