Redis使用纪要

一、基础

1、redis简介

Redis是一个使用 C 语言编写的、开源的高性能非关系型(NoSQL)数据库。

Redis 为键值对数据库,键的类型只能为字符串,值支持五种数据类型:字符串、列表(link lists)、集合(sets)、散列表(hash tables)、有序集合(sorted sets)。

与传统数据库不同的是 Redis 的数据是存在内存中的,所以读写速度非常快,因此 redis 被广泛应用于缓存方向,每秒可以处理超过 10万次读写操作,是已知性能最快的Key-Value DB(键值对数据库)。
Redis 也经常用来做分布式锁。除此之外,Redis 支持事务 、持久化、LUA脚本、LRU驱动事件、多种集群方案。

1.1、Hash tables类型的项目使用实例
场景:以用户id为键,将用户加购物车商品(信息包含pid、商品数量)放入redis缓存;查看购物车时全部取出展示。
1)存:redisTemplate.opsForHash().put(userId, productId, productNumber);
2)只取全部的商品idList<String> pIdList = redisTemplate.opsForHash().values("userId");
3)取全部商品信息Map<String, int> map = redisTemplate.opsForHash().entries("userId");

存的时候只能一条一条数据存、相互之间没有联系,但是取的时候可以像从一张表中取出的一样,这就是非关系型数据库“非关系”的核心奥义。

2、Redis有哪些优缺点?

1)优点:

读写性能优异, Redis能读的速度是110000次/s,写的速度是81000次/s。

支持数据持久化,支持AOF和RDB两种持久化方式。

支持事务,Redis的所有操作都是原子性的,同时Redis还支持对几个操作合并后的原子性执行。

数据结构丰富,除了支持string类型的value外还支持hash、set、zset、list等数据结构。

支持主从复制,主机会自动将数据同步到从机,可以进行读写分离。

2)缺点
我能想到的缺点只有:受物理内存的限制,redis不能用作海量数据的高性能读写,只适应于,在数据量较小场景下的操作和运算,有些局限。

3、redis的数据类型

redis的value常用的数据类型有以下几种:
1)string:能表达字符串,整数,浮点数

2)list:可以存储有序,可重复的元素

List在实际开发中常常不会用Redis List结构存储,而是存为Redis String;
原因:Redis List 适合频繁增删元素的场景(如消息队列),而 List 作为整体存取时,序列化为字符串更高效。
比如,存设备上报数据List,常常需要再每次存取的时候,把所有数据都取出来处理一下再放进去、而不能每次存取一个,这种情况就更适合用Redis String,而不是Redis List。

实现
存的时候

# 先用fastjson键List<MyObj>序列化未json字符串
String json = JSON.toJSONString(userList);
# 再用set(key, value)存入redis
jedisCluster.set(key, json);

取的时候

# 先用get方法取出json串
String json = jedisCluster.get(key);
if (json == null) return new ArrayList<>(); // 避免 NullPointerException
# 再用fastjson反序列化为 List<MyObj>
List<MyObj> list = JSON.parseArray(json, MyObj.class);

2.2)注意事项:保证序列化与反序列化的一致性

禁止进行二次序列化
开发中常常会对redis的操作方法进行封装,有一次我用封装的put()方法存list,先用fastjson序列化为json串再用put存入,然后再取的时候用fastjson反序列化报错了,说取出来的json串格式不对、转换失败;
后来才发现,封装的put()方法,内部就已经对放入的value进行了一次序列化了,而我在调用put前进行了一次序列化,相当于进行了两次序列化,第二次序列化相当于对字符串进行序列化,导致最终的json串无法再反序列化为最初的list。

3)set:无序去重的集合。set提供了交集,并集等方法,对于实现共同好友,共同关注等功能特别方便
4)zset:有序set。内部维护了一个score的参数来实现。适用于排行榜和带权重的消息队列等场景

5)hash:键值对集合

以jedis为例,hash的设置一般用hset()方法,hset()入参有两种
hset(key, map)
或者
hset(key, feild, value)
其中key为键,feild为字段(其实也是键),value为值,
这里我一般把key理解为分组,feild为键,value为值;比如我们有一个产品组,每个产品有多个设备,每个设备有一个对应的数据值,那么就可以hset(产品Code,设备Code,设备Data)这样把数据分门别类的放入redis。
hash取的时候可以用hget()和hgetAll()方法;
hget()方法要传两个值,key和feild,还是以产品-设备-数据为例,hget可以直接得到对应产品的指定设备的数据;
hgetAll()方法传一个key值,得到一个Map,map的key即为feild,也就是说hgetAll()会一下获取产品下所有设备的数据,通过map返回。

4、redis在实际开发中的应用场景

1)缓存

将热点数据放到内存中,设置内存的最大使用量以及淘汰策略来保证缓存的命中率。

2)分布式锁实现

在分布式场景下,无法使用单机环境下的锁来对多个节点上的进程进行同步。可以使用 Redis 自带的 SETNX 命令实现分布式锁,除此之外,还可以使用官方提供的 RedLock 分布式锁实现。

redis分布式锁实现方案:

a、用setNX命令,key为对应的资源标记,value存获取到锁的线程设置的唯一标记;
b、setNX返回1,表示获取到锁,就可以执行任务;
c、setNX返回0,表示获取锁失败;

此分布式锁方案的一些问题及解决办法:

a、死锁问题:采用setNX + expire过期时间解决死锁(同时,为了保证两个命令的原子性,可用lua脚本同时执行2个命令);
b、误删问题:value存获取到锁的线程设置的唯一标记就是为了解决误删问题,要求线程释放锁前先判断value,是当前线程加的锁,才可用释放;
c、锁过期释放、但任务未完成的问题(续期问题):开启一个守护线程,定期检查锁是否存在,存在则适当延长过期时间。
d、采用Redisson分布式锁框架,其特有的看门狗watch dog,可以解决续期问题。

3)计数器

可以对 String 进行自增自减运算,从而实现计数器功能。Redis 这种内存型数据库的读写性能非常高,很适合存储频繁读写的数据。

4)防止消息重复消费(具体看Rabbit MQ)

5、Redis 的持久化机制是什么?分别做一些说明

1)Redis持久化的原因:如果把数据放在内存中,电脑关闭或重启数据就会丢失,所以放在内存中的数据不是持久化的,而放在磁盘就算是一种持久化。
Redis 的数据存储在内存中,如果 linux 宕机或重启,又或者 Redis 崩溃或重启,所有的内存数据都会丢失,为解决这个问题,Redis 提供两种机制对数据进行持久化存储,便于发生故障后能迅速恢复数据。

2)Redis 提供两种持久化机制 RDB(默认) 和 AOF 机制,
RDB就是在指定的时间间隔内将内存中的数据集快照写入磁盘,数据恢复时将快照文件直接再读到内存。RDB 保存了在某个时间点的数据集(全部数据),存储在一个二进制文件中,默认叫 dump.rdb。RDB 技术非常适合做备份,可以保存最近一个小时,一天,一个月的全部数据;保存数据是在单独的进程中写文件,不影响 Redis 的正常使用;RDB 恢复数据时比其他 AOF 速度快。
AOF就是Redis每次接收到一条改变数据的命令时,它将把该命令写到一个 AOF 文件中(只记录写操作,读操作不记录),当 Redis 重启时,它通过执行 AOF 文件中所有的命令来恢复数据。

两种持久化机制的实现方式,都是在redis.conf 文件中做相应配置即可。

3)两种持久化方式的优缺点:
RDB恢复方便,恢复速度也快;但是会丢失一部分数据看,而且会分出一个进程,如果数据库数据量大、服务器cpu也比较弱的时候,可能每次备份数据就会比较慢,可能达到1s。
AOF是一个可以提供完整数据的保障方案;缺点是,AOF 文件会在操作过程中变得越来越大,而且其中很多记录对最终的结果是无用的。

可以同时使用两种持久化方案,redis默认会用aof以保证数据的完整性。

6、Redis中key长度对性能的影响

今天我们一起用代码来验证一下key的长度对redis读取key的性能影响。
网络环境:本地
内存:8G
redis版本:redis-5.0.7
实验代码如下,读写1000次长度为16、128、512、1024、2048、4096、9012、20000、100000长度的key获取执行的总时长:

在这里插入图片描述
随机生成指定长度的字符串方法如下:
在这里插入图片描述
运行main方法三次,数据表现基本一致,下图是运行输出的三组数据:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
结论:
在这里插入图片描述
当key的长度不超过1024(即512个字符)的长度的时候,基本上对性能不造成影响,但是一旦超过1024长度,随着key长度的增加,耗时也会随之增加。

所以,key长度对redis读写性能的影响是当key长度超过1024字节之后,因此我们在实际开发过程中可以根据自己的key长度预估对redis是否存在性能影响。

在实际业务开发中,基本上大家的key不会超过1024字节,因此可以在命名的时候,尽量取一些能见名知义的key,不必刻意为了缩短key长度而降低key的可读性。

当有这种key就必须特别长的时候,或者不确定是否超过1024字节,我们可以对key做一次hash后取哈希值作为redis的key,这样就可以大幅提高redis的性能了。

7、Redis官网关于key的一些规则

1.非常长的key是不推荐的。一个1024 bytes是一个非常坏的注意,不仅仅是因为内存浪费,更是因为在数据集中搜索对比的时候需要耗费更多的成本。当要处理的是匹配一个非常大的值,从内存和带宽的角度来看,使用这个值的hash值是更好的办法(比如使用SHA1)。

2.特别短的key通常也是不推荐的。在写像u100flw这样的键的时候,有一个小小的要点,我们可以用user:1000:followers代替。可读性更好,对于key对象和value对象增加的空间占用与此相比来说倒是次要的。当短的key可以很明显减少空间占用的时候,你的工作就是找到正确的平衡。

3.尝试去固定一个schema。比如object-type:id是一个好主意,-和.通常用于多个字符的域,就像comment🔢reply.to,或者comment🔢reply-to。

4.最大的key允许512MB。

8、Redis的一些开发规范

key命名设计

(1)【建议】: 可读性和可管理性 以业务名(或数据库名)为前缀(防止key冲突),用冒号分隔,比如业务名:表名:id。

(2)【建议】: 简洁性 保证语义的前提下,控制key的长度,当key较多时,内存占用也不容忽视,例如:U_O_P_HS:#userId代表用户已经购买的商品Id的hash存储。

(3)【强制】:不要包含特殊字符反例:包含空格、换行、单双引号以及其他转义字符。

value设计

(1)【强制】:拒绝bigkey(防止网卡流量、慢查询)string类型控制在10KB以内,hash、list、set、zset元素个数不要超过5000。反例:一个包含200万个元素的list。非字符串的bigkey,不要使用del删除,使用hscan、sscan、zscan方式渐进式删除,同时要注意防止bigkey过期时间自动删除问题(例如一个200万的zset设置1小时过期,会触发del操作,造成阻塞,而且该操作不会不出现在慢查询中(latency可查)),查找方法和删除方法

(2)【推荐】:选择适合的数据类型。例如:实体类型(要合理控制和使用数据结构内存编码优化配置,例如ziplist,但也要注意节省内存和性能之间的平衡)正例:hmset user:1 name tom age 19 favor football

(3).【推荐】:控制key的生命周期,redis不是垃圾桶。建议使用expire设置过期时间(条件允许可以打散过期时间,防止集中过期),不过期的数据重点关注idletime。

二、集群

1、集群的概念

集群,就是通过添加服务器的数量,提供相同的服务,从而让服务器达到一个稳定、高效的状态。

redis集群就是多个redis节点(组)一起工作的模式。它没有代理节点和中心节点,各个节点平等。

2、集群的必要性

1)单个redis存在不稳定性。当redis服务宕机了,就没有可用的服务了。

2)单个redis的读写能力是有限的。

总结:redis集群是为了强化redis的读写能力,提高容错(当集群中的某一个节点故障时,redis还可以继续处理客户端的请求)

3、Redis集群(redis cluster)介绍

1)集群组成 及 故障转移方式

一、每个主Redis只有一个库db0(这点不同于单节点);
二、每个主Redis只能存0~16384个槽的一部分;
三、如果一半以上的主Redis判断某个主Redis断了(所以为了投票,主Redis只能是奇数个,至少3个),启用这个Redis的副Redis为主,若后面这个"主"Redis又重启了,它就是副了;

2)分配槽slot的概念

一个Redis集群包含16384个插槽,数据库中每个键都属于这16384槽中的一个,集群使用键的哈希值 % 16384来计算键属于哪一个槽。

每个节点负责处理一部分插槽,如一个集群有3个节点,A节点负责处理0-5500号插槽,节点B负责处理5501-11000号插槽,节点C负责处理11001-16383号插槽。

redis-cli查询键值时,如客户端对应的服务器中不存在该键,则Redis会报错。

而使用redis-cli -c -p port中的-c参数就可以实现自动重定向。

不在一个slot中的数据,不能使用mget和mset等多键操作。

3)集群模式的缺点

1. 客户端实现复杂,驱动要求实现Smart Client,缓存slots mapping信息并及时更新,提高了开发难度。
目前仅JedisCluster相对成熟,但异常处理也还不完善,比如常见的“max redirect exception”
2. 节点会因为某些原因发生阻塞(阻塞时间大于 cluster-node-timeout)被判断下线,这种failover是没有必要的
3. 数据通过异步复制,不保证数据的强一致性
4. slave充当“冷备”,不能缓解读压力
5. 批量操作限制,目前只支持具有相同slot值的key执行批量操作,对mset、mget、sunion等操作支持不友好
6. key事务操作支持有线,只支持多key在同一节点的事务操作,多key分布不同节点时无法使用事务功能
7. 不支持多数据库空间,单机redis可以支持16个db,集群模式下只能使用一个,即db 0

4、Redis主从复制介绍

1)基础概念

一、主从复制模式中包含一个主数据库实例(master)与一个或多个从数据库实例(slave)
在这里插入图片描述
客户端可对主数据库进行读写操作,对从数据库进行操作,主数据库写入的数据会同步给从数据库。

二、主从库具体的同步机制

1、slave启动后,向master发送SYNC命令,master接收到SYNC命令后通过bgsave保存快照(即上文所介绍的RDB持久化),并使用缓冲区记录保存快照这段时间内执行的写命令
2、master将保存的快照文件发送给slave,并继续记录执行的写命令
3、slave接收到快照文件后,加载快照文件,载入数据
4、master快照发送完后开始向slave发送缓冲区的写命令,slave接收命令并执行,完成复制初始化
5、此后master每次执行一个写命令都会同步发送给slave,保持master与slave之间数据的一致性

5、Redis主集群模式 与 主从复制的关系

1)集群与主从复制是互相补充的技术,主从复制不是集群模式的一种;

2)集群是确立1个redis组与另一个redis组之间的运行关系;

3)主从复制是确立1个redis组中,主、副两个库之间的运行关系;

X、其它琐碎

<think>好的,用户之前问过关于个人知识库的介绍,现在他想知道如何使用DeepSeek搭建本地个人知识库。我需要先理解DeepSeek是什么。根据我的知识库,DeepSeek是一家中国的公司,专注于让AGI成为现实,可能提供相关的工具或服务。不过用户可能指的是他们的某个具体产品,比如可能的大模型或者知识库管理工具。 首先,我需要确认用户提到的“DeepSeek”具体指什么。如果是他们的大模型,可能用户想用该模型来处理本地知识库的数据,比如通过API进行问答或信息提取。如果DeepSeek有开源的工具,可能需要指导用户如何部署本地环境,整合这些工具。 接下来,用户的需求是搭建本地个人知识库,所以需要强调本地部署的步骤,可能包括数据准备、工具安装、模型集成、检索系统搭建等。需要分步骤解释,可能需要结合常见的工具如LangChain、ChromaDB等,同时结合DeepSeek的模型。 用户可能的深层需求是希望有一个高效、私密的个人知识管理系统,能够利用先进的AI模型进行智能检索和处理。需要注意隐私保护,因为数据存储在本地,所以需要确保步骤中包括数据安全的部分。 还需要考虑用户的技术背景,是否需要简化步骤,或者提供不同的方案选择,比如自动化脚本、手动配置等。可能需要提供参考链接或GitHub仓库,帮助用户获取更多资源。 另外,用户之前得到过关于个人知识库的通用介绍,现在需要具体到DeepSeek的实现,因此需要将之前的通用步骤具体化,结合DeepSeek的工具或模型。例如,使用DeepSeek的API进行知识处理,或者使用其开源模型进行本地部署。 最后,可能需要提醒用户注意依赖安装、环境配置、数据格式处理等常见问题,以及如何测试和优化知识库的效果。确保回答清晰、步骤明确,适合不同技术水平的用户参考。</think>以下是使用DeepSeek搭建本地个人知识库的详细方案,结合其大模型能力与本地工具链,实现高效知识管理与智能检索: --- ### **1. 准备工作** #### **工具选择** - **核心框架**:DeepSeek-R1(深度求索开源模型) + LangChain(知识库框架) - **向量数据库**:ChromaDB(轻量级本地向量库)或 Milvus(高性能) - **文本处理**:Unstructured(文档解析)、Sentence-Transformers(文本向量化) - **环境依赖**:Python 3.8+、Docker(可选) #### **数据准备** - 将个人知识文件(PDF/Word/Markdown/网页等)统一存放于 `./data` 目录 - 推荐格式:结构化Markdown(便于AI解析) --- ### **2. 搭建流程** #### **步骤1:部署DeepSeek本地模型** - **方案A:API调用**(需网络,适合快速验证) ```python from deepseek_api import DeepSeek # 假设官方提供SDK model = DeepSeek(api_key="your_key", model="deepseek-r1") ``` - **方案B:本地部署**(需GPU资源) 下载开源模型权重(如DeepSeek-7B),使用LLAMA.cpp量化推理: ```bash git clone https://github.com/ggerganov/llama.cpp ./llama.cpp -m deepseek-7b-q4_0.gguf --prompt "知识库问答" ``` #### **步骤2:构建知识向量库** ```python from langchain.document_loaders import DirectoryLoader from langchain.text_splitter import RecursiveCharacterTextSplitter from langchain.embeddings import HuggingFaceEmbeddings from langchain.vectorstores import Chroma # 加载本地文档 loader = DirectoryLoader('./data', glob="**/*.md") docs = loader.load() # 文本分块(每块500字符,重叠50字符) text_splitter = RecursiveCharacterTextSplitter( chunk_size=500, chunk_overlap=50 ) chunks = text_splitter.split_documents(docs) # 生成向量并存储 embeddings = HuggingFaceEmbeddings(model_name="BAAI/bge-small-zh") vector_db = Chroma.from_documents(chunks, embeddings, persist_directory="./chroma_db") ``` #### **步骤3:集成DeepSeek问答链** ```python from langchain.chains import RetrievalQA from langchain.prompts import PromptTemplate # 自定义提示模板 prompt_template = """基于以下上下文回答用户问题: {context} 问题:{question} 答案(简洁中文,不超过3句话): """ PROMPT = PromptTemplate(template=prompt_template, input_variables=["context", "question"]) # 构建问答系统 qa_chain = RetrievalQA.from_chain_type( llm=model, # 替换为实际DeepSeek实例 chain_type="stuff", retriever=vector_db.as_retriever(), chain_type_kwargs={"prompt": PROMPT} ) # 示例提问 response = qa_chain.run("如何用PyTorch实现线性回归?") print(response) ``` --- ### **3. 优化方向** #### **性能提升** - 使用`FAISS`替代Chroma加速向量检索 - 对高频问题设置缓存层(如Redis) - 量化模型降低推理资源消耗 #### **功能扩展** - 添加自动摘要功能(利用DeepSeek生成章节摘要) - 实现知识图谱可视化(通过NetworkX+PyVis) - 支持语音输入/输出(集成Whisper+GPT-SOVITS) #### **安全增强** - 使用Vault对敏感知识加密 - 设置本地防火墙限制外部访问 - 定期备份向量数据库 --- ### **4. 典型使用场景** 1. **智能检索**: `输入`:自然语言问题(如“2023年AI顶会有哪些趋势?”) `输出`:关联论文笔记+模型生成的整合分析 2. **自动整理**: 上传会议录音 → 自动转写 → DeepSeek提取关键结论 → 生成结构化纪要 3. **灵感辅助**: 输入碎片想法 → 知识库关联已有笔记 → 推荐拓展阅读方向 --- ### **5. 注意事项** - 硬件要求:最低8GB RAM(纯CPU),推荐NVIDIA GPU(16GB显存+) - 中文优化:需使用`bge-zh`等中文专用嵌入模型 - 数据更新:设置文件监视器(如Watchdog)实现增量索引 - 隐私保护:敏感数据建议全程离线处理 --- **完整代码示例**可参考: [DeepSeek-Knowledge-Base GitHub仓库](https://github.com/deepseek-ai/examples)(需官方提供) 通过此方案,可构建具备语义理解能力的个人知识中枢,实现从“信息存储”到“智能洞察”的升级。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值