2024年9月

CogVLM2是一款视觉语言模型(Visual Language Model),由智谱AI和清华KEG潜心打磨。这款模型是CogVLM的升级版本,支持高达 1344 * 1344 的图像分辨率,提供支持 中英文双语 的开源模型版本。

这类模型可以做很多跨领域的活儿,比如给图片配上描述文字、回答关于图片的问题(这叫VQA,就是视觉问答)、或者根据描述去找对应的图片等等。为了更好地完成这些任务,CogVLM2用了更高级的设计和技术,比如用更大的数据量来训练、更深的神经网络结构,还有更聪明的训练方法。

CogVLM 的进步主要归功于一个核心理念:“视觉优先”。以前的多模态模型常常把图像特征简单地放到和文本特征一样的层面上处理,而且用来处理图像的那部分通常比较简单,这样一来,图像就像是文本的“配角”,所以效果也就一般。而CogVLM则让视觉信息占据了更重要的位置。

环境准备

本地部署

CogVLM在Github上发布了开源的程序代码,可以做图片推理、视频推理,甚至进行模型的微调(不过GPU资源需求很大),Github地址:
https://github.com/THUDM/CogVLM2

建议使用Linux系统,搭配 NVIDIA GPU,显存最少需16G以上。

具体的安装使用方法,大家可以看官方的这篇介绍:

https://github.com/THUDM/CogVLM2/blob/main/basic_demo/README_zh.md

使用云环境

如果你本地没有足够的GPU资源,对编程也是一窍不通,或者只是想先看看效果,可以使用我打包的云平台镜像,一键启动,直接运行,不浪费时间。

云平台对新用户有一定的赠送额度,足够体验这个应用,平台注册地址:

仅体验图片推理,无需任何技术操作,请打开这个网址:
https://www.haoee.com/applicationMarket/applicationDetails?appId=39&IC=XLZLpI7Q

应用创建成功后,即可在“控制台”->“我的应用”中打开这个应用。

因为平台限制,如果还想使用API或者做视频推理,请打开这个网址:https://bbs.haoee.com/postDetail/656

点击页面右下方的“创建实例”:

注意如果你要做视频推理,因为需要的资源比较多,这里需要选择2张卡才能跑的起来:

实例启动成功后,我们可以在“控制台”->“容器实例”中打开对应实例的 JupyterLab 交互工具。

在 JupyterLab 中可以在左边选择要使用的功能,右边启动应用,查看运行日志。

然后回到容器实例页面,点击“公网访问”获取对应程序的外网访问地址。

图片推理WebUI使用说明

1、容器实例启动成功后,在实例列表页面找到对应的实例,点击操作中的“JupyterLab”。

2、在打开的页面中点击“基础页面启动器”,然后继续点击页面中的重启按钮,启动对应的程序,如下图所示:

3、待程序启动成功后,回到实例列表页面,点击“公网访问”:

复制其中的第一个链接,然后在浏览器中打开。

4、在浏览器打开应用后,页面下方:

(1)首先上传一张图片;

(2)然后针对这张图片提出你的问题。

这里用黑悟空的一张照片来演示,效果如下:

如果要开启新的会话,请点击页面右上角的这个按钮:

图片推理API使用说明

1、容器实例启动成功后,在实例列表页面找到对应的实例,点击操作中的“JupyterLab”。

2、在打开的页面中点击“基础API启动器”,然后继续点击页面中的重启按钮,启动对应的程序,如下图所示:

3、待程序启动成功后,回到实例列表页面,点击“公网访问”:

其中的第2个链接就是API的访问地址。

访问API的代码请参考:

https://github.com/THUDM/CogVLM2/blob/main/basic_demo/openai_api_request.py

注意:图片推理API是单独的程序,使用单显卡时会关闭页面推理程序。如需同时启动,需要双显卡,并修改 CogVLM2/startup/start_basic_api.sh 中的 CUDA_VISIBLE_DEVICES=1。

视频推理使用说明

1、视频推理需要的显存比较多,在好易平台上需要2个4090D的显卡,所以创建实例的时候需要选择2卡,如下图所示:

2、容器实例启动成功后,在实例列表页面找到对应的实例,点击操作中的“JupyterLab”。

3、在打开的页面中点击“视频识别启动器”,然后继续点击页面中的重启按钮,启动对应的程序,如下图所示:

4、待程序启动成功后,回到实例列表页面,点击“公网访问”:

其中的两个连接分别提供了网页和API的访问地址。

5、在浏览器打开网页后,页面中:

(1)首先上传一个视频(1分钟以内的);

(2)然后针对这个视频提出你的问题。

6、使用视频推理API

参考代码如下,请注意替换其中的API地址和本地视频文件路径。

import requests
url = 'http://127.0.0.1:7861/video_qa'
video_file = "../resources/videos/lion.mp4"
question = "Describe this video in detail."
temperature=0.2
files = {'video': open(video_file, 'rb')}
data = {'question': question,'temperature': temperature}
response = requests.post(url, files=files, data=data)
print(response.json()["answer"])

参加赠书活动

为了回馈各位读者,萤火君和机械工业出版社搞了一个赠书活动,就是下边这本机器学习四大名著之一的『机器学习实战』全新升级第3版!中文版豆瓣评分9.6!读者公认对入门和实践极其友好的机器学习书籍之一!

  • 读者公认对入门和实践极其友好的机器学习书籍之一!
  • 具体的示例+简单的理论+可用于生产环境的Python框架
  • 帮助你直观地理解并掌握构建智能系统所需要的概念和工具
  • 配备大量代码示例,帮助你学以致用!

想要领书的同学,请给公/众/号 “萤火遛AI” 发消息 “机器学习实战”,即可参与抽奖,9月9日上午10点开奖!

C#用户控件之指示灯

在体现通讯状态、运行状态等用一个靓眼的指示灯如何做?

思路(GDI)

  • 外环用笔绘制(Pen),内圆用画刷(SolidBrush);

两个方法(用笔画圆,用画刷填充圆的内部):

  1. 绘制边界RectangleF定义的椭圆/圆

DrawEllipse(Pen pen,RectangleF rect)

  1. 填充RectangleF定义边框的椭圆的内部

FillEllipse(Brush brush,RectangleF rect)


定义属性

  • 指示灯颜色、外环与边界的间隙、内圆与边界的间隙、外环宽度、当前颜色
//外环宽度
private float outWidth = 4.0f;
[Browsable(true)]
[Category("布局_G")]
[Description("外环的宽度")]
public float OutWidth
{
    get { return outWidth; }
    set
    {
         if (value <=0||value<0.1*this.Width ) return;
        outWidth = value; this.Invalidate();
    }
}


//颜色(Color)——备注:写5种颜色属性(灰色=Gray、棕色=DarkGoldenrod、红色=Red、蓝色=Blue、绿色=limeGreen<比Green好看些>)
private Color zcolor1 = Color.Gray;   //灰色.......写5种
 [Browsable(true)]
 [Category("布局_G")]
 [Description("颜色1")]
 public Color ZColor1
 {
     get { return zcolor1; }
     set { zcolor1 = value; this.Invalidate(); }
 }
//当前颜色获取(定义一个私有方法)(Int)
  private Color GetCurColor()
  {
      List<Color> colors = new List<Color>();
      colors.Add(zcolor1);
      colors.Add(zcolor2);
      colors.Add(zcolor3);
      colors.Add(zcolor4);
      colors.Add(zcolor5);
      return colors[curValue];
  }
//间隙(float),属性都是一个样往下敲就是
注意:间隙设置值的范围(外环间隙要小于内圆间隙)


GDI绘制图形:(外环、内圆)

Color getCurColor = GetCurColor();  //获取当前颜色

//绘制外环(DrawEllipse-用笔画椭圆)
p = new Pen(getCurColor, outWidth);
RectangleF rec = new RectangleF(this.gapOut, this.gapOut, this.width - 2 * this.gapOut, this.height - 2 * gapOut);
g.DrawEllipse(p, rec);

//绘制内圆(FillEllipse-填充椭圆内部)
sb = new SolidBrush(getCurColor);
rec = new RectangleF(gapIn, gapIn, this.width - 2 * this.gapIn, this.height - 2 * gapIn);
g.FillEllipse(sb, rec);


最后生成
(闪烁的话,是不是对用户更友好呢)


两种闪烁方法

关键在于timer定时器的使用,在定时器的Tick方法中定义变量更替


【1】只内圆闪烁(定义内圆画刷颜色Transparent<透明色>、GetCurColor<当前色>两种画刷)

if (this.flickerAct == true)
{
    if (this.blink == true)  //将blink标志位在定时器的Tick方法中取反 (blink=!blink)
    {
        sb = new SolidBrush(zcolor6);  //zcolor6为透明色
    }
    else
    {
        sb = new SolidBrush(getCurColor);  //getCurColor为当前色
    }
}
else
{
    sb = new SolidBrush(getCurColor);  //不闪烁就定义当前色画刷
}
rec = new RectangleF(gapIn, gapIn, this.width - 2 * this.gapIn, this.height - 2 * gapIn);
g.FillEllipse(sb, rec);


【2】整体都闪烁(定义控件的Visible)

 private void MyTimer_Tick(object sender, EventArgs e)  //定时器Tick事件方法
 {
     if (this.flickerVis == true)
     {
         //显隐控件
         this.Visible=!this.Visible;  //整体闪烁只定义Visible即可
         this.blink=false;
     }
     else
     {
         //内圆闪烁标志
         this.blink = !this.blink;
     }
     this.Invalidate();
 }

【3】频率可调(定时器的Interval)


private bool flickerAct = false;
[Browsable(true)]
[Category("布局_G")]
[Description("是否闪烁")]
public bool FlickerAct
{
    get { return flickerAct; }
    set
    {
        if (value == true)
        {
            myTimer.Interval = this.flickerFre;  //传递给定时器Interval 一个int(毫秒刷新率)值即可
            this.myTimer.Start();  //闪烁定时器开始
        }
        else
        {
            this.myTimer.Stop();  //不闪烁定时器停止;同时将标志位、显示置为默认值
            this.blink = false;
            this.Visible = true;
        }
        flickerAct = value; this.Invalidate();
    }
}


闪瞎双眼,捂脸


想要二进制使用示例

  private void led1_Load(object sender, EventArgs e)
  {
      bool b = false;
      //三元运算定义两种颜色即可
      this.led1.CurValue = b ? 2 : 3; 
  }


End

上一篇文章讲解述首次启动 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