高质量编程及编码规范 | 青训营

97 阅读3分钟

1.1 简单性、可读性、生产力
1.2 编码规范
1.2.1 代码格式:gofmt自动格式化代码/goimprts=gofmt+依赖包管理
1.2.2 注释:代码作用、如何做的、实现原因、什么情况会出错
· 公共符号始终要注释
1.2.3 命名规范:
variable - 缩略词全大写,位于变量开头且不需要导出时,使用全小写 - 全局变量需要在名字中提供更多上下文信息
function
- 不携带包名的上下文信息 - 当名为foo的包某个函数返回类型Foo时,可以省略类型信息而不出现歧义 - 当名为foo的包某个函数返回类型T时,可以在函数名中加入类型信息
package - 只有小写字母组成 - 不与标准库同名 - 不适用常用变量名作为包名 - 使用单数而不是复数 - 谨慎使用缩写
1.2.4 控制流程 - 避免嵌套
1.2.5 错误和异常处理
- 简单错误:优先使用errors.New(string)创建匿名变量直接表示简单错误;如果有格式化要求,使用fmt.Errorf - 错误的Wrap(包装)和Unwrap(解包装):提供一个error嵌套另一个error,生成error的跟踪链;在fmt.Errorf中使用%w来将一个错误关联至错误链中
- 错误判定:判定一个错误是否为特定错误,使用error.ls,可以判断错误链上的所有错误是否含有特定错误;使用errors.As在错误链上获取特定种类的错误 - panic:不建议 - recover:只能在被defer的函数中使用;嵌套无法生效;只在当前goroutine生效;defer的语句是后进先出。如果需要更多上下文信息,可以recover后在log中记录当前的调用栈
1.3 性能优化建议
1.3.1 Benchmarkgo test -bench=. -benchmen
1.3.2 Slice预分配内存;大内存未释放(copy代替re-slice)
1.3.3 Map预分配内存
1.3.4 字符串处理:使用strings.Builder/strings.Buffer做字符串拼接
1.3.5 空结构体:节省内存
1.3.6 atomic包:效率比锁高;sync.Mutex应该用来保护一段逻辑而不是保护一个变量;对于非数值操作,而可以使用atomic.Value
2. 性能调优
2.1 性能分析工具pprof:可视化和分析性能分析数据,可以知道程序在什么地方耗费了多少CPU、Memory
github.com/wolfogre/go…

go tool pprof "http://localhost:6060/debug/pprof/profile?seconds=10"   //进入pprof
top         //查看占用资源最多的函数
list 关键字  //查找代码行
web         //调用关系可视化
go tool pprof -http=:8080 "http://localhost:6060/debug/pprof/heap"  //处理堆内存问题

image.png

2.2 性能调优案例
2.2.1 业务服务优化
2.2.1.1 流程
- 建立服务性能评估手段
- 服务性能评估方式
- 请求流量构造
- 压测范围
- 单机器压测
- 集群压测
- 性能数据采集
- 单机性能数据
- 集群性能数据
- 分析性能数据(使用库不规范、高并发场景优化不足...)
- 重点优化项改造(diff)
- 优化效果验证 - 重复压测验证
- 上限评估优化结果:关注服务监控、逐步放量、收集性能数据 - 进一步优化,服务整体链路分析
- 规范上有服务调用接口
- 分析链路,提升服务性能
2.2.2 基础库优化
- AB实验SDK优化 - 设计完善改造方案、数据按需获取、数据序列协议优化
- 内部压测验证
- 对光业务服务落地验证
2.2.3 Go语言优化
- 编译器优化:内存分配、代码编译流程、内部压测验证、推广业务服务落地验证