Rob Pike曾说“复杂性是以乘积方式增长的”。 当我们在快速发布的压力之下,不断的增加系统功能、选项、以及配置,一点点的将系统的某个部分变的更加复杂,难以理解,最终变的不可维护!
因此,为了尽可能的前期少留坑,周末做了两件小事儿,收获挺多,整理分享!
1、重读一周的代码,完善README
2、重读《Go程序设计语言》
一、重读代码
coding了一周,疲于沟通,联调和开发。太多的战略和趋势的高谈阔论,总觉的越来越缺少,冷静下来,对关键细节深度思考
!
趁着周末,好好回顾了一下自己这一周开发的项目!
1.1 关于几个选型
1.1.1 uuid选型
项目中用到了唯一健,用了公司的ice,那么ice做的怎么样?选型是否有坑?
先贴结论:整体来看,目前ice完全够用,针对时钟回拨和趋势递增问题也可以简单封装解决,但在细节问题的实现上,不如百度的UidGenerator和美团的leaf!
uuid有四种通用解决方案(mysql自增、、伪随机本地hash、GUID/UUID方案、类snowflake方案)
具体细节就不做介绍了,都或多或少有些小问题。那么公司的ice是否解决了相关问题?
- 实现方案:mysql自增+cache批量预取
- 高可用方案:多IDC部署 + 超长预加载容灾+ 时间戳算法降级兜底 + 异地多活。
- 性能问题:增加了预取,RPC提供(项目中不是瓶颈,实测在ms级别,可以自己加个预取cache提升)
- 水平扩展:proxy负载均衡提供扩展能力。
- 趋势递增问题解决:未解决(
如果担心泄露信息,那就必须业务封装打乱位置
) - 时钟回拨问题解决:时钟回拨目前看也没有解决。(
不确认是否有启动时钟检查,但是预取去重能部分解决
) - 跨机房重复问题:机房前缀解决。
1.1.2 json解析的选型
go的json解析历来被认诟病,目前采用github.com/json-iterator/go,压测下。
先贴结论:json-iterator针对实际业务中的长json,性能在30us左右,短json在1us左右,完全满足要求。
但是:目前采用go 1.13.5 官方库的实际压测结果由于jsoniter
,不折腾,切官方库!
jsoniter的一些优化点:
1、流式读取到内存,降低GC压力。
2、按照schema解析,减少if-else判断和反射消耗。
3、int直接解析,无需两遍处理。
1 | 实际数据: |
1.1.3 go mod和glide
glide挺好,从使用上看有两个小问题。
- 位置强指定:非标准库必须位于GOPATH指定的src下。
- 偶尔bug:例如,出现几次glide update 不能更新的问题,需要强制glide cc。
既然用了1.13.5,那最好选用根红苗正的go mod。
从实际使用上看和IDE结合的很棒,开启GO111MODULE=on之后,基本上包管理完全无感知
,所以到现在也不会几个go mod命令 ̄□ ̄||!
关于包管理的一些设计可以参考:package manager
1.2 关于项目的一些约定整理
只是最近这两周用到的一些内容的梳理,补充readme
1.2.1 common和util却别
项目中util和common两个文件如何使用?
utils 放通用的工具类,和业务没有任何关系
,可以独立迁移,比如:time,json,math,hash等
common 放和业务可能有关系的通用类,比如:errors,log,request,conf,cache,db等,含有业务的局部配置信息!
1.2.2 关于变量/常量位置
系统级别的变量:写在conf,通过conf读取放入内存
请求级别的变量:写入context,随context value流转,同时,传输给下游时候,注意清理!
系统级常量:放common.consts
服务级常量:放对应的dao(否则整体的consts会很乱)
1.2.3 关于接口是否独立文件和单测
推荐每个接口一个独立文件
,每个大类放在一个包里,清晰明了!
比如:1
2
3
4
5xxModel
├── getXX.go
├── setXX.go
├── deleteXX.go
└── xxx_test.go
1.2.4 状态位约定
没啥,必须采用int16,int4的1、2、3连续的状态位存在扩展风险
,遇到过坑!
Exception和DONE 状态置高危,比如8XX,9xx
1.2.5 关于一些封装的约定
涵盖但不限于request,mysql,redis,http请求,httpserv,response的简单封装,不要过度,必须标明封装背景,比如1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19//GetReqBody 读取body体封装
//解决:body体很大时,需要多次内存扩容,耗费cpu,增加gc压力,而且最后可能还会浪费一半的内存空间的问题
func GetReqBody(ctx *context.Context,r *http.Request) ([]byte, error) {
var b []byte
var err error
cLen := r.ContentLength
if cLen > 0 {
b = make([]byte, cLen, cLen)
_, err = io.ReadFull(r.Body, b)
} else {
b, err = ioutil.ReadAll(r.Body)
}
_ = r.Body.Close()
// set request 2 context
*ctx = context.WithValue(*ctx,consts.CtxReqBytes,b)
return b, err
}
二、重读《GO程序设计语言》
每次读程序设计语言感觉都不一样,周末又翻了翻,还没翻完!
可能最近写博客的原因,整体更侧重于整体的设计布局,分层逻辑和重要细节!
暂时未写完,下周续上