资料地址1:pan.baidu.com/s/1VbX0_mXo… 提取码: pwgf 资料地址2:share.weiyun.com/IJepWsJc 密码:5wnvaz
一、P2C负载均衡算法 & EWMA 在go-zero中默认使用的是P2C的负载均衡算法。 算法的原理:即随机从所有可用节点中选择两个节点,然后计算这两个节点的负载情况,选择负载较低的一个节点来服务本次请求。 为了避免某些节点一直得不到选择导致不平衡,会在超过一定的时间后强制选择一次。
使用EWMA指数移动加权平均,记录每个节点的平均延迟,该算法相对于算数平均来说对于突然的网络抖动没有那么敏感,从而可以让算法更加均衡。
g0-zer0 ,是一个集成了各种工程实践的 web 和 rpc 框架。通过弹性设计保障了大并发服务端的稳定性,经受了充分的实战检验。go-zero 包含极简的 AP!定义和生成工具 goctl,可以根据定义的 api文件一键生成 Go, i0s, Android,Kotlin, Dart,Typescript,javascript 代码并可直接运行。 使用 go-zero 的好处: 轻松获得支撑千万日活服务的稳定性 内建级联超时控制、限流、自适应熔断、自适应降载等微服务治理能力,无需配置和额外代码 微服务治理中间件可无缝集成到其它现有框架使用 极简的 API 描述,一键生成各端代码 自动校验客户端请求参数合法性 大量微服务治理和并发工具包
二、源码阅读 2.1EWMA记录节点的平均延迟 buildDoneFunc返回函数会复制给 PickResult.Done, RPC完成调用后会执行PickResult.Done方法。
/* // Done is called when the RPC is completed. rpc 完成时将会执行该函数 */ func (p *p2cPicker) buildDoneFunc(c *subConn) func(info balancer.DoneInfo) { //start 记录subConn被选中的时间 start := int64(timex.Now()) return func(info balancer.DoneInfo) { //...... now := timex.Now() last := atomic.SwapInt64(&c.last, int64(now)) //本次请求 和 上次请求 请求间隔 td := int64(now) - last if td < 0 { td = 0 } //e^x 距离最后一次请求 时间约久,权重约低 w := math.Exp(float64(-td) / float64(decayTime)) //本次请求花费的时间 lag := int64(now) - start if lag < 0 { lag = 0 } // olag := atomic.LoadUint64(&c.lag) if olag == 0 { w = 0 } atomic.StoreUint64(&c.lag, uint64(float64(olag)w+float64(lag)(1-w))) success := initSuccess if info.Err != nil && !codes.Acceptable(info.Err) { success = 0 } osucc := atomic.LoadUint64(&c.success) atomic.StoreUint64(&c.success, uint64(float64(osucc)w+float64(success)(1-w)))
//每一分钟记录一次请求日志
//......
}
go-zero 框架设计思考 对于微服务框架的设计,我们期望保障微服务稳定性的同时,也要特别注重研发效率。所以设计之初,我们就有如下一些准则: 保持简单 高可用 高并发 易扩展 弹性设计,面向故障编程 尽可能对业务开发友好,封装复杂度 尽可能约束做一件事只有一种方式
使用go-zero框架的时候,发现在API请求过程中如果出现错误,接口会直接返回http400错误。这对前端或者其它服务端很不友好,他们需要获得详细错误信息,并且不返回http错误。同时,对于有错误的请求和成功的请求,接口返回的数据不一致。 总的来说,我们需要解决以下三个问题: 处理框架自带参数解析失败后产生的error(需自己处理) 处理逻辑层处理失败后产生的error(官方已处理) 修改模板,统一接口返回值(官方已处理) 后两个官方已处理,并加入官方学习文档,可自行查阅: 逻辑层错误官方解决方案:官方错误处理方法 统一接口返回值官方解决方案:官方统一请求返回方法