Guitar 🎸

指板

chords
在乐音体系中,七个具有独立名称的音级叫做基本音级(也叫自然音级)。 基本音级用“C、D、E、F、G、A、B”七个字母来表示,这就是基本音级的音名唱名是人们在演唱音乐的谱子时所使用的名称,即:“Do,Re,Mi,Fa,Sol,La,Si” 这七个唱名。
简谱上 唱名、音名的表示
十二平均律,是将一个八度的音程等分成十二个半音的律制,各相邻两律之间的波长之比完全相等。一等份为一个半音(小二度),对应吉他一品的距离。两等份为一个全音(大二度)。将一个八度分成12等份有着惊人的一些巧合,这是因为它的纯五度音程的两个音的波长比为(1/2)^(7/12)≈0.6674,与2/3≈0.6667非常接近。 一个八度内 全全半全全全半

C大调音阶在吉他指板上可以有不同的把位 https://www.zhihu.com/tardis/zm/art/496745355?source_id=1005
C大调音阶图

扫弦节奏型:1)下 下 下上 上下上下 下上
节拍

乐理

HUB GUITAR: https://hubguitar.com/zh_han/music-theory 指板: https://hubguitar.com/zh_han/fretboard

弹奏第一品位上的B弦,这就是 C音,一个以一定频率振动的音波。接下来你拨第十三品的同一根弦,同样地,它听上去好像是同一个音,但这个音高更高。这是因为声波的振动是原来的两倍之快,可以表达为1:2, 它们是有同一特性的音。如果两种不同的乐器同时弹奏C音,这个比例是1:1,这称为 同音。在下图中,第一品的音符将会是最左边的C,第十三品的音则是在最右边。所有在这两者之间的音符都是特定的音符,但一旦重新回到C音,就重新按照这个顺序继续下去。

音程:就是两个音符之间的高低关系。在较低的一个 “C” 音和另一个较高的 “C” 音之间的音程就是 八度(八音音阶)。八度是音高的基本来源,其余的还包括将它分成更小的部分而得到的音高,称为 音数。半音就是移动一格,从 C 到 C♯。全音移动两格,从 C 到 D。 大多数现代音乐将八度分割为12级,如图所示,你可以按照这个音符的顺序来弹奏,从第一品的 B 弦开始,每次移动一个品位,直到第十三品,重新回到 C,一边弹奏一边大声说出这个音符的名字。所有这十二个音符一起组成了 半音音阶。音阶就是音符的顺序,并且没有重复的音符,所有的音符以升序,从低到高的顺序来弹奏。

根音?它就是一首歌的主调音,它是一个单音,其余的东西全在它的基础上变化,想像它是重力中心,它是一种吸引力,吸引着一首歌曲里其余所有的音,不管什么情况下都会回到根音上来。

TABS


晴天 - 周杰倫

Hey Jude - The Beatles

小情歌 - 蘇打綠 https://www.bilibili.com/video/BV1R64y1p7WB/

紅豆 - 方大同

找自己 - 陶喆

普通朋友 - 陶喆 https://www.bilibili.com/video/BV1zw4m1a7CU

Canon in C https://www.bilibili.com/video/BV1if4y1A7SZ/

揪心的玩笑與漫長的白日夢 - 萬能青年旅店
https://www.bilibili.com/video/BV1cuHjetENY/?vd_source=ff210768dfaee27c0d74f9c8c50d7274

Maven

1. Maven是什么?

  • 基本概念
    Maven是Apache基金会的开源项目管理和构建自动化工具,使用POM(Project Object Model) 文件描述项目结构、依赖关系和构建配置。

  • 是否专门用于Java?
    主要定位:主要用于Java项目
    可扩展性:通过插件可支持其他语言(Scala、Groovy、Kotlin等)
    生态系统:虽然不限于Java,但在Java生态中最为成熟

  • 核心功能

    1
    2
    3
    4
    5
    ├── 依赖管理(Dependency Management)
    ├── 项目构建(Build Lifecycle)
    ├── 统一项目结构(Standard Directory Layout)
    ├── 插件体系(Plugin Architecture)
    └── 仓库管理(Repository)
  • Maven依赖的本质

    • 通过pom.xml引入的依赖,默认下载的是已编译的JAR包,主要包含:
      内容 说明 是否必须
      .class文件 已编译的字节码(人类可读的.java源代码文件编译而来) ✅ 必须,用于运行
      pom.xml 依赖的元数据 ✅ 必须,用于传递依赖解析
      源代码(.java) 可选,用于调试 ❌ 可选,IDE可单独下载
      javadoc API文档 ❌ 可选,IDE可单独下载
    • 依赖获取过程
      1
      2
      3
      4
      5
      6
      // pom.xml中的依赖声明
      <dependency>
      <groupId>com.google.guava</groupId>
      <artifactId>guava</artifactId>
      <version>31.1-jre</version>
      </dependency>
    • 实际下载的文件
      1
      2
      3
      4
      5
      6
      7
      ~/.m2/repository/com/google/guava/guava/31.1-jre/
      ├── guava-31.1-jre.jar // 主要JAR,包含.class文件
      ├── guava-31.1-jre.pom // 该依赖的pom文件
      ├── _remote.repositories // 仓库信息
      └── 可能还有:
      ├── guava-31.1-jre-sources.jar // 源代码
      └── guava-31.1-jre-javadoc.jar // 文档

2. Maven基本命令

常用命令速查表

命令 功能 说明
mvn clean 清理项目 删除target目录
mvn compile 编译源码 生成target/classes
mvn test 运行测试 执行src/test下的测试
mvn package 打包项目 生成jar/war包
mvn install 安装到本地仓库 mvn package + 将jar安装到本地 ~/.m2/repository
mvn deploy 部署到远程仓库 发布到Nexus/Artifactory
mvn clean install 清理并安装 常用组合命令
mvn dependency:tree 查看依赖树 分析依赖关系
mvn spring-boot:run 运行Spring Boot 需要对应插件

Maven生命周期阶段

A[clean] –> B[validate] –> C[compile] –> D[test] –> E[package] –> F[verify] –> G[install] –> H[deploy]

1. mvn compile - 编译阶段

相当于:执行 javac 编译源代码

1
2
3
4
5
6
7
8
9
10
11
12
# 实际操作
# 1. 编译主代码
javac -cp "所有依赖的jar" -d target/classes src/main/java/**/*.java
# 2. 处理资源文件
cp src/main/resources/** target/classes/

# 生成目录结构
target/
├── classes/ # 编译输出的.class文件
│ ├── com/example/Main.class
│ └── application.properties
└── generated-sources/ # 生成的代码(如有)

当您运行 mvn compile时,Maven 会:
解析依赖:读取 pom.xml 中的
下载依赖:从远程仓库下载到本地 ~/.m2/repository/
构建依赖图:处理传递依赖
关键点:Maven 管理的这些依赖是已经编译好的 .class 文件(JAR 包),不是 .java 文件。

然后 Maven 会:
编译您的代码:src/main/java/下的 .java 文件
使用依赖:编译时将下载的依赖 JAR 加入 classpath
打包:将您的 .class 文件 + 资源文件打包

todo:那么打包的时候到底保护包含依赖?我自己的源代码编译 .class + 依赖包的 .class ??

2. mvn package - 打包阶段

相当于根据packaging类型不同,将编译结果打包成可分发的格式(注意:普通mvn package生成的jar不包含依赖!依赖需要单独配置)

1
2
3
4
5
6
<!-- pom.xml中指定打包类型 -->
<packaging>jar</packaging> <!-- 默认值 -->
<!-- 或 -->
<packaging>war</packaging>
<!-- 或 -->
<packaging>pom</packaging>

打包过程

1
2
3
4
5
6
7
# 对于jar包:
jar cvf target/myapp-1.0.jar -C target/classes .

# 生成的jar内容:
# META-INF/MANIFEST.MF # 清单文件
# com/example/Main.class # 你的类
# application.properties # 资源文件

3. mvn install - 安装阶段

mvn install 做了两件事:
1 执行之前所有阶段:validate → compile → test → package → verify → install
2 将当前项目的构建结果安装到本地仓库,安装位置 →

1
2
3
4
~/.m2/repository/com/yourcompany/yourapp/1.0.0/
├── yourapp-1.0.0.jar # 打包的jar
├── yourapp-1.0.0.pom # 当前项目的pom.xml
└── yourapp-1.0.0-sources.jar # 源代码(如果生成)

命令组合示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 标准开发流程
mvn clean compile
mvn test
mvn package

# 跳过测试
mvn clean install -DskipTests

# 指定配置文件
mvn clean install -Pprod

# 查看帮助
mvn help:effective-pom
mvn help:describe -Dcmd=package

3. 打包Java服务为可运行JAR

三种打包方式对比

方式 插件 特点 适用场景
普通JAR maven-jar-plugin 不包含依赖 库项目
Fat JAR maven-assembly-plugin 包含所有依赖 简单应用
可执行JAR spring-boot-maven-plugin Spring Boot专用 Spring Boot应用
Shadow JAR maven-shade-plugin 重命名包解决冲突 复杂依赖

Spring Boot项目(最常用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<!-- pom.xml -->
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.example.MainApplication</mainClass>
<!-- 包含依赖 -->
<layout>JAR</layout>
</configuration>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
1
2
3
4
# 打包命令
mvn clean package
# 运行
java -jar target/your-app-1.0.0.jar

完整构建流程示例

项目结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
my-project/
├── src/
│ ├── main/
│ │ ├── java/
│ │ │ └── com/example/
│ │ │ └── App.java
│ │ └── resources/
│ │ └── config.properties
│ └── test/
│ └── java/
│ └── com/example/
│ └── AppTest.java
├── target/ # 构建输出目录
└── pom.xml

执行流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 1. 清理 + 编译
mvn clean compile
# 生成: target/classes/ 目录

# 2. 运行测试
mvn test
# 生成: target/test-classes/ 和 target/surefire-reports/

# 3. 打包
mvn package
# 生成: target/my-project-1.0.jar

# 4. 安装到本地仓库
mvn install
# 生成: ~/.m2/repository/com/example/my-project/1.0/

4. IDEA中使用Maven与问题解决

IDEA Maven配置位置

1
File → Settings → Build, Execution, Deployment → Build Tools → Maven

常用操作

  1. 刷新依赖:Maven工具窗口的刷新按钮 🔄
  2. 执行命令:双击生命周期中的阶段
  3. 查看依赖图:右键项目 → Show Dependencies
  4. 排除冲突:在依赖树上右键排除

问题分类

  1. Import报红
    本地仓库缺失
    版本冲突
    网络问题
  2. 编译失败
    依赖下载不全
    编译版本不匹配
  3. 运行时异常
    依赖冲突
    ClassNotFound

解决方案

  1. 点击刷新按钮
  2. 仍未解决,检查网络–> 清除本地仓库–> 清理IDEA缓存 –> 检查依赖冲突 –> 重新导入项目

具体问题解决步骤

问题1:刷新按钮无效

症状:点击刷新后,依赖仍然报红

解决方案

  1. 强制刷新

    1
    2
    # 命令行执行
    mvn clean install -U

    -U 参数强制更新快照版本

  2. 删除本地仓库

    1
    2
    3
    4
    5
    # Windows
    rd /s /q %USERPROFILE%\.m2\repository

    # Mac/Linux
    rm -rf ~/.m2/repository
  3. 清除IDEA缓存

    1
    File → Invalidate Caches and Restart

问题2:依赖下载慢/失败

解决方案

  1. 配置阿里云镜像settings.xml):

    1
    2
    3
    4
    5
    6
    7
    8
    <mirrors>
    <mirror>
    <id>aliyun</id>
    <name>aliyun maven</name>
    <url>https://maven.aliyun.com/repository/public</url>
    <mirrorOf>central</mirrorOf>
    </mirror>
    </mirrors>
  2. IDEA配置镜像

    1
    2
    File → Settings → Build Tools → Maven
    修改 User settings file 为包含镜像的settings.xml

问题3:依赖冲突

症状:NoSuchMethodError, ClassNotFoundException

排查命令

1
2
3
4
5
6
7
8
# 查看依赖树
mvn dependency:tree

# 查看冲突
mvn dependency:tree -Dverbose

# 分析依赖
mvn dependency:analyze

IDEA可视化排查

  1. 右键项目 → Analyze → Analyze Dependencies
  2. 查看冲突标记(红色)

解决冲突示例

1
2
3
4
5
6
7
8
9
10
11
<dependency>
<groupId>com.example</groupId>
<artifactId>problematic-lib</artifactId>
<version>1.0</version>
<exclusions>
<exclusion>
<groupId>conflict-group</groupId>
<artifactId>conflict-artifact</artifactId>
</exclusion>
</exclusions>
</dependency>

问题4:版本不兼容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!-- 统一管理版本 -->
<properties>
<spring.version>5.3.23</spring.version>
</properties>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

IDEA Maven工具窗口使用技巧

1. 快速操作

图标 功能 快捷键
🔄 重新导入所有Maven项目 Ctrl+Shift+O
🏃 运行Maven目标 右键→Run Maven
📊 显示依赖图 右键→Show Dependencies
🧹 执行clean 双击Lifecycle→clean

2. 配置文件切换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- pom.xml 中定义不同环境 -->
<profiles>
<profile>
<id>dev</id>
<activation>
<activeByDefault>true</activeByDefault>
</activation>
<properties>
<env>dev</env>
</properties>
</profile>
<profile>
<id>prod</id>
<properties>
<env>prod</env>
</properties>
</profile>
</profiles>

在IDEA Maven工具窗口的Profiles中勾选激活。

终极解决方案清单

当遇到顽固依赖问题时,按顺序执行:

  1. 第一步:清理缓存

    1
    mvn clean install -U
  2. 第二步:删除本地仓库对应目录

    1
    2
    # 删除有问题依赖的目录
    rm -rf ~/.m2/repository/com/example/problem-dependency
  3. 第三步:IDEA完全清理

    • File → Invalidate Caches and Restart
    • 删除项目下的 .idea 目录和 *.iml 文件
    • 重新导入
  4. 第四步:检查Maven配置

    1
    2
    3
    4
    5
    # 查看有效POM
    mvn help:effective-pom

    # 查看有效设置
    mvn help:effective-settings
  5. 第五步:网络代理检查

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    <!-- settings.xml 配置代理 -->
    <proxies>
    <proxy>
    <id>optional</id>
    <active>true</active>
    <protocol>http</protocol>
    <host>proxy.company.com</host>
    <port>8080</port>
    </proxy>
    </proxies>

预防措施

  1. 使用依赖锁定

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-enforcer-plugin</artifactId>
    <version>3.2.1</version>
    <executions>
    <execution>
    <id>enforce</id>
    <configuration>
    <rules>
    <dependencyConvergence/>
    </rules>
    </configuration>
    <goals>
    <goal>enforce</goal>
    </goals>
    </execution>
    </executions>
    </plugin>
  2. 定期清理本地仓库

    1
    2
    # 清理失败下载
    find ~/.m2/repository -name "*.lastUpdated" -delete
  3. 使用CI/CD环境验证
    在Jenkins/GitHub Actions中设置定期构建,提前发现问题。

常见错误代码与解决

错误代码 含义 解决方案
501 HTTPS Required 仓库需要HTTPS 更新settings.xml,使用https仓库
401 Unauthorized 认证失败 配置正确的server认证
Could not transfer artifact 网络/权限 检查网络,清理.lastUpdated文件
No compiler is provided JDK配置错误 配置JAVA_HOME,或在pom中指定javac

高级技巧

  1. 离线模式(网络不稳定时)

    1
    mvn clean install -o
  2. 跳过测试

    1
    2
    3
    mvn clean install -DskipTests
    # 或
    mvn clean install -Dmaven.test.skip=true
  3. 多线程构建

    1
    mvn clean install -T 4
  4. 调试模式

    1
    mvn -X clean install

Milvus

📚 文档链接: 快速入门 | Milvus 文档

什么是向量嵌入?

向量嵌入是从机器学习模型中提取的数值表示,捕捉非结构化数据的语义含义。这些嵌入通过神经网络或变压器架构对数据中的复杂相关性进行分析,创建一个密集的向量空间,其中每个点对应于数据对象(如文档中的词)的“含义”。

这个过程将文本或其他非结构化数据转换为反映语义相似性的向量——在这个多维空间中,意义相关的词被放置得更近,从而实现一种称为“密集向量搜索”的搜索方式。这与依赖精确匹配和使用稀疏向量的传统关键词搜索形成对比。向量嵌入的发展,通常源于大型科技公司广泛训练的基础模型,使得搜索能够捕捉数据的本质,超越词汇或稀疏向量搜索方法的局限性。

向量:可以理解为在多维空间中的一个点,它由一组数字(坐标)表示。在 AI 中,无论是文本、图像还是声音,都可以通过特定模型(如 qwen3-embedding-4b-torch)转换为一个向量。这个向量捕捉了原始数据的深层特征。
维度:就是指这个向量有多少个数字。例如,一个 [0.12, 0.45, -0.23, …, 0.78]的向量,如果它有 1024 个数字,我们就说它是一个 1024 维​ 的向量。维度的选择通常由您选用的嵌入模型决定,并且在创建 Milvus 集合时必须正确定义,因为所有存入的向量都必须有相同的维度。

非结构化数据、Embeddings 和 Milvus

非结构化数据(如文本、图像和音频)格式各异,蕴含丰富的潜在语义,因此分析起来极具挑战性。Embeddings 被用来将非结构化数据转换成能够捕捉其基本特征的数字向量。然后将这些向量存储在向量数据库中,从而实现快速、可扩展的搜索和分析。

Milvus 提供强大的数据建模功能,使您能够将非结构化或多模式数据组织成结构化的 Collections。它支持多种数据类型,适用于不同的属性模型,包括常见的数字和字符类型、各种向量类型、数组、集合和 JSON,为您节省了维护多个数据库系统的精力。
与处理结构化数据并执行精确搜索操作的传统关系数据库不同,向量数据库擅长使用 Approximate Nearest Neighbor(ANN)算法等技术进行语义相似性搜索。这种能力对于开发推荐系统、聊天机器人和多媒体内容搜索工具等各种领域的应用程序,以及解决 ChatGPT 等大型语言模型和 AI 带来的挑战(如理解上下文和细微差别以及 AI 幻觉)至关重要。

Milvus 概念 类比关系型数据库概念 说明
Collection(集合) Table(表) 存储向量和关联元数据(如文本内容、来源)的基本单位。
Entity(实体) Row(行) 一条完整的记录,包含主键、向量字段和标量字段(元数据)。
Field(字段) Column(列) 包括向量字段(存储向量)和标量字段(存储 ID、标签等结构化数据)。
Index(索引) Index(索引) 为向量字段建立的索引(如 HNSW、IVF_FLAT),是高速检索的关键。
  1. 写入数据(以 Python 为例)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    from pymilvus import connections, Collection, FieldSchema, CollectionSchema, DataType

    # 1. 连接到您的 Milvus 服务
    connections.connect("default", host='localhost', port='19530')

    # 2. 定义集合结构(假设向量维度为1024)
    fields = [
    FieldSchema(name="id", dtype=DataType.VARCHAR, is_primary=True, max_length=100),
    FieldSchema(name="text_content", dtype=DataType.VARCHAR, max_length=65535),
    FieldSchema(name="embedding_vector", dtype=DataType.FLOAT_VECTOR, dim=1024)
    ]
    schema = CollectionSchema(fields, description="问答助手知识库")
    collection = Collection("qa_knowledge_base", schema)

    # 3. 插入数据(假设您已使用 embedding 模型将文本转换为向量)
    data = [
    ["doc_001", "CMDB是配置管理数据库,用于...", [0.12, 0.34, ...]], # 1024维向量
    ["doc_002", "MongoDB的聚合管道用于...", [0.56, 0.78, ...]],
    ]
    collection.insert(data)
    collection.flush() # 确保数据持久化

    # 4. 创建索引(以HNSW为例)
    index_params = {
    "index_type": "HNSW",
    "metric_type": "COSINE", # 使用余弦相似度
    "params": {"M": 16, "efConstruction": 200}
    }
    collection.create_index("embedding_vector", index_params)
    collection.load() # 将集合加载到内存以提供服务
  2. 读取与搜索

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    # 用户提出问题,并转换为向量
    question = "如何查询CMDB中的主机信息?"
    question_vector = embed(question) # 使用相同的模型生成1024维向量

    # 在 Milvus 中搜索最相似的 Top K 个向量
    search_params = {"metric_type": "COSINE", "params": {"ef": 50}}
    results = collection.search(
    data=[question_vector],
    anns_field="embedding_vector",
    param=search_params,
    limit=3, # 返回最相似的3条结果
    output_fields=["id", "text_content"] # 指定需要返回的元数据字段
    )

    # 处理结果
    for hits in results:
    for hit in hits:
    print(f"相似度得分: {hit.score}, 关联知识: {hit.entity.get('text_content')}")
  3. Milvus 支持的搜索类型
    ANN 搜索:查找最接近查询向量的前 K 个向量。
    过滤搜索:在指定的过滤条件下执行 ANN 搜索。
    范围搜索:查找查询向量指定半径范围内的向量。
    混合搜索:基于多个向量场进行 ANN 搜索。
    全文搜索:基于 BM25 的全文搜索。
    获取:根据主键检索数据。
    查询使用特定表达式检索数据。

  4. Rerankers
    在基础的 RAG 流程中,系统通过 Embedding 模型​ 将用户查询和知识库文档转换为向量,然后利用向量数据库进行快速的相似性搜索,找出最相关的几个文档片段作为上下文提供给 LLM 。然而,这种基于向量相似度的检索有时无法完美捕捉深层次的语义关联,可能返回一些看似相关实则无关的“噪声”文档 。
    Reranker 模型的作用就在于此。它通常在向量检索之后介入,像一个专业的裁判,对初步检索到的候选文档(例如 Top 20 或 Top 50)进行二次精排 。其核心工作原理是:
    1、精细化语义理解:不同于 Embedding 模型分别处理查询和文档,典型的 Cross-encoder Reranker​ 会将查询和一个候选文档同时输入模型,让模型直接分析两者之间的交互信息,从而给出一个更精确的相关性分数 。
    2、结果重排序:Reranker 为所有候选文档重新打分并排序,最终只将排名最靠前的、真正相关的少量文档(如 Top 3 或 Top 5)传递给 LLM 。

Milvus 4 RAG

在 RAG 流程中,Milvus 扮演着 知识库与高速检索引擎 的角色。

  1. 检索(Retrieval):当用户提问时,系统首先使用嵌入模型将问题转换为查询向量。随后,Milvus 在该查询向量与知识库中所有文档向量之间进行高速的相似性比较(不同于结构化数据库的精确查询,是支持相似语义的模糊查询),找出最相关的几个知识片段。
  2. 增强(Augmentation):将这些检索到的知识片段(元数据中的原始文本)作为上下文,与用户的问题组合成一个更丰富的 Prompt
  3. 生成(Generation):将这个富含上下文的提示词发送给大语言模型(如 qwen3-235b-a22b),由它来生成精准、有据可依的最终答案。

人工智能集成:

  1. Embeddings 模型集成:将非结构化数据转换为其在高维数据空间中的数字表示,以便您可以将其存储在 Milvus 中。目前,PyMilvus(Python SDK)集成了多个嵌入模型,因此您可以快速将数据准备成向量嵌入。
  2. Reranker 模型集成:在信息检索和生成式人工智能领域,Reranker 是优化初始搜索结果顺序的重要工具。PyMilvus 也集成了几种 Rerankers 模型,以优化初始搜索返回结果的顺序。
  3. LangChain 和其他人工智能工具集成:在 GenAI 时代,LangChain 等工具受到了应用程序开发人员的广泛关注。作为核心组件,Milvus 通常在此类工具中充当向量存储。要了解如何将 Milvus 集成到您喜爱的人工智能工具中,请参阅我们的集成和教程。

Agentic RAG(智能体驱动的 RAG,Agentic RAG = RAG + Agent:基础的 RAG 中,检索-增强-生成是一次性完成的。而Agentic RAG则引入了“智能体”的概念,智能体可以根据对大模型初步生成内容的理解,主动地、多次地 与向量数据库(Milvus)进行交互。这使 RAG 系统从静态的“文档查找”升级为动态的、具有决策能力的“研究助手”。例如:

  • 判断是否需要进一步检索:如果首次检索到的信息不足以回答问题,智能体可以重新生成搜索 query,多轮检索,直到信息足够。
  • 分解复杂问题:对于复杂问题,智能体可以将其拆解成多个子问题,然后针对每个子问题去 Milvus 中检索相关信息,最后综合所有信息生成答案。
  • 工具调用(Tool Use):智能体可以将 Milvus 的检索功能视为一个可调用的工具,根据对话进程决定何时以及如何调用这个工具。

Agent

AI Agent的本质是能够感知环境、自主决策并执行行动的智能实体。与传统AI系统最大的区别在于Agent具有自主性、反应性、目标导向和学习能力,它不再是简单的工具,而是能够主动规划和完成复杂任务的智能体。从1997年击败国际象棋世界冠军的IBM“深蓝”,到2011年苹果推出的个人助理Siri,都展示了Agent在特定领域的强大能力,关键的转折点发生在2023年左右,大语言模型LLM的出现为Agent提供了强大的通用理解和推理能力,使其不再局限于单一任务。

Agent 架构模式

  1. 组成组件
    Agent:智能代理,它是一个能够感知环境、做出决策并执行动作的软件实体(比起LLM只能“回答问题”,Agent可以真正地“执行任务”)。在LLM语境中,Agent通常利用LLM作为大脑,来理解用户输入、决定需要执行的动作(比如调用工具)、处理工具返回的结果并生成响应。
    LLM(大语言模型):如GPT系列,是Agent的核心,负责理解自然语言、进行推理和生成文本。
    Tool:工具,是Agent可以调用的函数,用于执行特定任务,比如查询数据库、调用API。Tool扩展了Agent的能力,使其能够获取实时信息或执行具体操作。
    Function Calling:函数调用,是LLM的一种能力,允许模型根据用户输入决定何时以及如何调用哪个函数(Tool),并以结构化格式(如JSON)输出函数调用参数。然后由外部系统执行该函数。
    Prompt:提示词,是引导LLM生成期望输出的文本。在Agent中,Prompt通常包含系统指令(定义Agent的角色和能力)、用户输入、对话历史以及工具描述等。
    RAG(检索增强生成):通过从外部知识库检索相关信息,并将其作为上下文提供给LLM,从而生成更准确、更相关的回答。
    MCP(模型上下文协议):MCP可以包含本地tools和外部API,但通常 MCP更强调于将工具(无论是本地tools还是外部API)以标准化的上下文协议暴露给AI模型。MCP可以看作是一个中间层,它将工具抽象成标准的接口,使得AI Agent可以通过统一的协议来调用这些工具,从而实现模型与工具之间的解耦。
  2. 一个典型的工作流程如下:
    用户输入自然语言请求。
    Agent将用户输入、对话历史、可用的工具描述(通过Function Calling定义)以及系统提示词组合成一个Prompt,发送给LLM。
    LLM根据Prompt判断是否需要调用工具。如果需要,LLM会返回一个函数调用请求(包括函数名和参数)。
    Agent解析LLM返回的函数调用请求,并执行对应的工具(Tool)。
    工具执行后返回结果,Agent将工具执行结果作为上下文,再次调用LLM,生成最终的自然语言响应。
    Agent将响应返回给用户。
    在这个过程中,RAG可以在第一步之前或之中介入,通过检索外部知识库来增强Prompt的上下文。
  3. a demo
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    #### main.py
    from pydantic_ai.models.gemini import GeminiModel
    from pydantic_ai import Agent
    from dotenv import load_dotenv
    import tools

    # 模型API Key等可以写到.env文件 并加载到环境变量
    load_dotenv()
    model = GeminiModel("gemini-2.5-flash-preview-04-17")

    # 将llm模型、系统prompt、工具tools “注册” 到 Agent
    agent = Agent(model,
    system_prompt="You are an experienced programmer",
    tools=[tools.read_file, tools.list_files])

    def main():
    history = []
    while True:
    # eg. Input: list and read file. base on your konwledge tell me what lang each file use.
    user_input = input("Input: ")
    # 将用户输入、历史对话(上下文)发给 agent 并记录本次对话(短期记忆)
    resp = agent.run_sync(user_input,
    message_history=history)
    history = list(resp.all_messages())
    print(resp.output)

    if __name__ == "__main__":
    main()
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    #### tools.py
    from pathlib import Path
    import os

    base_dir = Path("./test")

    def read_file(name: str) -> str:
    # docstring 帮助模型理解 tools
    """Return file content. If not exist, return error message.
    """
    print(f"(read_file {name})")
    try:
    with open(base_dir / name, "r") as f:
    content = f.read()
    return content
    except Exception as e:
    return f"An error occurred: {e}"

    def list_files() -> list[str]:
    print("(list_file)")
    file_list = []
    for item in base_dir.rglob("*"):
    if item.is_file():
    file_list.append(str(item.relative_to(base_dir)))
    return file_list

MCP

MCP 可以看作是一个中间层,它将工具抽象成标准的接口,使得AI Agent可以通过统一的协议来调用这些工具,从而实现模型与工具之间的解耦。MCP 可以包含本地tools和外部API,但通常 MCP更强调于将工具(无论是本地tools还是外部API)以标准化的上下文协议暴露给AI模型。

  1. Agent通过集成的MCP Client向MCP Server发送请求,调用工具。因此,Agent不再直接调用具体的工具函数,而是可以使用任何符合MCP协议的工具,无论工具是本地还是远程。MCP模式下,我们不再直接注册这些Tools到Agent(如传统框架LangChain),而是注册MCP Client(可以看作是Tools的抽象层),然后Agent通过MCP Client来动态获取MCP Server提供的Tools列表,并在需要时调用它们。
    示例流程:
    步骤1:启动一个MCP Server,它提供了一些工具(例如,天气查询、计算器等)。
    步骤2:在Agent框架中,配置MCP Client,并连接到该MCP Server。
    步骤3:Agent在需要时,通过MCP Client查询MCP Server提供了哪些工具。
    步骤4:当用户提问时,Agent决定调用哪个工具,然后通过MCP Client发送调用请求给MCP Server。
    步骤5:MCP Server执行工具,并将结果返回给MCP Client,然后Agent接收结果并生成最终回答。?
  2. MCP代表了AI应用架构的演进方向,从紧耦合的工具注册转向松耦合的工具治理,特别适合企业级AI应用的复杂集成场景。

RAG

RAG​ 的核心思想是:在让大模型回答问题之前,先从一个外部的、可随时更新的知识库中检索相关信息,然后将这些“新鲜”信息作为上下文和问题一起交给模型,从而引导模型生成更准确、及时且可追溯的答案。它能有效减少模型“幻觉”(即胡编乱造),让AI应用在知识密集型任务中变得真正可靠。以及,它能帮助构建专业领域专家对话机器人。

一个典型的RAG系统工作流程包含三个关键阶段:

  1. 知识库索引构建(Indexing)
    这是准备阶段,目的是将您的私有知识库“灌输”进向量数据库。
    文档解析与分块:首先,系统会解析各种格式的文档(如PDF、Word、HTML),将其转换为纯文本。然后,根据语义或结构将长文本切分成大小适宜的“文本块”(Chunks),以适应模型上下文长度限制。
    向量化(Embedding):使用嵌入模型将每个文本块转换为一个高维向量(一组数字)。这个向量就像是文本在数学空间中的“坐标”,语义相近的文本,其向量在空间中的距离也更近。
    向量存储:将这些向量及其对应的原始文本块、元数据(如来源、标题)一并存入向量数据库。
  2. 实时检索(Retrieval)
    当用户提出问题时,系统执行以下操作:
    使用相同的嵌入模型将用户问题也转换为一个向量。
    将这个“问题向量”送入向量数据库,进行相似性搜索。数据库会快速找出与问题向量最相似的K个“文档向量”。
    为了提高检索质量,常采用混合检索策略,结合语义向量搜索和传统关键词搜索,并利用重排序模型对初步结果进行精细排序,以提升准确性。
  3. 增强生成(Generation)
    提示词增强:将检索到的最相关的文本块作为上下文,与用户的原始问题一起组合成一个结构化的提示词(Prompt)。
    智能生成:将这个富含信息的提示词发送给LLM,基于您提供的权威上下文,而非仅凭其内部可能过时的知识,来生成最终答案

Agent流程编排

业务逻辑

LangChain

LangChain 是一个功能强大的大语言模型应用开发框架。与Spring在Java后端开发中的定位类似。
https://python.langchain.com/docs/concepts/
https://arxiv.org/abs/2302.07842

LangChain 包:通过 pip 命令(类似于Java的Maven或Gradle)安装到项目中,避免重复造轮子。

LangGraph

LangGraph 核心认知:用“有向图”构建智能体的新一代框架,是 用于构建有状态、多步骤、多分支智能体(Agent) 的框架,核心是将 Agent 的行为拆解为节点(Nodes)边(Edges),用有向图(Directed Graph) 替代老版本的“线性循环” 以支持更复杂的流程编排。
LangGraph 可以理解为:给 Agent 设计“流程图”的工具,而老版本 ReAct Agent 只是这个流程图中最基础的“单循环分支”。
https://docs.langchain.com/oss/python/langgraph/overview

  • LangGraph 核心概念解析(多节点、边是关键)
    1. 核心基础:状态(State)
      • 作用:整个图的“共享内存”,所有节点都能读写这个状态(比如用户问题、LLM 思考结果、工具调用结果、最终回答等)。
      • 举例:在你之前的 CMDB Agent 中,状态里会包含:
        1
        2
        3
        4
        5
        {
        "messages": [{"role": "user", "content": "显示运行中的Linux服务器"},
        {"role": "ai", "content": "思考过程+工具调用指令"},
        {"role": "tool", "content": "工具调用结果"}]
        }
      • 特点:状态是持久化的(通过 Checkpoint 如 InMemorySaver),支持中断、恢复、回溯(比如多轮对话的上下文保留)。
    2. 最小执行单元:节点(Node)
      • 定义:图的最小操作单元,对应一个具体的功能(比如调用 LLM、调用工具、格式化回答、清洗用户问题)。
      • 类型(实际开发中常见):
      • LLM 节点:调用大模型生成思考结果或工具调用指令(比如你之前看到的“分析问题+工具选择”)。
      • 工具调用节点:执行具体的工具函数(比如 cmdb_searchcmdb_query)。
      • 预处理/后处理节点:清洗用户问题、格式化最终回答。
      • 判断节点:根据状态判断流程走向(比如“是否需要继续调用工具?”)。
      • 多节点的价值:你可以把 Agent 的复杂行为拆分成多个独立节点,比如:
        用户输入清洗节点LLM 思考节点CMDB 工具节点日志工具节点回答格式化节点
    3. 流程的灵魂:边(Edge)
      • 定义:节点之间的连接关系,定义流程的走向。LangGraph 支持三种边,这也是“多分支”的核心:
      • 普通边(Direct Edge):直接从 A 节点跳转到 B 节点(比如“清洗节点”执行完,直接到“LLM 思考节点”)。
      • 条件边(Conditional Edge):根据状态的内容判断跳转方向(最核心的“多分支”能力)。
        • 举例:LLM 输出“需要调用 CMDB 工具”,则跳转到 cmdb_search 节点;如果输出“需要调用日志工具”,则跳转到 log_search 节点;如果输出“无需调用工具”,则跳转到“回答节点”。
      • 入口/出口边:定义图的开始节点(比如用户输入节点)和结束节点(比如回答节点)。
      • 多边的价值:打破了老版本“单一循环”的限制,支持分支、并行、循环等复杂流程。
    4. 关键能力:检查点(Checkpoint)
      • 作用:记录图的执行状态,支持中断、恢复、回溯(比如你之前用的 InMemorySaver 就是内存级的检查点,还可以用 Redis、SQL 实现持久化)。
      • 场景:多轮对话中,用户可以“回退”到上一步,或 Agent 崩溃后恢复执行。
  • LangGraph 中 Agent 与 Tools 的工作机制(结合你的 CMDB 例子)
    以你之前的“显示运行中的 Linux 服务器”为例,LangGraph 的执行流程可以拆解为一个极简的有向图
    1
    2
    3
    4
    5
    6
    7
    8
    9
    [入口节点:用户输入] 
    ↓(普通边)
    [LLM 思考节点]:分析问题,生成工具调用指令(cmdb_search + 入参)
    ↓(条件边:判断需要调用工具)
    [工具调用节点]:执行 cmdb_search,将结果写回状态
    ↓(条件边:判断无需继续调用工具)
    [LLM 回答节点]:基于工具结果生成最终回答
    ↓(普通边)
    [出口节点:输出回答]
    核心细节:
    1. 状态驱动:所有节点都通过状态交互,没有直接的函数调用——LLM 节点从状态中读用户问题,工具节点从状态中读工具调用指令,执行后写回结果。
    2. 工具的解耦:工具本身是独立的函数(如 cmdb_search),LangGraph 只通过工具调用节点统一管理,支持多工具的动态选择和调用。
    3. 循环执行:通过条件边实现“思考→工具→再思考→再工具”的循环(比如用户问“查生产主机并统计数量”,可能需要先调用 cmdb_search,再调用 cmdb_query 统计)。
  • LangGraph vs 老版本 ReAct Agent(核心区别)
    老版本 ReAct Agent(LangChain v0.x 的 AgentExecutor)是 LangGraph 的简化版,两者的核心差异在于流程的编排能力
    维度 老版本 ReAct Agent(AgentExecutor) LangGraph
    架构基础 线性循环(Single Loop) 有向图(Directed Graph)
    节点/边 无物理节点拆分,只有“思考→工具”的逻辑两步;无多分支边,只有单一循环。 支持多节点、多类型边(条件边、普通边),可编排复杂流程。
    状态管理 临时状态(每次循环重新生成,无持久化) 统一的状态对象,支持持久化、回溯(Checkpoint)。
    流程灵活性 只能“思考→工具→思考”的单一循环,多工具需按顺序调用(一次一个)。 支持多分支(比如不同工具的并行调用)、条件跳转、中断恢复。
    扩展性 扩展复杂流程(如多工具并行)需要大量自定义代码。 通过图的编排即可实现,无需修改核心逻辑。
    老版本 ReAct Agent 的核心是 AgentExecutor单一循环
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    while True:
    # 1. 调用 LLM 生成思考结果和工具调用指令
    llm_output = llm.invoke(状态)
    # 2. 判断是否需要调用工具
    if 需要调用工具:
    tool_result = tool.invoke(llm_output 中的指令)
    # 将工具结果加入状态,继续循环
    else:
    # 生成最终回答,退出循环
    break
    它的“节点”只是逻辑上的两步(思考、工具),没有物理上的节点拆分,也没有多分支的边——即使有多个工具,也只能按顺序单次调用(一次调一个),无法实现并行或多分支跳转。
    比如:
    老版本要实现“查生产主机+查今日告警”,只能先调用 cmdb_search,再调用 alert_search,通过多次循环实现。
    LangGraph 可以通过多节点和条件边,甚至并行执行这两个工具(比如同时调用 CMDB 和告警工具,提升效率)。
  • 五、总结:为什么需要 LangGraph?
    1. 从“单一循环”到“复杂图”:老版本 Agent 适合简单的单工具循环场景,而 LangGraph 适合需要复杂流程编排的场景(比如多工具、多分支、有状态的智能体)。
    2. 可视化与可维护性:将 Agent 的行为拆解为节点和边,流程更清晰,便于调试和维护(比如你之前看到的“两轮 LLM 调用”,在 LangGraph 中就是两个节点的执行)。
    3. 生产级能力:Checkpoint、状态持久化、中断恢复等能力,让 LangGraph 更适合生产环境的部署。

Spring AI

集成到Java

MongoDB


MongoDB 是一个基于文档的开源 NoSQL 数据库,使用类似 JSON 的文档模型灵活存储数据,旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。
MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。
https://www.mongodb.com/zh-cn/docs/manual/crud/

MongoDB 概念 类比 MySQL 概念 类比 Elasticsearch 概念 核心解析
文档 (Document) 行 (Row) 文档 (Document) 数据的基本单元,是一个键值对的有序集合。它类似于一条完整的记录。
集合 (Collection) 表 (Table) 索引 (Index) 一组文档的容器。它类似于一张数据表。
数据库 (Database) 数据库 (Database) 无直接对应(可类比为索引的逻辑分组) 最高层的命名空间,用于组织和管理多个集合。一个 MongoDB 实例可以运行多个数据库,每个数据库在文件系统上有独立的文件。
字段 (Field) 列 (Column) 字段 (Field) 文档中的键值对,代表一个数据属性。
  • 关键特性与对比
    1. BSON:MongoDB 的“增强版JSON”
    BSON(Binary JSON)是 MongoDB 用来存储文档和数据交换的二进制格式。您可以把它理解为 JSON 的超级版,它支持 JSON 的所有数据类型,但更强大: 二进制编码:比 JSON 更紧凑,存储和扫描效率更高。更丰富的数据类型:除了字符串、数字、数组、对象外,还支持日期、对象ID(ObjectId)、二进制数据等特定类型。
    2. 灵活的模式(Schema)
    这是 MongoDB 与 MySQL 最根本的区别之一。同一个集合内的文档不需要具有相同的字段集。您可以随时为文档添加新字段,而无需像关系型数据库那样进行复杂的 ALTER TABLE 操作。
  • 如何根据场景选择
    特性 MongoDB MySQL Elasticsearch
    数据模型 文档模型,动态模式 关系模型,固定模式 文档模型,可定义映射
    查询语言 面向对象的 API 方法 标准 SQL 语句 JSON-based DSL
    核心优势 敏捷开发、水平扩展、存储复杂数据结构 复杂查询、事务一致性、数据完整性 全文搜索、日志分析、复杂聚合
    典型场景 内容管理系统、用户画像、实时分析、物联网 金融交易系统、ERP、CRM等需要严格事务的系统 搜索引擎、日志和指标分析、应用内搜索
  • Mongo CRUD汇总
    操作类型 方法示例 功能说明
    创建 (Create) db.hosts.insertOne({hostname: "web-01", ip: "192.168.1.100"}) 向集合中插入一条新文档。若集合不存在,会自动创建。
    批量创建 db.hosts.insertMany([{hostname: "web-01"}, {hostname: "db-01"}]) 批量插入多条文档。
    查询 (Read) db.hosts.find({status: "running"}) 查询所有符合条件的文档。不传参数则返回所有文档。
    条件查询 db.hosts.find({"specs.memory": {$gte: 8}}, {hostname: 1, _id: 0}) 使用查询操作符进行过滤,并使用投影选择返回的字段。
    更新 (Update) db.hosts.updateOne({hostname: "web-01"}, {$set: {"specs.memory": 32}}) 更新一条匹配的文档。$set 操作符用于修改特定字段的值。
    批量更新 db.hosts.updateMany({environment: "production"}, {$inc: {visits: 1}}) 更新所有匹配的文档。$inc 操作符用于将字段的值增加指定数额。
    删除 (Delete) db.hosts.deleteOne({hostname: "web-01"}) 删除一条匹配的文档。
    批量删除 db.hosts.deleteMany({status: "terminated"}) 删除所有匹配的文档。

读写

  • 写入确认:默认情况下,MongoDB 的写入操作是异步的。如果你的应用需要确保数据已经安全写入,可以设置 写关注(Write Concern)来控制确认级别。
  • 单文档原子性:所有 CRUD 操作在 单个文档 级别是原子的。例如,一条文档的更新操作要么完全成功,要么完全失败,不会出现只更新一半字段的情况。需要注意的是,insertMany 这样的多文档操作,默认情况下并非一个整体事务。
  • 比较操作符:$gt (大于), $gte (大于等于), $lt (小于), $lte (小于等于), $ne (不等于)。
    逻辑操作符:$and, $or, $in (匹配数组中任意值), $nin (不匹配数组中任何值)。
  • 关键操作:
    1
    2
    3
    4
    5
    6
    7
    // 创建
    db.hosts.insertOne({
    hostname: "web-01",
    ip: "192.168.1.100",
    specs: { cpu: 8, memory: 16 }, // 嵌入式文档
    tags: ["web", "production"]
    })
    1
    2
    3
    4
    5
    // 查询与投影
    db.hosts.find(
    { "specs.memory": { $gte: 8 }, "status": "running" },
    { hostname: 1, ip: 1, _id: 0 } // 投影:只返回指定字段
    )
    1
    2
    3
    4
    5
    6
    7
    8
    9
    // 更新操作符
    db.hosts.updateOne(
    { hostname: "web-01" },
    {
    $set: { "specs.memory": 32 }, // 设置字段
    $push: { tags: "upgraded" }, // 数组追加
    $inc: { "stats.visits": 1 } // 数值递增
    }
    )
  • 复杂查询模式:
    1
    2
    3
    4
    5
    6
    7
    // 逻辑组合查询
    db.hosts.find({
    $or: [ // $or逻辑操作符用于筛选出符合任意一组给定条件的文档
    { "environment": "production", "status": "running" }, // 每个条件组内部使用隐式的AND逻辑,需同时满足
    { "criticality": "high", "last_backup": { $gte: yesterday } } // $gte是“大于或等于”的比较操作符
    ]
    })
    1
    2
    3
    4
    5
    // 数组查询
    db.hosts.find({
    "tags": { $all: ["web", "load_balancer"] }, // 包含所有指定标签
    "ips": { $size: 3 } // 数组长度匹配
    })
    1
    2
    3
    4
    // 正则表达式与文本搜索
    db.hosts.find({
    "hostname": { $regex: "^web-.*", $options: "i" }
    })

聚合框架

  • 聚合和管道是 MongoDB 最强大、最独特的特性之一。核心概念用工厂流水线来理解:想象一下数据处理就像一条工厂装配线
    • 普通查询:像是在成品仓库里筛选符合条件的产品。例如:“给我找出所有红色的汽车。” 你得到的是原始产品列表。
    • 聚合管道:像是把原材料送进一条多阶段的加工流水线,每个工位(阶段)都对数据进行特定处理,最终产出全新的、经过深度加工的产品。例如:原材料 → 切割 → 焊接 → 喷漆 → 组装 → 全新的汽车模型+统计报告。
  • 目的:对数据进行多阶段转换、分组、计算,生成全新的数据结构。
  • 详细对比解析
    1. 普通查询:检索和筛选文档。你得到的是原始数据。
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      // 场景:找出所有生产环境的Linux主机
      db.hosts.find({
      environment: "production",
      "os.type": "Linux"
      })

      // 返回结果:原始文档数组
      [
      {hostname: "web-01", environment: "production", os: {type: "Linux"}, memory_gb: 16, ...},
      {hostname: "db-01", environment: "production", os: {type: "Linux"}, memory_gb: 32, ...},
      // ... 直接返回所有匹配的文档
      ]
    2. 复杂查询:在检索时进行一些简单计算或逻辑处理。
      1
      2
      3
      4
      5
      6
      7
      // 场景:找出内存大于8G的生产环境主机,按内存降序排列,只显示主机名和内存
      db.hosts.find(
      { environment: "production", memory_gb: { $gt: 8 } },
      { hostname: 1, memory_gb: 1, _id: 0 } // 投影:选择字段
      ).sort({ memory_gb: -1 }).limit(10)

      // 返回结果:经过筛选和排序的文档,但结构基本不变
    3. 聚合管道 (Aggregation Pipeline) :对数据进行多阶段转换、分组、计算,生成全新的数据结构
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      // 目标:查询生产环境的应用,并获取其运行主机的详细信息
      db.applications.aggregate([ // 在'applications'集合上执行聚合管道
      // 阶段 1: $match - 筛选文档
      {
      $match: { // 过滤条件:只处理符合以下条件的应用文档
      "environment": "production", // 条件1: 环境为'production'
      "status": "active" // 条件2: 状态为'active'
      }
      },

      // 阶段 2: $lookup - 关联查询(连表查询)
      {
      $lookup: { // 从左集合(applications)关联到右集合(hosts)
      from: "hosts", // 要关联的集合名称:'hosts'
      localField: "app_name", // 左集合(applications)中的关联字段:应用名称
      foreignField: "running_apps", // 右集合(hosts)中的关联字段:运行的应用列表
      as: "host_details" // 将关联匹配到的主机文档存入此新字段(是一个数组)
      }
      },

      // 阶段 3: $unwind - 展开数组字段
      {
      $unwind: "$host_details" // 将`host_details`数组拆分为多条独立的文档,每条包含一个应用和一个主机
      },

      // 阶段 4: $project - 重塑文档结构
      {
      $project: { // 定义输出文档的字段
      "_id": 0, // 不显示原始的_id字段(0为排除)
      "application": "$app_name", // 将app_name重命名为application
      "team": "$owner_team", // 显示负责团队
      "criticality": 1, // 显示应用关键程度(1为包含)
      // 从关联的主机文档中提取信息
      "hostname": "$host_details.hostname", // 显示主机名
      "ip_address": "$host_details.ip_address", // 显示IP地址
      "cpu_cores": "$host_details.specs.cpu_cores", // 显示CPU核心数
      "memory_gb": "$host_details.specs.memory_gb", // 显示内存大小
      "disk_gb": "$host_details.specs.disk_gb" // 显示磁盘大小
      }
      },

      // 阶段 5: $sort - 结果排序
      {
      $sort: { // 排序条件
      "team": 1, // 首先按团队名称升序排列 (1: 升序, -1: 降序)
      "criticality": -1, // 其次按应用关键程度降序排列 (high比medium优先级高)
      "memory_gb": -1 // 关键程度相同时,按主机内存降序排列
      }
      }
      ])
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      // 应用文档示例
      {
      "_id": ObjectId("67a1b2c3d4e5f6a1b2c3d4e5"),
      "app_name": "订单服务",
      "environment": "production", // 环境: production, staging, development
      "owner_team": "order-team",
      "criticality": "high"
      }
      // 主机文档示例
      {
      "_id": ObjectId("77a1b2c3d4e5f6a1b2c3d4e5"),
      "hostname": "prod-order-01",
      "ip_address": "192.168.1.100",
      "environment": "production",
      "specs": {
      "cpu_cores": 8,
      "memory_gb": 32,
      "disk_gb": 500
      },
      "running_apps": ["订单服务", "用户服务"] // 在此主机上运行的应用名称数组
      }
      // 返回结果:完全重新组织的数据
      [
      {
      "application": "订单服务",
      "team": "order-team",
      "criticality": "high",
      "hostname": "prod-order-01",
      "ip_address": "192.168.1.100",
      "cpu_cores": 8,
      "memory_gb": 32,
      "disk_gb": 500
      },
      {
      "application": "支付网关",
      "team": "payment-team",
      "criticality": "critical",
      "hostname": "prod-payment-01",
      "ip_address": "192.168.1.101",
      "cpu_cores": 16,
      "memory_gb": 64,
      "disk_gb": 1000
      }
      // ... 其他结果
      ]
    4. CMDB 应用场景
      问题1:”显示每个团队负责的主机数量,并按环境分别统计”
      1
      2
      3
      4
      5
      6
      7
      8
      db.hosts.aggregate([
      { $match: { status: "running" } },
      { $group: {
      _id: { team: "$owner_team", env: "$environment" },
      host_count: { $sum: 1 }
      }},
      { $sort: { host_count: -1 } }
      ])
      问题2:”找出生产环境中,哪些应用依赖的主机平均内存使用率超过80%”
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      db.applications.aggregate([
      { $match: { environment: "production" } },
      { $lookup: {
      from: "hosts",
      localField: "dependent_hosts",
      foreignField: "hostname",
      as: "host_details"
      }},
      { $project: {
      app_name: 1,
      avg_memory_usage: { $avg: "$host_details.memory_usage_percent" }
      }},
      { $match: { avg_memory_usage: { $gt: 80 } } }
      ])

索引策略

  1. 索引类型与应用场景:
  • 单字段索引:db.hosts.createIndex({ hostname: 1 })
  • 复合索引:db.hosts.createIndex({ environment: 1, status: 1 })
  • 多键索引:数组字段索引 db.hosts.createIndex({ tags: 1 })
  • 文本索引:全文搜索 db.hosts.createIndex({ description: "text" })
  • TTL索引:自动过期数据 db.logs.createIndex({ createdAt: 1 }, { expireAfterSeconds: 3600 })
  1. 索引优化原则:
  • ESR规则:Equality(等值) → Sort(排序) → Range(范围)
  • 覆盖查询:索引包含所有查询字段,避免回表
  • 索引交集:MongoDB可自动组合多个索引

高可用与扩展

1. 复制集(Replica Set)深度

  • 架构组成
    1
    2
    3
    4
    5
    Primary(主节点)← 读写操作
    ↓ 数据同步
    Secondary-1(从节点)← 只读查询
    Secondary-2(从节点)← 只读查询
    Arbiter(仲裁节点)← 仅参与选举
  • 配置示例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // 复制集配置
    cfg = {
    _id: "cmdb-rs",
    members: [
    {_id: 0, host: "mongo1:27017", priority: 2},
    {_id: 1, host: "mongo2:27017", priority: 1},
    {_id: 2, host: "mongo3:27017", priority: 1, arbiterOnly: true}
    ]
    }
    rs.initiate(cfg)
  • 读写关注
    1
    2
    3
    4
    5
    6
    7
    // 强一致性写操作
    db.hosts.insertOne(doc, {
    writeConcern: { w: "majority", wtimeout: 5000 }
    })

    // 从节点读取(最终一致性)
    db.hosts.find().readPref("secondary")

2. 分片集群(Sharded Cluster)

  • 分片策略选择
    • 基于范围分片:适合范围查询,可能产生热点
    • 基于哈希分片:数据分布均匀,范围查询效率低
    • 区域分片:基于标签的智能数据分布
  • 分片键选择考量
    1
    2
    3
    4
    5
    // 好的分片键:基数高、分布均匀
    sh.shardCollection("cmdb.hosts", { "tenant_id": 1, "hostname": 1 })

    // 避免的选择:低基数、单调递增
    // sh.shardCollection("cmdb.hosts", { "created_date": 1 }) // 不好!

CMDB助手查询工具设计(基于MCP)

  • MCP工具架构设计
    1
    自然语言查询 → MCP Server → 查询解析器 → MongoDB查询生成器 → 结果格式化
  • MCP Server 核心代码
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    from mcp import MCPServer, Context
    import pymongo
    from typing import Dict, List, Any

    class CMDBAgentMcpServer:
    def __init__(self, mongo_uri: str):
    self.client = pymongo.MongoClient(mongo_uri)
    self.db = self.client.cmdb
    self.setup_tools()

    @mcp_tool(
    name="query_hosts",
    description="根据条件查询主机信息",
    args_schema={
    "type": "object",
    "properties": {
    "environment": {"type": "string", "enum": ["production", "staging", "development"]},
    "os_type": {"type": "string"},
    "min_memory": {"type": "integer"},
    "status": {"type": "string", "enum": ["running", "stopped", "maintenance"]},
    "tags": {"type": "array", "items": {"type": "string"}},
    "limit": {"type": "integer", "default": 10}
    }
    }
    )
    async def query_hosts(self, ctx: Context, **filters) -> List[Dict]:
    """智能主机查询工具"""
    # 构建MongoDB查询
    query = self._build_host_query(filters)

    # 执行查询
    cursor = self.db.hosts.find(query["filter"], query["projection"])
    cursor = cursor.sort(query["sort"]).limit(query["limit"])

    results = list(cursor)
    return self._format_host_results(results)

    def _build_host_query(self, filters: Dict) -> Dict:
    """将自然语言参数转换为MongoDB查询"""
    query_filter = {}

    # 环境过滤
    if filters.get("environment"):
    query_filter["environment"] = filters["environment"]

    # 操作系统过滤(支持模糊匹配)
    if filters.get("os_type"):
    query_filter["os.type"] = {"$regex": filters["os_type"], "$options": "i"}

    # 内存条件
    if filters.get("min_memory"):
    query_filter["specs.memory_gb"] = {"$gte": filters["min_memory"]}

    # 状态过滤
    if filters.get("status"):
    query_filter["status"] = filters["status"]

    # 标签查询
    if filters.get("tags"):
    query_filter["tags"] = {"$all": filters["tags"]}

    return {
    "filter": query_filter,
    "projection": {"_id": 0, "hostname": 1, "ip": 1, "environment": 1, "os": 1, "specs": 1},
    "sort": [("last_seen", -1)],
    "limit": filters.get("limit", 10)
    }

    @mcp_tool(
    name="analyze_infrastructure",
    description="基础设施统计分析",
    args_schema={
    "type": "object",
    "properties": {
    "analysis_type": {"type": "string", "enum": ["environment", "os", "team"]},
    "metric": {"type": "string", "enum": ["count", "memory", "cpu"]}
    }
    }
    )
    async def analyze_infrastructure(self, ctx: Context, analysis_type: str, metric: str = "count"):
    """聚合分析工具"""
    pipeline = self._build_analysis_pipeline(analysis_type, metric)
    results = list(self.db.hosts.aggregate(pipeline))
    return self._format_analysis_results(results, analysis_type, metric)

    # 使用示例
    server = CMDBAgentMcpServer("mongodb://localhost:27017/cmdb")
  • Agent提示词设计
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    你是一个CMDB专家,可以查询和分析基础设施信息。

    可用工具:
    1. query_hosts - 查询主机信息,支持按环境、操作系统、内存等条件过滤
    2. analyze_infrastructure - 统计分析基础设施资源分布

    示例交互:
    用户:列出生产环境中所有运行CentOS的主机
    AI:我将使用query_hosts工具查询...
    工具调用:query_hosts(environment="production", os_type="CentOS")

    用户:按环境统计主机数量
    AI:使用analyze_infrastructure进行分析...
    工具调用:analyze_infrastructure(analysis_type="environment", metric="count")
  • 高级查询特性支持
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    # 支持复杂查询的扩展工具
    @mcp_tool(
    name="advanced_host_search",
    description="高级主机搜索,支持复杂条件组合"
    )
    async def advanced_search(self, ctx: Context, search_expression: str):
    """支持自然语言复杂查询"""
    # 使用LLM解析复杂查询条件
    parsed_query = await self.llm_parse_search(search_expression)
    return await self.execute_advanced_query(parsed_query)

    # 关系查询工具
    @mcp_tool(
    name="find_related_assets",
    description="查找相关资产和依赖关系"
    )
    async def find_related_assets(self, ctx: Context, hostname: str, relation_type: str):
    """查询资产关系"""
    pipeline = [
    {"$match": {"hostname": hostname}},
    {"$graphLookup": { # 使用图查询查找关系
    "from": "asset_relations",
    "startWith": "$_id",
    "connectFromField": "from_asset",
    "connectToField": "to_asset",
    "as": "relationships"
    }}
    ]
    return list(self.db.hosts.aggregate(pipeline))

Kubernetes

2023-07-31 10:25:07 Docker /

Docker 是一种开源平台,一种快速构建、运行和管理应用的工具。它使用容器化技术,使得应用程序及其依赖性可以打包到一个容器中,并在任何支持 Docker 的环境中运行。
1 MobarXterm 通过 SSH 连接 linux虚拟机,操作虚拟机上的 Docker。
2 Windows本地:通过wsl安装Linux发行版本,安装docker desktop(将自动在WSL中配置Docker环境,借助linux内核运行)

容器(Container)

  • 容器是一个轻量级的、可移植的、自包含的单元,包括应用程序和其所有依赖项。
  • Docker 利用容器技术,将应用程序及其依赖项打包成一个容器,确保在不同环境中的一致性运行。
  • Docker 位于容器 和 服务器-操作系统/硬件 之间,是运行容器的引擎。
  • 隔离网络、文件、进程等环境。一个容器是一个沙盒隔离环境。
  • 相对于虚拟机技术,docker 启动更快、更清量。但容器共用宿主机的内存、CPU物理资源,多容器可能存在互相抢占资源的情况。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    docker run -d \                  # 创建并运行一个容器,-d 是让容器在后台运行;同一个镜像可创建多个容器
    --name mysgl \ # 给容器起名字,必须唯一
    -p 3306:3306 \ # 设置 宿主机端口:容器端口 映射
    -e TZ=Asia/Shanghai \ # 设置环境变量
    -e MYSQL_ROOT_PASSWORD=123 \ # 指定运行的镜像名,一般为 [镜像名]:[镜像版本]
    mysql
    docker ps # 查看本地容器(运行中的)
    docker ps a # 查看所有容器 (包括未运行)
    docker start <容器ID> # 启动容器
    docker stop <容器ID> # 停止容器中的进程,容器未删除
    docker rm <容器ID> # 删除容器
    docker inspect <容器ID> # 查看容器配置信息
    docker log <容器ID> # 查看容器日志
    docker exec -it <容器ID> bash # 进入容器内部,命令行模式(容器内部模拟出一个操作系统)
    容器打包成镜像: docker commit -a "作者信息" -m "log信息" <容器ID><目标镜像名称:tag版本>
    拷贝文件到容器: docker cp <文件目录> <容器ID>:<目标目录>
    拷贝容器文件到宿主机:docker cp <容器ID>:<文件目录><宿主机目标目录>
    更新容器设置:docker update <容器ID><相关设置>

镜像(Image)

  • 镜像是一个只读的模板,包含运行应用程序所需的所有信息,包括代码、运行时、库、环境变量和配置文件。
  • 容器是通过运行镜像创建的(像光盘),本地容器是真正运行的实例。镜像是容器的模板,是从容器打包来的,可以在不同操作系统,不同服务器之间传播。
  • 1
    2
    3
    4
    5
    6
    7
    docker images                                # 查看本地镜像
    docker search <名称关键字> # 搜索镜像仓库
    docker pull <镜像名:tag版本> # 下载镜像
    docker push <镜像名:tag版本> # 上传镜像
    docker rmi <镜像名:tag版本> # 删除镜像
    docker save -o <输出文件路径><镜像名:tag版本> # 打包本地镜像文件
    docker load -i <加载文件路径 # 导入本地镜像文件

仓库(Registry)

  • 仓库是存储和组织 Docker 镜像的地方。Docker Hub 是一个常见的公共仓库,你也可以搭建私有仓库。
  • Docker 镜像可以从仓库中拉取,也可以推送到仓库。

沙箱

  • 沙箱是一种安全机制,用于隔离和限制程序或应用程序的运行环境,以防止其对系统或其他程序产生潜在的危害。沙箱技术旨在创建一个受控制的环境,使得运行在其中的代码无法直接影响到系统的其他部分。这种隔离有助于确保安全性、防止恶意软件传播,同时提供一定程度的控制和监控。
  • 容器化平台(如 Docker)使用沙箱技术来隔离容器中的应用程序,确保它们互相独立运行。

容器创建

镜像结构:入口,层,基础镜像。分层的好处是可复用,,

  • 通过命令直接创建,需要完整镜像,几个G常有,稳定。
  • 通过dockerfile创建,不需要完整镜像,更灵活。
    Dockerfile 是一个包含构建镜像步骤的文本文件,包含一个个的指令。通过编写 Dockerfile,你可以定义如何构建镜像,包括基础镜像、安装依赖、复制文件等步骤。
  • 使用 Docker 的基本步骤
    1. 安装 Docker: 根据操作系统的不同,安装适合的 Docker 版本。
    2. 创建 Dockerfile: 编写包含应用程序构建步骤的 Dockerfile。
    3. 构建镜像: 在包含 Dockerfile 的目录中运行 docker build 命令构建镜像。(如java项目还需要jar包)
    4. 运行容器: 使用 docker run 命令基于构建的镜像创建和运行容器。
    5. 发布镜像: 将构建的镜像推送到 Docker 仓库,以便其他人可以拉取使用。

数据卷

  • 数据卷(volume)是一个虚拟目录,是容器内目录与宿主机目录之间映射的桥梁(两边文件同时修改)。
    (容器一般只包括支持运行的最少文件,一般无vi或其他编辑器,所以无法进入容器直接对容器中的文件进行修改)
  • 如何挂载数据卷?在创建容器时,利用-v 数据卷名:容器内目录完成挂载。创建时如果发现挂载的数据卷不存在,会自动创建。
    1
    2
    3
    4
    docker volumels        # 查看数据卷
    docker volume rm # 删除数据卷
    docker volume inspect # 查看数据卷详情
    docker volume prune # 删除未使用的数据卷

容器编排(Orchestration):运维人员

容器编排是指在生产环境中管理和协调多个容器的过程。Docker 提供了 Docker Compose 工具,用于定义和运行多容器的应用。


Kubernetes

1. 什么是Kubernetes

Kubernetes是一个开源的容器编排引擎,可以用来管理容器化的应用,包括容器的自动化的部署、扩容、缩容、升级、回滚等等;
它是Google在2014年开源的一个项目,它的前身是Google内部的Borg系统。

Kubernetes出现之前,我们一般都是使用Docker来管理容器化的应用,但是Docker只是一个单机的容器管理工具,它只能管理单个节点上的容器,当我们的应用程序需要运行在多个节点上的时候,就需要使用一些其他的工具来管理这些节点,比如Docker Swarm、Mesos、Kubernetes等等;
这些工具都是容器编排引擎,它们可以用来管理多个节点上的容器,但是它们之间也有一些区别,比如Docker Swarm是Docker官方提供的一个容器编排引擎,它的功能比较简单,适合于一些小型的、简单的场景,而Mesos和Kubernetes则是比较复杂的容器编排引擎;
Mesos是Apache基金会的一个开源项目,而Kubernetes是Google在2014年开源的,目前已经成为了CNCF(Cloud Native Computing Foundation)的一个顶级项目,基本上已经成为了容器编排引擎的事实标准了。

2.1 Kubernetes 资源对象

Node:k8s集群节点,可以是物理机/虚拟机
Pod:k8s最小调度单元,容器(运行app/数据库/..镜像)的抽象,可以是一/多个容器的组合,但除非高度耦合,一个pod只运行一个容器
Service:将一组pod封装成一个服务并且提供统一访问入口(解决了一组数据库pod中一个重建后ip变化的问题,类似于“服务发现”)
Ingress:为了对外提供服务,将外部请求路由转发到内部集群的service上

ConfigMap:封装配置信息
Secret:封装敏感信息
其他安全机制:网络安全,访问控制,身份认证
Volumn:将数据挂在到本地磁盘或远程存储上,实现持久化存储

Deployment:部署无状态应用程序,将一/多个Pod组合到一起;冗余备份,相当于对Pod的抽象;具有副本控制、滚动更新、自动扩缩容等功能,实现应用程序的高可用
Statefulset:部署有状态应用程序,如DB、MQ、缓存以及保留会话状态的应用程序

2.2 Kubernetes 架构

分为Master和Worker节点
apiserver:位于master节点上,是k8s集群的API接口;交互方式包括 kubectl 命令行、Dashboard界面或API接口

3. 使用minikube搭建kubernetes集群环境

minikube是一个轻量级的kubernetes集群环境,可以用来在本地快速搭建一个单节点的kubernetes集群;
https://kubernetes.io/zh-cn/docs/tutorials/hello-minikube/ 你好,Minikube

4. 使用Multipassk3s搭建kubernetes集群环境

minikube只能用来在本地搭建一个单节点的kubernetes集群环境,
下面介绍如何使用Multipassk3s来搭建一个多节点的kubernetes集群环境,

5. 在线实验环境

Killercoda Play-With-K8s

6. kubectl常用命令

6.1 基础使用

1
2
3
4
5
6
7
8
# 查看帮助
kubectl --help

# 查看API版本
kubectl api-versions

# 查看集群信息
kubectl cluster-info

6.2 资源的创建和运行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 创建并运行一个指定的镜像
kubectl run NAME --image=image [params...]
# e.g. 创建并运行一个名字为nginx的Pod
kubectl run nginx --image=nginx

# 根据YAML配置文件或者标准输入创建资源
kubectl create RESOURCE
# e.g.
# 根据nginx.yaml配置文件创建资源
kubectl create -f nginx.yaml
# 根据URL创建资源
kubectl create -f https://k8s.io/examples/application/deployment.yaml
# 根据目录下的所有配置文件创建资源
kubectl create -f ./dir

# 通过文件名或标准输入配置资源
kubectl apply -f (-k DIRECTORY | -f FILENAME | stdin)
# e.g.
# 根据nginx.yaml配置文件创建资源
kubectl apply -f nginx.yaml

6.3 查看资源信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 查看集群中某一类型的资源
kubectl get RESOURCE
# 其中,RESOURCE可以是以下类型:
kubectl get pods / po # 查看Pod
kubectl get svc # 查看Service
kubectl get deploy # 查看Deployment
kubectl get rs # 查看ReplicaSet
kubectl get cm # 查看ConfigMap
kubectl get secret # 查看Secret
kubectl get ing # 查看Ingress
kubectl get pv # 查看PersistentVolume
kubectl get pvc # 查看PersistentVolumeClaim
kubectl get ns # 查看Namespace
kubectl get node # 查看Node
kubectl get all # 查看所有资源

# 后面还可以加上 -o wide 参数来查看更多信息
kubectl get pods -o wide

# 查看某一类型资源的详细信息
kubectl describe RESOURCE NAME
# e.g. 查看名字为nginx的Pod的详细信息
kubectl describe pod nginx

6.4 资源的修改、删除和清理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# 更新某个资源的标签
kubectl label RESOURCE NAME KEY_1=VALUE_1 ... KEY_N=VALUE_N
# e.g. 更新名字为nginx的Pod的标签
kubectl label pod nginx app=nginx

# 删除某个资源
kubectl delete RESOURCE NAME
# e.g. 删除名字为nginx的Pod
kubectl delete pod nginx

# 删除某个资源的所有实例
kubectl delete RESOURCE --all
# e.g. 删除所有Pod
kubectl delete pod --all

# 根据YAML配置文件删除资源
kubectl delete -f FILENAME
# e.g. 根据nginx.yaml配置文件删除资源
kubectl delete -f nginx.yaml

# 设置某个资源的副本数
kubectl scale --replicas=COUNT RESOURCE NAME
# e.g. 设置名字为nginx的Deployment的副本数为3
kubectl scale --replicas=3 deployment/nginx

# 根据配置文件或者标准输入替换某个资源
kubectl replace -f FILENAME
# e.g. 根据nginx.yaml配置文件替换名字为nginx的Deployment
kubectl replace -f nginx.yaml

6.5 调试和交互

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 进入某个Pod的容器中
kubectl exec [-it] POD [-c CONTAINER] -- COMMAND [args...]
# e.g. 进入名字为nginx的Pod的容器中,并执行/bin/bash命令
kubectl exec -it nginx -- /bin/bash

# 查看某个Pod的日志
kubectl logs [-f] [-p] [-c CONTAINER] POD [-n NAMESPACE]
# e.g. 查看名字为nginx的Pod的日志
kubectl logs nginx

# 将某个Pod的端口转发到本地
kubectl port-forward POD [LOCAL_PORT:]REMOTE_PORT [...[LOCAL_PORT_N:]REMOTE_PORT_N]
# e.g. 将名字为nginx的Pod的80端口转发到本地的8080端口
kubectl port-forward nginx 8080:80

# 连接到现有的某个Pod(将某个Pod的标准输入输出转发到本地)
kubectl attach POD -c CONTAINER
# e.g. 将名字为nginx的Pod的标准输入输出转发到本地
kubectl attach nginx

# 运行某个Pod的命令
kubectl run NAME --image=image -- COMMAND [args...]
# e.g. 运行名字为nginx的Pod
kubectl run nginx --image=nginx -- /bin/bash

7. Portainer的安装和使用

Portainer 是一个轻量级的容器管理工具,可以用来管理Docker和Kubernetes,它提供了一个Web界面来方便我们管理容器
官方网址: https://www.portainer.io/

8. Helm的安装和使用

Helm 是一个Kubernetes的包管理工具,可以用来管理Kubernetes的应用,它提供了一个命令行工具来方便我们管理Kubernetes的应用
官方网址: https://helm.sh/

集群存储

https://kubernetes.io/zh-cn/docs/concepts/storage/persistent-volumes/

InfluxDB

InfluxDB 是一个由InfluxData开发的开源时序型数据库,专注于海量时序数据的高性能读、高性能写、高效存储与实时分析等;
在DB-Engines Ranking时序型数据库排行榜上排名第一,广泛应用于DevOps监控、IoT监控、实时分析等场景。
https://jasper-zhang1.gitbooks.io/influxdb/content/Introduction/getting_start.html

influxdb-cluster 是InfluxDB的集群版本,InfluxDB Enterprise 的开源替代方案,设计用于大规模数据存储和高可用性需求。
可以实现数据的分片和复制,从而提高系统的可用性和扩展性。数据安全。operator缺失
https://github.com/chengshiwen/influxdb-cluster/wiki

集群体系结构

InfluxDB Enterprise由两组软件进程组成: Data 数据节点 和 Meta 元节点。集群内的通信是这样的:

influxdb使用的默认端口号为分别为用于meta集群内部服务的8091端口,meta节点通信的8089端口,data集群内部服务的8088端口,以及data节点对外提供http服务的8086端

  • Meta 节点通过 TCP 协议和 Raft 共识协议相互通信,默认都使用端口 8089,此端口必须在 Meta 节点之间是可访问的。默认 Meta 节点还将公开绑定到端口 8091 的 HTTP API,influxd-ctl 命令使用该 API。
  • Data 节点通过绑定到端口 8088 的 TCP 协议相互通信。Data 节点通过绑定到 8091 的 HTTP API 与 Meta 节点通信。这些端口必须在 Meta 节点和 Data 节点之间是可访问的。
  • 在集群内,所有 Meta 节点都必须与所有其它 Meta 节点通信。所有 Data 节点必须与所有其它 Data 节点和所有 Meta 节点通信。

Where data lives

InfluxDB 集群中,一个节点要么是专门用于存储和查询时间序列数据的数据节点,要么是专门用于存储集群元数据的元节点。数据节点负责存储实际的数据和处理查询请求,而元节点则负责管理集群的元数据,包括节点信息、数据库和保留策略等。

Meta

元节点保存以下所有元数据:

  • 集群中的所有节点及其角色
  • 集群中存在的所有数据库和保留策略
  • 所有分片和分片组,以及它们存在于哪些节点上
  • 集群用户及其权限
  • 所有连续查询

元节点将这些数据保存在磁盘上的Raft数据库中,由BoltDB提供支持。默认情况下,Raft数据库是/var/lib/influxdb/meta/raft.db。
注意:Meta节点需要/ Meta目录。

  • influxd-meta 元数据服务
    1
    2
    3
    4
    5
    # 配置文件示例(meta节点)
    [meta]
    dir = "/var/lib/influxdb/meta" # 元数据存储路径
    bind-address = ":8089" # Raft协议通信端口
    http-bind-address = ":8091" # 管理API端口
  • influxd-ctl 集群管理
    1
    2
    3
    4
    5
    6
    7
    8
    # 查看分片分布
    kubectl exec influxdb-meta-0 -- influxd-ctl show-shards
    # 强制同步分片到新节点
    kubectl exec influxdb-meta-0 -- influxd-ctl copy-shard 3 influxdb-data-0:8088
    # 节点维护操作
    influxd-ctl remove-data influxdb-data-0:8088 # 下线节点
    # 检查Meta节点Raft状态
    kubectl exec influxdb-meta-0 -- influxd-ctl raft-state

Data

数据节点保存所有原始时间序列数据和元数据,包括:

  • measurements
  • tag keys and values
  • field keys and values

在磁盘上,数据总是按照//组织。默认父目录为/var/lib/influxdb/data。注意:数据节点需要/var/lib/influxdb/的所有四个子目录,包括/meta(specifically, the clients.json file)、/data、/wal和/hh。

  • influx CLI工具
    1
    2
    3
    4
    5
    6
    7
    # 进入容器执行CLI
    kubectl exec -it influxdb-data-0 -n influxdb -- influx -username admin -password 'xxx'

    # 常用命令
    SHOW DATABASES; # 显示所有数据库
    SELECT * FROM cpu; # 查询数据
    CREATE RETENTION POLICY "1d" ON db3 DURATION 1d REPLICATION 2; # 创建保留策略
  • influxd 数据节点服务
    1
    2
    3
    4
    5
    6
    # 查看运行状态
    kubectl exec influxdb-data-0 -- ps aux | grep influxd

    # 关键参数
    -data-dir /var/lib/influxdb/data # 数据存储目录
    -wal-dir /var/lib/influxdb/wal # WAL日志目录
  • influx_inspect 数据工具
    1
    2
    3
    4
    5
    6
    7
    8
    # 导出TSM文件(需进入容器)
    kubectl exec -it influxdb-data-0 -- influx_inspect export \
    -datadir /var/lib/influxdb/data \
    -waldir /var/lib/influxdb/wal \
    -out backup.gz -compress

    # 验证数据完整性
    influx_inspect verify -dir /var/lib/influxdb/data/db3

Data 与 Meta节点交互机制

  1. 通信协议

    组件 端口 用途 协议
    Meta节点间 8089 Raft协议同步元数据 TCP
    Data节点间 8088 分片数据复制 TCP
    Data→Meta节点 8091 注册节点/获取分片元信息 HTTP
  2. 核心交互场景
    节点注册 : Data节点启动时通过HTTP API向Meta节点注册(POST /data
    分片分配 : Meta节点根据replication-factor策略分配分片到Data节点
    写入协调 : 客户端写入数据时,由Meta节点确定目标分片所在Data节点
    故障转移 : Meta节点检测Data节点离线后,自动通过Hinted Handoff机制转移副本

一个集群至少要有三个独立的元节点才能允许一个节点的丢失,如果要容忍n个节点的丢失则需要2n+1个元节点。集群的元节点的数目应该为奇数。不要是偶数元节点,因为这样在特定的配置下会导致故障。
一个集群运行只有一个数据节点,但这样数据就没有冗余了。这里的冗余通过写数据的RP中的副本个数来设置。一个集群在丢失n-1个数据节点后仍然能返回完整的数据,其中n是副本个数。为了在集群内实现最佳数据分配,我们建议数据节点的个数为偶数。

术语 / Glossary

  • measurement:描述了存在关联field中的数据的意义,measurement是字符串。作为tag,fields和time列的容器。相当于MySQL的table,关系/表的意思。单个measurement可以有不同的retention policy(即 一个measurement 中的不同 tag set 可以有不同的 retention policy,构成多组 series)
  • Continuous Query (CQ)是在数据库内部自动周期性跑着的一个InfluxQL的查询,CQs需要在SELECT语句中使用一个函数,并且一定包括一个GROUP BY time()语句。
  • Retention Policy (RP)是InfluxDB数据结构的一部分,描述了InfluxDB保存数据的长短,数据存在集群里面的副本数,以及shard group的时间范围。RPs在每个database里面是唯一的,?连同measurement和tag set定义一个series。当创建一个database时,InfluxDB会自动创建一个叫做autogen的retention policy,其duration为永远,replication factor为1,shard group的duration设为七天。
    • duration:决定InfluxDB中数据保留多长时间。在duration之前的数据会自动从database中删除掉。
    • replication factor:决定在集群模式下数据的副本的个数。InfluxDB在N个数据节点上复制数据,其中N就是replication factor。
    • shard group duration决定了每个shard group跨越多少时间。具体间隔由retention policy中的SHARD DURATION决定。例如,如果retention policy的SHARD DURATION设置为1w,则每个shard group将跨越一周,并包含时间戳在该周内的所有点。
  • series:InfluxDB数据结构的集合,一个特定的series由measurement,tag set和retention policy组成。!field set不是series的一部分
  • schema:数据在InfluxDB里面怎么组织。InfluxDB的schema的基础是database,retention policy,series,measurement,tag key,tag value以及field keys。
  • shard:包含实际的编码和压缩数据,并由磁盘上的TSM文件表示。 每个shard都属于唯一的一个shard group。多个shard可能存在于单个shard group中。每个shard包含一组特定的series。给定shard group中的给定series上的所有点将存储在磁盘上的相同shard(TSM文件)中。
  • shard group:是shard的逻辑组合。shard group由时间和retention policy组织。包含数据的每个retention policy至少包含一个关联的shard group。给定的shard group包含其覆盖的间隔的数据的所有shard。每个shard group跨越的间隔是shard的持续时间。

InfluxDB读写

  1. 命令行工具
    • influx命令行连接本地InfluxDB:直接通过InfluxDB的HTTP接口(如果没有修改,默认是8086)来和InfluxDB通信。(说明:也可以直接发送裸的HTTP请求来操作数据库,例如curl)
      1
      2
      3
      4
      $ influx -precision rfc3339
      Connected to http://localhost:8086 version 1.2.x //
      InfluxDB shell 1.2.x
      >
      InfluxDB的HTTP接口默认起在8086上,所以influx默认也是连的本地的8086端口。-precision参数表明了任何返回的时间戳的格式和精度,如 rfc3339是让InfluxDB返回RFC339格式(YYYY-MM-DDTHH:MM:SS.nnnnnnnnnZ)的时间戳。
    • 数据格式:将数据点写入InfluxDB,只需要遵守如下的行协议:
      1
      <measurement>[,<tag-key>=<tag-value>...] <field-key>=<field-value>[,<field2-key>=<field2-value>...] [unix-nano-timestamp]
      InfluxDB里存储的数据被称为时间序列数据,其包含一个数值。时序数据有零个或多个数据点,每一个都是一个指标值。数据点包括time(一个时间戳),measurement(例如cpu_load),至少一个k-v格式的field(也即指标的数值例如 “value=0.64”或者“temperature=21.2”),零个或多个tag,其一般是对于这个指标值的元数据(例如“host=server01”, “region=EMEA”)。
      可以将measurement类比于SQL里的table,其主键索引总是时间戳。tag和field是在table里的其他列,tag是被索引起来的,field没有。不同之处在于InfluxDB里,你可以有几百万的measurements,不用事先定义数据的scheme,且null值不会被存储。
    • 使用CLI插入单条的时间序列数据到InfluxDB中,用INSERT后跟数据点:
      1
      2
      3
      > use testdb
      Using database testdb
      > INSERT cpu,host=serverA,region=us_west value=0.64
      这样一个measurement为cpu,tag是host和region,value值为0.64的数据点被写入了InfluxDB中。
    • 现在我们查出写入的这笔数据:
      1
      2
      3
      4
      5
      6
      7
      > SELECT "host", "region", "value" FROM "cpu"
      name: cpu
      ---------
      time host region value
      2015-10-21T19:28:07.580664347Z serverA us_west 0.64

      > delete FROM "cpu" WHERE "host" = 'serverA' # 不带where将删除measurement所有数据
      我们在写入的时候没有包含时间戳,当没有带时间戳的时候,InfluxDB会自动添加本地的当前时间作为它的时间戳。
  2. HTTP 请求
    • 写数据
      1
      curl -i -XPOST 'http://localhost:8086/write?db=mydb' --data-binary 'cpu_load_short,host=server01,region=us-west value=0.64 1434055562000000000'
    • 读数据
      1
      curl -G 'http://localhost:8086/query?pretty=true' --data-urlencode "db=mydb" --data-urlencode "q=SELECT \"value\" FROM \"cpu_load_short\" WHERE \"region\"='us-west'"
  3. 客户端库,InfluxDB 提供了多种编程语言的客户端库,如Python、Go、Java等,可以方便地在应用程序中读写数据。
  4. 采样和数据保留 https://jasper-zhang1.gitbooks.io/influxdb/content/Guide/downsampling_and_retention.html

集群读写

  • 分片Shard:InfluxDB集群读写的基本单位分片是时间序列数据的物理存储单位,每个分片包含一段时间范围内的数据。
    复制因子为X,则在每个分片的数据同步到X个节点(部署influxdb的主机)上。
    分片的划分依据是时间范围和数据的存储策略(Retention Policy)。在集群环境中,分片可以分布在不同的节点上,以实现数据的分布式存储和负载均衡。这样可以提高数据的读写性能和系统的可扩展性。
    确定数据属于哪个分片的过程主要涉及以下几个步骤:数据写入时,首先根据时间戳确定属于哪个Shard Group(分片组)。然后,基于Measurement和Tag的值计算哈希值。最后,根据哈希值将数据分配到具体的分片。

    shard := shardGroup.shards[fnv.New64a(key) % len(shardGroup.Shards)]

  • 分片组Shard groups:集群在一个分片组内创建分片,以最大限度地利用数据节点的数量。
    分片数计算:当集群有 N 个数据节点且副本因子为 X 时,每个分片组中会创建 floor(N/X) 个分片(向下取整)
    示例:若集群有 4 个数据节点,副本因子为 2,则每个分片组包含 4/2=2 个分片(每个分片在 2 个节点上复制)
  • 集群写入:
    假设一个HTTP写操作被发送到服务器D,数据属于分片1。写操作需要被复制到分片1的所有者:数据节点A和B。当写操作进入D时,该节点从其亚转移的本地缓存中确定需要将写操作复制到A和B,并立即尝试对两者进行写操作。
    每个对HTTP API的请求都可以通过一致性查询参数指定一致性级别。 https://docs.influxdata.com/enterprise_influxdb/v1/concepts/clustering/#write-consistency
  • 集群查询:
    根据查询的时间段和数据的复制因子进行分布的。例如,如果保留策略的复制因子为4,则接收查询的协调数据节点将随机选择存储该分片副本的4个数据节点中的任何一个来接收查询。如果我们假设系统的分片持续时间为一天,那么对于查询覆盖的每一天,协调节点都会选择一个数据节点来接收当天的查询。
    协调节点尽可能在本地执行和完成查询。如果一个查询必须扫描多个shard组(在上面的例子中是多个天),协调节点将查询转发给其他节点,以查找本地没有的shard。查询与扫描自己的本地数据并行转发。查询被分发到尽可能多的节点,以查询每个分片组一次。当结果从每个数据节点返回时,协调数据节点将它们组合成返回给用户的最终结果。
  • Shard Group 与 Shard 的实战示例:
    1. 场景描述,假设有以下配置:
      Retention Policy: Duration: 30d | Replication Factor: 2 | Shard Group Duration: 1d,
      集群数据节点: 4 个(A/B/C/D)
    2. 分片组创建
      时间划分:每天 00:00 自动创建新的分片组(如 2025-04-02 ~ 2025-04-03)
      分片数:4/2=2 个分片(Shard 1 & 2)
    3. 分片分布
      分片 1 | 副本节点 A, B | 存储内容 所有哈希值模2=0的 Series Key 数据
      分片 2 | 副本节点 C, D | 存储内容 所有哈希值模2=1的 Series Key 数据
    4. 数据写入示例
      当写入 cpu,host=svr1 usage=80:Series Key = cpu,host=svr1,哈希值模2=1 ⇒ 分片2,数据同时写入节点 C 和 D
    5. 数据查询流程
      查询 SELECT * FROM cpu WHERE time > '2025-04-02':定位到 2025-04-02 分片组, 协调节点同时向 A/B(分片1)和 C/D(分片2)发起查询, 合并结果后返回

集群部署

Docker安装操作单例InfluxDB https://www.cnblogs.com/nhdlb/p/16409849.html
Docker快速开始集群InfluxDB https://github.com/chengshiwen/influxdb-cluster/wiki#docker-%E5%BF%AB%E9%80%9F%E5%BC%80%E5%A7%8B

在使用容器多节点部署InfluxDB时,数据库、容器、Docker、主机和Kubernetes(k8s)之间的关系可以理解如下:

  • 数据库(InfluxDB):InfluxDB是一个时序数据库,用于存储和查询时间序列数据。在多节点部署中,InfluxDB可以运行在多个容器中,以实现高可用性和负载均衡。
  • 容器:容器是一个轻量级、独立的运行环境,用于打包和运行应用程序及其依赖项。InfluxDB可以被打包成一个容器镜像,并在多个容器实例中运行。
  • Docker:Docker是一个容器化平台,用于创建、部署和管理容器。Docker负责启动和管理运行InfluxDB的容器。
  • 主机:主机是运行Docker和容器的物理或虚拟机器。在多节点部署中,可能有多个主机,每个主机上运行一个或多个InfluxDB容器。
  • Kubernetes(k8s):一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。Kubernetes可以管理多个主机上的容器,提供服务发现、负载均衡、自动扩展和自愈能力。在多节点部署中,Kubernetes可以管理InfluxDB容器的部署,确保它们在多个节点上运行,并提供高可用性和扩展性。
  • 关系总结:InfluxDB 作为数据库运行在 容器 中。容器 由 Docker 创建和管理。Docker 运行在 主机 上。Kubernetes 管理多个 主机 上的 Docker 容器,提供编排和管理功能。通过这种方式,InfluxDB可以在一个分布式环境中高效运行,利用Kubernetes的编排能力实现自动化管理和扩展。

Kubernetes 存储与 InfluxDB Shard 的关系解析

  1. PV/PVC:是 Kubernetes 管理存储资源的抽象层。PV 描述物理存储资源(如 NFS、云盘等),PVC 是 Pod 对存储资源的请求声明。PVC 绑定到 PV 后,Pod 通过挂载 PVC 使用持久化存储。
  2. Shard:是 InfluxDB 存储引擎的物理存储单元,表现为磁盘上的 TSM 文件(Time-Structured Merge Tree),每个 Shard 对应一个时间范围内的时序数据块。Shard 的存储路径通常位于 PVC 挂载的 /var/lib/influxdb/data 目录下。
    每个 Shard 包含:时间序列索引(.tsi 文件),压缩后的时序数据块(.tsm 文件),WAL(Write-Ahead Log)日志文件(.wal) 其路径结构为:/var/lib/influxdb/data/<database>/<retention_policy>/<shard_id>
  3. 重建 PVC 导致数据丢失的本质问题
    PVC 删除与 PV 回收策略:若 PVC 的回收策略为 Delete(默认),删除 PVC 会导致 Kubernetes 清理其绑定的 PV 及底层存储数据(如 NFS 目录、云盘等)。此时 /var/lib/influxdb 下的 datameta 目录被清空,导致 Shard 文件丢失。
    • Shard 文件丢失会导致对应时间范围的时序数据不可查询,触发 ERR: shard not found 错误。
    • Meta 文件丢失会破坏集群元数据一致性,导致用户权限、分片策略等配置失效。

InfluxDB 备份与恢复

https://docs.influxdata.com/enterprise_influxdb/v1/administration/backup-and-restore/
https://blog.csdn.net/weixin_46560589/article/details/127748939

InfluxDB Enterprise支持在集群实例、单个数据库和保留策略以及单个分片中备份和恢复数据。

  1. 备份整个实例,即所有数据库(全量备份)。命令如下:
    1
    influxd backup -portable /path/to/backup
  2. 备份单个数据库
    1
    influxd backup -portable -database <database_name> /path/to/backup
  3. 增量备份:对于较大的数据集,可以进行增量备份,只备份自上次全量或增量备份以来的数据
    1
    influxd backup -portable -start <timestamp> /path/to/backup

备份的数据可以恢复到新实例或现有实例中。

  1. 恢复整个实例,包括所有的数据库。命令如下:
    1
    influxd restore -portable /path/to/backup
  2. 恢复单个数据库
    1
    influxd restore -portable -db <database_name> /path/to/backup
  3. 有时你可能希望将备份的数据恢复到另一个数据库,可以使用 -newdb 选项来实现:
    1
    influxd restore -portable -db <old_database_name> -newdb <new_database_name> /path/to/backup

导出和导入数据

对于大多数InfluxDB Enterprise应用程序,备份和恢复实用程序提供了备份和恢复策略所需的工具。但是,在某些情况下,标准备份和恢复实用程序可能无法充分处理应用程序中的大量数据。作为标准备份和恢复实用程序的替代方案,可以使用InfluxDB influx_inspect export和涌入-import命令为灾难恢复和备份策略创建备份和恢复过程。

  1. 数据库导出:容器层面命令,指定 数据文件和 写前日志(WAL)文件的存储目录,将指定数据库中指定时间的数据导出到指定文件。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    root@influxdb-e2cb6c913a191e56c134e-data-0:/# influx_inspect export -datadir "/var/lib/influxdb/data" -waldir "/var/lib/influxdb/wal" -out "influxdb_test01_dump_out" -database "test01" -start "2024-10-22T00:00:00Z"
    writing out tsm file data for test01/autogen...complete.
    writing out wal file data for test01/autogen...complete.
    root@influxdb-e2cb6c913a191e56c134e-data-0:/# cat influxdb_test01_dump_out
    # INFLUXDB EXPORT: 2024-10-22T00:00:00Z - 2262-04-11T23:47:16Z
    # DDL
    CREATE DATABASE test01 WITH NAME autogen
    # DML
    # CONTEXT-DATABASE:test01
    # CONTEXT-RETENTION-POLICY:autogen
    # writing tsm data
    temp,location=room1 value=24.5 1729589246099070937
    temp,location=room2 value=22.5 1729589253425715740
    temp,location=room3 value=22 1729649010554978701
    # writing wal data
  2. 数据库导入:容器层面执行命令,使用admin账号,指定文件、数据库、时间戳精度
    1
    2
    3
    4
    root@influxdb-e73f149ff7192bd87d190-data-1:/# influx -import -path='influxdb_test01_dump_out' -precision=ns -username='' -password=''
    2024/10/25 03:21:47 Processed 1 commands
    2024/10/25 03:21:47 Processed 2 inserts
    2024/10/25 03:21:47 Failed 0 inserts
  3. 实例导出:把influxdb集群实例中所有数据库的数据导出,不加 -database,加 -compress
  4. 实例导入:加-compressed 导入压缩文件,本质上是先解压后倒入

InfluxDB节点迁移

Data节点迁移方案评审:先迁移后逐个恢复分片数据。已验证在分片副本大小70M、写入数据达2000point/s的情况下直接copy-shard会导致增量数据丢失,考虑在copy-shard前先执行truncate-shards截断热分片(集群中所有写入最新数据的分片,截断后关闭写入,变成冷分片),并在所有Data节点上创建该分片的新热分片副本,也就是在迁移节点上恢复了全部原有分片的新热分片副本,最新数据写入这个副本,然后再逐个从健康节点上的冷分片副本copy-shard恢复出分片的历史数据(迁移前分片副本原有的数据&迁移过程中未能写入的数据),该分片数据完全恢复;自测符合预期

  1. 在做迁移操作前,先记录迁移节点拥有的分片副本,后续从健康节点的相同副本中恢复出来;
    1
    kubectl exec -i influxdb-xx-meta-0 -n influxdb -- influxd-ctl show-shards # 或influx命令行执行show shards
  2. 迁移后更新节点/分片元信息,新data-0节点丢失db1的shard3,另外_internal的db1转移到健康节点data-1上了
    1
    2
    kubectl exec -i influxdb-xx-meta-0 -n influxdb -- influxd-ctl remove-data influxdb-xx-data-0.influxdb-xx-data:8088
    kubectl exec -i influxdb-xx-meta-0 -n influxdb -- influxd-ctl add-data influxdb-xx-data-0.influxdb-xx-data:8088
  3. 持续写入数据到db1(只能写入健康节点上的db1分片副本),某一时刻执行truncate-shards,db1的shard3切断,新热分片shard4的分片副本分配到data-1以及迁移后的data-0中,此刻开始写入db1的新数据在data-0和data-1上的分片中一致(一个数据库的分片可能有多个,但只有一个正在写入,其他都是冷分片)
    1
    kubectl exec -i influxdb-xx-meta-0 -n influxdb -- influxd-ctl truncate-shards
  4. 最后再恢复历史数据,也就是执行迁移前的data-0节点拥有的分片副本数据,以及迁移完成前应该写入但没有写入data-0的数据。从健康的data-1上的分片副本copy-shard而来,导出文件可见data-0和data-1上的db1数据完全一致
    1
    2
    3
    # 对于_internal分片的转移 先copy后remove
    kubectl exec -i influxdb-xx-meta-0 -n influxdb -- influxd-ctl copy-shard influxdb-xx-data-1.influxdb-xx-data:8088 influxdb-xx-data-0.influxdb-xx-data:8088 1
    kubectl exec -i influxdb-xx-meta-0 -n influxdb -- influxd-ctl remove-shard influxdb-xx-data-1.influxdb-xx-data:8088 1
    1
    2
    3
    # 分片的物理文件 wal&tsm
    kubectl exec -i influxdb-xx-data-0 -n influxdb -- ls /var/lib/influxdb/data
    kubectl exec -i influxdb-xx-data-0 -n influxdb -- ls /var/lib/influxdb/wal
    1
    2
    3
    # 可能要等wal落tsm
    kubectl exec -i influxdb-xx-data-0 -n influxdb -- influx_inspect export -datadir "/var/lib/influxdb/data" -waldir "/var/lib/influxdb/wal" -out "influxdb_dump_out" -database "db1"
    kubectl exec -i influxdb-xx-data-0 -n influxdb -- md5sum influxdb_dump_out

Golang


Go 是一个开源的编程语言,它能让构造简单、可靠且高效的软件变得容易。
Go 语言被设计成一门应用于搭载 Web 服务器,存储集群或类似用途的巨型中央服务器的系统编程语言。 对于高性能分布式系统领域而言,Go 语言无疑比大多数其它语言有着更高的开发效率。它提供了海量并行的支持,这对于游戏服务端的开发而言是再好不过了。

除了OOP外,近年出现了一些小众的编程哲学,Go语言对这些思想亦有所吸收。例如,Go语言接受了函数式编程的一些想法,支持匿名函数与闭包。再如,Go语言接受了以Erlang语言为代表的面向消息编程思想,支持goroutine和通道,并推荐使用消息而不是共享内存来进行并发编程。总体来说,Go语言是一个非常现代化的语言,精小但非常强大。

Go

  • Go 语言最主要的特性
    自动垃圾回收 更丰富的内置类型 函数多返回值 错误处理 匿名函数和闭包 类型和接口 并发编程 反射 语言交互性
    https://www.runoob.com/go/go-tutorial.html
  • Go 和 Java 有很多共同之处
    C 系列 (强类型,括号) 静态类型 垃圾收集 内存安全 (nil 引用,运行时边界检查) 变量总是初始化 (zero/nil/false)
    方法 接口 类型断言 (实例) 反射
  • Go 与 Java 的不同之处
    代码程序直接编译成机器码,没有 VM
    静态链接二进制 内存布局控制 函数值和词法闭包 内置字符串 (UTF-8) 内置泛型映射和数组/片段 内置并发
  • Go 特意去掉了大量的特性
    没有类 没有构造器 没有继承 没有 final 没有异常 没有注解 没有自定义泛型
  • 为 Java 程序员准备的 Go 语言入门 PPT https://www.runoob.com/w3cnote/go-for-java-programmers.html

Go 项目构建

  • Module:是 Go 语言用于管理项目依赖和版本的一种机制。go.mod 文件定义了模块的元数据和依赖关系。
    go.mod 文件是声明依赖的地方,记录了项目的依赖关系。如果项目中没有 go.mod,需要先运行 go mod init 来初始化模块。然后使用 go get(或其他命令)来引入依赖,下载到本地缓存(~/go/pkg/mod),并更新 go.mod,添加对应的模块路径和版本要求。
  • Makefile:是一个用于自动化构建、测试和其他任务的工具。它允许你定义复杂的构建流程和依赖关系。
    Makefile 可以包含多个targets,例如 build、test、clean 等。make 命令会查找当前目录下的 Makefile 并执行指定的目标。
    构建过程本身不负责引入依赖,它假定所有必要的依赖已经通过 go.mod 文件声明并被解析(否则报错),将编译代码并链接所有必要的依赖来生成最终的可执行文件或库文件。如果 go.mod 中声明的依赖尚未下载,Go 工具链会自动为你下载这些依赖。如果你的项目中没有 go.mod,go build 将无法正确识别和下载依赖(除非是 Go 1.11 前的版本)
  • 项目构建…
    • 对于一个带有 go.mod 文件的 Go 项目,项目所需的依赖不会自动下载到本地环境中。需要手动运行 go mod downloadgo mod tidy 来下载依赖,或者直接运行 go build 以触发依赖的下载。
    • 如果本地已有的依赖版本与 go.mod 文件中声明的版本不同,Go 工具链会优先使用 go.mod 文件中指定的版本。Go 会从远程仓库下载与 go.mod 兼容的依赖版本,并将其存储在本地缓存目录(通常是 ~/go/pkg/mod)中。
    • Go 项目使用的依赖是项目特定的,存储在项目的本地缓存中,而不是全局的 GOPATH 或者 GOROOT 目录。这意味着不同的项目可以依赖同一库的不同版本,而不会发生冲突。其实际工作目录go env中的配置(看上去是如果配置全局 PATH=%GOPATH%\bin 就使用 GOPATH 中的go.exe和pkg)
    • 对于复杂的构建流程和依赖关系,有时还需要根据 Makefile 文件,执行 build来构建项目。
  • VSCode 连接 WSL的Linux环境 开发 Go 项目(先用ubuntu开发,后再centos验证)
    1
    2
    3
    4
    5
    6
    7
    D:\Users\caifeng7>wsl -l -v
    NAME STATE VERSION
    * Ubuntu Running 2
    CentOS7 Running 2

    D:\Users\caifeng7>wsl # 管理员cmd进入wsl的默认linux发行版
    root@caifeng7138:/mnt/d/Users/caifeng7#
    安装go到linux,配置ubuntu上的golang开发环境(centos使用yum管理包)
    1
    2
    sudo apt update
    sudo apt install golang-go
    将GOPATH/bin添加到的PATH环境变量中
    1
    2
    echo 'export PATH=$PATH:/root/go/bin' >> ~/.bashrc
    source ~/.bashrc
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    root@caifeng7138:/mnt/c/Windows/system32# go env
    GO111MODULE=''
    GOARCH='amd64'
    GOBIN='' # 编译后的二进制文件的存放位置
    GOCACHE='/root/.cache/go-build' # Go编译缓存的路径
    GOENV='/root/.config/go/env'
    GOEXE=''
    GOEXPERIMENT=''
    GOFLAGS=''
    GOHOSTARCH='amd64'
    GOHOSTOS='linux'
    GOINSECURE=''
    GOMODCACHE='/root/go/pkg/mod'
    GONOPROXY=''
    GONOSUMDB=''
    GOOS='linux'
    GOPATH='/root/go' # Go工作空间的根目录,用于存放你的Go项目和依赖。
    GOPRIVATE=''
    GOPROXY='https://proxy.golang.org,direct' # 修改代理 export GOPROXY=https://goproxy.cn,direct
    GOROOT='/usr/lib/go-1.22' # Go语言的安装目录,包含了Go的编译器、标准库和工具。
    GOSUMDB='sum.golang.org'
    GOTMPDIR=''
    GOTOOLCHAIN='auto'
    GOTOOLDIR='/usr/lib/go-1.22/pkg/tool/linux_amd64'
    GOVCS=''
    GOVERSION='go1.22.2'
    GCCGO='gccgo'
    GOAMD64='v1'
    AR='ar'
    CC='gcc'
    CXX='g++'
    CGO_ENABLED='1'
    GOMOD='/dev/null'
    GOWORK=''
    CGO_CFLAGS='-O2 -g'
    CGO_CPPFLAGS=''
    CGO_CXXFLAGS='-O2 -g'
    CGO_FFLAGS='-O2 -g'
    CGO_LDFLAGS='-O2 -g'
    PKG_CONFIG='pkg-config'
    GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffil...'
    VSCode使用WSL:Remote Explorer选择linux发行版,使用Ubuntu环境打开Go项目目录: /mnt/d/code/datamars-agent/
    此时自动下载了项目go.mod要求的go版本? 项目中的环境变量发生变化 ↓
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    root@caifeng7138:/mnt/d/code/datamars-agent# go env
    # 个人用户的Go工作空间。用于存放Go项目和依赖
    GOPATH='/root/go'
    # Go的安装目录,指向通过模块系统安装的一个特定版本(1.22.4),而不是 /usr/lib/go(全局路径)
    GOROOT='/root/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.22.4.linux-amd64'
    # Go工具链的安装目录
    GOTOOLDIR='/root/go/pkg/mod/golang.org/toolchain@v0.0.1-go1.22.4.linux-amd64/pkg/tool/linux_amd64'
    GOVERSION='go1.22.4'
    # Go模块缓存的路径
    GOMOD='/mnt/d/code/datamars-agent/go.mod'
    在WSL中,安装protoc,添加到PATH;
    执行make,通过makefile中的配置构建项目,编译proto文件,生成Go,grpc程序
    Protobuf 是一种由 Google 开发的用于序列化结构化数据的语言中立、平台中立的可扩展机制,Protoc 可以将 定义了数据结构和序列化规则的 .proto 文件编译生成包括 Go,Java的多种语言。用于grpc请求的数据同步。。

Lic Ai

保 险

社会保障

通过对国民收入的再分配,使公民在遇到特定风险或困难时能够获得基本生活保障。本质是追求一种公平。

社会保险

  1. 养老保险:为了保障老年人退休后的基本生活,通过个人和单位的缴费,在退休后按月领取养老金。个人在达到法定退休年龄时,如果满足缴费年限等条件,就可以领取养老金。
  2. 医疗保险:旨在为参保人员提供医疗费用的报销或补偿,以减轻医疗费用的负担。参保人员在生病住院或接受治疗时,可以通过医保报销一部分或全部的医疗费用。
  3. 失业保险:为因非个人原因失去工作的参保人员提供一定时间内的生活保障金,帮助他们在失业期间维持基本生活。
  4. 工伤保险:用于保障因工作原因遭受意外伤害或职业病的劳动者,提供医疗费用和伤残补助,甚至提供生活保障金等。
  5. 生育保险:主要为参保女性在生育期间提供一定的经济补助和医疗费用报销。

社保卡

佛山社保卡如何申领?“一人一卡”清理又是个啥? https://mp.weixin.qq.com/s/9uQ5qGOYv35BGRgs4OvzvA
没领佛山社保卡可以使用医保报销吗?可以,微信支付时会显示报销数额。
如何使用医保余额?办理实体医保卡,可以查到余额。

医保

  • 医疗保险是一种社会保障制度。通常由个人和单位共同缴纳,参保人员在医疗机构就诊时可以通过医保报销部分或全部的医疗费用。
    通过医保报销的费用是由医保基金支付的,而这个基金是由全体参保人员(包括你和你的单位)共同缴纳的资金组成的。个人缴纳的那部分医保费用只是整个基金的一部分,而报销的金额往往远超过个人单独缴纳的部分,这正是医保体系的优势所在
  • 佛山医疗保险享受指引
    1. 门诊选点:公众号-粤医保
    2. 异地就医备案
      办理条件:异地安置退休人员、异地长期居住人员、常驻异地工作人员、临时外出就医人员
      办理途径:公众号-粤医保-线上办理-异地就医备案
    3. 医保报销方式
      定点联网机构住院(?)费用:凭社保卡/医保电子凭证/身份证现场结算;未能即使结算的,先挂账后结算;无法补记账结算的,垫付费用后申请零星保险。(医保里的钱可以用吗?怎么用?
      零星报销:提供资料到参保所属医保经办机构办理
      https://ihr.midea.com/selfhelp/ihr/selfhelp/pdf?businessId=8a928ead90719d3201907b3b580d00b7&mc_widget_identifier=com.midea.msd.ihrcommonmx&scene=selfhelp_sdc&page=showPdf&type=1

住房公积金

  • 住房公积金是一种社会福利制度,而不是严格意义上的社会保障。住房公积金是国家为帮助职工解决住房问题而设立的一项长期住房储金。它由职工个人和单位共同缴纳,归职工个人所有,并在一定条件下用于购房、建房、房屋维修或者租房等住房相关支出。
  • 职工可以在以下情况下提取住房公积金:购买、建造、翻建、大修自住住房。偿还住房贷款本息(利率低)。支付房租。离职或退休后可以提取全部住房公积金。
  • 住房公积金可以断缴。如果有购房计划或其他需要公积金支持的需求,最好避免长时间断缴。
    • 可以断缴:如果你换工作、辞职、或者暂时没有固定工作,住房公积金可以暂时断缴。没有法律强制要求必须连续缴纳。一旦找到新工作或稳定下来,你可以恢复缴纳住房公积金。新单位会重新为你开设账户或继续使用之前的账户。
    • 断缴的影响
      贷款购房影响影响贷款资格,在申请住房公积金贷款时,很多地方要求申请人在最近的6个月或12个月内连续缴纳公积金。如果公积金断缴,可能会影响你申请住房公积金贷款的资格。贷款额度影响,公积金贷款额度通常与公积金的缴纳时间和余额挂钩。如果断缴时间较长,贷款额度可能会受到影响。
      影响提取条件:如果计划通过提取公积金支付房租或购房时,断缴可能会影响提取公积金的条件,因为很多地方要求提取前必须有一定的连续缴纳记录。
    • 如何减少断缴的影响:1、补缴:在新单位入职后,你可以尝试与单位协商,进行断缴期间的补缴。以恢复在断缴期间的公积金记录。2、灵活就业人员公积金:有些城市允许灵活就业人员或个体工商户自行缴纳公积金,以避免断缴。
  • 住房公积金在中国是可以随着工作地点的变更而进行转移的。通常的步骤是:在新城市的新工作单位会为你开设一个新的住房公积金账户。向新单位的公积金管理中心申请将旧账户的公积金余额转入新账户。新单位所在的公积金管理中心会联系原城市的公积金管理中心,办理资金转移。公积金转移通常需要一定时间,一旦转移完成,你的住房公积金余额将会合并到新城市的账户中。
  • 佛山公积金提取:wx公众号办理租房提取业务,选择按年/月提取,隔日到账。

个人所得税

工资条计算步骤

  1. 应发合计 = 基本工资 + 考评绩效 + 其他发放 + 福利
    2月说明:12330=3555+8445+0+330(餐补)
  2. 实发工资 = 应发合计 - 代扣代缴
    代扣代缴项:包括五险一金(专项扣除)、本月预扣个人所得税。
    2月说明::9612.2=12330-2717.8
  3. 累计预扣预缴应纳税所得额 = 累计收入 - 累计减除费用 - 累计专项扣除 - 累计专项附加扣除
    累计减除费用:每月5,000元起征点,年度累计为60,000元(如工作满12个月)。
    专项附加扣除:包括子女教育(每月2,000元/孩)、房贷利息(每月1,000元)、赡养老人(每月2,000元)等,需在个税APP填报。
    2月说明:11101.74=35710(2024.12起重新计算?) - 15000 - 6308.26(累计个人缴纳社保&公积金) - 3300, 公式逻辑:逐月累计收入及扣除项,动态计算全年税基。
  4. 扣税 = 累计预扣预缴应纳税所得额 × 税率 - 速算扣除数 - 累计已预扣预缴税额
    税率表:采用七级超额累进税率(3%-45%),按月累计收入匹配税率档位。若某月税额突增,可能是累计收入进入更高税率区间,属正常现象。
    示例:若累计应纳税所得额36,000元,对应税率10%,速算扣除数2,520元,则当月预扣税额 = 36,000×10% - 2,520 - 已缴税额。

退税条件与计算

个人所得税丨2024年个人综合所得年度汇算操作指引 https://mapmpm5.midea.com/newservicenopages/#/content/preview?id=1896853229331374081
个人的汇算清缴,就是把您2024年一整年取得的劳动收入(税法中叫“综合所得”,具体指工资薪金、劳务报酬、稿酬、特许权使用费共4项)合并计算个税,得出应纳个人所得税,与2024年实际预扣预缴的个税比较,税款多退少补。预缴税款与实际应缴税款产生差异的核心原因在于预扣预缴机制与全年综合计算的逻辑差异
预扣预缴是基于局部数据和固定规则的估算,而汇算清缴是基于完整数据和真实扣除的精准计算
建议:通过“个人所得税APP”提前核对收入明细和扣除项,利用汇算规则合法降低税负(如优化年终奖计税方式)。以下是具体原因分析:

  1. 收入结构与预扣方式的差异
    预扣预缴的“分段计算”特性 : 工资薪金采用累计预扣法,按月计算税款(逐月累加收入并匹配税率),而劳务报酬、稿酬等按固定比例预扣(如劳务报酬预扣率20%)。若全年收入波动大(如年终奖集中发放)或存在多处收入,可能导致:1. 前期预缴税率低,后期税率跳档:例如前半年收入低按3%预扣,后半年累计收入超过36,000元后按10%计税,全年汇算需补差额。 2. 劳务报酬预扣率高于综合税率:劳务报酬预扣时按20%扣税,但全年综合所得实际税率可能仅为3%或10%,汇算时可退税。
    年终奖计税方式选择的影响 : 年终奖可选择单独计税(按“年终奖/12”匹配月度税率)或合并计税(并入综合所得)。若预缴时选择单独计税,但汇算时合并后适用更高税率,则需补税。
  2. 扣除项目的动态调整
    专项附加扣除的补充申报 :预缴时未填报的专项附加扣除(如租房、赡养老人等),可在汇算时补充扣除,直接减少应纳税额。例如:租房扣除(1,500元/月):若全年未申报,汇算时补充可减少18,000元应税所得额,按10%税率计算可退1,800元。大病医疗扣除:只能在次年汇算时申报,直接影响退税额度。
    • 其他扣除项的汇算调整:如公益捐赠(需在汇算时提供凭证)、职业资格继续教育等扣除,预缴时未计入的,汇算时可补充抵扣。
  3. 收入合并的税负效应
    综合所得合并计算的税率跃升 :工资、劳务报酬等四项收入合并后,可能使全年应纳税所得额跨越税率档位。例如:单独计算时未超档:工资10万元(适用10%税率)+ 劳务报酬5万元(预扣20%但实际税率10%),合并后15万元应纳税所得额适用20%税率,需补税。多处收入叠加:从两家单位取得工资,每家均按5,000元起征点预扣,但全年合并收入超过6万元的部分需补税。
    • 稿酬的特殊计算规则:按“(稿酬收入×80%)×70%”计入综合所得,若预缴时未按此规则计算(如企业误操作)汇算时需调整。
  4. 政策与实操的特殊情形
    免税收入的误计入 : 部分免税补贴(如差旅津贴、误餐补助)若被错误计入工资,预缴时多缴税款,汇算时可申请剔除并退税。
    预缴申报的误差 : 企业可能因操作失误导致预缴税款错误(如漏报专项扣除),需通过汇算修正。

劳动合同

  1. N+1补偿的适用场景与条件
    触发条件企业合法解除劳动合同但未提前30日通知,需支付“N+1”(经济补偿金+代通知金)。
    • 具体情形包括:
    ◦ 劳动者医疗期满后无法返岗且无法调岗;
    ◦ 劳动者经培训或调岗仍不胜任工作;
    ◦ 客观情况重大变化(如部门撤销、搬迁)导致合同无法履行。
  2. 计算规则
    N:按工作年限计算(每满1年支付1个月工资,不满半年按0.5个月计算)。 N按离职前12个月平均工资计算,包含奖金、津贴等。
    +1:额外支付1个月工资(按解除合同前12个月平均工资或上月工资计算)。
    • ​月工资上限:若月工资高于当地上年度职工月平均工资3倍,按3倍标准支付且年限最高12年
  3. 员工主动离职的经济补偿可能性
    一般情况:员工主动离职无补偿。
    例外情形(企业存在过错,员工被迫离职):
    • 企业未足额支付工资、未缴社保、未提供劳动保护等(依据《劳动合同法》第38条);
    • 此时员工可主张N倍经济补偿金(无“+1”),但需书面通知并保留证据(如工资流水、社保记录)。
  4. 违法解除劳动合同的赔偿标准(2N) :若企业无合法依据解除合同(如无故辞退、程序违法、裁撤孕期员工等),需支付2N赔偿金(经济补偿金的双倍)。
  5. 实务对比与维权建议
    情形 补偿标准 法律依据 维权路径
    企业合法解除未提前通知 N+1 《劳动合同法》第40条 协商或仲裁主张代通知金
    企业违法解除 2N 《劳动合同法》第87条 劳动仲裁或诉讼索赔双倍赔偿
    员工被迫离职(企业过错) N 《劳动合同法》第38条 提交证据申请仲裁

商业保险

【当代年轻人没了铁饭碗,还能负重奔跑多久?北京二胎家庭如何转移风险?】 https://www.bilibili.com/video/BV16F4m1V7wv/?share_source=copy_web&vd_source=2cbe8cdd54a75d0c43fcdefa624d3fbe

“年纪轻的一定要买百万医疗险和意外险,还有抗癌险,关键时候真的能救命的,有余裕买个重疾险,如果生病了确证了就能拿到几十万的保额,可以作为治疗和康复期的生活费开销,医疗费有医保和百万医疗险,到时候真生比较严重的病百分之九十能报销,年纪轻买了便宜加起来一年千把块,父母没生病可以给他们买众民保和中银全名保,还有当地的惠民保三个加起来六百块不到,不看健康告知年龄大可以报销,配合医保大概能报销八十花的多甚至能报销到九十,给家里老人多套保障,不会出现得了病只能放弃的人间惨剧,如果老人没医保可以买城乡医保一年几百块”

mom:东莞农村?居民社保医保,莞家福,莞家福居民保?,midea家属保险

2025年度商业保险开始投保了~ 员工(统一投保无需美福下单)本人及任选两名家属的免费/自付费升级方案 https://mapnew5.midea.com/newservicenopages/#/content/detail?id=1902351310562877442&type=2

快速了解一个保险的7个核心要素

  1. 保障范围(核心)
    • 保什么:疾病类型(如60种重疾)、门诊/住院/手术等报销范围。
    • 特别关注:是否包含社保外费用(如进口药、质子重离子)、癌症特药清单。
    • 图片信息提示:图中“重大疾病列表”需核对乳腺癌是否被列为赔付疾病。
  2. 购买条件
    • 年龄:是否限制60岁以上?续保是否允许超龄?
    • 健康告知:是否询问癌症病史?如有,如何核保?(图片中未提及健康告知,可能宽松)
    • 等待期:生效前等待期(通常30-90天,重疾险可能180天)。
  3. 免赔额与报销比例
    免赔额:如“意外住院补贴限额100元/天”可能指单日免赔额。
    报销比例:社保内是否100%?社保外是否有比例限制?(图中“社保范围内7.5万/位”需进一步解读)。
  4. 既往症条款
    • 关键问题:乳腺癌术后治疗是否被定义为“既往症”?若属于,报销比例是多少?(图中“免检责任”可能指部分疾病免检,需核实)
  5. 保额与限额
    • 单项限额:如“意外住院补贴7.5万/位”是否够用?
    • 年度总限额:重大疾病总保额是否充足(至少100万以上)。
  6. 增值服务
    • 实用性:医疗垫付、重疾绿通、二次诊疗意见(图中未提及,需向HR确认)。
  7. 免责条款
    • 雷区排查:如“不覆盖胎液”(图片底部注释)可能指免责先天性疾病,需明确免责清单。

从报销顺序理解

  1. “社保医保”“惠民保”:基本保障,看病报销“社保范围”内的如60%
  2. 团保商业保险:企业与保险公司合作提供,一方面能够报销“社保范围”内剩余40%中的部分,一方面能保重疾住院等
  3. 百万医疗险:看病报销“社保范围”外的部分,?有患癌史无法购买,可选择众民保
  4. 重疾保:以上“医疗险”报销看病本身的费用,而“重疾险”为支付单笔保费,用于后续正常生活;需要安全告知
  5. 意外险:负责意外事故以及某些“医疗险”不涵盖的病
  6. 可以按照“医疗险”,“重疾险”,“意外险”来搭配购买,但也存在商业保险覆盖其中多种的能力

根据您母亲的情况(47岁、乳腺癌病史、已参保东莞社保及莞家福),结合健康限制和保障需求,以下是商业保险的配置建议及具体产品的分析:

一、基础保障优先级(必选)

  1. 普惠型医疗险(补充社保和莞家福)
    推荐产品:全国版惠民保(如众民保)、东莞本地惠民保(如已参保莞家福需确认既往症规则)
    适用性
    ◦ 无健康告知,覆盖乳腺癌术后治疗费用(报销比例通常为30%-50%,需查看具体条款)。
    ◦ 年保费约100-200元,保额高达300万,覆盖医保内外费用(部分产品含特药)。
    注意事项
    ◦ 优先选择支持“乳腺癌复发治疗”的产品,如众民保对复发医疗费按比例报销。
  2. 乳腺癌复发险(专项核心保障)
    推荐产品
    泰康粉红卫士:0-2期患者可投保,复发或转移一次性赔付最高50万,报销型最高100万(含41种特药)。
    太平洋粉红守护:支持0-2期患者,可选对侧乳腺癌保障,含48种特药报销,续保稳定性较好。
    适用性
    ◦ 覆盖乳腺癌复发、转移、对侧新发,报销比例100%(含社保外费用)。
    ◦ 年保费约1400-3000元(根据保额选择),等待期90天。

二、补充保障(根据预算可选)

  1. 意外险
    推荐产品:众安高危职业意外险、平安综合意外险
    适用性
    ◦ 无健康告知,保意外身故/伤残(50-100万)、意外医疗(不限社保)。
    ◦ 年保费约200-500元,杠杆率高。
  2. 团体医疗险(企业合作产品)
    适用性
    ◦ 您提到的太平洋人寿企业合作套餐,若无健康告知或宽松告知,可作为基础住院医疗补充(覆盖门诊住院费用)。
    ◦ 需确认是否覆盖社保外费用及乳腺癌复发相关治疗。

三、不推荐或限制类产品

  1. 常规重疾险/百万医疗险
    • 因乳腺癌病史,99%产品拒保或除外责任。
  2. 防癌医疗险
    • 仅少数产品允许投保(如支付宝终身防癌险),但通常除外乳腺癌责任。

具体产品对比分析

产品类型 推荐产品 核心优势 局限性 年保费参考
乳腺癌复发险 泰康粉红卫士 保费最低(1400元起),特药覆盖最全(41种) 仅限0-2期患者,续保需审核 1400-5000元
乳腺癌复发险 太平洋粉红守护 含对侧乳腺癌保障,特药清单更新快(48种) 仅限0-2期患者,保费较高 2000-8000元
惠民保 众民保(全国版) 覆盖复发治疗,含CAR-T疗法和质子重离子 免赔额高(2万),报销比例50%-80% 150-300元
团体医疗险 太平洋企业合作套餐 无健康告知,可能覆盖既往症 需确认保额和报销范围(可能仅限社保内) 企业合作价(待确认)

四、配置方案建议

  1. 预算有限方案(年保费约1600元)
    必选:泰康粉红卫士(基础型1400元)+ 众民保(200元)。
    作用:覆盖乳腺癌复发高额医疗费,补充普惠报销。
  2. 全面保障方案(年保费约5000元)
    必选:太平洋粉红守护(含特药责任3000元)+ 众民保(200元)+ 团体医疗险(企业合作)。
    可选:叠加意外险(300元),覆盖意外风险。
  3. 区分保险类型,明确赔付规则
  • 可叠加赔付的保险类型(给付型)
    重疾险:若确诊合同约定的疾病(如癌症、心梗等),不同保司的重疾险可同时赔付,互不影响。例如:投保两份50万保额的重疾险,确诊后可获100万赔付。
    寿险/意外险身故/伤残保障:身故或伤残保额可叠加赔付,但未成年人受保额限制(如10岁以下身故保额最高20万)。
    年金险:按合同约定固定给付生存金,多份保单可同时领取。
  • 不可叠加赔付的保险类型(报销补偿型)
    医疗险(含意外医疗):以实际医疗费用为上限,发票原件仅能用于一次报销。若A公司已全额赔付,B公司不再赔付;若A公司仅报销80%,剩余20%可向B公司申请(需提供分割单)。
    财产险(车险、家财险):遵循损失补偿原则,赔付总和不超过实际损失。例如:车辆全损价值50万,即使投保两份车险,最高仅赔50万。
  1. 保障范围叠加策略
  • 优先覆盖不同风险场景
    疾病+意外+身故组合:例如「重疾险+医疗险+意外险」,覆盖疾病治疗、意外伤害和身故风险。
    高低保额搭配:小额医疗险(覆盖1万内费用) + 百万医疗险(覆盖大额住院费用),减少免赔额影响。
  • 避免重复投保同类报销型保险
    • 同时购买多份百万医疗险无意义(均需扣除1万免赔额),但可搭配无免赔额的小额医疗险。
  • 注意隐性条款冲突
    • 部分医疗险限制“仅报销社保目录内费用”,若另一份医疗险覆盖社保外费用,可互补。
  1. 总结建议
    合理搭配类型:给付型(重疾、寿险) + 报销型(医疗险) + 财产险,避免同类报销险重复。
    重点核查条款:健康告知、免责范围、赔付优先级(如医疗险报销顺序)。
    动态调整保障:定期检视保单,根据家庭阶段(如生子、购房)增减保额或险种。

五、注意事项

  1. 健康告知:购买前务必确认条款中的“既往症定义”,乳腺癌相关治疗可能被除外。
  2. 报销材料:需保存医疗发票、诊断证明、用药清单等,多数产品需先经医保报销。
  3. 续保稳定性:众民保为1年期产品,不保证续保,但众安产品历史稳定性较好。

建议优先投保乳腺癌复发险(专项保障),再补充惠民保和意外险,最后根据企业团体险条款决定是否叠加。
建议通过保险顾问协助核保(如众安、慧择平台),确保理赔无争议。


投资

三、个性化投资策略建议

1. 资金配置方案(月均5000元)

类别 比例 工具示例 目的
学习投入 10% 付费研报、专业课程 知识体系构建
模拟交易 0% 同花顺模拟盘、Backtrader 策略验证
指数定投 40% 沪深300ETF(A股) 强制储蓄+市场β收益
行业ETF 30% 半导体ETF(512480) 把握结构性机会
现金储备 20% 货币基金 应对黑天鹅事件

2. 技术赋能投资的具体路径

  • 量化入门
    1. 用Python复现经典策略(如双均线策略)
    2. 开发舆情监控爬虫(抓取雪球、股吧热词)
    3. 构建多因子选股模型(参考WorldQuant Alpha库)
  • 工具推荐
    • 数据平台:AKShare(开源替代Tushare)
    • 回测框架:QLib(阿里开源)
    • 可视化:Plotly+Dash构建交互式看板

3. 阶段目标管理

  • 新手期(0-1年)
    • 目标:年化收益率跑赢货币基金(2%-3%)
    • 关键动作:完成10个策略回测、建立投资checklist
  • 进阶期(1-3年)
    • 目标:年化收益率8%-10%(同期沪深300水平)
    • 关键动作:开发自动化交易信号系统

四、风险控制工具箱

  1. 极端情况应对预案
    • 设置动态止损线(如回撤超15%强制减仓)
    • 保留3-6个月生活费的现金储备
    • 建立黑天鹅事件清单(如中美脱钩、疫情反复)
  2. 认知偏差矫正方法
    • 交易日志模板:
      1
      2
      3
      | 日期 | 操作 | 决策依据 | 情绪状态 | 事后评估 |
      |------|------|----------|----------|----------|
      | 2023-08-01 | 买入XX股 | MACD金叉 | 焦虑追涨 | 错误:未考虑成交量萎缩 |
  3. 推荐监控指标
    • 十年期美债收益率(全球资产定价锚)
    • 人民币汇率波动区间
    • 融资融券余额变化率

六、推荐资源清单

  1. 数据源
    • 国家统计局宏观数据库
    • FRED(美联储经济数据)
  2. 工具链
    • Jupyter Notebook + Pandas(数据分析)
    • TensorFlow/PyTorch(预测模型)
  3. 深度阅读
    • 《主动型指数投资》(王延巍)
    • 《量化投资:以Python为工具》(蔡立耑)

下一步行动建议

  1. 本周内注册模拟交易账户
  2. 用Matplotlib复现近5年行业轮动图谱
  3. 加入量化投资开源社区(如JoinQuant)

你的技术背景是独特优势,建议从**”工程师型投资者”路径切入,将编程能力转化为投资生产力。记住:在认知不充分时,不亏损追求收益**更重要。