Redis的Q&A (二)

本文围绕Redis展开,介绍了缓存穿透、击穿、雪崩的概念及解决方法,如存储null值、加互斥锁等。还阐述了Redis的集群方案,包括主从复制、哨兵sentinel、内置集群cluster,以及如何提高集群cluster的高可用性,如加入主从模式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Redis的基础知识可参照Redis基础知识

什么是缓存穿透?怎么去解决?

        缓存穿透 是指缓存和数据库中都没有的数据,⽽⽤户不断发起请求,我们数据库的 id 都是1开始⾃增上去的,如发起为id值为 -1 的数据或 id 为特别⼤不存在的数据,会短时间的大量请求落到数据库上。这时的⽤户很可能是攻击者,攻击会导致数据库压⼒过⼤,严重会击垮数据库。

解决方法:

  • 存储 null值
    如果从数据库查询出来的对象是空的,也可以放入缓存,其格式为,key为用户提交过来的主键值(id) ,value为null,但是将设定的缓存过期时间比较短,比如设置为60秒。这样如果该用户连续的去查找不存在的id时,也会只到Redis中查询,这样可以将数据库保护起来。
  • 添加校验
    也可以在接口层增加校验,比如用户的鉴权校验,对用户输入的参数进行校验,不合法的参数直接将代码return。
  • 布隆过滤器
    使用布隆过滤器 (Bloom Filter)也能很好的防止缓存穿透的情况发生。

        布隆过滤器的原理就是利用高效的数据结构和算法来快速判断出当前这个key是否存在数据库中,若是不存在就直接return。

什么是缓存穿击?怎么去解决?

        缓存击穿,是指一个key非常热点(例如双十一期间进行抢购的商品数据),在不停的扛着大并发,大并发集中对这一个点进行访问,当这个key在失效的瞬间,持续的大并发就穿破缓存,直接请求到数据库上,就像在一个屏障上凿开了一个洞。

解决方法:

  • 热点数据永不过期
    对高访问量的热点数据设置永不过期,这样就使得高并发集中访问的时候key突然失效。
  • 加互斥锁
    这个方法可以使用,但是会导致大量线程阻塞,会使吞吐量降低。

什么是缓存雪崩?怎么去解决?

        缓存雪崩,是指在某一个时间段,缓存集中过期失效。在缓存集中失效的这个时间段对数据的访问查询,都落到了数据库上,对于数据库而言,就会产生周期性的压力波峰。

        和缓存穿击不同的是,缓存穿击指的是并发查同一条数据,而缓存雪崩是不同数据在某一时间段中都过期,很多数据都无法从Redis中查到,从而要去访问数据库。

解决方法:

  • 均匀过期时间
    可以将缓存的数据设置不同的失效时间,这样可以避免缓存数据再某一时间段集中失效。通常可以为有效期增加随机值或者统一规划有限期。
  • 加互斥锁
    同一时间只让一个线程构建缓存,其他线程阻塞排队。
  • 设置缓存永不过期
    对于热点数据 (访问频率高的数据) 设置为永不过期。
  • 双层缓存策略
    采用主缓存和备份缓存的模式,当主缓存突然失效后,可以从数据库加载最新的值,备份缓存在获取锁失败时读取,主缓存更新是需要同步更新备份缓存。

Redis的集群方案有哪些?

        单台Redis服务性能不足的问题。这就需要使用到Redis的集群,构建Redis集群也是有多种方案。

  1. 主从复制模式
  2. 哨兵(Sentinel)模式
  3. 集群cluster

什么是主从复制?

        在主从复制模式下Redis节点分为两种角色:主节点(也称为master)和从节点(也称为slave)。这种模式
集群是由一个主节点和多个从节点构成。

在这里插入图片描述

        原则:Master会将数据同步到slave,而slave不会将数据同步到master。Slave启动时会连接master来
同步数据。

  • 主节点说明
            利用master来处理写操作,slave提供读操作。这样可以有效减少单个机器的并发访问数量。要实现主从复制这种模式非常简单,主节点不用做任何修改,直接启动服务即可。
  • 从节点说明
            从节点需要修改redis.conf配置文件。加入配置:
slaveof <主节点ip地址> <主节点端口号>

        例如master的ip地址为192.168.200.129,端口号为6379,那么slave只需要在redis.conf文件中配置slaveof 192.168.200.129.6379即可。

        主节点的写操作,从节点立刻就能看到相同的数据。但是在从节点进行写操作,提示 READONLY You can't write against a read only slave不能写数据到从节点。

        这样就可以通过这种方式配置多个从节点进行读操作,主节点进行写操作,实现读写分离。

什么是哨兵sentinel?

        Redis实现主从复制,可将主节点数据同步给从节点,实现了读写分离,提高Redis的性能。但是现在还存在一个问题,就是在主从复制这种模式下只有一个主节点,一旦主节点宕机,就无法再进行写操作。

        这不能体现高可用性,为了解决这个问题,出现了哨兵模式。

        sentinel(哨兵)是用于监控redis集群中Master状态的工具,其本身也是一个独立运行的进程,同时sentinel也可以实现集群,是Redis的高可用解决方案,sentinel哨兵模式已经被集成在redis2.4之后的版本中。
在这里插入图片描述

        其工作流程:

        sentinel可以监视一个或者多个redis master服务,以及这些master服务的所有从服务;当某个master服务下线时,自动将该master下的某个从服务升级为master服务替代已下线的master服务继续处理请求,同时通知客户端,并且其余从节点开始从新的主节点复制数据。

什么是sentinel的故障转移?

在了解什么是故障转移之前,先了解两种触发故障转移的情况:

  • 主观下线
            每个sentinel都会定时向主节点和从节点进行心跳检查(通过ping的方式),当检测出主节点出现超时状态的时候,会认为这个主节点已经不可用了,这种判定就是主观下线
  • 客观下线
            在出现主观下线后,该sentinel会通过sentinel ismaster-down-by-addr命令向其他 Sentinel 节点询问对主节点的判断,如果quorum个的sentinel节点都认为该主节点不可用了,就会执行客观下线

        quorum通常为 Sentinel节点总数/2+1,即半数以上节点做出主观下线判断就可以执行客观下线。

        达到了客观下线的情况,就会开始进行 故障转移。这一步操作只要一个sentinel就能完成,这时就会基于Raft算法选取一个sentinel来进行故障转移。

  1. 在从节点中按照一定的选举要求来选出一个节点作为新的主节点
  2. 对选出来的从节点执行slaveof no one命令让其成为主节点。
  3. sentinel就会向剩余的从节点发送命令,让他们从新的主节点上复制数据。
  4. 如果这时原主节点恢复,但是不会变回主节点,sentinel会将其变成从节点, 并对其进行监控, 发送命令去复制新的主节点。

Redis内置集群cluster是什么?

        引入Cluster模式的原因:

        不管是主从模式还是哨兵模式都只能由一个master在写数据,在海量数据高并发场景,一个节点写数据容易出现瓶颈,引入Cluster模式可以实现多个节点同时写数据。

        Redis Cluster是Redis的内置集群,在Redis3.0推出的实现方案。在Redis3.0之前是没有这个内置集群的。Redis Cluster是无中心节点的集群架构,依靠Gossip协议协同自动化修复集群的状态。

        Redis cluster在设计的时候,就考虑到了去中心化,去中间件,也就是说,集群中的每个节点都是平等的关系,都是对等的,每个节点都保存各自的数据和整个集群的状态。
在这里插入图片描述

        每个节点都和其他所有节点连接,而且这些连接保持活跃,这样就保证了我们只需要连接集群中的任意一个节点,就可以获取到其他节点的数据。

        值得注意的是,这种集群模式下的每个节点保存的数据并不是完整的数据,而只是部分的数据。其分配规则就是使用 哈希槽

        Redis 集群是采用一种叫做哈希槽 (hash slot) 的方式来分配数据的。redis cluster 默认分配了16384 个slot,当我们set一个key 时,会用 CRC16 算法来取模得到所属的 slot ,然后将这个key 分到哈希槽区间的节点上,具体算法就是: CRC16(key) % 16384

如何提高集群cluster的高可用性?

        可以在cluster中加入主从模式,一个主节点对应一个或多个从节点,主节点提供数据存取,从节点则是从主节点拉取数据备份,当这个主节点挂掉后,就会在这些从节点中选取一个来充当主节点,从而保证集群不会挂掉。
在这里插入图片描述
个人理解,有误希望大家多多指出😁😁😁

<think>好的,我需要设计一个企业级的问答系统。首先,我得理解用户的需求是什么。用户想要一个公司内部的问答系统,可能用于员工之间的知识共享,或者对外提供客户支持。接下来,我得考虑系统的架构,可能需要分层次设计,比如前端、后端、数据库等。 然后,功能模块方面,用户管理、问题处理、搜索功能都是必须的。用户认证可以使用OAuth或者JWT来实现,确保安全性。问题分类可能需要自然语言处理技术,比如用NLP模型来自动分类问题,或者打标签。搜索模块需要高效的搜索引擎,Elasticsearch是个不错的选择,支持全文检索和模糊匹配。 数据库设计也很关键。考虑到企业级的数据量和查询效率,可能需要关系型数据库如MySQL或PostgreSQL,或者NoSQL如MongoDB,根据具体需求来定。数据表的设计要规范,比如用户表、问题表、回答表等,还要考虑索引优化。 接下来是核心的问答处理流程。用户提问后,系统需要先进行预处理,比如去除停用词、分词等。然后,通过语义分析理解问题的意图,可能需要用到预训练模型如BERT来提取特征。回答生成部分,可以用检索式方法从知识库中匹配答案,或者用生成式模型如GPT来生成回答。但生成式模型可能会有准确性的问题,需要结合检索结果。 性能方面,系统需要高并发处理能力,可能引入负载均衡和缓存机制,比如Redis缓存热门问答,减少数据库压力。安全性也不能忽视,数据加密、防止SQL注入、XSS攻击等都是必要的措施。 扩展性方面,设计微服务架构,各个模块独立部署,方便后续功能扩展。比如将来增加多语言支持,可以单独开发一个翻译服务。维护性方面,良好的日志记录和监控系统能帮助快速定位问题,比如使用ELK栈进行日志分析,Prometheus监控系统健康状态。 技术选型上,前端可以用React或Vue构建响应式界面,后端用Spring Boot或Node.js提供RESTful API。数据库根据需求选择,全文搜索用Elasticsearch。机器学习框架用TensorFlow或PyTorch,部署模型时可以用TensorFlow Serving或Flask封装API。 测试和部署阶段,单元测试、集成测试确保各个模块正常工作。压力测试模拟高并发情况,优化系统性能。部署可以用Docker容器化,Kubernetes管理集群,提高可用性和扩展性。 最后,参考现有的资料,比如引用中提到的C/S架构和数据库设计,可以借鉴其模块划分和连接管理的方法。同时,结合企业实际需求,可能需要定制权限管理,确保不同角色的员工访问权限不同,比如HR部门的问题只有特定人员可以回答。 可能遇到的问题包括如何处理模糊查询,提高搜索准确率,或者实时更新知识库。需要定期更新模型,保持问答的时效性。另外,用户反馈机制也很重要,收集用户对回答的满意度,持续优化系统。</think>### 企业级问答系统设计与实现 #### 1. 系统架构设计 企业级问答系统通常采用分层架构,包含以下模块: - **用户接口层**:支持Web、移动端、API等访问方式,例如使用React/Vue构建前端界面[^1]。 - **业务逻辑层**:处理问答流程、用户权限、数据分析等核心逻辑。 - **数据处理层**:集成自然语言处理(NLP)模型、知识图谱和数据库,例如使用Elasticsearch实现语义搜索[^2]。 - **基础设施层**:部署在云服务器或容器化环境(如Kubernetes),支持高可用和弹性扩展。 #### 2. 核心功能模块 | 模块 | 功能描述 | |---------------|--------------------------------------------------------------------------| | 用户认证 | 支持SSO/OAuth2.0/JWT,实现角色权限管理(如管理员、普通用户) | | 问题处理 | 包含问题分类($P(c|q)=\frac{P(q|c)P(c)}{P(q)}$)、实体识别、相似问题匹配 | | 答案生成 | 结合检索式(基于知识库)和生成式(如GPT-3.5)方法 | | 知识管理 | 支持多格式数据导入(PDF/Excel/数据库),定期更新知识图谱 | | 数据分析 | 统计高频问题、回答准确率、用户满意度等指标 | #### 3. 关键技术实现 **示例:基于BERT的语义匹配** ```python from transformers import BertTokenizer, BertModel import torch tokenizer = BertTokenizer.from_pretrained('bert-base-uncased') model = BertModel.from_pretrained('bert-base-uncased') def get_embedding(text): inputs = tokenizer(text, return_tensors="pt", padding=True, truncation=True) outputs = model(**inputs) return outputs.last_hidden_state.mean(dim=1) # 获取句向量表示 ``` **数据库设计示例** ```sql CREATE TABLE questions ( id INT PRIMARY KEY AUTO_INCREMENT, content TEXT NOT NULL, category VARCHAR(50) INDEX, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); CREATE TABLE answers ( id INT PRIMARY KEY AUTO_INCREMENT, question_id INT FOREIGN KEY, content TEXT NOT NULL, confidence FLOAT CHECK (confidence BETWEEN 0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是哈猿啊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值