9.Spring ai alibaba 运维助手实战
Spring ai alibaba 运维助手实战
一、🧱Redis Stack与原生Redis对比
Redis Stack是基于Redis构建的扩展套件,在原生Redis基础上增加了诸多功能和优化。以下是两者在多个维度的对比:
功能维度 | 原生Redis | Redis Stack增强功能 |
---|---|---|
数据结构 | 基础的数据结构,如字符串、列表、集合、哈希等,满足简单数据存储和操作需求。 | 新增了JSON、图、时间序列、概率结构等高级类型,提供了更丰富的数据表达和处理能力。例如JSON类型可直接存储和操作JSON文档;图结构用于处理复杂的关系数据。 |
查询能力 | 仅支持基于键值的简单查询,适用于快速查找特定键对应的值。 | 具备强大的查询功能,支持全文搜索、向量搜索、图查询、JSON查询。全文搜索可用于文本数据的快速检索;向量搜索适用于相似性搜索场景,如推荐系统;图查询便于在关系数据进行复杂的路径查找等操作。 |
使用场景 | 主要用于缓存、消息队列、计数器、分布式锁等常见场景,是互联网应用中常用的基础组件。 | 除覆盖原生Redis的场景外,还能应用于实时推荐、时序分析、知识图谱、文档数据库、AI向量检索等领域。例如在实时推荐中利用向量搜索快速找到相似物品;在时序分析中使用时间序列数据结构存储和处理时间相关的数据。 |
开发体验 | 通过命令行进行操作,开发和维护时需要手动拼装复杂的业务逻辑,开发和调试成本较高。 | 提供了RedisInsight这一可视化工具,可方便地进行数据管理、查询调试等操作。同时还有对象映射库,能将应用程序对象与Redis数据结构进行映射,简化开发流程,提高开发效率。 |
二、🔧环境准备与安装
1️⃣Docker下安装Redis Stack
可以使用以下命令在Docker中安装并运行Redis Stack:
sudo docker run -d \--name redis-stack \-p 6379:6379 \-e REDIS_ARGS="--requirepass yumeko" \-v redis_stack_data:/data \--restart no \redis/redis-stack-server:latest
-
-d
:以后台模式运行容器。 -
--name redis-stack
:指定容器名称为redis-stack
。 -
-p 6379:6379
:将主机的6379端口映射到容器的6379端口。 -
-e REDIS_ARGS="--requirepass yumeko"
:设置Redis的访问密码为yumeko
。 -
-v redis_stack_data:/data
:将容器内的/data
目录挂载到主机的redis_stack_data
卷,用于持久化存储数据。 -
--restart no
:容器退出时不自动重启。 -
redis/redis-stack-server:latest
:使用的Redis Stack镜像为最新版本。
2️⃣验证安装
通过以下命令进入Redis Stack的命令行界面并进行身份验证:
docker exec -it redis-stack redis-cli
AUTH yumeko
3️⃣验证持久化
docker volume ls
4️⃣ReJSON-RL提供的主要命令
-
JSON.SET:用于设置JSON值。
-
JSON.GET:用于获取JSON值。
-
JSON.DEL:用于删除JSON值。
-
JSON.MGET:可批量获取多个键的JSON值。
-
JSON.TYPE:用于获取JSON值的类型。
-
JSON.NUMINCRBY:对JSON中的数字进行增量操作。
-
JSON.STRAPPEND:将字符串追加到JSON字符串。
-
JSON.STRLEN:用于获取JSON字符串的长度。
三、📌运维助手
实现一个专为运维工程师设计的智能异常处理辅助工具,提供全面的异常处理。该工具通过自定义异常体系,帮助运维团队快速定位和解决各类技术问题。
四、⚙️技术栈集成配置
1️⃣导入依赖pom.xml
<dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter-dashscope</artifactId></dependency><!--添加向量数据库--><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-vector-store-redis</artifactId></dependency>
2️⃣配置applcation.properties
# ====SpringAIAlibaba Config=============
spring.ai.dashscope.api-key=${qwen-api}
sping.ai.darshscope.chat.options.model=deepseek-v3.1
spring.ai.dashscope.embedding.options.model=text-embedding-v3# =======Redis Stack==========
spring.data.redis.host=192.168.88.129
spring.data.redis.port=6379
spring.data.redis.username=default
spring.data.redis.password=......
spring.ai.vectorstore.redis.initialize-schema=true
spring.ai.vectorstore.redis.index-name=custom-index
spring.ai.vectorstore.redis.prefix=custom-prefix:
五、🧠核心实现代码
1️⃣redis序列化配置
package com.alibaba.springaialibabaredisrag.config;import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;@Configuration
public class RedisConfig
{@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactor){RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();redisTemplate.setConnectionFactory(redisConnectionFactor);//设置key序列化方式stringredisTemplate.setKeySerializer(new StringRedisSerializer());//设置value的序列化方式json,使用GenericJackson2JsonRedisSerializer替换默认序列化redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.setHashKeySerializer(new StringRedisSerializer());redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());redisTemplate.afterPropertiesSet();return redisTemplate;}
}
2️⃣LLM 模型配置
@Configuration
public class MultiModelConfig {@BeanChatClient chatClient(ChatClient.Builder builder) {return builder.defaultOptions(ChatOptions.builder().model("qwen-plus") // 设置您想要的模型.build()).build();}
六、🔄向量化数据初始化
1️⃣运维知识库准备 (ops.txt)
00000 系统OK正确执行后的返回
C2222 Kafka消息解压严重
注:
- 此处读取ops文件到向量数据库
- 可以读取到本地内存 (招聘助手文档涉猎过)
- 可以读取到向量数据库 (本文文档)
- 可以直接使用百炼平台知识库(后续看心情写,😄)
2️⃣向量数据库初始化
@Configuration
public class InitVectorDatabaseConfig
{@Autowiredprivate VectorStore vectorStore;@Autowiredprivate RedisTemplate<String,String> redisTemplate;@Value("classpath:ops.txt")private Resource opsFile;@PostConstruct //当所有Bean都完成依赖注入后,带有 @PostConstruct 的方法会自动调用public void init(){//1 读取文件TextReader textReader = new TextReader(opsFile);textReader.setCharset(Charset.defaultCharset());//2 文件转换为向量(开启分词)List<Document> list = new TokenTextSplitter().transform(textReader.read());//3 写入向量数据库RedisStack//vectorStore.add(list);// 解决上面第3步,向量数据重复问题,使用redis setnx命令处理//4 去重复版本String sourceMetadata = (String)textReader.getCustomMetadata().get("source");String textHash = DigestUtils.md5DigestAsHex(sourceMetadata.getBytes());String redisKey = "vector:ops:" + textHash;// 判断是否存入过,redisKey如果可以成功插入表示以前没有过,可以假如向量数据Boolean retFlag = redisTemplate.opsForValue().setIfAbsent(redisKey, "1");System.out.println("是否初始化过: "+retFlag);if(Boolean.TRUE.equals(retFlag)){//键不存在,首次插入,可以保存进向量数据库vectorStore.add(list);}else {//键已存在,跳过或者报错//throw new RuntimeException("---重复操作");System.out.println("------向量初始化数据已经加载过,请不要重复操作");}}}
七、🤖 RAG 服务接口
1️⃣ 控制器实现
package com.alibaba.springaialibabaredisrag.controller;import jakarta.annotation.Resource;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.rag.advisor.RetrievalAugmentationAdvisor;
import org.springframework.ai.rag.retrieval.search.VectorStoreDocumentRetriever;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;@RestController
public class RagController
{@Resourceprivate ChatClient chatClient;@Resourceprivate VectorStore vectorStore;/*** http://localhost:8012/rag4aiops?msg=00000* http://localhost:8012/rag4aiops?msg=C2222* @param msg* @return*/@GetMapping(value = "/rag4aiops")public Flux<String> rag(@RequestParam (value = "msg") String msg){String systemInfo = """你是一个运维工程师,按照给出的{msg}给出对应故障解释,否则回复找不到信息。并且根据故障信息给出最优解决方案.并且给出详细的操作步骤.最终给出优化方案""";RetrievalAugmentationAdvisor advisor = RetrievalAugmentationAdvisor.builder().documentRetriever(VectorStoreDocumentRetriever.builder().vectorStore(vectorStore).topK(5) // 检索返回的文档数量.similarityThreshold(0.7) // 相似度阈值.build()).build();return chatClient.prompt().system(systemInfo).user(msg).advisors(advisor).stream().content().doOnNext(data -> {// 可以添加日志查看实际返回的数据System.out.println("Stream data: " + data);});}
}
2️⃣验证向量初始化数据
keys *
[{"value": "custom-prefix:b8049f33-1831-4d3d-bf25-432abf67ce42"},{"value": "vector:ops:f39c4b5b34868b3e4d9910f59f16a24e"}
]
get vector:ops:f39c4b5b34868b3e4d9910f59f16a24e
[{"value": "1"}
]
json.get custom-prefix:b8049f33-1831-4d3d-bf25-432abf67ce42
[{"value": {"charset": "UTF-8","embedding": [-0.023758734, .......],"source": "ops.txt","content": "00000 系统OK正确执行后的返回\r\nC2222 Kafka消息解压严重"}}
]
3️⃣根据编码调用辅助工具
http://localhost:8012/rag4aiops?msg=00000
GET http://localhost:8012/rag4aiops?msg=00000HTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Transfer-Encoding: chunked
Date: Thu, 02 Oct 2025 23:54:27 GMT系统正常,正确执行后的返回值为00000,表示无故障,服务运行稳定。解决方案:无需处理。操作步骤:1. 确认当前系统返回码为00000。
2. 检查相关服务日志,确认无异常记录。
3. 继续监控系统运行状态,确保持续稳定。优化方案:- 建立定期巡检机制,自动采集返回码并记录。
- 配置监控告警系统,对非00000返回码实时预警。
- 完善日志分析系统,提前识别潜在风险。Response code: 200; Time: 5186ms (5 s 186 ms); Content length: 194 bytes (194 B)
http://localhost:8012/rag4aiops?msg=C2222
GET http://localhost:8012/rag4aiops?msg=C2222HTTP/1.1 200
Content-Type: text/plain;charset=UTF-8
Transfer-Encoding: chunked
Date: Thu, 02 Oct 2025 23:56:17 GMTC2222 表示Kafka消息解压严重,通常指在消费Kafka消息时,消息体使用了压缩(如gzip、snappy、lz4等),但在解压过程中出现异常或负载过高,导致消费端处理能力下降,可能出现消息积压、CPU占用高、消费延迟等问题。**解决方案:**1. **确认压缩类型与客户端支持一致性**- 检查生产者端配置的压缩格式(compression.type)。- 确保消费者端支持该压缩算法,并已安装对应依赖库(如Snappy需要本地库支持)。2. **临时规避措施:重启消费者并监控资源**- 重启受影响的消费者实例,释放内存压力。- 监控JVM堆内存、GC频率和CPU使用率。3. **优化消费者资源配置**- 增加消费者堆内存:调整`-Xmx`参数,例如设置为`-Xmx4g`。- 启用批处理限流:通过配置`max.poll.records`(如设为500)控制每次拉取的消息量,防止瞬时解压压力过大。4. **检查并调整Kafka Broker压缩策略**- 若无需压缩,可在Broker端或Producer端关闭压缩:```propertiescompression.type=none```- 或改为服务端压缩、客户端无压缩方式,由Broker负责压缩/解压。5. **升级客户端版本**- 使用较老版本的Kafka Client可能存在解压bug,建议升级到最新稳定版(如2.8+或3.x)。6. **启用消费者反压机制**- 在应用层实现背压控制,当解压处理不过来时暂停拉取消息。**详细操作步骤:**1. 登录消费者服务器,查看日志定位C2222错误:```bashgrep "C2222" application.log
2. 查看当前JVM资源使用情况:jstat -gc <pid>top -p <pid>3.修改消费者JVM参数(以Spring Boot为例):
-Xms2g -Xmx4g -XX:+UseG1GC
.........
好记性,不如来赖笔头,一堆理论记不住,直接实践.