第五课 Go容器化微服务系统实战-熔断、限流和负载均衡
tags:
- GO
- 慕课网
categories:
- 熔断(hystrix-go)
- 限流
- 负载均衡
- API网关
第一节 微服务熔断、限流、负载均衡、网关介绍安装
1.1 微服务熔断(hystrix-go)介绍
- 熔断的目的:
- 熔断可以阻止故障的连锁反应
- 熔断可以快速失败并迅速恢复
- 熔断可以回退并优雅降级
- 熔断可以提供近实时的监控与告警
- 熔断使用过程的一些原则
- 防止任何单独的依赖耗尽资源(线程)
- 过载立即切断并快速失败,防止排队
- 尽可能提供回退以保护用户免受故障
- 通过近实时的指标,监控和告警,确保故障被及时发现
- 微服务熔断(hystrix-go )的请求原理
1.2 微服务熔断(hystrix-go)核心概念
- 微服务熔断( hystrix-go )的熔断器状态
- CLOSED关闭状态∶允许流量通过。
- OPEN打开状态∶不允许流量通过,即处于降级状态,走降级逻辑。
- HALF_OPEN半开状态∶允许某些流量通过,如果出现超时、异常等情况,将进入OPEN状态,如果成功,那么将进入CLOSED状态。
- 微服务熔断(hystrix-go )的重要字段
- Timeout :执行command的超时时间,默认时间是1000毫秒
- MaxConcurrentRequests:最大并发量,默认值是10
- SleepWindow:熔断打开后多久进行再次尝试,默认值5000毫秒
- RequestVolumeThreshold : 10秒内的请求量,默认值20,判断是否熔断
- ErrorPercentThreshold :熔断百分比,默认值50%,超过启动熔断
- 微服务熔断(hystrix-go )的熔断计数器
- 每一个Command都会有一个默认统计控制器
- 默认的统计控制器DefaultMetricCollector
- 保存熔断器的所有状态,调用次数,失败次数,被拒绝次数等信息
- 微服务熔断(hystrix-go )的状态信息上报过程原理。每一秒创建一个bucket,根据请求状态判断熔断是否打开。
1.3 微服务熔断(hystrix-go)观测面板安装
# 下载镜像
docker pull mlabouardy/hystrix-dashboard
# 后台启动
docker run --name hystrix-dashboard -d -p 9002:9002 mlabouardy/hystrix-dashboard:latest
# 访问ip:9002
1.4 微服务限流介绍
- 微服务三剑客之限流( uber/limit)作用
- 限制流量,在服务端生效,上面hystrix-go写在客户端访问服务端中。
- 保护后端服务
- 与熔断互补(客户端发现服务端不可用,快速熔断下)
- 微服务三剑客之限流(uber/limit)漏桶算法原理
1.5 微服务负载均衡介绍
- 微服务三剑客之负载均衡作用
- 提高系统扩展性
- 支持:HTTP、HTTPS、TCP、UDP请求
- 主要算法:循环算法和随机算法,默认随机算法
1.6 微服务API网关介绍
- 微服务之API网关-总体架构
- 第一层Micro api网关
- 第二层聚合业务层 api层
- 第三层基础服务层
- 微服务之API网关-路径说明
- 通过网关请求/greeter/say/hello,这个路径,网关会将请求转发到go.micro.api.greeter服务的Say.Hello方法处理
- go.micro.api是网关的默认服务名的前缀
- 路径中/cartApi/cartApi/findAll(两个路径相同)也可以写成/cartApi/findAll
第二节 购物车服务端开发
2.1 购物车服务端目录
- 购物车加入熔断(客户端),限流(服务端),负载均衡(客户端)
- 用上节课方法自动生成我们的目录文件。
sudo docker pull micro/micro
sudo docker run --rm -v $(pwd):$(pwd) -w $(pwd) micro/micro new cart
- 新建domain文件夹,并在domain中创建model、repository、service三个文件夹。
- 删除go.mod,重新通过下面命令生成。
go mod init git.imooc.com/qnhyn/cart
go mod tidy
- 新建common文件夹。
2.2 购物车服务端proto开发
- 创建cart文件夹,把cart.proto移动过去。
- 生成go文件
# 生成之后看下product.pb.micro.go 用到的版本 主要要是v2(v3会在编译时报错)
protoc *.proto --gofast_out=. --micro_out=.
syntax = "proto3";
package go.micro.service.cart;
service Cart {
rpc AddCart(CartInfo) returns (ResponseAdd) {}
rpc CleanCart(Clean) returns (Response){}
rpc Incr(Item) returns (Response){}
rpc Decr(Item) returns (Response){}
rpc DeleteItemByID (CartID) returns (Response){}
rpc GetAll(CartFindAll) returns (CartAll){}
}
message CartInfo {
int64 id = 1;
int64 user_id =2;
int64 product_id = 3;
int64 size_id = 4;
int64 num =5;
}
message ResponseAdd{
int64 cart_id =1;
string msg =2;
}
message Clean {
int64 user_id =1;
}
message Response {
string meg =1;
}
message Item {
int64 id =1;
int64 change_num = 2;
}
message CartID{
int64 id =1;
}
message CartFindAll {
int64 user_id =1;
}
message CartAll {
repeated CartInfo cart_info =1;
}
2.3 购物车服务端domain开发
- model文件夹下cart.go
package model
type Cart struct{
ID int64 `gorm:"primary_key;not_null;auto_increment" json:"id"`
ProductID int64 `gorm:"not_null" json:"product_id"`
Num int64 `gorm:"not_null" json:"num"`
SizeID int64 `gorm:"not_null" json:"size_id"`
UserID int64 `gorm:"not_null" json:"user_id"`
}
- repository文件夹下cart_repository.go
package repository
import (
"errors"
"git.imooc.com/qnhyn/cart/domain/model"
"github.com/jinzhu/gorm"
)
type ICartRepository interface {
InitTable() error
FindCartByID(int64) (*model.Cart, error)
CreateCart(*model.Cart) (int64, error)
DeleteCartByID(int64) error
UpdateCart(*model.Cart) error
FindAll(int64) ([]model.Cart, error)
// 清空购物车
CleanCart(int64) error
IncrNum(int64, int64) error
DecrNum(int64, int64) error
}
// NewCartRepository 创建cartRepository
func NewCartRepository(db *gorm.DB) ICartRepository {
return &CartRepository{
mysqlDb: db}
}
type CartRepository struct {
mysqlDb *gorm.DB
}
// InitTable 初始化表
func (u *CartRepository) InitTable() error {
return u.mysqlDb.CreateTable(&model.Cart{
}).Error
}
// FindCartByID 根据ID查找Cart信息
func (u *CartRepository) FindCartByID(cartID int64) (cart *model.Cart, err error) {
cart = &model.Cart{
}
return cart, u.mysqlDb.First(cart, cartID).Error
}
// CreateCart 创建Cart信息
func (u *CartRepository) CreateCart(cart *model.Cart) (int64, error) {
db := u.mysqlDb.FirstOrCreate(cart, model.Cart{
ProductID: cart.ProductID, SizeID: cart.SizeID, UserID: cart.UserID})
if db.Error != nil {
return 0, db.Error
}
if db.RowsAffected == 0 {
return 0, errors.New("购物车插入失败")
}
return cart.ID, nil
}
// DeleteCartByID 根据ID删除Cart信息
func (u *CartRepository) DeleteCartByID(cartID int64) error {
return u.mysqlDb.Where("id = ?", cartID).Delete(&model.Cart{
}).Error
}
// UpdateCart 更新Cart信息
func (u *CartRepository) UpdateCart(cart *model.Cart) error {
return u.mysqlDb.Model(cart).Update(cart).Error
}
// FindAll 获取结果集
func (u *CartRepository) FindAll(userID int64) (cartAll