【微服务网关——hystrix-go类库】

1.hystrix-go类库

hystrix-go 是 Netflix 开源的 Hystrix 库在 Go 语言中的实现,用于处理服务中的故障和延迟问题。它通过提供熔断器(Circuit Breaker)、隔离、降级、限流、以及实时监控等机制,帮助开发者构建健壮的分布式系统。hystrix-go 旨在提高系统的容错能力和稳定性。

  • 熔断器(Circuit Breaker):
    • 监控操作的成功率和失败率,当失败率达到一定阈值时,熔断器会“跳闸”,短路后续的请求,从而防止系统被不稳定的服务压垮。
    • 熔断器会定期尝试恢复正常的请求流,当检测到服务恢复正常时会“闭合”,恢复正常的请求处理。
  • 隔离(Isolation):
    • 提供基于并发数或线程池的隔离机制,防止单个操作耗尽系统资源,影响其他操作。
    • 通过配置最大并发数限制,确保资源使用在可控范围内。
  • 降级(Fallback):
    • 在操作失败或超时时提供降级处理逻辑,确保服务在部分故障的情况下仍然能够提供部分功能。
    • 允许定义备用逻辑或返回默认值,以避免服务中断。
  • 限流(Rate Limiting):
    • 控制请求速率,防止系统过载。
    • 通过限制单位时间内的请求数,确保系统在高负载情况下仍能稳定运行。
  • 实时监控:
    • 提供实时监控指标,如请求成功率、失败率、超时次数等,帮助开发者了解系统的健康状态。
    • 集成监控仪表盘工具(如 Hystrix Dashboard)可以实时查看各个熔断器的状态和指标。

2. 基本使用方式

package main

import (
	"errors"
	"fmt"
	"github.com/afex/hystrix-go/hystrix"
	"log"
	"net/http"
	"testing"
	"time"
)

func Test_main(t *testing.T) {
	// 初始化流统计服务器
	hystrixStreamHandler := hystrix.NewStreamHandler()
	hystrixStreamHandler.Start()
	go http.ListenAndServe(":8074", hystrixStreamHandler)
	// 配置熔断器
	hystrix.ConfigureCommand("aaa", hystrix.CommandConfig{
		Timeout:                1000, // 单次请求 超时时间(ms)
		MaxConcurrentRequests:  1,    // 最大并发量,限流(基于token令牌,使用完会放回)
		SleepWindow:            5000, // 熔断后多久去尝试服务是否可用(ms)
		RequestVolumeThreshold: 1,    // 熔断器在评估跳闸前,需要至少统计的请求数
		ErrorPercentThreshold:  1,    // 验证熔断的 错误百分比
	})
	// 使用
	for i := 0; i < 10000; i++ {
		//异步调用使用 hystrix.Go
		err := hystrix.Do("aaa", func() error {
			//test case 1 并发测试
			if i == 0 {
				return errors.New("service error")
			}
			//test case 2 超时测试
			//time.Sleep(2 * time.Second)
			log.Println("do services")
			return nil
		}, func(err error) error {
			fmt.Println("短暂出现了错误,请让服务器休息一下")
			return err
		})
		if err != nil {
			log.Println("hystrix err:" + err.Error())
			time.Sleep(1 * time.Second)
			log.Println("sleep 1 second")
		}
	}
	time.Sleep(100 * time.Second)
}

3. hystrix-go dashboard

3.1 docker安装

https://github.com/mlabouardy/hystrix-dashboard-docker/tree/master
在这里插入图片描述
这里我的电脑不支持docker,但是我们发现这是一个jar包,我们可以尝试直接使用java -jar来启动即可。(请保证你的java版本为8即可)

3.2 使用教程

启动后输入:http://localhost:8080/hystrix即可进入界面
在这里插入图片描述
输入要监控的地址:http://localhost:8074
启动上面给的test代码:
即可看到效果:
在这里插入图片描述

4. 核心源码

4.1 流量统计

// DefaultMetricCollector 结构体保存了关于接口状态的各种指标信息。
// 这个 MetricCollector 的实现是关于接口的信息的标准来源。
// 它用于所有内部 hystrix 操作,包括接口健康检查和发送到 hystrix 仪表板的指标。
//
// Metric Collectors 不需要 Mutex 来保护,因为它们在受锁定的上下文内被接口更新。
type DefaultMetricCollector struct {
    mutex *sync.RWMutex // 用于控制并发访问的读写锁

    numRequests *rolling.Number // 请求总数
    errors      *rolling.Number // 错误数

    successes               *rolling.Number // 成功执行次数
    failures                *rolling.Number // 失败执行次数
    rejects                 *rolling.Number // 拒绝执行次数
    shortCircuits           *rolling.Number // 短路执行次数
    timeouts                *rolling.Number // 超时次数
    contextCanceled         *rolling.Number // 上下文取消次数
    contextDeadlineExceeded *rolling.Number // 上下文截止时间超过次数

    fallbackSuccesses *rolling.Number // 回退成功次数
    fallbackFailures  *rolling.Number // 回退失败次数
    totalDuration     *rolling.Timing // 总执行时间
    runDuration       *rolling.Timing // 实际执行时间
}

// Number 结构体跟踪一个有限数量时间桶的 numberBucket。
// 当前每个桶的时长为一秒钟,仅保留最近的 10 秒钟数据,新的数据会把旧的数据替换出去。
type Number struct {
	Buckets map[int64]*numberBucket // 存储时间桶数据的映射,int64表示时间,numberBucket表示并发量
	Mutex   *sync.RWMutex           // 用于并发访问控制的读写锁
}
type numberBucket struct {
	Value float64
}

4.2 流量控制

基于可放回的token实现了流量控制

type executorPool struct {
    Name    string        // 池子的名称
    Metrics *poolMetrics  // 池子的指标信息
    Max     int           // 最大并发请求数量
    Tickets chan *struct{} // 用于控制并发访问的通道,存放还在的token令牌
}

func newExecutorPool(name string) *executorPool {
    p := &executorPool{} // 创建 executorPool 结构体实例
    p.Name = name // 设置池子的名称
    p.Metrics = newPoolMetrics(name) // 初始化池子的指标信息
    p.Max = getSettings(name).MaxConcurrentRequests // 获取并设置最大并发请求数量
    p.Tickets = make(chan *struct{}, p.Max) // 初始化 Tickets 通道,缓冲大小为最大并发数
    
    for i := 0; i < p.Max; i++ {
        p.Tickets <- &struct{}{} // 在 Tickets 中预先放入最大并发数个空结构体指针
    }
    return p // 返回初始化后的 executorPool 实例
}

func (p *executorPool) Return(ticket *struct{}) {
    if ticket == nil {
        return // 如果票据为空,则直接返回
    }
    // 发送池子的更新指标信息到 Metrics 的 Updates 通道
    p.Metrics.Updates <- poolMetricsUpdate{
        activeCount: p.ActiveCount(), // 更新活跃任务数量
    }
    p.Tickets <- ticket // 将票据放回 Tickets 通道中
}

4.3 实时数据流

// 初始化流统计服务器
hystrixStreamHandler := hystrix.NewStreamHandler()
hystrixStreamHandler.Start()
go http.ListenAndServe(":8074", hystrixStreamHandler)

type StreamHandler struct {
	requests map[*http.Request]chan []byte//存放请求和对应的通道
	mu       sync.RWMutex
	done     chan struct{}
}

func (sh *StreamHandler) loop() {
    tick := time.Tick(1 * time.Second) // 创建一个每秒触发的定时器

    for {
        select {
        case <-tick:
            circuitBreakersMutex.RLock() // 获取断路器列表的读锁
            for _, cb := range circuitBreakers { // 遍历所有的断路器
                sh.publishMetrics(cb) // 发布断路器的指标信息
                sh.publishThreadPools(cb.executorPool) // 发布断路器关联的线程池信息
            }
            circuitBreakersMutex.RUnlock() // 释放断路器列表的读锁
        case <-sh.done:
            return // 如果收到 sh.done 通道的信号,结束循环
        }
    }
}


func (sh *StreamHandler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
    // 确保 writer 支持刷新操作。
    f, ok := rw.(http.Flusher)
    if !ok {
        http.Error(rw, "Streaming unsupported!", http.StatusInternalServerError)
        return
    }
    // 注册请求,获取事件通道。
    events := sh.register(req)
    defer sh.unregister(req)
    // 监听连接关闭通知。
    notify := rw.(http.CloseNotifier).CloseNotify()
    // 设置响应头部信息。
    rw.Header().Add("Content-Type", "text/event-stream")
    rw.Header().Set("Cache-Control", "no-cache")
    rw.Header().Set("Connection", "keep-alive")
    // 循环处理事件和通知。
    for {
        select {
        case <-notify:
            // 客户端断开连接。
            return
        case event := <-events:
            // 发送事件给客户端。
            _, err := rw.Write(event)
            if err != nil {
                return
            }
            f.Flush() // 刷新响应,确保事件立即发送给客户端。
        }
    }
}

所以当我们访问127.0.0.1:8074接口时就会不停的接受到实时数据流
在这里插入图片描述

5. 总结

hystrix-go 是一个用于实现断路器模式的类库,它是 Netflix 的 Hystrix 的 Go 语言实现版本。它主要用于分布式系统中的容错和弹性设计,特别是在处理微服务架构中的服务间调用时非常有用。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/751110.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

初学51单片机之长短键应用定时炸弹及扩展应用

51单片机RAM区域划分 51单片机的RAM分为两个部分&#xff0c;一块是片内RAM&#xff0c;一块是片外RAM。 data&#xff1a; 片内RAM从 0x00 ~0x7F 寻址范围&#xff08;0-127&#xff09; 容量共128B idata: 片外RAM从 0x00~0xFF 寻址范围(0-255) 容量共256B pdata&am…

ADC位数、增益调制与参考电压

位数&#xff1a;12bit、10bit、8bit 一般就是对应的ADC值分别为&#xff1a;4095、1023、255&#xff0c;也就选用对应位数时ADC的最大值。 增益的作用 增益设置用于放大或缩小输入信号&#xff0c;使其适配到ADC的输入范围。增益设置可以通过配置SAADC的通道配置寄存器来实…

java基于ssm+jsp 毕业生就业信息管理系统

1管理员功能模块 管理员输入个人的用户名、密码、角色登录系统&#xff0c;这时候系统的数据库就会在进行查找相关的信息&#xff0c;如果我们输入的用户名、密码不正确&#xff0c;数据库就会提示出错误的信息提示&#xff0c;同时会提示管理员重新输入自己的用户名、密码&am…

高通安卓12-安卓系统定制1

1.改变系统默认语言 从build/make/target/product/full_base.mk 2.修改开机图片 安卓原版操作方式 找到生成脚本&#xff1a;device\qcom\common\display\logo\logo_gen.py 其中readme.txt有操作说明 命令&#xff1a; sudo apt-get install python-imaging python ./logo_…

[AIGC] Doris:一款高效的MPP数据仓库引擎

在大数据处理的领域中&#xff0c;Apache Doris&#xff08;原百度 Palo&#xff09;是一个高效的MPP&#xff08;大规模并行处理&#xff09;数据仓库&#xff0c;最初由百度开发&#xff0c;现在已经成为Apache的孵化项目。 (图片取自百度) – 文章目录 1. Doris的基础知识…

RocketMQ:日常开发中有哪些使用MQ的场景

什么是消息队列&#xff1f; 消息队列是一种通信方法&#xff0c;允许应用程序通过发送和接收消息来互相通信。这些消息/任务/指令存储在一个中间介质中&#xff08;即队列&#xff09;&#xff0c;并由生产者发送&#xff0c;消费者接收。 使用场景 场景一&#xff1a;任务…

输出100以内的质数

质数&#xff1a;只能被1和自身整除的数 let count; for(let i2; i<100; i){for(let j1; j<i; j){if(i % j 0){// 只要能被整除&#xff0c;count就加1count;}} if(count 2) {// 从1到自身被整除完之后&#xff0c;如果count只有两次&#xff0c;则说明i为质数co…

【技巧】如何检查多个GPU之间是否支持P2P通信

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 需要用到cuda_samples&#xff1a;GitHub - NVIDIA/cuda-samples 该工具的详细解释可以看这个&#xff1a; 【知识】详细介绍 CUDA Samples 示例工程…

[数据集][目标检测]电力场景下电柜箱门把手检测数据集VOC+YOLO格式1167张1类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;1167 标注数量(xml文件个数)&#xff1a;1167 标注数量(txt文件个数)&#xff1a;1167 标注…

Leetcode Hot100之链表

1.相交链表 解题思路 快慢指针&#xff1a;分别求出两个链表的长度n1和n2&#xff0c;在长度较长的那个链表上&#xff0c;快指针先走n2 - n1&#xff0c;慢指针再出发&#xff0c;最后能相遇则链表相交 时间复杂度O(mn)&#xff0c;空间复杂度O(1)代码# Definition for singl…

白敬亭章若楠甜度报表的难哄大师

#白敬亭章若楠&#xff0c;甜度爆表的难哄大师#&#x1f389;&#x1f389;&#x1f389;各位小伙伴们&#xff0c;你们还记得那个让我们心跳加速、嘴角上扬的CP组合吗&#xff1f;没错&#xff0c;就是白敬亭和章若楠&#xff01;他们可是凭借一部新剧&#xff0c;再次让我们感…

520. 检测大写字母

题目 我们定义&#xff0c;在以下情况时&#xff0c;单词的大写用法是正确的&#xff1a; 全部字母都是大写&#xff0c;比如 “USA” 。单词中所有字母都不是大写&#xff0c;比如 “leetcode” 。如果单词不只含有一个字母&#xff0c;只有首字母大写&#xff0c;比如 “Go…

World of Warcraft [CLASSIC] plugin lua

World of Warcraft [CLASSIC] plugin lua 魔兽世界lua脚本插件 World of Warcraft API - Wowpedia - Your wiki guide to the World of Warcraft D:\World of Warcraft\_classic_\Interface\AddOns zwf.lua function CountdownFunc()CountdownFrame CreateFrame("Fram…

常见的字符串函数(包含头文件string.h)和字符函数(2)

八. strstr函数 1.strstr的定义 char *strstr( const char *str1, const char *str2 ); ->1. strstr查找子串(str2)在字符串(str2)中第一次出现的位置&#xff0c;记录并返回该位置的指针&#xff0c;如果找不到&#xff0c;则返回NULL ->2. str1&#xff1a;查找字符…

不用再找了,这是大模型实践最全的总结

随着ChatGPT的迅速出圈&#xff0c;加速了大模型时代的变革。对于以Transformer、MOE结构为代表的大模型来说&#xff0c;传统的单机单卡训练模式肯定不能满足上千&#xff08;万&#xff09;亿级参数的模型训练&#xff0c;这时候我们就需要解决内存墙和通信墙等一系列问题&am…

Mysql索引的实现原理,B+Tree,WAL

InnoDB 引擎&#xff0c;每一个数据表有两个文件 .frm和.ibd&#xff0c;分别为表结构&#xff0c;数据和索引&#xff0c;数据挂在主索引的叶子节点上&#xff0c;此主索引称为聚簇索引。 MyISAM 引擎&#xff0c;每一个数据表有三个文件.frm和.MYI和.MYD&#xff0c;分别为表…

测试报告-HTMLTestRunner报告优化(中/英文)

引用原始的HTMLTestRunner.py文件生成的测试报告在美观性不是很好&#xff0c;使用在此文件基础上优化后的HTMLTestReportCN.py文件(生成的报告为中文)、HTMLTestReportEN.py文件(生成的报告为英文)。 1 首先新建一个Python项目 例如&#xff1a;testHtmlReport 创建case包&am…

指纹浏览器是什么?跨境多账号安全如何保证?

随着电子商务的蓬勃发展&#xff0c;越来越多的商家选择开设多店来扩大经营规模。然而多店运营也带来了一系列的挑战&#xff0c;其中之一就是账号安全。 1. 了解反检测浏览器和代理服务器 在我们开始讨论如何有效地使用反检测浏览器之前&#xff0c;我们首先需要了解这两个工…

如何用亚马逊合作伙伴网络快速上线跨境电商

目前跨境电商已成为行业发展主流&#xff0c;如何快速、低成本打造品牌海外独立站和智能客服营销中心、构建全链路跨境电商体系是出海电商商家都会遇到的难题。亚马逊云科技凭借与亚马逊电商平台易于集成的先天优势成为首选的电商解决方案平台。本文介绍了如何用亚马逊云科技平…

SpringCloud分布式微服务链路追踪方案:Skywalking

一、引言 随着微服务架构的广泛应用&#xff0c;系统的复杂性也随之增加。在这种复杂的系统中&#xff0c;应用通常由多个相互独立的服务组成&#xff0c;每个服务可能分布在不同的主机上。微服务架构虽然提高了系统的灵活性和可扩展性&#xff0c;但也带来了新的挑战&#xf…