2024年9月

上一篇文章讲解述首次启动 ComfyUI 会自动打开一个最基础的文生图工作流。实际上,后续我们可以通过菜单选项,或者快捷键
ctrl + D
来打开这个默认工作流。默认工作流如下:

这是一个最基础的文生图工作流,本文通过对这个工作流的讲解,让大家对 ComfyUI 工作流有一个基本的认识。

一、文生图工作流核心节点

前面入坑铺垫这篇文章有推荐秋葉大佬的原理讲解视频,如果不了解也还没有看过的朋友,推荐去看看,传送门
B站秋葉大佬的视频

对原理有个大概了解的朋友应该知道,大模型是在潜空间处理图像的,人能识别的渲染出来的图片成为像素图。输入的条件信息,经过编码,传入潜空间,在潜空间里采样器去除噪波,最后在经过解码,输出像素图像。所以采样器是生成图片的最核心节点之一,下面就从采样器开始,依次介绍默认工作流中的节点。

1.1 【K采样器】

采样器节点有多种,默认工作流中d是最简单的
KSample
。下面说说 K采样器的参数:

  • 随机种子:每生成一张图就会显示该图的数值,默认为 0;可选项有每次随机、固定、每次递增、每次递减。
  • 步数:是指潜空间里的去除噪波迭代步数,一般设置为 25-40 左右。这个越大,所生成的图细节越多,但是生成图片需要的时间越长,并且一般超过 35 以后,则效果不是太明显,步数设置太小,则生成的图片一般质量越差。需要不断尝试,以确定每个大模型最适合的值。
  • CFG: 提示词相关性。参数越大,图片效果越接近提示词。参数越小,AI 发挥空间越大,图片效果与提示词差异越大。一般设置在 10 左右就好,默认为 8。
  • 采样器与调度器:采样器是与调度器结合一起使用的,采样器一般使用优化后/最新的采样器:euler_ancestral (简称 euler a)、dpmpp_2m 系列、dpmpp_3m 系列,调度器一般选择 normal 或 Karras
  • 降噪:降噪:和步数有关系,1 就是我们 100% 的按照上方输入的步数去完成,0.1 就是 10%,一般不用懂,默认填 1 就行。

1.2 【主模型加载器】

K采样器节点左边输入项,需要输入模型,所以需要添加一个主模型加载器,
Load Checkpoint
,。
主模型加载器只有一个参数,设置一个主模型。主模型的好坏决定了出图的整体质量,主要风格。
主模型加载器有三个输出项目,其中模型输出,就是 K 采样器的模型输入,需要把这两个点用线连接起来。

1.3 【Clip文本编码器】

K采样器左边的输入项需要正面条件和负面条件,所谓的正面条件就是通过指令,告诉采样器,我要生成的图包含什么元素,负面条件就是通过指令告诉采样器,我要生成的图不包含什么样的元素。既然是文生图,当然是通过输入文字提示词发送指令,注意这里的提示词必须是英文,(英文水平不好的同学也不要着急,后面会讲解翻译节点)。但是,正常输入的文字,不能直接被采样器识别使用,需要经过编码,转换成采样器能识别的指令。这里就是通过
CLIP Text Encode (Prompt) conditioning
进行编码。这里的两个 Clip 文本编码器作用是一样的,文本编码器,需要针对模型配合使用的,所以这里它的输入端,应该连接到主模型输出项的 Clip 点。Clip 文本编码器输出的条件,分别连接到 K 采样器输入端的正面条件和负面条件。

1.4 【空 Latent】

现在 K 采样器输入项还差一个 Latent, 这里有一个空 Latent 作为输入项。
Empty Latent Image
节点有三个参数,宽度、高度指定了潜空间生成图像的宽高,注意这里是单位是像素。批次大小,意思是一次生成多少张图片。

1.5 【VAE 解码】

K 采样器的左边输入项和参数都填完了,那 K 采样器生成图片之后需要输出结果,前面提到,潜空间里的图像是数字信号的形式,需要经过解码,转换成像素图像,这里就需要用到
VAE Decode

VAE 解码器有两个输入项, Latent 输入点连接到 K 采样器的输出点。
另一个 AVE 用到的模型,一般主模型都嵌入了VAE模型,连接到主模型即可,默认工作流中,就是直接连接到主模型加载器输出项的VAE。当然也可以自己主动加载额外的 VAE 模型。

1.6 【保存图像】

经过 VAE 解码后的图像,最后输出到
Save Image
节点可以预览,并保存。默认保存路径,在 ComfyUI 安装目录下的
output
文件夹,
该节点有一个参数,设置保存文件名的前缀。

二、ComfyUI 模型知识

2.1 模型后缀名的区别

模型的后缀名有很多。常见的有
.ckpt

.pt

.pth

.pkl

.safetensors
等。

CheckPoint 是一个概念,在模型训练过程中,不能保证一次就训练成功,中途可能会有各种因素导致失败,并且训练成功是一个伪概念,某些算法模型训练步数也不是越多越好,过多的训练会出现过拟合的情况。所以我们能做的是每训练一定的步数,保存一次训练结果,类似于存档。一方面使用某次训练的结果,觉得效果符合预期了,就可以停止训练了,最后将这个模型用于发布即可。另一方面,中途训练失败了,可以从某个 CheckPoint 继续开始训练。

  • .ckpt 是 checkpoint 的单词简写,仅仅是单词简写,不要认为 .ckpt 后缀的模型就是主模型,它俩没有关系。.ckpt 是 TensorFlow 中用于保存模型参数的格式。TensorFlow 是 Google 发布的深度学习框架。

  • .pt 是 PyTorch 保存模型参数的格式。PyTorch 是 Meta(facebook) 发布的深度学习框架。PyTorch 保存模型的格式,除了 .pt 之外还有.pth 和 .pkl。.pt 和 .pth 之间没有本质区别。而 .pkl 仅仅是多了一步使用 python 进行了序列化。

  • .safetensors 从名字可以看出,该格式更加安全。前面提到,可以从某个 CheckPoint 恢复训练,则需要在该 .ckpt 模型中保存了一些训练信息,比如模型的权重,优化器的状态,Python 代码等等,这就容易造成信息泄露,同时容易被植入恶意代码。所以 .ckpt 模型存在不安全因素,同时体积会比较大。.safetensors 是 huggingface 推出的新的模型存储格式,专门为 StableDiffusion 设计的,它只包含模型权重信息,模型体积更小,更加安全,加载速度也更快,通常用于模型的最终版本。而 .ckpt 模型适合用于对模型的微调、再训练。

2.2 模型的分类

ComfyUI 中用到的模型种类非常之多,为了方便理解和学习,我们可以对模型进行分类,大致可以分为以下几类:
1. checkpoint
主模型、大模型、底模、基础模型等。通过特定训练最终形成的一个保持该领域特征的一种综合算法合集,可以精准的匹配你的需求。比如摄影写实模型、3D模型、二次元模型、室内设计模型等等。Checkpoint 的训练难度大,需要的数据集大,生成的体积也较大,动则占用几个G的磁盘空间。
2. Lora
Lora 模型作为大模型的一种补充,能对生成的图片进行单一特征的微调,比如生成的人物图片具有相同的人脸特征、穿着特定服装、具备特定画风等等。Lora 模型体积较小,一般几十几百兆, 个人主机就可训练自己需要的 Lora 模型。
3. VAE
VAE 模型可以当作滤镜,目前针对 Stable Diffusion 主流的 VAE 模型有两个,二次元使用
kl-f8-anime2VAE
, 写实风格使用
vae-ft-mse-840000-ema-pruned

4. EMBEDDING
文本嵌入模型,应用于提示词中,是一类经过训练的提示词合集,主要用来提升画质,规避一些糟糕的画面。比如:
badhandv4

Bad_picture

bad_prompt

NG_Deep Negative

EasyNegative
,这些是经常用到的反向提示词嵌入模型,可以单独使用或者组合使用。
5. 其它
比如 controlnet模型、ipadapter模型、faceswap 模型、放大模型等等

对于 Stable Diffusion 的模型,现在也有了众多版本。常见版本有 SD1.5、SD2.0/2.1、 SDXL,其中 SDXL 模型生成的图片质量最高,相应地对硬件要求也相对高一点,而 SD1.5 生态最完善,这两个版本使用的最多。
需要强调的一点是:使用时,不同类型模型的版本需要对应上,比如主模型选择的是 SDXL 版本,Lora 使用 SD1.5 模型是无法正常运行的。

2.3 模型的存放路径

ComfyUI 的安装目录中有专门存放模型的文件夹。只需要将下载下来的模型放到对应的文件夹下。

2.4 模型的下载地址

推荐两个主流的模型下载地址:
C 站:
https://civitai.com/
抱脸:
https://huggingface.co/

这两个网站中能下载到任何你想要的模型。
C 站查找模型可以过滤分类

2.5 模型的架构

常见的的模型的架构分类:

Latent Diffusion 模型架构分类

文本编码 去噪扩散 编码解码 变体
SD1.5 CLIP UNET VAE
SDXL ClipL/ClipG UNET VAE Kolors/Pony/Playground
SD3 ClipL/ClipG/T5 Dit VAE DIT混元/AuraFlow/Flux

SD 快速模型

LCM Turbo Lightning
Latent Consistency Models 潜在一致性模型,清华大学研发的一款新一代生成模型,图像生成速度提升 5-10 倍,LCM-SD1.5、LCM-SDXL、LCM-Lora、Animatediff LCM、 SVD LCM 官方在 SDXL1.0基础上采用了新的蒸馏方案,1-4 步就可以生成高质量图像,网络架构与 SDXL 一致。只适用于 SDXL, SD1.5无该类型模型 字节跳动在 SD1.0 基础上结合渐进式对抗蒸馏提炼出来的扩散蒸馏方法,本质上也是 SDXL 模型

关于模型架构的知识比较复杂,我也只是浅浅的了解。不懂这部分,对使用 ComfyUI 绘图影响不大,但是了解这些架构信息,对模型的兼容性方面会有一定的认识,有助于解决后面在使用过程中因模型版本、兼容性导致的问题。

三、其它常用节点简单介绍

插件的安装方法上一篇文章已经介绍过,不清楚的可以先去看看。

3.1 汉化插件 AIGODLIKE-COMFYUI-TRANSLATION

使用秋叶整合包,默认是安装了汉化节点的。作用是将菜单、设置等界面元素汉化。安装完汉化节点后,重启 ComfyUI ,然后再在设置中找到语言栏,切换为中文即可。

3.2 提示词翻译插件 ComfyUI_Custom_Nodes_AlekPet

前面提到,Clip 文本编码器需要输入英文提示词。如果英文不好,则可以安装提示词翻译插件。

使用方式:

  1. 鼠标放在 Clip 文本编码器节点上,右键 -> 转换为输入 -> Convert text to input。
    将参数转换成输入节点。

  2. 新建一个提示词翻译节点。
    在空白处,右键 -> 新建节点 -> Alek 节点 -> 文本 -> 翻译文本(高级)

    或者,在空白处双击左键,输入
    tanslate
    会自动匹配出节点,选择正确的节点。

  3. 将提示词翻译节点与 Clip 文本编码器连接起来

这样我们就可以在在提示词翻译节点中填入中文提示词。需要注意的是,该提示词翻译插件使用的是 Google 翻译,需要外网环境。

使用技巧:

  • 节点是可以复制粘贴的。比如需要对负面提示词添加同样的节点,直接复制一个就可以了。

3.3 元节点 primitive

图中分别表示小数、文本、布尔值、整数、多行文本。
元节点,简单来说就是把原始输入数据原封不动输出。那这样有什么作用呢,最典型的就是复用。

重要说明:一个节点的输入点只能有一个,但是输出点可以有多个。

使用技巧:
所有节点的参数和正向节点组件输入都是可以相互转化的。很多时候可以把相同的参数,转换为输入节点,然后用共同的元组件输入。

3.4 预览图像节点 Preview Image

前面说到保存图像节点,会自动保存到 output 文件夹下面,有时候我们只是想看看图片是什么样,并不想保存。比如中间过程的图片,或者不确定图片是否使我们想要的。这时候可以使用预览图像节点。

后记

本文从默认文生图工作流入手,介绍了其中的核心节点。同时介绍了 Stable Diffusion 中的模型分类。更多节点使用,将在后续文章中介绍,敬请关注。

在软件开发和测试过程中,我们经常会遇到需要对网络请求进行录制和回放的需求,以便进行调试、测试和分析。为了模拟真实的用户请求,我们通常会使用各种流量录制回放工具来记录并重放网络请求。

其中,
jvm-sandbox-repeater
是一款功能强大的流量录制回放工具,可以帮助我们轻松实现对网络请求的录制和回放。

1、介绍

jvm-sandbox-repeater
是一个基于
JVM-Sandbox
采用Java来实现的流量录制回放工具,或者可以理解为它是一个基于Java虚拟机的插件,可以直接运行中JVM中,无需对目标应用程序进行任何修改。

它可以在运行时自动拦截和记录 Java 应用程序的网络请求和响应。它是利用
JVM Sandbox
的字节码增强技术,对Java应用进行无侵入式的流量录制和回放。这意味着通过使用
jvm-sandbox-repeater
,我们可以在不修改源代码的情况下,即可轻松实现流量的录制和回放功能。

2、功能特性

jvm-sandbox-repeater 的主要功能特性包括有:

  • 无侵入式录制
    :jvm-sandbox-repeater 通过 JVM-Sandbox字节码增强技术,在运行时对Java应用进行录制,在运行时自动拦截和记录网络请求,无需对源代码进行任何修改。

  • 支持多种协议
    :jvm-sandbox-repeater 支持多种网络协议,包括HTTP/HTTPS、gRPC、Dubbo、TCP 等多种协议的拦截和记录。

  • 灵活的配置
    :jvm-sandbox-repeater 提供了丰富的配置选项,可以根据需要对录制和回放的行为进行定制。

  • 高性能
    :jvm-sandbox-repeater 基于 JVM-Sandbox 技术,具有较低的性能损耗,对应用程序的影响较小。

  • 高精度录制
    :该工具能够精确记录请求和响应的详细信息,包括请求头、请求体、响应状态码、响应体等,确保回放的准确性。

  • 灵活的回放策略
    :支持多种回放策略,如按照时间顺序回放、并发回放等,满足不同的测试需求。

  • 可视化界面
    :提供易于使用的可视化界面,方便用户进行流量的录制、管理和回放操作,降低使用门槛。

  • 高扩展性
    :基于JVM Sandbox平台,易于与其他工具进行集成和扩展。

3、应用场景

在工作中使用
jvm-sandbox-repeater
工具,主要就是借用其中的三类基本能力:

  • 流量录制
    :jvm-sandbox-repeater 可以实时捕获目标应用程序的网络请求,并将其记录下来。通过录制功能,获取目标应用程序的实际网络请求数据,用于后续的分析和调试。

  • 流量回放
    :jvm-sandbox-repeater 支持对录制的网络请求进行回放。通过回放功能,模拟目标应用程序的网络请求,以验证其正确性和稳定性。

  • 请求修改
    :jvm-sandbox-repeater 允许开发人员对录制的网络请求进行修改。通过修改功能,调整网络请求的参数和头部信息,以模拟不同的场景和测试用例。

借助上述这三类基本能力,在测试开发工作中,常用于如下场景应用:

  • 接口测试
    :通过录制生产环境的真实接口流量,在测试环境中进行回放,可以模拟各种复杂场景,验证接口的稳定性和性能。
  • 性能测试
    :利用录制的流量数据进行性能测试,能够更真实地反映系统的性能表现,帮助发现和解决性能瓶颈。
  • 兼容性测试
    :通过在不同版本的Java应用或不同环境下回放录制的流量,可以验证系统的兼容性。

4、原理一:JVM-Sandbox技术是如何工作的?

jvm-sandbox-repeater
是一个基于
JVM-Sandbox
实现的流量回放工具,但估计很多读者,对于JVM-Sandbox是什么,以及它是如何工作的还不太清楚,这里扩展一下。

JVM-Sandbox简单来说,它是一款Java应用沙箱,旨在为Java应用程序提供一个隔离、安全的运行环境。沙箱(Sandbox)技术的主要目的是保护系统安全和稳定性,同时提供更好的应用程序开发和测试环境。通过隔离程序运行的环境,沙箱技术可以防止程序访问到不应访问的资源和数据,从而降低安全风险。

JVM-Sandbox的工作原理可以概括为以下几个关键步骤:

1、类加载
:在JVM沙箱中,所有的类都由Java虚拟机的类加载器加载。类加载器负责从文件系统、网络或其他来源加载Java类,并将其转换为可执行代码。

2、字节码验证
:加载过程中,JVM会对字节码进行验证,以确保其符合Java语言规范。这一步骤的目的是检测潜在的安全漏洞,如类型转换错误、数组越界访问等。

3、安全检查
:经过字节码验证后,JVM会进一步进行安全检查,限制应用程序的行为,防止对系统造成危害。这包括对应用程序的访问权限和资源使用进行限制,例如文件系统访问、网络访问、系统调用等。

4、沙箱执行
:一旦通过了字节码验证和安全检查,JVM会将应用程序放入一个受控的沙箱环境中执行。这个沙箱环境限制了应用程序对系统资源的访问,确保它只能在限定的范围内执行。

此外,
JVM-Sandbox
还利用虚拟化技术创建隔离环境,并通过字节码增强将被mock(模拟)的方法添加到隔离环境中。当这些方法被调用时,JVM-Sandbox通过反射机制查找它们,并使用代理对象将其转发给沙箱中的虚拟机执行。执行完毕后,结果会返回给主程序。

5、原理二:字节码增强技术又是啥?

字节码增强技术
是一种对Java字节码进行修改以增强其功能的技术。它主要是在Java字节码生成之后,通过读取和修改字节码文件,实现对类、方法、字段等元素进行增强。这种技术相当于对应用程序的二进制文件进行修改,主要目的是减少冗余代码,提高性能等。

字节码增强的主要步骤包括:

  • 修改字节码
    :在内存中获取到原来的字节码,然后通过一些工具(如ASM、Javassist)来修改它的byte[]数组,得到一个新的byte数组。
  • 使修改后的字节码生效
    :这可以通过两种方法实现:一是自定义ClassLoader来加载修改后的字节码;二是在JVM加载用户的Class时,拦截并返回修改后的字节码,或者在运行时,使用Instrumentation.redefineClasses方法来替换掉原来的字节码。

字节码增强技术的应用非常广泛,例如可以用于APM(应用性能管理)工具,监控和管理应用软件性能和可用性,保证软件应用程序的正常运行;还可以用于Java问题定位工具,如BTrace

6、安装、使用

1. 下载或引入依赖

首先,你需要从 jvm-sandbox-repeater 的官方网站或 GitHub 仓库下载最新版本的插件 jar 文件。

或者直接在项目的 pom.xml 文件中添加 jvm-sandbox-repeater 的依赖:

<dependency>
    <groupId>com.github.jvm-sandbox-repeater</groupId>
    <artifactId>jvm-sandbox-repeater</artifactId>
    <version>最新版本</version>
</dependency>

2. 配置 Sandbox

将 jvm-sandbox-repeater 插件添加到 JVM 中,将下载的 jvm-sandbox-repeater 插件 jar 文件添加到目标应用程序的类路径中,或者通过 Javaagent 参数将其添加到 JVM 中。

在项目的启动参数中添加以下配置,启用 JVM-Sandbox 和 jvm-sandbox-repeater:

java -javaagent:path/to/jvm-sandbox-repeater.jar=config.yaml -jar your-application.jar

其中,config.yaml 是 jvm-sandbox-repeater 的配置文件,配置 jvm-sandbox-repeater 的相关参数,比如录制文件保存路径、回放速度等可以根据实际情况进行修改。

3. 编写配置文件

创建一个名为 config.yaml 的文件,用于配置 jvm-sandbox-repeater。以下是一个简单的示例:

repeater:
  enabled: true
  recordDir: /path/to/record/dir
  replayDir: /path/to/replay/dir
  filter:
    classes:
      - com.example.service.*
    methods:
      - com.example.service.UserService.getUserInfo

在这个示例中,我们启用了 jvm-sandbox-repeater,并指定了录制和回放的目录。同时,我们还定义了一个过滤器,只对 com.example.service 包下的 UserService 类的 getUserInfo 方法进行录制和回放。

4. 录制和回放

在目标应用程序运行时,jvm-sandbox-repeater 会实时捕获网络请求,并将其记录到指定的录制文件夹中。当需要回放请求时,可以使用 jvm-sandbox-repeater 提供的命令行工具或 API 进行操作。

# 录制请求
java -jar jvm-sandbox-repeater.jar record -c config.yaml

# 回放请求
java -jar jvm-sandbox-repeater.jar replay -c config.yaml

或者,你也可以在代码中使用 jvm-sandbox-repeater 提供的 API 进行录制和回放。以下是一个简单的示例:

import com.github.jvm.sandbox.repeater.Repeater;
import com.github.jvm.sandbox.repeater.Recorder;
import com.github.jvm.sandbox.repeater.Replayer;

public class MyApp {
    public static void main(String[] args) {
        // 初始化 Repeater
        Repeater repeater = new Repeater();
        repeater.init();

        // 开始录制请求
        Recorder recorder = repeater.startRecording();
        recorder.record("http://example.com/api/user", "GET");

        // 停止录制请求
        recorder.stopRecording();

        // 开始回放请求
        Replayer replayer = repeater.startReplaying();
        replayer.replay("http://example.com/api/user", "GET");

        // 停止回放请求
        replayer.stopReplaying();
    }
}

通过以上步骤,你可以使用 jvm-sandbox-repeater 对 Java 应用程序进行流量录制和回放。

5. 查看与分析结果

在回放过程中或回放结束后,可以通过jvm-sandbox-repeater提供的可视化界面查看回放的状态、结果以及性能数据等,进行结果分析。

7、总结

总的来说,
jvm-sandbox-repeater
是一款功能强大、易于使用的流量录制回放工具,可以帮助开发人员或测试人员轻松地实现对网络请求的录制和回放。通过
jvm-sandbox-repeater
,我们可以更加高效地进行调试、测试和分析,提高软件开发测试的效率和质量。如果你正在寻找一款优秀的流量录制回放工具,不妨试试
jvm-sandbox-repeater
,相信它会给你带来意想不到的惊喜!

jvm-sandbox-repeater
的项目源码:

git clone https://github.com/alibaba/jvm-sandbox-repeater.git

1.问题背景

GaussDB轻量化分布式集群安装完成后,进行
openssh和openssl升级,现有环境openssh-8.2p1-9.p03.ky10.x86_64和openssl-1.1.1f-2.ky10.x86_64版本,可以安装数据库,然后升级这两个版本到openssh-8.2p1-9.p15.ky10.x86_64和openssl-1.1.1f-4.p17.ky10.x86_64。

对集群安装完成后的命令测试,启停机群节点都没问题,然后但是被协调节点被剔除以后,修复出现了这个故障,出现了报错,跟第一次安装的集群出现了一样的问题,报错截图如下:

集群状态如下,有一个
CN节点显示被剔除,集群状态变为降级,DN正常,集群仍为可用状态

2.
进行
openssh和openssl版本规避

修改说明:

1. 修改GaussDB(DWS) 的环境变量文件/opt/huawei/Bigdata/mppdb/.mppdbgs_profile, 调整LD_LIBRARY_PATH变量执行
修改前:
[omm@redhat
-4 ~]$ cat /opt/huawei/Bigdata/mppdb/.mppdbgs_profile | grep -inLD_LIBRARY_PATH5:export LD_LIBRARY_PATH=$GPHOME/lib:$LD_LIBRARY_PATH7:export LD_LIBRARY_PATH=$GPHOME/lib/libsimsearch:$LD_LIBRARY_PATH11:export LD_LIBRARY_PATH=$GAUSSHOME/lib:$LD_LIBRARY_PATH12:export LD_LIBRARY_PATH=$GAUSSHOME/lib/libsimsearch:$LD_LIBRARY_PATH

修改后
:

[omm@redhat-4 ~]$ cat  /opt/huawei/Bigdata/mppdb/.mppdbgs_profile  | grep -inLD_LIBRARY_PATH5:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$GPHOME/lib7:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$GPHOME/lib/libsimsearch11:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$GAUSSHOME/lib12:export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$GAUSSHOME/lib/libsimsearch
增加内容如下:
export LD_LIBRARY_PATH
=/lib64:$LD_LIBRARY_PATH2. 在/etc/profile中增加LD_LIBRARY_PATH变量。其中/lib64为ssh二进制工具的依赖库路径。
增加内容如下:
export LD_LIBRARY_PATH
=/lib64:$LD_LIBRARY_PATH

3.重新修复CN

3.1重新进行
gs_replace
修复协调节点,但是有其他报错

[omm@DN01 ~]$ gs_replace -t config -h DN02
Checking all the cm_agent instances.
There are [
0] cm_agents need to be repaired incluster.
Fixing all the CMAgents instances.
Checking and restoring the secondary standby instance.
The secondary standby instance does not need to be restored.
Configuring
Waiting
forpromote peer instances.
.
Successfully upgraded standby instances.
Configuring replacement instances.
Successfully configured replacement instances.
Deleting abnormal CN
frompgxc_node on the normal CN.
No abnormal CN needs to be deleted.
Unlocking cluster.
Successfully unlocked cluster.
Locking cluster.
Successfully locked cluster.
Unlocking cluster.
Successfully unlocked cluster.
Creating all
fixedCN on the normal CN.
No CN needs to be created.
Warning: failed to turn off O
&M management. Please re-execute "cm_ctl set --maintenance=off"once again.
[GAUSS
-51400] : Failed to execute the command: source /opt/huawei/Bigdata/mppdb/.mppdbgs_profile ; cm_ctl set --maintenance=on -n 2. Error:
cm_ctl: Starting to enable the maintenance mode.
cm_ctl: Close maintenance mode on cm instances.
cm_ctl: Close maintenance mode on cm instances failed.

3.2 执行如上面报错提示

[omm@DN01 ~]$ source /opt/huawei/Bigdata/mppdb/.mppdbgs_profile
[omm@DN01
~]$
[omm@DN01
~]$ cm_ctl set --maintenance=on -n 2cm_ctl: Starting to enable the maintenance mode.
cm_ctl: Close maintenance mode on cm instances.
cm_ctl: Close maintenance mode on cm instances failed.

3.3 查看日志

[omm@DN01 ~]$ cd $GAUSSLOG/bin/cm_ctl
[omm@DN01 cm_ctl]$ less cm_ctl
-2024-07-13_191612-current.log

报错截图如下:

3.4三节点移除pssh文件

[omm@DN01 cm_ctl]$ sudo mv /usr/bin/pssh /usr/bin/pssh.bak
[omm@DN02 cm_ctl]$ sudo mv
/usr/bin/pssh /usr/bin/pssh.bak
[omm@DN03 cm_ctl]$ sudo mv
/usr/bin/pssh /usr/bin/pssh.bak

3.5重新调用提示命令

[omm@DN01 cm_ctl]$ cm_ctl set --maintenance=on  -n 2cm_ctl: Starting to enable the maintenance mode.
cm_ctl: Close maintenance mode on cm instances.
cm_ctl: Close maintenance mode on cm instances successfully.
cm_ctl: Generate and distribute the maintenance white
-list file.
cm_ctl: Generate and distribute the maintenance white
-list file successfully.
cm_ctl: Set maintenance mode on related cm instances.
cm_ctl: Set maintenance mode on related cm instances successfully.
cm_ctl: Reload configuration on related cm instances.
cm_ctl: Reload configuration on related cm instances successfully.
cm_ctl: Query the maintenance mode
fromthe primary cm server.
cm_ctl: Enable the maintenance mode successfully.

The following nodes enter the maintenance mode:
node_2

3.6 重新调用gs_replace

[omm@DN01 cm_ctl]$ gs_replace -t config -h DN02
Checking all the cm_agent instances.
There are [
0] cm_agents need to be repaired incluster.
Fixing all the CMAgents instances.
Checking and restoring the secondary standby instance.
The secondary standby instance does not need to be restored.
Configuring
Waiting
forpromote peer instances.
.
Successfully upgraded standby instances.
Configuring replacement instances.
Successfully configured replacement instances.
Deleting abnormal CN
frompgxc_node on the normal CN.
No abnormal CN needs to be deleted.
Unlocking cluster.
Successfully unlocked cluster.
Locking cluster.
Successfully locked cluster.
Incremental building CN
fromthe Normal CN.
Successfully incremental built CN
fromthe Normal CN.
Creating
fixedCN on the normal CN.
Successfully created
fixedCN on the normal CN.
Starting the
fixedcns.
Successfully started the
fixedcns.
Creating
fixed CN on the fixedCN.
Successfully created
fixed CN on the fixedCN.
Unlocking cluster.
Successfully unlocked cluster.
Creating unfixed CN on the
fixedand normal CN.
No CN needs to be created.
Configuration succeeded.

3.7 gs_replace启动CN

[omm@DN01 cm_ctl]$ gs_replace -t start -h DN02
Starting.
======================================================================.
Successfully started instance process. Waiting to become Normal.
====================================================================== ======================================================================Start succeeded.

3.8集群balanced操作

[omm@DN01 cm_ctl]$ gs_om -t switch --reset
Operating: Switch reset.
cm_ctl: cmserver
isrebalancing the cluster automatically.
.......
cm_ctl: switchover successfully.
Operation succeeded: Switch reset.

3.9集群状态

集群修复

[omm@DN01 cm_ctl]$ gs_om -t status --detail
[ CMServer State ]

node node_ip instance state
--------------------------------------------------------------------------- 1 DN01 10.254.21.75 1 /opt/huawei/Bigdata/mppdb/cm/cm_server Primary3 DN03 10.254.21.77 2 /opt/huawei/Bigdata/mppdb/cm/cm_server Standby

[ Cluster State ]

cluster_state : Normal
redistributing : No
balanced : Yes

[ Coordinator State ]

node node_ip instance state
-------------------------------------------------------------------------- 1 DN01 10.254.21.75 5001 /srv/BigData/mppdb/data1/coordinator Normal2 DN02 10.254.21.76 5002 /srv/BigData/mppdb/data1/coordinator Normal3 DN03 10.254.21.77 5003 /srv/BigData/mppdb/data1/coordinator Normal

[ Central Coordinator State ]

node node_ip instance state
------------------------------------------------------------------------- 3 DN03 10.254.21.77 5003 /srv/BigData/mppdb/data1/coordinator Normal

[ GTM State ]

node node_ip instance state sync_state
--------------------------------------------------------------- 3 DN03 10.254.21.77 1001 /opt/huawei/Bigdata/mppdb/gtm P Primary Connection ok Sync1 DN01 10.254.21.75 1002 /opt/huawei/Bigdata/mppdb/gtm S Standby Connection ok Sync

[ Datanode State ]

node node_ip instance state
| node node_ip instance state |node node_ip instance state-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 1 DN01 10.254.21.75 6001 /srv/BigData/mppdb/data1/master1 P Primary Normal | 2 DN02 10.254.21.76 6002 /srv/BigData/mppdb/data1/slave1 S Standby Normal | 3 DN03 10.254.21.77 3002 /srv/BigData/mppdb/data1/dummyslave1 R Secondary Normal1 DN01 10.254.21.75 6003 /srv/BigData/mppdb/data2/master2 P Primary Normal | 3 DN03 10.254.21.77 6004 /srv/BigData/mppdb/data1/slave2 S Standby Normal | 2 DN02 10.254.21.76 3003 /srv/BigData/mppdb/data1/dummyslave2 R Secondary Normal2 DN02 10.254.21.76 6005 /srv/BigData/mppdb/data1/master1 P Primary Normal | 3 DN03 10.254.21.77 6006 /srv/BigData/mppdb/data2/slave1 S Standby Normal | 1 DN01 10.254.21.75 3004 /srv/BigData/mppdb/data1/dummyslave1 R Secondary Normal2 DN02 10.254.21.76 6007 /srv/BigData/mppdb/data2/master2 P Primary Normal | 1 DN01 10.254.21.75 6008 /srv/BigData/mppdb/data1/slave2 S Standby Normal | 3 DN03 10.254.21.77 3005 /srv/BigData/mppdb/data2/dummyslave2 R Secondary Normal3 DN03 10.254.21.77 6009 /srv/BigData/mppdb/data1/master1 P Primary Normal | 1 DN01 10.254.21.75 6010 /srv/BigData/mppdb/data2/slave1 S Standby Normal | 2 DN02 10.254.21.76 3006 /srv/BigData/mppdb/data2/dummyslave1 R Secondary Normal3 DN03 10.254.21.77 6011 /srv/BigData/mppdb/data2/master2 P Primary Normal | 2 DN02 10.254.21.76 6012 /srv/BigData/mppdb/data2/slave2 S Standby Normal | 1 DN01 10.254.21.75 3007 /srv/BigData/mppdb/data2/dummyslave2 R Secondary Normal

3.10正常状态数据库环境变量

[root@DN01 ~]# tail -5f /etc/profile
fi
#TMOUT
=600export TMOUT=0#LD_LIBRARY_PATH=/usr/local/lib/export LD_LIBRARY_PATH=/lib64:$LD_LIBRARY_PATH
[omm@DN01 ~]$ cat .bash_profile
# Source
/root/.bashrc ifuser has one
[
-f ~/.bashrc ] && . ~/.bashrc
source
/home/omm/.profile

LD_LIBRARY_PATH
=/usr/local/lib/export LD_LIBRARY_PATH=/lib64:$LD_LIBRARY_PATH
[omm@DN01 ~]$ cat /opt/huawei/Bigdata/mppdb/.mppdbgs_profile
#LD_LIBRARY_PATH
=/usr/local/lib
export MPPDB_ENV_SEPARATE_PATH
=/opt/huawei/Bigdata/mppdb/.mppdbgs_profile
export LDAPCONF
=/opt/huawei/Bigdata/mppdb/ldap.conf
export GPHOME
=/opt/huawei/Bigdata/mppdb/wisequery
export PATH
=$PATH:$GPHOME/script/gspylib/pssh/bin:$GPHOME/script
export LD_LIBRARY_PATH
=$LD_LIBRARY_PATH:$GPHOME/lib
export LD_LIBRARY_PATH
=$LD_LIBRARY_PATH:$GPHOME/lib/libsimsearch
export PYTHONPATH
=$GPHOME/lib
export GAUSS_WARNING_TYPE
=1export GAUSSHOME=/opt/huawei/Bigdata/mppdb/core
export PATH
=$GAUSSHOME/bin:$PATH
export S3_CLIENT_CRT_FILE
=$GAUSSHOME/lib/client.crt
export GAUSS_VERSION
=8.2.1export PGHOST=/opt/huawei/Bigdata/mppdb/mppdb_tmp
export GS_CLUSTER_NAME
=FI-MPPDB
export GAUSSLOG
=/var/log/Bigdata/mpp/omm
export LD_LIBRARY_PATH
=$LD_LIBRARY_PATH:$GAUSSHOME/lib
export LD_LIBRARY_PATH
=$LD_LIBRARY_PATH:$GAUSSHOME/lib/libsimsearch
export ETCD_UNSUPPORTED_ARCH
=386 if [ -f '/opt/huawei/Bigdata/mppdb/core/utilslib/env_ec' ] && [ `id -u` -ne 0 ]; then source '/opt/huawei/Bigdata/mppdb/core/utilslib/env_ec'; fi
export GAUSS_ENV
=2export LD_LIBRARY_PATH=/lib64:$LD_LIBRARY_PATH

再过半年就40岁了,人到中年的我,正在经历着职业生涯中最大的一次坎坷,我失业了。24年的3月份,我上了公司的裁员名单,经过一个月的拉扯,在4月初,我收拾收拾东西,离开了公司,正式进入了失业大军。距离现在已经半年多了,在这半年里,我有很多的尝试,也有很多的感受,就和大家聊一聊吧。

离职谈判

最近两年公司一直在裁员,基本上半年就要走一拨。最开始是和外包终止合作,然后是各种裁员,甚至技术的高管也裁了四五个人,同事都说最后都要走向被裁的道路,所以公司主动离职的人很少。这次自己被裁也在意料之中,不过真到被裁的时候,心里也不是滋味儿。刚开始人力找我谈的时候,说只有N+1的补偿,未休年假折换成工资,其他的就没有了。我想,公司也太能算计了,要在3月底之前把我干掉,这样就不用给我年终奖了。这里要说明一下,公司去年刚上市,所以一个完整财年是4月份到次年3月份,所以年终奖的计算也要截至到3月底。公司发布的年终考核明确说了,考核周期结束前离职是没有年终奖的。公司要在3月份之前干掉我,明显是想省下年终奖的钱。这我是绝对不能同意的,要拖也要拖过3月份,我也明确和人力说了,要不公司强制辞退我,要不过了3月份再说。公司的人力也不是很强硬,和我说公司没有强制辞退的意思,这不是和您在协商吗?我说,要是协商的话,这个条件我不能同意。说完我就离开会议室,回到工位继续工作了。
这里和大家普及个知识吧:大家平时说的N+1都是__协商离职__,协商的意思大家都懂吧,就是双方商量,双方都同意。所以在和人力谈的时候,对自己不利的条件要坚决不同意。另外一种就是强制辞退了,这种情况最好办,去劳动仲裁拿2N就可以了。
之后,公司又找我谈了两三次,我都坚持要过了3月份,拿了年终奖再走。在这期间,我也在收集一些证据,以便在劳动仲裁时使用。甚至我都已经在劳动仲裁网上提交了资料,保存为草稿了,如果公司和我玩硬的,我就直接点提交,立刻走劳动仲裁。最后公司也没有为难我,答应了我的要求。也是,4月初,我离开了公司,回家了。

在这家公司工作了3年多,公司里的同事都是985211毕业的,虽然他们的学历都很高,但是感觉书生气太重,无论是刚毕业工作两三年的,还是工作了10多年的,还是没有摆脱身上的学生气,我在他们中间显得格格不入。既然从学校毕业了,开始混社会了,就要用社会人的规则,身上那股学生气该去掉就去掉吧。很多大厂里,都用“某某同学”称呼对方,即使被裁了,也用“毕业”,这就是这些大厂要保留大家的学生气、书生气,这样便于管理,如果大家都是社会人,混社会的,那这些大厂的管理成本要大幅提高了。哈哈,这可能也是中国教育的悲哀吧,想想100年前,那群有学问有知识的年轻人,哪个不是一身的阳刚之气。

社会工作者

在离职前的一段时间里,我在晚上没事儿刷着某音,经常刷到考社会工作者证的视频,说考下社会工作者证,到社区上班,工作稳定,朝九晚五不加班,平时上班也没啥事,还不耽误接孩子上下学,考试很简单,都是选择题。这确实让我很心动,虽然钱不多,但是够吃够喝了,事少离家近,还能接孩子上下学,于是我就报名了。真正报完名,已经是4月中旬了,考试是在6月中旬,还有两个月的时间,要考3门课。在这两个月的时间里,我整天在网上看课程的视频,刷题。真正学习起来,发现这个考试并不容易,这也是一个国家级的考试,据说通过率只有7%,难度确实不小,并不像某音里说的那样。就这样被套路了一回,最后我也是只过了两门,剩下的那门只能来年再考了。

这两个月的时间,应该是我失业后最失落了一段时间,这段时间整天刷boss,投简历,基本上都是已读不回。北京的JAVA行情是要崩了吗?记得口罩前还不是这个样子,boss都是主动联系你的。而现在你主动投,人家都懒得搭理你,这是大环境的原因吗?还是自己的原因?干了这么多年,自己在技术上,管理上都是挺不错的。难道是年龄的原因?哎,不管什么原因吧,用辩证法分析,就是内因和外因。继续投简历继续找工作,慢慢碰吧。

尝试接私活

社工考试失利后,我想在今年找工作比较困难的情况下,是不是可以尝试做一些其他的事情。自认为技术能力不错的我,在几个比较大的接单平台注册了账号,尝试接单。不久平台就给我推了一个单子,让我自己去聊,说需求很笼统。于是我和对方联系了一下,发现对方离我住的地方不远,我们就约好了线下聊,线下见面后,我才了解到,对方要做的是一套部队用的系统,目前只有一个系统要求,具体的需求没有,只有一些目录菜单。我和对方说,您还是细化需求吧,这个现在进入不了开发阶段,太笼统了。对方说现在还在招标阶段,让我帮他搞标书,画架构图。我也和对方说了,标书中技术部分我可以搞,其他部分我就搞不了了。我回去给对方画了个架构图,对方还是比较满意的。过了几天,对方给我打电话,说要我陪他去出差,说是去部队,和人家谈投标的事,明天就走。这也太突然了,今天打电话,明天就走,而且也没有说车票和住宿的问题,我拒绝了对方,之后就没有再联系过。这种单子确实没法做,还在投标阶段,没有成果物,也没有办法和对方谈钱,我本来也是想着和对方保持着合作的关系,钱不钱的先放一边,可对方又让我出差,而且没有谈费用,这让我接受不了,虽然拒绝了出差,但是我想如果对方继续联系我,我还是会合作的,但是对方也一直没有联系我,这个单子就终止了。

没多久,平台又给我推了一个单子,这个单子的需求要明确一些,就是两个系统之间导数据。这个需求比较简单,和对方视频联系了一下,聊的也很好,我感觉这个的单子应该能够拿下。可是随后几天和对方深入了解需求,发现两套系统的字段完全对不上,我把问题反馈给了对方,甚至把两套系统的字段列了出来,让对方找对应关系,对方也意识到了问题,说是和第三方系统的人去聊。接下来就是漫长的等待,期间也和对方聊这个项目还要不要做,对方说要做,可是后面就没什么进展了。这个项目也黄了。

我自己属于比较保守的,在接单平台并没有交会员费,既然没有交费,人家也不会把那些需求明确,上手就能干的单子给你。现在的接单平台真的是两头赚,一边赚需求方的,另一边赚开发者的。有的平台接单前要交3W多的费用,我还没有接到单,还没有挣到钱,先要交平台3W多,这风险太大了。还是朋友推荐的靠谱,可是我没有这方面的资源。这两个单子没接成,后面也没有再尝试。

玩电商

接私活失败后,就到了7月中旬,孩子放暑假了,于是带着家人去呼伦贝尔完了一圈,历时半个月吧。回来后想着总要干点事吧,正在发愁之际,某音的一波推流让我搞起了失败的电商。经常刷到一个人在家做电商的视频,视频中介绍做无货源,轻松月入过万。先和大家说说什么是无货源电商吧,就是你开个网店,不用先进货,而是去某某88上找你要卖的货,比如你想卖鞋子,就去某某88上去找鞋子,然后通过铺货软件把商品详情的内容搬运到你的网店里,你的网店里就会有同样的产品了,然后你再设置好价格,就可以商家去卖了,用户下单好,订单也会通过软件自动同步给某某88的供应商,你在中间就赚差价。很轻松是不是,我也觉得是,而且某音里都是教你怎么做网店的视频,不去做就怕错过这一波机会呀。于是乎兴致勃勃的注册了营业执照,开通了网店,按照视频的说法,新店没有流量没有订单,要用货损的方式起店,货损就是亏钱卖,找个几块钱的产商品,每单亏一两块钱,这样很快就会有订单,我也是按照这种方式去做的,但是这里的坑也是很深的。因为某某88的商品质量问题,俗话说得好,便宜没好货,好货不便宜,为了出单,我找的都是七八块钱的商品,用货损出单,开始确实出单很快,很快店铺出了体验分,但是随之而来的是退货,商品质量不行,用户退货很多,这就是网上购物的缺点吧,看不见货,其实就是在卖图片,谁的图片拍的好,谁的单子就多,当用户收到货后,发现质量不行马上就会退货。我在某某88上看到的野餐垫不错,就铺到了我的店铺,图片看着是挺不错的,价格也不贵,我就交我媳妇买了一个,结果送到家后,打开一看,和一张塑料布没有什么区别,这简直就是骗子,我赶紧就把这个野餐垫下架了。哎,想出单就要便宜,但是便宜没好货,这里边还是有很多门道的。群里有个店主卖的是大裤衩,结果自己买了一个,到家打开一看,直接就给扔了。

上面说的都是货的问题,如果打算卖的好,还真是要好好选选自己卖的商品,在网上看不到实物,不知道质量如何,你卖了差品那就是你的问题。再一个就是“割韭菜”的问题,网店没开几天,你的电话就会被打爆,一群做代运营的天天骚扰你,代运营就是他们帮你经营店铺,店铺上他们的垃圾货,通过你的店铺卖出去,然后他们再抽佣,等于赚了两份钱,你店铺的流量和单量就上去了,但是你的后面你的退货率很高,你真正想卖的东西也是卖不动的。这种代运营的,我根本没有理他们,他们割不到我的韭菜。其实仔细想想就好,他们那么会经营店铺,为什么不自己开店铺卖货呢?归根结底还是现在电商不好做,看看网上那些教人做电商的,那么好做,你自己闷声做发大财就行了,干嘛还要叫别人呢?明显就是割韭菜。

我的店铺基本已经死了,没什么流量。瞎搞吧,铺货软件花了35,货损差不多20多吧,基本上是亏了五六十块吧,和别人比起来我这就不叫赔。

何去何从

半年多的时间,基本上就是瞎搞,各个方向也有所尝试,没有找到出路。期间也有过几个面试,基本都是小公司,而且还没有成功,面试的感觉也不错,就是不想要我,也没办法,慢慢碰吧。继续投简历,有面试积极准备面试。我想后续我还是回归的技术上来吧,毕竟干了10多年了,但是怎么通过技术去变现,还没有想好,慢慢去尝试吧。这一段时间,应该是我职业生涯甚至是我人生中最困难的一段时间,慢慢熬吧~~

概述

Hystrix 为 微服务架构提供了一整套服务隔离、服务熔断和服务降级的解决方案。它是熔断器的一种实现,主要用于解决微服务架构的高可用及服务雪崩等问题

Hystrix 的特性如下:

  • 服务熔断:Hystrix 熔断器就像家中的安全阀一样,一旦某个服务不可用,熔断器就会直接切断该链路上的请求,避免大量的无效请求影响系统稳定,并且熔断器有自我检测和恢复的功能,在服务状态恢复正常后会自动关闭
  • 服务降级:Hystrix 通过 falback 实现服务降级,在需要进行服务降级的类中定义一个 falback 方法,当请求的远程服务出现异常时,可以直接使用 fallback 方法返回异常信息,而不调用远程服务
  • 依赖隔离:Hyslrix 通过线程池和信号量两种方式实现服务之间的依赖隔离,这样即使其中一个服务出现异常,资源迟迟不能释放,也不会影响其他业务线程的正常运行
    • 线程池的隔离策略:Hystrix 线程池的资源隔离为每个依赖的服务都分配一个线程池,每个线程池都处理特定的服务,多个服务之间的线程资源互不影响,以达到资源隔离的目标。当某个依赖服务异常时,只会阻塞这个依赖服务的线程资源,不影响其他依赖服务
    • 信号量的隔离策略:Hystrix 信号量的隔离策略是为每个依赣的服务都分配一个信号量(原子计数器),当请求某个依赖服务时,先判断该服务的信号量值是否超过最大值。如果超过,则直接丢弃并返回错误提示,如果不超过,则在处理请求前执行“信号量+1”的操作,在请求返回后执行“信号量-1”的操作
  • 请求缓存:Hystrix 按照请求参数把请求结果缓存起来,当后面有相同的请求时不会再走完整的调用链流程,而是把上次缓存的结果直接返回,以达到服务快速响应和性能优化的目的。同时,缓存可作为服务降级的数据源,当远程服务不可用时,直接返回缓存数据,对于消费者来说,只是可能获取了过期的数据,这样就优雅地处理了系统异常
  • 请求合井:当微服务需要调用多个远程服务做结果的汇总时,需要使用请求合并。Hystrix 采用异步消息订阅的方式进行请求合并,当应用程序需要请求多个接口时,采用异步调用的方式提交请求,然后订阅返回值,应用程序的业务可以接着执行其他任务而不用阻塞等待,当所有请求都返回时,应用程序会得到一个通知,取出返回值合并即可


Hystrix 服务降级流程

  1. 当有服务请求时,首先会根据注解创建一个 HystrixCommand 指令对象,该对象设置了服务调用失败的场景和调用失败后服务降级的业务逻辑方法
  2. 熔斯器判断状态,当熔断器处于开路状态时,直接调用服务降级的业务逻辑方法返回调用失败的反馈信息
  3. 当熔断器处于半开路或者闭路状态时,服务会进行线程池和信号量等检查如果有可用资源,有则调用正常业务逻辑。如果调用正常业务逻辑成功,则返回成功后的息,如果失败,则调用降级的业务逻辑,进行服务降级
  4. 当熔断器处于半开路或者闭路状态时,如果在当前服务线程池和信号量中无可用资源,则执行服务降级的业务逻辑,返回调用失败的信息
  5. 当熔断器处于半开路状态并且本次服务执行失败时,熔断器会进入开路状态
  6. 当正常业务逻辑处理超时或者出现错误时,HystrixCommand 会执行服务降缓的业务逐辑,返回调用失败的信息
  7. 线程池和信号量的资源检查及正常业务逻辑会将自己的状态和调用结果反馈给监控,监控将服务状态反馈给熔断器,以便熔断器判断熔断状态


Hystrix 应用

Hystrix 的使用主要分为服务熔断、服务降级和服务监控三个方面

在 pom.xml 文件中引入 Hystrix 依赖,其中,spring-cloud-slarter-netflix-hystrix 和 hystrix-javanica 为 Hystrix 服务熔断所需的依赖,spring-cloud-netflix-hystrix-dashboard 为 Hystrix 服务监控所需的依赖

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-eureka</artifactId>
  <version>1.4.6.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
  <version>1.4.6.RELEASE</version>
</dependency>
<dependency>
  <groupId>com.netflix.hystrix</groupId>
  <artifactId>hystrix-javanica</artifactId>
  <version>RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework.cloud</groupId>
  <artifactId>spring-cloud-netflix-hystrix-dashboard</artifactId>
  <version>1.4.6.RELEASE</version>
</dependency>

通过 @EnableHystrix 注解开启对服务熔断的支持,通过 @EnableHystrixDashboard 注解开启对服务监控的支持。注意,Hystrix 一般和服务发现配合使用,这里使 @EnableEurekaClient 开启了对服务发现客户端的支持

@SpringBootApplication
@EnableEurekaClient
@EnableHystrix
@EnableHystrixDashboard
public class HystrixServiceApplication {

  public static void main(String[] args) {
    SpringApplication.run(HystrixServiceApplication.class, args);
  }

  @Bean
  public IRule ribbonRule() {
    return new RandomRule();
  }

  @Bean
  @LoadBalanced
  public RestTemplate restTemplate() {
    return new RestTemplate();
  }
}

配置 application.properties 文件

#服务名
spring.application.name=hystrix
#服务的端口
server.port=9005
#注册中心的地址
eureka.client.serviceUrl.defaultZone=http://localhost:9001/eureka/
eureka.client.registry-fetch-interval-seconds=30

服务熔断和降级,定义了一个远程调用的方法 hystrixHandler(),并通过 @HystrixCommand(fallbackMethod="exceptionHandler") 在方法上定义了一个服务降级的命令,当远程方法调用失败时,Hystrix 会自动调用 fallbackMethod 来完成服务熔断和降级,这里会调用 exceptionHandler 方法

@Autowired
private RestTemplate restTemplate;

//定义服务降级命令
@HystrixCommand(fallbackMethod = "exceptionHandler")
@RequestMapping(value = "/service/hystrix", method = RequestMethod.GET)
public String hystrixHandler() {
  return restTemplate.getForEntity("http://EUREKA-CLIENT/serviceProducer", String.class).getBody();
}

public String exceptionHandler() {
  return "提供者服务挂了";
}


异步处理

上节中的远程调用请求必须等到网络请求返回结果后,才会执行后面的代码,即阻塞运行。而在实际使用过程中,应用程序常常希望使用非阻塞 IO 来更优雅地实现功能.Hyslrix 为非阻塞 IO 提供了两种实现方式,分别是表示将来式的 Future 和表示回调式的 Callable

1. Future

定义 HystrixCommand

public class CommandFuture extends HystrixCommand<String> {

  private String name;

  private RestTemplate restTemplate;

  public CommandFuture(String name, RestTemplate restTemplate) {
    super(Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey("ExampleGroup"))
                //1:通过 HystrixCommandKey 工厂定义依赖的名称
                .andCommandKey(HystrixComnandKey.Factory.asKey("HelloWorld"))
                //2:通过 HystrixThreadPoolKey 工厂定义线程池的名称
                .andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("HelloWorldPool")));
    this.name = name;
    this.restTemplate = restTemplate;
  }

  //3:定义远程调用的方法体
  @Override
  protected String run() {
    String result = restTemplate.getForEntity("http://EUREKA-CLIENT/serviceProducer", String.class).getBody();
    return result;
  }

  //4:服务降级的处理逻辑
  @Override
  protected String getFallback() {
    return "远程服务异常";
  }
}

以上代码通过继承 HystrixCommand 定义了一个 CommandFuture 来实现异步请求,其中,正常业务执行的逻辑在覆写的 run() 方法体中被执行,服务降级的方法在 getFallback() 中被执行。需要注意的是,这里使用 andCommandKey(HystrixCommandKey.Factory.asKey("HelloWorld")) 实现了使用 HystrixCommandKey 工厂定义依赖的名称,每个 CommandKey 都代表一个依赖抽象,相同的依赖要使用相同的 CommandKey 名称。依赖隔离的本质敦是对相同
CommandKey 的依赖进行离,使用 andThreadPoolKey(HystrixThreadPoolKey.Factory.asKey("HelloWorldPool")) 实现了基于 HystrixThreadPoolKey 工厂定义线程池的名称。当对同一业务的依赖进行资源隔离时,使用 CommandGroup 进行区分,但是当对同一依赖进行不同的远程调用时(例如,一个是 Redis 服务,一个是 HTTP 服务),则可以使用 HystrixThreadPoolKey 进行隔离区分

使用 HystrixCommand

@RequeatMapping(value = "/service/hystrix/future", method = RequestMethod.GET)
public String hystrixFutureHandler() throws ExecutionException, InterruptedException {
  //定义基于Future的异步调用,请求会以队列的形式在线程池中被执行
  Future<String> future = new CommandFuture("future", restTemplate).queue();
  return future.get();
}

2. Callable

预定义一个回调任务,Callable 在发出请求后,主线程继续执行,在请求执行完成并返回结果后,Callable 会自动调用回调任务

定义 HystrixObservableCommand

public class CommandObservable extends HystrixObservabCommand<String> {

  private String name;
  private RestTemplate restTemplate;

  public CommandObservable(String nane, RestTemplate restTemplate) {
    
    super(HystrixConmandGroupKey.Factory.asKey("ExampleGroup"));
    this.nane = name;
    this.restTemplate = restTemplate;
  }

  //基于观察者模式的请求发布
  @Override
  protected Observable<String> construct () {
    return Observable.create(new Observable.OnSubscribe<String>() {
      @Override
      public void call(Subscriber<? super String> subscriber) {
        try {
          //执行远程过程调用
          if(!subscriber.isUnsubscribed()) {
            String result = restTemplate.getForEntity("http://EUREKA-CLIENT/serviceProducer", String.class).getBody();
            //将调用结果传递下去
            subscriber.onNext(result):
            subscriber.onCompleted();
          }
        } catch(Exception e) {
          e.printStackTrace();
          subscriber.onError(e);
        }
      }
    }
  } 

  //服务降级的处理逻辑
  @Override
  protected Observable<String> resumeWithFallback() {
    return Observable.create(new Observable.OnSubscribe<String>() {
      @Override
      public void call(Subscriber<? super String> subscriber) {
        try {
          if(!subscriber.isUnsubscribed()) {
            subscriber.onNext("远程服务异常”);
            subscriber.onCompleted();
        } catch (Exception e) {
            subscriber.onError(e);        
        }
      }
    }
  }
}

以上代码定义了名为 CommandObservable 的类,该类继承自 HystrixObservableCommand 接口,并通过覆写 HystrixObservableCommand 接口中的 construct() 实现观察者模式。具体实现为通过 Obsenvable.create() 创建并返回一个 Observable
对象,在创建对象时,通过 new Observable.OnSubscribe () 实现消息的监听和处理。其中,call 方法用于消息的接收和业务的处理,在消息处理完成后通过 subscriber.onNext(result) 将调用结果传递下去,当所有任务都执行完成时通过 subscriber.onCompleted() 将总体执行结果发布出去。resumeWithFallback 方法是服务降级的处理逻辑,当服务出现异常时,通过 subscriber.onNext("远程服务异常") 进行服务熔断和异常消息的发布,实现服务降级处理

使用 HystrixObservableCommand

public String hystrixCallableHandler() throws ExecutionException, InterruptedException {

  List<String> list = new ArrayList<>();

  //定义基于消息订间的异步调用,请求结果会以事件的方式通知
  Observable<String> observable = new CommandObservable("observer", restTemplate).observe();
  //基于观察者模式的清求结果订阅
  observable.subscribe(new Observer<String>() {
    //onCompleted方法在所有请求完成后执行@
    @Override
    public void onCompleted() {
      System.out.println("所有请求已经完成...”);
    }
    @Override
    public void onError(Throwable throwable) {
      throwable.printStackTrace();
    }
    //订阅调用事件,请求结果汇聚的地方,用集合将返回的结果收集起来
    @Override
    public void onNext(String s) {
      System.out.printin("结果来了...");
      list.add(s);
      return list.toString();
    }
  }
}

以上代码通过 new CommandObservable("observer", restTemplate).observe() 定义了一个实现服务发布的命令。通过调用 abservabe.subscribe() 来实现基于观察者模式的请求结果订阅,其中,订阅的数据结果在 onNext() 中被通知,总体调用结果在 onCompleted() 中被通知。服务处理异常结果在 onError() 中被通知


Hystrix Dashboard

HystrixDashboard 主要用于实时监控 Hystrix 的各项运行指标。通过 HystrixDashboard 可以查询 Hystrix 的实时信息,用于快速定位和发现问题。Hystrix Dashboard 的使用简单、方便,首先在 pom.xml 文件中加入 spring-cloud-netfix-hystrix-dashboard 依赖,然后使用 @EnableHystrixDashboard 注解开启 Dashboard 功能即可。在服务启动后,在浏览器地址栏中输人
http://127.0.0.1:9005/hystrix
,就可以看到监控界面