Go-Micro服务熔断初步使用

xiaohai 2021-05-09 22:31:20 2307人围观 标签: Go 
简介Go-Micro服务熔断初步使用

1、服务熔断库安装

go get github.com/afex/hystrix-go/hystrix

2、客户端熔断添加

package main

import (
    "context"
    "github.com/afex/hystrix-go/hystrix"
    "github.com/gin-gonic/gin"
    "github.com/micro/go-micro"
    "github.com/micro/go-micro/client"
    "github.com/micro/go-micro/registry"
    "github.com/micro/go-micro/web"
    "github.com/micro/go-plugins/registry/consul"
    "log"
    services "micro-home/service/model"
    "strconv"
)

func InitMiddleware(service services.StudentListService) gin.HandlerFunc {
    return func(context *gin.Context) {
        context.Keys = make(map[string]interface{})
        context.Keys["student_service"] = service
        context.Next()
    }
}

//装饰器
type logWrapper struct {
    client.Client
}

//每次调用都会执行这个方法
func (c *logWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
    log.Print("请求")
    return c.Client.Call(ctx, req, rsp)
}
func NewLogWrapper(c client.Client) client.Client {
    return &logWrapper{c}
}

func main() {
    register := consul.NewRegistry(func(options *registry.Options) {
        options.Addrs = []string{
            "192.168.1.171:8500",
            "192.168.1.177:8500",
            "192.168.1.178:8500",
        }
    })
    //微服务需要注册
    homeService := micro.NewService(
        micro.Name("micro-home-client"),
        micro.Registry(register),
        micro.WrapClient(NewLogWrapper), //在注册时只需要传入方法名即可,底层会自动给这个方法传入client
    )
    //实例化服务
    studentListService := services.NewStudentListService("student-service", homeService.Client())

    routers := gin.Default()

    routers.Use(InitMiddleware(studentListService)) //使用中间件,将服务传递到context中

    routers.GET("/", func(context *gin.Context) {
        service := context.Keys["student_service"].(services.StudentListService)
        number := context.DefaultQuery("number", "0")
        num, err := strconv.Atoi(number)
        if err != nil {
            num = 1
        }
        if num <= 0 {
            num = 1
        }
        //熔断配置
        hystrix.ConfigureCommand("student-service", hystrix.CommandConfig{
            Timeout: 1000,
        })
        var studentListResponse *services.StudentListResponse
        //熔断处理
        err = hystrix.Do("student-service", func() error {
            studentListResponse, err = service.GetStudentListService(context, &services.StudentListRequest{
                Num: int32(num),
            })
            return err
        }, nil)//fallback这里为nil,可以自己定义需要返回的处理,如果这里调用服务出现问题会直接抛出异常,如果不想抛出异常,可以实现对应的方法,下面我们会处理
        if err != nil {
            context.JSON(400, gin.H{
                "status": "",
                "data":   err.Error(),
            })
        } else {
            context.JSON(200, gin.H{
                "status": studentListResponse.Status,
                "data":   studentListResponse.Data,
            })
        }
    })

    service := web.NewService(
        web.Name("home-service-api"),
        web.Address(":8081"),
        web.Handler(routers),
        web.Registry(register),
    )

    service.Run()
}

3、将服务接口处理时间延迟,可以睡眠几秒钟

4、熔断返回处理

package main

import (
    "context"
    "github.com/afex/hystrix-go/hystrix"
    "github.com/gin-gonic/gin"
    "github.com/micro/go-micro"
    "github.com/micro/go-micro/client"
    "github.com/micro/go-micro/registry"
    "github.com/micro/go-micro/web"
    "github.com/micro/go-plugins/registry/consul"
    "log"
    services "micro-home/service/model"
    "strconv"
)

func InitMiddleware(service services.StudentListService) gin.HandlerFunc {
    return func(context *gin.Context) {
        context.Keys = make(map[string]interface{})
        context.Keys["student_service"] = service
        context.Next()
    }
}

//装饰器
type logWrapper struct {
    client.Client
}

//每次调用都会执行这个方法
func (c *logWrapper) Call(ctx context.Context, req client.Request, rsp interface{}, opts ...client.CallOption) error {
    log.Print("请求")
    return c.Client.Call(ctx, req, rsp)
}
func NewLogWrapper(c client.Client) client.Client {
    return &logWrapper{c}
}

func main() {
    register := consul.NewRegistry(func(options *registry.Options) {
        options.Addrs = []string{
            "192.168.1.171:8500",
            "192.168.1.177:8500",
            "192.168.1.178:8500",
        }
    })
    //微服务需要注册
    homeService := micro.NewService(
        micro.Name("micro-home-client"),
        micro.Registry(register),
        micro.WrapClient(NewLogWrapper), //在注册时只需要传入方法名即可,底层会自动给这个方法传入client
    )
    //实例化服务
    studentListService := services.NewStudentListService("student-service", homeService.Client())

    routers := gin.Default()

    routers.Use(InitMiddleware(studentListService)) //使用中间件,将服务传递到context中

    routers.GET("/", func(context *gin.Context) {
        service := context.Keys["student_service"].(services.StudentListService)
        number := context.DefaultQuery("number", "0")
        num, err := strconv.Atoi(number)
        if err != nil {
            num = 1
        }
        if num <= 0 {
            num = 1
        }
        hystrix.ConfigureCommand("student-service", hystrix.CommandConfig{
            Timeout: 1000,
        })
        var studentListResponse *services.StudentListResponse
        err = hystrix.Do("student-service", func() error {
            studentListResponse, err = service.GetStudentListService(context, &services.StudentListRequest{
                Num: int32(num),
            })
            return err
        }, func(e error) error {//熔断处理,当发生熔断后,就返回如下数据
            var studentModel []*services.StudentModel
            studentModel = append(studentModel, &services.StudentModel{
                Id:   0,
                Name: "熔断返回",
                Sex:  "女",
            })
            studentListResponse = &services.StudentListResponse{
                Status: 200,
                Data:   studentModel,
            }
            return nil
        })
        if err != nil {
            context.JSON(400, gin.H{
                "status": "",
                "data":   err.Error(),
            })
        } else {
            context.JSON(200, gin.H{
                "status": studentListResponse.Status,
                "data":   studentListResponse.Data,
            })
        }
    })

    service := web.NewService(
        web.Name("home-service-api"),
        web.Address(":8081"),
        web.Handler(routers),
        web.Registry(register),
    )

    service.Run()
}

5、可以使用go-micro的wrapper来对熔断进行封装