从0到1实现完整的微服务框架-熔断限流和降级
使用sentinel实现熔断限流和降级。
服务雪崩
服务提供者不可用导致 服务调用的不可用,并将不可用现象放大
服务雪崩三个阶段
- 服务提供者不可用
- 硬件故障
- 程序bug
- 缓存击穿
- 用户大量请求
- 重试加大请求流量
- 用户重试
- 代码逻辑重试
- 服务调用者不可用
- 同步等待造成资源耗尽。
应对的策略
- 应用库容
- 增加机器数量
- 升级规格
- 流控 不至于让服务挂掉
- 限流
- 关闭重试
- 缓存
- 缓存预加载
- 服务降级 当前访问用户过多,请稍后重试
- 服务接口拒绝服务
- 页面拒绝服务
- 延迟持久化
- 随机拒绝
- 服务熔断 调用方调用都超时?保险丝
服务限流
shop\api\user-api\initialize\sentinel.go
package initialize
import (
sentinel "github.com/alibaba/sentinel-golang/api"
"github.com/alibaba/sentinel-golang/core/flow"
"go.uber.org/zap"
"github.com/jimyag/shop/api/user/global"
)
func InitSentinel() {
err := sentinel.InitDefault()
if err != nil {
global.Logger.Fatal("初始化 sentinel 失败 .....", zap.Error(err))
}
_, err = flow.LoadRules([]*flow.Rule{
{
Resource: "get-user-list",
TokenCalculateStrategy: flow.Direct,
ControlBehavior: flow.Reject,
Threshold: 100, // 通过几个
StatIntervalInMs: 1, // 多少秒
},
})
if err != nil {
global.Logger.Fatal("加载 sentinel 配置失败....", zap.Error(err))
}
global.Logger.Info("加载 sentinel 配置成功....", zap.Error(err))
}
shop\api\user-api\api\user.go
func GetUserList(ctx *gin.Context) {
pageNum := ctx.DefaultQuery("pageNum", "1")
pageNumInt, err := strconv.Atoi(pageNum)
if err != nil {
global.Logger.Info("pageNum invalid")
}
pageSize := ctx.DefaultQuery("pageSize", "5")
pageSizeInt, err := strconv.Atoi(pageSize)
if err != nil {
global.Logger.Info("pageNum invalid")
}
// 增加的开始
e, b := sentinel.Entry("get-user-list", sentinel.WithTrafficType(base.Inbound))
if b != nil {
// block le
response.FailWithMsg("请求频率过快,请稍后重试", ctx)
return
}
// 增加的结束
rsp, err := global.UserSrvClient.GetUserList(ctx, &proto.PageIngo{
PageNum: uint32(pageNumInt),
PageSize: uint32(pageSizeInt),
})
if err != nil {
handle_grpc_error.HandleGrpcErrorToHttp(err, ctx)
return
}
// 增加的开始
e.Exit()
// 增加的结束
// ....
}