经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » 编程经验 » 查看文章
重构服务的一些想法
来源:cnblogs  作者:文一路挖坑侠  时间:2024/7/17 11:00:41  对本文有异议

重构服务的一些想法

最近对一个服务进行了大重构(不仅仅是代码的重构,还有构建、部署和单元测试等),之前很多实践的经验都应用上了,实践下来效果比较满意。

模块设计

需要明确服务的核心功能

  1. 执行时机(被谁驱动)
  2. 执行内容
  3. 和非核心功能的关系

从模块话的角度看,这三个部分其实都可以独立实现,这样更利于单元测试用例的编写,扎实的单元测试覆盖率大大提高对稳定性的信心。

执行时机一般都是外部驱动,如收到任务、请求甚至内部定时器驱动。

核心功能的执行内容一般不多,但是实现需要严谨,不要轻易放过错误。因为被非核心功能依赖,这部分的稳定可以减少非核心功能不必要的防御性代码,

和非核心功能的关系参考内核的各种 HOOK 实现,核心功能提供 HOOK 点,非核心功能在这些 HOOK 点上被执行,这样各模块就被解藕了。

构建

尽量选择依赖少的三方库,除非没得选(一般是性能要求)。

构建尽量静态链接,如果存在三方依赖但手动实现简单的话,那么可以考虑手动进行实现。

CI 构建的方式应该和手动构建方式并存(前者调用后者),在规模不是非常大的情况下 CI 速度是没有本地编译的速度快的,这样对开发环境的更新可以效率高一些。

三方工具的构建应该持久化构建过程,比如使用 Dockerfile 来保存构建过程,这样有信创这种需求过来一般稍加修改即可。

C++ 尽量使用 cmake,不用写 makefile及可以生成 compile_commands.json。

代码规范

锁只出现在公有函数中,私有函数只实现功能,不考虑资源同步的情况(如果必须控制小粒度另说)。

业务代码优先定义好接口,由外部逻辑调用接口进行驱动,业务直接实现接口即可,接口定义好坏的一个判断参考:后续增加业务无需修改驱动逻辑,新增接口实现业务逻辑就被集成进去。

代码尽量模块化,模块化清晰一个判断参考:能够直接通过单元测试启动这个模块。

函数实现显式化阻塞逻辑,然后交给外部调用决定是否需要启动线程/协程将其放至后台。

Go 的函数参数只放必要参数,比如创建一个命名空间,那么命名空间名称就是关键的参数,超时时间这种就可以设计成 option 实现。

性能

以 profile 为准,不重写标准库函数,一般性能热点不会出现在这些地方,况且标准库也是会进化的(如早期 nginx 优化的 memcpy 早已比不上现在 glibc 的实现了)

优先实现功能,功能收敛后进行 profile,根据热点进行优化,在实现的时候可以使用一些常见的优化,如 C++ 中的 thread_local,Go 中的 sync.Pool

单元测试

核心功能尽量 100% 覆盖

非核心功能覆盖到关键路径

日志

日志分文件,不同的模块可以通过不同的日志文件进行区分

日志分等级

  • 在服务内部没有状态改变的情况,默认等级为 INFO 且日志不会增加,定时器的逻辑不能使用 INFO
  • 热点路径的日志只使用 TRACE 等级,并且日志代码语句放在日志等级判断逻辑里面,避免不必要的 CPU/Memory 消耗。

日志可动态调整,应对出现问题又保持现场的场景(生产环境)

部署

支持 systemd/docker 的方式

原文链接:https://www.cnblogs.com/shuqin/p/18303042

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号