<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Redis on Snow</title>
        <link>https://SymphonyW.github.io/zh-cn/tags/redis/</link>
        <description>Recent content in Redis on Snow</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh-cn</language>
        <copyright>Snow</copyright>
        <lastBuildDate>Tue, 07 Jul 2026 21:04:00 +0800</lastBuildDate><atom:link href="https://SymphonyW.github.io/zh-cn/tags/redis/index.xml" rel="self" type="application/rss+xml" /><item>
        <title>数据库全景指南：从 SQLite 到 MongoDB，一文搞懂选型与差异</title>
        <link>https://SymphonyW.github.io/zh-cn/p/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%85%A8%E6%99%AF%E6%8C%87%E5%8D%97%E4%BB%8E-sqlite-%E5%88%B0-mongodb%E4%B8%80%E6%96%87%E6%90%9E%E6%87%82%E9%80%89%E5%9E%8B%E4%B8%8E%E5%B7%AE%E5%BC%82/</link>
        <pubDate>Tue, 07 Jul 2026 21:04:00 +0800</pubDate>
        
        <guid>https://SymphonyW.github.io/zh-cn/p/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%85%A8%E6%99%AF%E6%8C%87%E5%8D%97%E4%BB%8E-sqlite-%E5%88%B0-mongodb%E4%B8%80%E6%96%87%E6%90%9E%E6%87%82%E9%80%89%E5%9E%8B%E4%B8%8E%E5%B7%AE%E5%BC%82/</guid>
        <description>&lt;img src="https://SymphonyW.github.io/zh-cn/p/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%85%A8%E6%99%AF%E6%8C%87%E5%8D%97%E4%BB%8E-sqlite-%E5%88%B0-mongodb%E4%B8%80%E6%96%87%E6%90%9E%E6%87%82%E9%80%89%E5%9E%8B%E4%B8%8E%E5%B7%AE%E5%BC%82/bg.png" alt="Featured image of post 数据库全景指南：从 SQLite 到 MongoDB，一文搞懂选型与差异" /&gt;&lt;h1 id=&#34;数据库全景指南从-sqlite-到-mongodb一文搞懂选型与差异&#34;&gt;数据库全景指南：从 SQLite 到 MongoDB，一文搞懂选型与差异
&lt;/h1&gt;&lt;blockquote&gt;
&lt;p&gt;MySQL、PostgreSQL、MongoDB、Redis、Cassandra、Neo4j、Elasticsearch…… 数据库多到让人眼花。本文从分类、原理、模型、选型、组合五个维度，带你看清它们各自的边界与适用场景。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;一为什么会有这么多数据库&#34;&gt;一、为什么会有这么多数据库？
&lt;/h2&gt;&lt;p&gt;先抛一个真实的尴尬场景：&lt;/p&gt;
&lt;p&gt;新人入职第一天，被安排设计一个博客系统。他下意识打开 Navicat，建了一张 &lt;code&gt;articles&lt;/code&gt; 表，写到第三天发现：文章正文要存富文本，字数可能上万；评论数据要嵌套在文章里；标签数量不固定；还要做全文搜索。继续用 MySQL 越写越别扭，最后只能上 ES 做搜索、MongoDB 存正文、MySQL 存元数据。&lt;/p&gt;
&lt;p&gt;这不是个例。&lt;strong&gt;没有一种数据库能赢下所有场景&lt;/strong&gt;，根本原因是存储需求里同时存在四组矛盾：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;结构化 vs 灵活&lt;/strong&gt;：业务模型固定还是多变&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;一致性 vs 可用性&lt;/strong&gt;：要数据绝对正确，还是允许短暂数据不一致换可用性&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;规模 vs 性能&lt;/strong&gt;：单机极致性能还是分布式海量吞吐&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;读写均衡 vs 海量写入&lt;/strong&gt;：典型 Web 应用还是 IoT 流式写入&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;围绕这些矛盾，业界演化出了关系型、键值、文档、列族、图、搜索、时序、列存分析等 &lt;strong&gt;八大分支&lt;/strong&gt;。每解决一组矛盾，就诞生一类新数据库。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;二数据库分类全景图&#34;&gt;二、数据库分类全景图
&lt;/h2&gt;&lt;p&gt;&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%85%A8%E6%99%AF%E6%8C%87%E5%8D%97%E4%BB%8E-sqlite-%E5%88%B0-mongodb%E4%B8%80%E6%96%87%E6%90%9E%E6%87%82%E9%80%89%E5%9E%8B%E4%B8%8E%E5%B7%AE%E5%BC%82/db-categories.svg&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%85%A8%E6%99%AF%E6%8C%87%E5%8D%97%E4%BB%8E-sqlite-%E5%88%B0-mongodb%E4%B8%80%E6%96%87%E6%90%9E%E6%87%82%E9%80%89%E5%9E%8B%E4%B8%8E%E5%B7%AE%E5%BC%82/db-categories.svg&#34; alt=&#34;数据库分类全景图&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;上图把主流数据库按&amp;quot;数据模型 + 适用场景&amp;quot;分成了 8 类。下面我们逐类展开，但在分类之前，必须先理解三个底层概念：&lt;strong&gt;ACID、CAP、BASE&lt;/strong&gt;。它们决定了数据库的&amp;quot;性格&amp;quot;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;三acid-vs-base两种一致性哲学&#34;&gt;三、ACID vs BASE：两种一致性哲学
&lt;/h2&gt;&lt;p&gt;&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%85%A8%E6%99%AF%E6%8C%87%E5%8D%97%E4%BB%8E-sqlite-%E5%88%B0-mongodb%E4%B8%80%E6%96%87%E6%90%9E%E6%87%82%E9%80%89%E5%9E%8B%E4%B8%8E%E5%B7%AE%E5%BC%82/acid-base.svg&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%85%A8%E6%99%AF%E6%8C%87%E5%8D%97%E4%BB%8E-sqlite-%E5%88%B0-mongodb%E4%B8%80%E6%96%87%E6%90%9E%E6%87%82%E9%80%89%E5%9E%8B%E4%B8%8E%E5%B7%AE%E5%BC%82/acid-base.svg&#34; alt=&#34;ACID vs BASE：两种一致性哲学&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;h3 id=&#34;acid关系型数据库的承诺&#34;&gt;ACID：关系型数据库的承诺
&lt;/h3&gt;&lt;p&gt;ACID 是事务的四大保证，是关系型数据库压箱底的能力：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;字母&lt;/th&gt;
&lt;th&gt;含义&lt;/th&gt;
&lt;th&gt;通俗解释&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;A&lt;/strong&gt; Atomicity 原子性&lt;/td&gt;
&lt;td&gt;事务要么全成功，要么全回滚&lt;/td&gt;
&lt;td&gt;转账扣款和加款必须同时发生&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;C&lt;/strong&gt; Consistency 一致性&lt;/td&gt;
&lt;td&gt;事务前后满足所有约束&lt;/td&gt;
&lt;td&gt;主键、外键、CHECK 不能被破坏&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;I&lt;/strong&gt; Isolation 隔离性&lt;/td&gt;
&lt;td&gt;并发事务互不干扰&lt;/td&gt;
&lt;td&gt;MVCC + 锁机制保证&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;D&lt;/strong&gt; Durability 持久性&lt;/td&gt;
&lt;td&gt;提交后即使宕机也不丢&lt;/td&gt;
&lt;td&gt;通过 WAL / redo log 实现&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;为 ACID 付出的代价&lt;/strong&gt;：锁竞争、跨节点协调延迟、水平扩展难。这也是为什么单机 MySQL 通常撑到几千 QPS 就开始考虑读写分离。&lt;/p&gt;
&lt;h3 id=&#34;base分布式系统的妥协&#34;&gt;BASE：分布式系统的妥协
&lt;/h3&gt;&lt;p&gt;当系统走向分布式，强一致性的代价过高，业界提出 BASE 作为 AP 系统的设计哲学：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;BA&lt;/strong&gt; Basically Available 基本可用：允许响应变慢、允许功能降级&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;S&lt;/strong&gt; Soft State 软状态：允许存在中间状态&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;E&lt;/strong&gt; Eventually Consistent 最终一致：不保证任意时刻一致，但保证最终收敛&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;关键认知：&lt;strong&gt;ACID 中的 C 是事务一致性（约束不被破坏），CAP 中的 C 是副本一致性（多节点数据相同）&lt;/strong&gt;，两者不是一回事。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr&gt;
&lt;h2 id=&#34;四cap-定理分布式系统的三角抉择&#34;&gt;四、CAP 定理：分布式系统的三角抉择
&lt;/h2&gt;&lt;p&gt;&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%85%A8%E6%99%AF%E6%8C%87%E5%8D%97%E4%BB%8E-sqlite-%E5%88%B0-mongodb%E4%B8%80%E6%96%87%E6%90%9E%E6%87%82%E9%80%89%E5%9E%8B%E4%B8%8E%E5%B7%AE%E5%BC%82/cap-theorem.svg&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%85%A8%E6%99%AF%E6%8C%87%E5%8D%97%E4%BB%8E-sqlite-%E5%88%B0-mongodb%E4%B8%80%E6%96%87%E6%90%9E%E6%87%82%E9%80%89%E5%9E%8B%E4%B8%8E%E5%B7%AE%E5%BC%82/cap-theorem.svg&#34; alt=&#34;CAP 定理：分布式系统的三角抉择&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;CAP 定理由 Eric Brewer 在 2000 年提出，断言：&lt;strong&gt;一个分布式系统最多只能同时满足 Consistency（一致性）、Availability（可用性）、Partition tolerance（分区容错）三者中的两个&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;三个关键认知&#34;&gt;三个关键认知
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;① P 不可避免&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;真实分布式系统必然存在网络分区（交换机抖动、机房断连、节点宕机）。所以工程师实际上只能在 &lt;strong&gt;C 和 A 之间做选择&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;分区时拒绝写入 → CP，保证数据正确，但牺牲可用性&lt;/li&gt;
&lt;li&gt;分区时仍可读写 → AP，保证可用性，但允许数据短暂不一致&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;② 三种组合的典型代表&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;组合&lt;/th&gt;
&lt;th&gt;牺牲项&lt;/th&gt;
&lt;th&gt;典型数据库&lt;/th&gt;
&lt;th&gt;典型场景&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CA&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;分区容错&lt;/td&gt;
&lt;td&gt;MySQL 单机、PostgreSQL 单机&lt;/td&gt;
&lt;td&gt;传统单机业务&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;CP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;可用性&lt;/td&gt;
&lt;td&gt;HBase、MongoDB、Redis 集群&lt;/td&gt;
&lt;td&gt;强一致优先的金融、配置&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AP&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;一致性&lt;/td&gt;
&lt;td&gt;Cassandra、DynamoDB、Eureka&lt;/td&gt;
&lt;td&gt;高可用的社交、推荐&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;③ 同一业务可灵活切换&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;注册中心是个经典例子：&lt;strong&gt;ZooKeeper 是 CP&lt;/strong&gt;，选举期间不可用；&lt;strong&gt;Eureka 是 AP&lt;/strong&gt;，节点之间不强制同步。Netflix 选 Eureka，因为它能容忍注册信息短暂不一致，但不能容忍服务发现挂掉。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;五关系型数据库稳如泰山的基石&#34;&gt;五、关系型数据库：稳如泰山的基石
&lt;/h2&gt;&lt;p&gt;关系型数据库以 &lt;strong&gt;二维表 + SQL + ACID 事务&lt;/strong&gt; 为核心，是 90% 业务系统的默认选择。&lt;/p&gt;
&lt;h3 id=&#34;51-五大主流-rdbms-对比&#34;&gt;5.1 五大主流 RDBMS 对比
&lt;/h3&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;数据库&lt;/th&gt;
&lt;th&gt;厂商 / 协议&lt;/th&gt;
&lt;th&gt;强项&lt;/th&gt;
&lt;th&gt;适用场景&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MySQL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;开源（GPL/商业双协议）&lt;/td&gt;
&lt;td&gt;生态成熟、运维资料最多&lt;/td&gt;
&lt;td&gt;Web 应用、电商、CMS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PostgreSQL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;开源（BSD）&lt;/td&gt;
&lt;td&gt;复杂查询、JSON、PostGIS、扩展性强&lt;/td&gt;
&lt;td&gt;复杂业务、地理数据、数据分析&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SQLite&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;开源（公有领域）&lt;/td&gt;
&lt;td&gt;嵌入式、零配置、单文件&lt;/td&gt;
&lt;td&gt;移动端、嵌入式、原型、测试&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Oracle&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;商业&lt;/td&gt;
&lt;td&gt;企业级功能、稳定性、技术支持&lt;/td&gt;
&lt;td&gt;银行、电信、政府核心系统&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SQL Server&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;商业（微软）&lt;/td&gt;
&lt;td&gt;与 .NET 生态深度集成&lt;/td&gt;
&lt;td&gt;企业内部系统、Windows 环境&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;52-选型经验&#34;&gt;5.2 选型经验
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;个人项目 / 小工具&lt;/strong&gt;：SQLite，单文件零配置&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Web 应用首选&lt;/strong&gt;：MySQL（运维生态好）或 PostgreSQL（功能强、复杂查询爽）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;企业核心系统有预算&lt;/strong&gt;：Oracle 或 SQL Server，看团队技术栈&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;要不要选 PostgreSQL 而不是 MySQL？&lt;/strong&gt; 如果业务里有复杂分析、地理数据、强约束、JSON 字段，PG 更合适；如果只是 CRUD + 简单关联，MySQL 更省心&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;53-关系型的硬伤&#34;&gt;5.3 关系型的硬伤
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;水平扩展难&lt;/strong&gt;：分库分表后跨库 JOIN、事务都成噩梦，需要引入 ShardingSphere、Vitess 之类的中间件&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Schema 变更贵&lt;/strong&gt;：上亿行表加索引可能锁表几小时&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;高并发写入瓶颈&lt;/strong&gt;：单机通常几千 QPS，靠缓存兜底&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;六nosql-的崛起四大家族&#34;&gt;六、NoSQL 的崛起：四大家族
&lt;/h2&gt;&lt;p&gt;NoSQL（Not Only SQL）的核心动机：&lt;strong&gt;通过放松某个约束（一致性 / Schema / 关系），换取扩展性、性能或灵活性&lt;/strong&gt;。&lt;/p&gt;
&lt;h3 id=&#34;61-sql-vs-nosql-数据模型对比&#34;&gt;6.1 SQL vs NoSQL 数据模型对比
&lt;/h3&gt;&lt;p&gt;&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%85%A8%E6%99%AF%E6%8C%87%E5%8D%97%E4%BB%8E-sqlite-%E5%88%B0-mongodb%E4%B8%80%E6%96%87%E6%90%9E%E6%87%82%E9%80%89%E5%9E%8B%E4%B8%8E%E5%B7%AE%E5%BC%82/sql-vs-nosql.svg&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%85%A8%E6%99%AF%E6%8C%87%E5%8D%97%E4%BB%8E-sqlite-%E5%88%B0-mongodb%E4%B8%80%E6%96%87%E6%90%9E%E6%87%82%E9%80%89%E5%9E%8B%E4%B8%8E%E5%B7%AE%E5%BC%82/sql-vs-nosql.svg&#34; alt=&#34;SQL vs NoSQL：数据模型架构对比&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;左图是关系型的方式：&lt;strong&gt;范式化拆表 + 外键关联&lt;/strong&gt;，查 Alice 的订单要 JOIN 两张表。
右图是文档型的方式：&lt;strong&gt;聚合存储 + 内嵌文档&lt;/strong&gt;，Alice 的订单直接嵌在她的文档里，一次读取拿全。&lt;/p&gt;
&lt;p&gt;两种模型各有利弊：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;维度&lt;/th&gt;
&lt;th&gt;关系型（SQL）&lt;/th&gt;
&lt;th&gt;文档型（NoSQL）&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Schema&lt;/td&gt;
&lt;td&gt;严格固定&lt;/td&gt;
&lt;td&gt;灵活可变&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;关联查询&lt;/td&gt;
&lt;td&gt;JOIN 强&lt;/td&gt;
&lt;td&gt;弱（要靠应用层）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;数据冗余&lt;/td&gt;
&lt;td&gt;低（范式化）&lt;/td&gt;
&lt;td&gt;高（反范式）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;事务&lt;/td&gt;
&lt;td&gt;强 ACID&lt;/td&gt;
&lt;td&gt;弱（多文档 4.0+ 才支持）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;扩展性&lt;/td&gt;
&lt;td&gt;垂直为主&lt;/td&gt;
&lt;td&gt;易水平分片&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;适合&lt;/td&gt;
&lt;td&gt;关系复杂、强一致&lt;/td&gt;
&lt;td&gt;模型多变、读多写少&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;62-键值型redis&#34;&gt;6.2 键值型：Redis
&lt;/h3&gt;&lt;p&gt;Redis 是最被低估的&amp;quot;瑞士军刀&amp;quot;。它表面上是个缓存，实际上能做：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;缓存&lt;/strong&gt;：最常见，热点数据加速&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;会话存储&lt;/strong&gt;：分布式 Session&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;排行榜&lt;/strong&gt;：ZSet 天生支持&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;消息队列&lt;/strong&gt;：List / Stream&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;限流器&lt;/strong&gt;：INCR + EXPIRE&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;分布式锁&lt;/strong&gt;：SETNX / Redlock&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;选型提醒&lt;/strong&gt;：Redis 是 &lt;strong&gt;CP 系统&lt;/strong&gt;（集群模式下）—— 主节点挂掉会触发故障转移，期间集群不可用。不是所有 Redis 都&amp;quot;高可用&amp;quot;。&lt;/p&gt;
&lt;h3 id=&#34;63-文档型mongodb&#34;&gt;6.3 文档型：MongoDB
&lt;/h3&gt;&lt;p&gt;MongoDB 用 BSON（二进制 JSON）存储，每个文档自包含。它的甜点场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;内容管理&lt;/strong&gt;：文章、评论、附件，结构天然嵌套&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;IoT 设备元数据&lt;/strong&gt;：不同设备字段不同，灵活 Schema 太香&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;快速迭代业务&lt;/strong&gt;：需求变就加字段，不用 ALTER TABLE&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;日志聚合&lt;/strong&gt;：MongoDB 的聚合管道 + 副本集很合用&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;坑点&lt;/strong&gt;：MongoDB 4.0 才支持多文档事务，复杂事务场景慎用。索引设计不当会让查询慢到怀疑人生。&lt;/p&gt;
&lt;h3 id=&#34;64-列族型cassandra--hbase&#34;&gt;6.4 列族型：Cassandra / HBase
&lt;/h3&gt;&lt;p&gt;列族型数据库把&amp;quot;行&amp;quot;打散成&amp;quot;列族&amp;quot;，&lt;strong&gt;同一列的数据连续存储&lt;/strong&gt;，对&amp;quot;按列聚合 + 海量写入&amp;quot;特别友好。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cassandra&lt;/strong&gt;：AWS Dynamo 论文的开源实现，无主架构，写入性能极强。Netflix、Instagram、Apple 都在用&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;HBase&lt;/strong&gt;：基于 HDFS，强一致，适合离线大数据&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ScyllaDB&lt;/strong&gt;：用 C++ 重写的 Cassandra，性能高一个数量级&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;典型场景&lt;/strong&gt;：时序数据、推荐特征存储、消息历史归档。Cassandra 在写入 QPS 上能轻松甩开 MySQL 一个数量级。&lt;/p&gt;
&lt;h3 id=&#34;65-图型neo4j&#34;&gt;6.5 图型：Neo4j
&lt;/h3&gt;&lt;p&gt;如果业务核心是 &lt;strong&gt;关系&lt;/strong&gt;（不是表关联，而是多跳关系遍历），用图数据库比 SQL 递归查询快几个数量级。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;// Neo4j 查询：找到 Alice 三度人脉里喜欢 Go 语言的人
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;MATCH (a:User {name:&amp;#39;Alice&amp;#39;})-[:KNOWS*1..3]-(friend:User)
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;WHERE friend.language = &amp;#39;Go&amp;#39;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;RETURN friend
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;典型场景&lt;/strong&gt;：社交网络（好友推荐）、反欺诈（团伙识别）、知识图谱、IT 资产拓扑。&lt;/p&gt;
&lt;p&gt;用 MySQL 写&amp;quot;找三度人脉&amp;quot;要用 4 层自连接，性能爆炸；Neo4j 用邻接表存储，时间复杂度近似 O(1)。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;七专用场景数据库搜索--时序--列存&#34;&gt;七、专用场景数据库：搜索 / 时序 / 列存
&lt;/h2&gt;&lt;p&gt;通用数据库做不到极致，专用数据库在特定领域把性能压榨到极限。&lt;/p&gt;
&lt;h3 id=&#34;71-搜索引擎elasticsearch&#34;&gt;7.1 搜索引擎：Elasticsearch
&lt;/h3&gt;&lt;p&gt;ES 用 &lt;strong&gt;倒排索引&lt;/strong&gt; 实现秒级全文检索，是 ELK（Elasticsearch + Logstash + Kibana）的核心。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;商品搜索&lt;/strong&gt;：分词、同义词、纠错、相关性排序&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;日志分析&lt;/strong&gt;：海量日志聚合，按时间维度切片&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可观测性&lt;/strong&gt;：APM、链路追踪数据存储&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;重要认知&lt;/strong&gt;：ES 不是数据库替代品。它写入延迟较高（近实时，1 秒刷新），不适合做强一致主存储。通常 &lt;strong&gt;MySQL 是真相源，ES 是搜索副本&lt;/strong&gt;，通过 Canal/Debezium 同步。&lt;/p&gt;
&lt;h3 id=&#34;72-时序数据库influxdb--timescaledb&#34;&gt;7.2 时序数据库：InfluxDB / TimescaleDB
&lt;/h3&gt;&lt;p&gt;时序数据有显著特征：&lt;strong&gt;写多读少、按时间顺序、自动降采样、旧数据可丢弃&lt;/strong&gt;。专用 TSDB 的写入性能比 MySQL 高 1-2 个数量级。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;InfluxDB&lt;/strong&gt;：Go 写的，单机性能强，TSM 存储引擎&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TimescaleDB&lt;/strong&gt;：PostgreSQL 扩展，能用 SQL，事务保证更好&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Prometheus&lt;/strong&gt;：监控专用，pull 模型&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TDengine&lt;/strong&gt;：国产，物联网场景优化&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;典型场景&lt;/strong&gt;：服务器监控、IoT 传感器、金融行情、用户行为埋点。&lt;/p&gt;
&lt;h3 id=&#34;73-列存分析clickhouse&#34;&gt;7.3 列存分析：ClickHouse
&lt;/h3&gt;&lt;p&gt;OLAP 场景的核心诉求：&lt;strong&gt;扫描 TB 级数据，做 GROUP BY 聚合，秒级返回&lt;/strong&gt;。行存数据库（MySQL）做这种扫描会读大量无关列，列存数据库只读需要的列，性能差几十倍。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;
&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9
&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class=&#34;lntd&#34;&gt;
&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-sql&#34; data-lang=&#34;sql&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;-- ClickHouse 典型查询：秒级扫描 10 亿行
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;SELECT&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;toDate&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;event_time&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;AS&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;day&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;city&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;AS&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pv&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;uniq&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;user_id&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;AS&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;uv&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;FROM&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;events&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;WHERE&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;event_time&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;&amp;gt;=&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;today&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;-&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;30&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;GROUP&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;BY&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;day&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;city&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;ORDER&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;BY&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;day&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;DESC&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;n&#34;&gt;pv&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;k&#34;&gt;DESC&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;对比&lt;/strong&gt;：同样的查询，MySQL 要几十分钟，ClickHouse 通常 1 秒内。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;八数据库选型决策树&#34;&gt;八、数据库选型决策树
&lt;/h2&gt;&lt;p&gt;讲了这么多，实战怎么选？下图给出一份决策路径：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%85%A8%E6%99%AF%E6%8C%87%E5%8D%97%E4%BB%8E-sqlite-%E5%88%B0-mongodb%E4%B8%80%E6%96%87%E6%90%9E%E6%87%82%E9%80%89%E5%9E%8B%E4%B8%8E%E5%B7%AE%E5%BC%82/db-selection.svg&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%85%A8%E6%99%AF%E6%8C%87%E5%8D%97%E4%BB%8E-sqlite-%E5%88%B0-mongodb%E4%B8%80%E6%96%87%E6%90%9E%E6%87%82%E9%80%89%E5%9E%8B%E4%B8%8E%E5%B7%AE%E5%BC%82/db-selection.svg&#34; alt=&#34;数据库选型决策树&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;h3 id=&#34;三条选型铁律&#34;&gt;三条选型铁律
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;① 先 SQL，后 NoSQL&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;绝大多数项目从 MySQL / PostgreSQL 起步就够了。遇到具体瓶颈（缓存、搜索、海量写入、复杂关系）再引入对应专用数据库。一开始就上&amp;quot;全家桶&amp;quot;是过度设计。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;② 没有银弹，组合使用&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;工业界真实系统几乎都是多库组合：核心业务用 MySQL/PG，缓存用 Redis，搜索用 ES，日志用 MongoDB/ES，监控用 InfluxDB，分析用 ClickHouse。&lt;strong&gt;让每个数据库只做它最擅长的事&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;③ 团队熟悉度优先&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;再先进的数据库，没人会运维也是灾难。Cassandra 写入性能强，但运维门槛极高，国内很多团队踩坑后还是换回了 MySQL 分库分表。&lt;strong&gt;选团队能掌控的，而不是最潮的&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;九真实项目中的数据库组合架构&#34;&gt;九、真实项目中的数据库组合架构
&lt;/h2&gt;&lt;p&gt;光说不练假把式。下图是一个典型电商系统的多库协同架构：&lt;/p&gt;
&lt;p&gt;&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%85%A8%E6%99%AF%E6%8C%87%E5%8D%97%E4%BB%8E-sqlite-%E5%88%B0-mongodb%E4%B8%80%E6%96%87%E6%90%9E%E6%87%82%E9%80%89%E5%9E%8B%E4%B8%8E%E5%B7%AE%E5%BC%82/stack-combination.svg&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/%E6%95%B0%E6%8D%AE%E5%BA%93%E5%85%A8%E6%99%AF%E6%8C%87%E5%8D%97%E4%BB%8E-sqlite-%E5%88%B0-mongodb%E4%B8%80%E6%96%87%E6%90%9E%E6%87%82%E9%80%89%E5%9E%8B%E4%B8%8E%E5%B7%AE%E5%BC%82/stack-combination.svg&#34; alt=&#34;真实项目中的数据库组合架构&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;h3 id=&#34;数据流拆解&#34;&gt;数据流拆解
&lt;/h3&gt;&lt;p&gt;&lt;strong&gt;① 写路径&lt;/strong&gt;：订单服务先写 MySQL（强一致保证），同时发 Kafka 事件，下游消费者异步更新 ES 搜索索引和推荐系统特征库。这是经典的 &lt;strong&gt;&amp;ldquo;先写主库，再异步同步&amp;rdquo;&lt;/strong&gt; 模式。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;② 读路径&lt;/strong&gt;：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;请求类型&lt;/th&gt;
&lt;th&gt;走的数据库&lt;/th&gt;
&lt;th&gt;理由&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;商品详情&lt;/td&gt;
&lt;td&gt;Redis 缓存 → MongoDB&lt;/td&gt;
&lt;td&gt;缓存挡 95% 流量，回源用文档库装多变 SKU&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;商品搜索&lt;/td&gt;
&lt;td&gt;Elasticsearch&lt;/td&gt;
&lt;td&gt;倒排索引秒级响应&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;好友推荐&lt;/td&gt;
&lt;td&gt;Neo4j&lt;/td&gt;
&lt;td&gt;多跳关系遍历&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;个人订单&lt;/td&gt;
&lt;td&gt;MySQL&lt;/td&gt;
&lt;td&gt;强一致，按用户分库&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;监控大盘&lt;/td&gt;
&lt;td&gt;InfluxDB&lt;/td&gt;
&lt;td&gt;时序聚合，秒级出图&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;③ 监控旁路&lt;/strong&gt;：所有服务通过 SDK 把指标推送到 InfluxDB，&lt;strong&gt;不参与业务主链路&lt;/strong&gt;，监控挂掉不影响交易。这是旁路系统的设计铁律。&lt;/p&gt;
&lt;h3 id=&#34;为什么要拆&#34;&gt;为什么要拆？
&lt;/h3&gt;&lt;p&gt;如果不拆，全塞进 MySQL 会发生什么？&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;商品搜索做 LIKE &amp;lsquo;%关键词%&amp;rsquo; → 全表扫描，慢到超时&lt;/li&gt;
&lt;li&gt;监控指标每秒几十万条写入 → MySQL 单机扛不住&lt;/li&gt;
&lt;li&gt;好友推荐用 4 层自连接 → 几秒出不来结果&lt;/li&gt;
&lt;li&gt;商品 SKU 字段每类目都不同 → ALTER TABLE 改到吐血&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;每个专用数据库的存在，都是为了 &lt;strong&gt;解决某一类 MySQL 不擅长的问题&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;十核心差异对照表&#34;&gt;十、核心差异对照表
&lt;/h2&gt;&lt;p&gt;最后用一张表把主流数据库的关键指标摊开对比：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;数据库&lt;/th&gt;
&lt;th&gt;类型&lt;/th&gt;
&lt;th&gt;一致性&lt;/th&gt;
&lt;th&gt;Schema&lt;/th&gt;
&lt;th&gt;事务&lt;/th&gt;
&lt;th&gt;水平扩展&lt;/th&gt;
&lt;th&gt;典型 QPS&lt;/th&gt;
&lt;th&gt;适合场景&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MySQL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;关系&lt;/td&gt;
&lt;td&gt;ACID&lt;/td&gt;
&lt;td&gt;严格&lt;/td&gt;
&lt;td&gt;强&lt;/td&gt;
&lt;td&gt;难（需中间件）&lt;/td&gt;
&lt;td&gt;几千&lt;/td&gt;
&lt;td&gt;Web 主流&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PostgreSQL&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;关系&lt;/td&gt;
&lt;td&gt;ACID&lt;/td&gt;
&lt;td&gt;严格&lt;/td&gt;
&lt;td&gt;强&lt;/td&gt;
&lt;td&gt;难&lt;/td&gt;
&lt;td&gt;几千&lt;/td&gt;
&lt;td&gt;复杂业务&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SQLite&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;关系&lt;/td&gt;
&lt;td&gt;ACID&lt;/td&gt;
&lt;td&gt;严格&lt;/td&gt;
&lt;td&gt;强&lt;/td&gt;
&lt;td&gt;不可&lt;/td&gt;
&lt;td&gt;单线程&lt;/td&gt;
&lt;td&gt;嵌入式&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Redis&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;KV&lt;/td&gt;
&lt;td&gt;CP&lt;/td&gt;
&lt;td&gt;无&lt;/td&gt;
&lt;td&gt;弱&lt;/td&gt;
&lt;td&gt;集群分片&lt;/td&gt;
&lt;td&gt;10万+&lt;/td&gt;
&lt;td&gt;缓存&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MongoDB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;文档&lt;/td&gt;
&lt;td&gt;CP（可调）&lt;/td&gt;
&lt;td&gt;灵活&lt;/td&gt;
&lt;td&gt;4.0+ 多文档&lt;/td&gt;
&lt;td&gt;易分片&lt;/td&gt;
&lt;td&gt;几万&lt;/td&gt;
&lt;td&gt;内容管理&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Cassandra&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;列族&lt;/td&gt;
&lt;td&gt;AP（可调）&lt;/td&gt;
&lt;td&gt;灵活&lt;/td&gt;
&lt;td&gt;弱&lt;/td&gt;
&lt;td&gt;极易&lt;/td&gt;
&lt;td&gt;10万+ 写入&lt;/td&gt;
&lt;td&gt;海量写入&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Neo4j&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;图&lt;/td&gt;
&lt;td&gt;ACID&lt;/td&gt;
&lt;td&gt;半结构&lt;/td&gt;
&lt;td&gt;强&lt;/td&gt;
&lt;td&gt;难&lt;/td&gt;
&lt;td&gt;几千&lt;/td&gt;
&lt;td&gt;关系网络&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Elasticsearch&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;搜索&lt;/td&gt;
&lt;td&gt;近实时&lt;/td&gt;
&lt;td&gt;动态映射&lt;/td&gt;
&lt;td&gt;弱&lt;/td&gt;
&lt;td&gt;易分片&lt;/td&gt;
&lt;td&gt;几万&lt;/td&gt;
&lt;td&gt;全文搜索&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;InfluxDB&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;时序&lt;/td&gt;
&lt;td&gt;CP&lt;/td&gt;
&lt;td&gt;标签+字段&lt;/td&gt;
&lt;td&gt;弱&lt;/td&gt;
&lt;td&gt;集群版收费&lt;/td&gt;
&lt;td&gt;10万+ 写入&lt;/td&gt;
&lt;td&gt;监控指标&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;ClickHouse&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;列存&lt;/td&gt;
&lt;td&gt;CP&lt;/td&gt;
&lt;td&gt;严格&lt;/td&gt;
&lt;td&gt;弱&lt;/td&gt;
&lt;td&gt;易分片&lt;/td&gt;
&lt;td&gt;100万+ 写入&lt;/td&gt;
&lt;td&gt;大数据分析&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&#34;总结&#34;&gt;总结
&lt;/h2&gt;&lt;p&gt;回到最初的问题：&lt;strong&gt;SQLite、MySQL、MongoDB 有什么区别？&lt;/strong&gt; 它们不是&amp;quot;谁更好&amp;quot;的关系，而是&amp;quot;为不同问题而生&amp;quot;的不同工具。&lt;/p&gt;
&lt;p&gt;回顾本文核心要点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;没有银弹&lt;/strong&gt;：每种数据库都是某组矛盾的产物，关系型解决一致性、NoSQL 解决扩展性、专用库解决极端场景&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;理论先行&lt;/strong&gt;：理解 ACID / BASE / CAP，是看懂所有数据库设计意图的钥匙&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SQL 不死&lt;/strong&gt;：关系型依然是 90% 业务系统的默认选择，NoSQL 是补充而非替代&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;组合才是常态&lt;/strong&gt;：工业界真实系统几乎都是多库协同，让每个数据库只做它最擅长的事&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;选型三铁律&lt;/strong&gt;：先 SQL 后 NoSQL、没有银弹要组合、团队熟悉度优先&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;下一步行动建议：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;审视你当前的项目&lt;/strong&gt;：是不是把所有数据都塞在 MySQL 里了？哪些场景其实更适合专用数据库？&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;挑一个不熟的数据库试一试&lt;/strong&gt;：Redis / MongoDB / ES 任选一个，跑一遍官方 Quick Start&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;关注 NewSQL&lt;/strong&gt;：TiDB、CockroachDB、YugabyteDB 这些&amp;quot;既有 ACID 又能水平扩展&amp;quot;的下一代数据库正在崛起&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;记住：&lt;strong&gt;好的架构师不在于会多少种数据库，而在于知道每种数据库的边界在哪&lt;/strong&gt;。&lt;/p&gt;
&lt;hr&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;本文涉及的所有数据库选型都基于公开文档与工程实践，具体落地还需结合团队技术栈、运维能力、预算综合判断。&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
</description>
        </item>
        <item>
        <title>Redis面试八股文（持续更新）</title>
        <link>https://SymphonyW.github.io/zh-cn/p/redis%E9%9D%A2%E8%AF%95%E5%85%AB%E8%82%A1%E6%96%87%E6%8C%81%E7%BB%AD%E6%9B%B4%E6%96%B0/</link>
        <pubDate>Wed, 25 Mar 2026 22:08:57 +0800</pubDate>
        
        <guid>https://SymphonyW.github.io/zh-cn/p/redis%E9%9D%A2%E8%AF%95%E5%85%AB%E8%82%A1%E6%96%87%E6%8C%81%E7%BB%AD%E6%9B%B4%E6%96%B0/</guid>
        <description>&lt;img src="https://SymphonyW.github.io/zh-cn/p/redis%E9%9D%A2%E8%AF%95%E5%85%AB%E8%82%A1%E6%96%87%E6%8C%81%E7%BB%AD%E6%9B%B4%E6%96%B0/bg.png" alt="Featured image of post Redis面试八股文（持续更新）" /&gt;&lt;p&gt;本文档整理了后端开发面试中关于 Redis 最常被问到的高频面试题和深度解析，重点聚焦于底层原理、高并发场景下的缓存设计及高可用架构。&lt;/p&gt;
&lt;h2 id=&#34;一-核心基础与数据结构&#34;&gt;&lt;strong&gt;一、 核心基础与数据结构&lt;/strong&gt;
&lt;/h2&gt;&lt;h3 id=&#34;1-redis-为什么这么快&#34;&gt;&lt;strong&gt;1. Redis 为什么这么快？&lt;/strong&gt;
&lt;/h3&gt;&lt;p&gt;官方测试 Redis 的 QPS 可以达到 10万+，主要原因有：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;完全基于内存&lt;/strong&gt;：绝大部分请求是&lt;strong&gt;纯内存&lt;/strong&gt;操作，速度极快。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;高效的数据结构&lt;/strong&gt;：Redis 专门设计了如 SDS（简单动态字符串）、&lt;strong&gt;跳表（SkipList）&lt;/strong&gt;、压缩列表（ZipList）等高效的数据结构。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;单线程模型&lt;/strong&gt;：Redis 的网络 IO 和键值对读写是由一个线程来完成的，&lt;strong&gt;避免了不必要的上下文切换和竞争条件&lt;/strong&gt;，不存在加锁解锁操作造成的性能损耗。（注：Redis 6.0 引入了多线程，但也只是用于网络 I/O 阶段，命令执行依然是单线程）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;I/O 多路复用模型&lt;/strong&gt;：采用 epoll 作为 &lt;strong&gt;I/O 多路复用&lt;/strong&gt;技术的实现，非阻塞 I/O，可以同时监听多个 Socket。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;2-redis-的五种基本数据类型及其底层数据结构&#34;&gt;&lt;strong&gt;2. Redis 的五种基本数据类型及其底层数据结构？&lt;/strong&gt;
&lt;/h3&gt;&lt;p&gt;面试不仅会问应用场景，一定会深挖底层结构：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:left&#34;&gt;数据类型&lt;/th&gt;
&lt;th style=&#34;text-align:left&#34;&gt;应用场景&lt;/th&gt;
&lt;th style=&#34;text-align:left&#34;&gt;底层数据结构（Redis 3.2+ / 7.0+ 有所演进）&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;&lt;strong&gt;String&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;缓存、计数器、分布式锁、Session（会话）&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;&lt;strong&gt;SDS&lt;/strong&gt; (简单动态字符串)。比 C 字符串更安全、获取长度 O(1)、防止缓冲区溢出。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;&lt;strong&gt;List&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;消息队列、文章列表、粉丝列表&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;&lt;strong&gt;QuickList&lt;/strong&gt; (快速列表，双向链表 + 压缩列表的组合)。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;&lt;strong&gt;Hash&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;存储对象、购物车&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;&lt;strong&gt;ZipList&lt;/strong&gt; (压缩列表，数据少时) / &lt;strong&gt;HashTable&lt;/strong&gt; (哈希表/字典，数据多时)。&lt;em&gt;注：Redis 7.0 后 ZipList 替换为 ListPack。&lt;/em&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;&lt;strong&gt;Set&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;共同好友、点赞、抽奖&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;&lt;strong&gt;IntSet&lt;/strong&gt; (整数集合，元素全为整数且较少时) / &lt;strong&gt;HashTable&lt;/strong&gt; (字典)。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;&lt;strong&gt;ZSet (Sorted Set)&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;排行榜、延时队列&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;&lt;strong&gt;ZipList&lt;/strong&gt; (数据少时) / &lt;strong&gt;SkipList + HashTable&lt;/strong&gt; (跳跃表+字典)。跳表保证范围查询效率 O(logN)，字典保证单点查询 O(1)。&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;3-zset-为什么使用跳表skiplist而不是红黑树或-b-树&#34;&gt;&lt;strong&gt;3. ZSet 为什么使用跳表（SkipList）而不是红黑树或 B+ 树？&lt;/strong&gt;
&lt;/h3&gt;&lt;p&gt;&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E9%9D%A2%E8%AF%95%E5%85%AB%E8%82%A1%E6%96%87%E6%8C%81%E7%BB%AD%E6%9B%B4%E6%96%B0/2026-04-15-19-17-00.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E9%9D%A2%E8%AF%95%E5%85%AB%E8%82%A1%E6%96%87%E6%8C%81%E7%BB%AD%E6%9B%B4%E6%96%B0/2026-04-15-19-17-00.png&#34; alt=&#34;跳表的示例，底层是多层有序链表&#34; width=&#34;744&#34; height=&#34;314&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;236&#34; data-flex-basis=&#34;568px&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;查询时，以查找 30 为例：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;从最高层的最左侧开始。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果当前节点的下一个节点比 30 小，就向右跳。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;如果当前节点的下一个节点比 30 大或者已经是末尾，就向下掉一层。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;重复此过程，直到在某一层找到 30，或者在底层确定该元素不存在。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;跳表通过随机层数机制，平均每层节点数是下一层的 1/2 或 1/4，查询效率 O(logN)。插入和删除时只需要修改相邻节点的指针，维护成本较低。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;对比红黑树&lt;/strong&gt;：跳表实现更简单；在进行范围查找（如排行榜获取前 10 名）时，跳表只需要找到起点然后顺着底层链表遍历即可，而红黑树需要中序遍历，跳表效率更高；跳表的插入/删除只需修改相邻节点的指针，不需要像红黑树那样做复杂的旋转。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E9%9D%A2%E8%AF%95%E5%85%AB%E8%82%A1%E6%96%87%E6%8C%81%E7%BB%AD%E6%9B%B4%E6%96%B0/2026-04-15-16-22-28.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E9%9D%A2%E8%AF%95%E5%85%AB%E8%82%A1%E6%96%87%E6%8C%81%E7%BB%AD%E6%9B%B4%E6%96%B0/2026-04-15-16-22-28.png&#34; alt=&#34;红黑树示例&#34; width=&#34;592&#34; height=&#34;313&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;189&#34; data-flex-basis=&#34;453px&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;对比 B+ 树&lt;/strong&gt;：B+ 树是为了最大限度减少磁盘 I/O 而设计的，树的高度较矮。但 Redis 是内存数据库，不需要考虑磁盘 I/O，跳表作为内存数据结构，其随机层数机制和简单的节点维护成本更低。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E9%9D%A2%E8%AF%95%E5%85%AB%E8%82%A1%E6%96%87%E6%8C%81%E7%BB%AD%E6%9B%B4%E6%96%B0/2026-04-15-16-25-12.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E9%9D%A2%E8%AF%95%E5%85%AB%E8%82%A1%E6%96%87%E6%8C%81%E7%BB%AD%E6%9B%B4%E6%96%B0/2026-04-15-16-25-12.png&#34; alt=&#34;B&amp;#43; 树示例&#34; width=&#34;544&#34; height=&#34;140&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;388&#34; data-flex-basis=&#34;932px&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id=&#34;二-持久化机制&#34;&gt;&lt;strong&gt;二、 持久化机制&lt;/strong&gt;
&lt;/h2&gt;&lt;h3 id=&#34;4-redis-的持久化是怎么实现的&#34;&gt;&lt;strong&gt;4. Redis 的持久化是怎么实现的？&lt;/strong&gt;
&lt;/h3&gt;&lt;p&gt;Redis 提供了两种持久化机制：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;RDB (Redis DataBase)&lt;/strong&gt;：&lt;strong&gt;快照&lt;/strong&gt;机制，定期将内存中的数据以二进制文件（dump.rdb）保存到磁盘。可以通过 save（阻塞）或 bgsave（异步，fork 子进程）命令触发，也可以配置自动触发条件。恢复时直接加载 RDB 文件到内存，速度快，但可能丢失两次快照之间的数据。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AOF (Append Only File)&lt;/strong&gt;：&lt;strong&gt;日志&lt;/strong&gt;机制，记录服务器执行的所有写操作命令（appendonly.aof）。可以配置不同的同步策略（always、everysec、no）。恢复时需要重新执行 AOF 文件中的命令，速度较慢，但数据安全性高（最多丢一秒的数据）。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;5-rdb-和-aof-持久化的区别&#34;&gt;&lt;strong&gt;5. RDB 和 AOF 持久化的区别？&lt;/strong&gt;
&lt;/h3&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&#34;text-align:left&#34;&gt;特性&lt;/th&gt;
&lt;th style=&#34;text-align:left&#34;&gt;RDB (Redis DataBase)&lt;/th&gt;
&lt;th style=&#34;text-align:left&#34;&gt;AOF (Append Only File)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;&lt;strong&gt;原理&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;&lt;strong&gt;快照&lt;/strong&gt;：将某个时间点的所有内存数据以二进制文件（dump.rdb）保存。&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;&lt;strong&gt;日志&lt;/strong&gt;：记录服务器执行的所有写操作命令（appendonly.aof）。&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;&lt;strong&gt;触发方式&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;save (阻塞), bgsave (异步，fork 子进程), 自动触发配置&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;always (每次写), everysec (每秒，默认), no (交由操作系统)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;&lt;strong&gt;文件大小&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;较小（二进制压缩格式）&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;较大（文本格式记录了所有写命令）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;&lt;strong&gt;恢复速度&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;&lt;strong&gt;快&lt;/strong&gt;（直接把数据读入内存即可）&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;&lt;strong&gt;慢&lt;/strong&gt;（需要把所有命令重新执行一遍）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&#34;text-align:left&#34;&gt;&lt;strong&gt;数据安全性&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;容易丢数据（两次快照之间的数据会丢失）&lt;/td&gt;
&lt;td style=&#34;text-align:left&#34;&gt;安全性高（最多丢一秒的数据）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;6-什么是-aof-重写aof-rewrite&#34;&gt;&lt;strong&gt;6. 什么是 AOF 重写（AOF Rewrite）？&lt;/strong&gt;
&lt;/h3&gt;&lt;p&gt;随着命令不断写入，AOF 文件会越来越大。AOF 重写机制就是&lt;strong&gt;用来压缩 AOF 文件&lt;/strong&gt;的。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;原理&lt;/strong&gt;：Redis 会 &lt;strong&gt;fork 出一个 bgrewriteaof 子进程&lt;/strong&gt;，它会扫描当前内存中的数据，为每一个键值对生成一条对应的插入命令，写入到新的 AOF 文件中。比如以前对一个 key 进行了 100 次自增，重写后只会变成一条 SET key 100 的命令，大大减小了体积。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;混合持久化&lt;/strong&gt;：Redis 4.0 引入，AOF 重写时，将当前内存数据以 &lt;strong&gt;RDB 格式&lt;/strong&gt;写入新 AOF 文件的开头，之后的新写入命令继续以 &lt;strong&gt;AOF 格式&lt;/strong&gt;追加。结合了 RDB 恢复快和 AOF 数据不丢失的优点。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;三-内存淘汰与过期策略&#34;&gt;&lt;strong&gt;三、 内存淘汰与过期策略&lt;/strong&gt;
&lt;/h2&gt;&lt;h3 id=&#34;7-redis-的过期键删除策略是什么&#34;&gt;&lt;strong&gt;7. Redis 的过期键删除策略是什么？&lt;/strong&gt;
&lt;/h3&gt;&lt;p&gt;Redis 使用了 &lt;strong&gt;惰性删除 + 定期删除&lt;/strong&gt; 的配合策略：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;惰性删除&lt;/strong&gt;：平时不主动管，只有当客户端试图访问某个 key 时，Redis 才去检查它是否过期，如果过期了就删除并返回空。优点是省 CPU，缺点是如果过期 key 一直不被访问，会造成&lt;strong&gt;内存泄漏&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;定期删除&lt;/strong&gt;：Redis 默认每秒执行 10 次清理操作，随机抽取一部分设置了过期时间的 key，检查并删除已过期的。这种机制可以防止内存被大量无人访问的过期 key 占满。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;8-redis-的内存淘汰策略有哪些当内存满了怎么办&#34;&gt;&lt;strong&gt;8. Redis 的内存淘汰策略有哪些？（当内存满了怎么办）&lt;/strong&gt;
&lt;/h3&gt;&lt;p&gt;当 Redis 内存使用达到 max memory 限制时，会触发淘汰策略：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;noeviction（默认）：不淘汰数据，如果有写请求直接报错 (OOM)。&lt;/li&gt;
&lt;li&gt;allkeys-lru：在所有 key 中，淘汰最近最少使用的 key（最常用）。&lt;/li&gt;
&lt;li&gt;volatile-lru：在设置了过期时间的 key 中，淘汰最近最少使用的。&lt;/li&gt;
&lt;li&gt;allkeys-random / volatile-random：随机淘汰。&lt;/li&gt;
&lt;li&gt;volatile-ttl：淘汰即将过期的 key。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;allkeys-lfu / volatile-lfu&lt;/strong&gt;（Redis 4.0+ 引入）：淘汰使用频率最少的 key（Least Frequently Used）。解决了 LRU 无法应对偶发性冷数据全表扫描的问题。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;四-缓存高并发经典问题穿透击穿雪崩&#34;&gt;&lt;strong&gt;四、 缓存高并发经典问题（穿透、击穿、雪崩）&lt;/strong&gt;
&lt;/h2&gt;&lt;h3 id=&#34;9-什么是缓存穿透如何解决&#34;&gt;&lt;strong&gt;9. 什么是缓存穿透？如何解决？&lt;/strong&gt;
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;定义&lt;/strong&gt;：查询一个&lt;strong&gt;根本不存在的数据&lt;/strong&gt;，缓存中肯定查不到（不命中），导致请求每次都要去数据库查，如果有人恶意疯狂请求这个不存在的 key，数据库可能会瞬间崩掉。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;解决方案&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;缓存空对象/默认值&lt;/strong&gt;：当数据库查不到时，依然把这个空结果（如 null）存入缓存，设置一个较短的过期时间。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;布隆过滤器 (Bloom Filter)&lt;/strong&gt;：在请求到达缓存之前，先经过布隆过滤器判断该 key 是否存在。如果布隆过滤器说不存在，那一定不存在，直接返回；如果说存在（有极小误判率），再去查缓存和 DB。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;补充：布隆过滤器是一个空间效率极高的概率型数据结构，可以判断一个元素是否在一个集合中。它使用多个哈希函数将元素映射到一个位数组上，查询时同样通过哈希函数检查对应位是否为 1。虽然存在误判（可能会误判某个不存在的元素为存在），但绝不会漏判（真正存在的元素一定会被识别）。因此非常适合用来做缓存穿透的第一道防线。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;10-什么是缓存击穿如何解决&#34;&gt;&lt;strong&gt;10. 什么是缓存击穿？如何解决？&lt;/strong&gt;
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;定义&lt;/strong&gt;：一个&lt;strong&gt;极度热点的数据&lt;/strong&gt;（比如秒杀商品），在&lt;strong&gt;缓存过期的瞬间&lt;/strong&gt;，有极其庞大的并发请求过来。因为缓存失效了，这几万个请求会同时去穿透到数据库，导致数据库瞬间崩溃。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;解决方案&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;互斥锁 (Mutex Lock)&lt;/strong&gt;：在缓存失效去数据库查询重建缓存的这个步骤加上分布式锁（如 Redis 的 SETNX）。保证只有一个请求能打到 DB 并更新缓存，其他请求拿不到锁就休眠重试。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;逻辑过期 (热点数据永不过期)&lt;/strong&gt;：物理上不设置 TTL，而是在 value 内部维护一个逻辑过期时间字段。发现逻辑过期时，异步开启一个线程去更新缓存，当前请求先返回旧数据。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;补充：分布式锁是分布式系统中用来保证多个进程或线程之间互斥访问共享资源的机制。它的实现细节非常重要，必须保证“谁加的锁只有谁能解”，防止误删别人的锁。通常会在加锁时设置一个唯一的随机值（如 UUID），解锁时通过 Lua 脚本比对这个值，只有匹配成功才删除锁。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;11-什么是缓存雪崩如何解决&#34;&gt;&lt;strong&gt;11. 什么是缓存雪崩？如何解决？&lt;/strong&gt;
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;定义&lt;/strong&gt;：&lt;strong&gt;大量的热点 key 在同一时间集中过期&lt;/strong&gt;，或者 &lt;strong&gt;Redis 服务宕机&lt;/strong&gt;。导致海量请求直接打到数据库，引发数据库宕机乃至整个系统雪崩。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解决方案&lt;/strong&gt;：
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;打散过期时间&lt;/strong&gt;：在设置 TTL 时，给基础时间加上一个随机值（如 1-5 分钟），避免大量 key 在同一秒过期。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;服务高可用&lt;/strong&gt;：搭建 Redis 哨兵 (Sentinel) 或 集群 (Cluster) 架构，防止 Redis 单点故障。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;限流降级&lt;/strong&gt;：在应用层（如使用 Sentinel/Hystrix）做好限流熔断，保护底层数据库。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;五-分布式锁与双写一致性&#34;&gt;&lt;strong&gt;五、 分布式锁与双写一致性&lt;/strong&gt;
&lt;/h2&gt;&lt;h3 id=&#34;12-如何用-redis-实现分布式锁&#34;&gt;&lt;strong&gt;12. 如何用 Redis 实现分布式锁？&lt;/strong&gt;
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;基础版本&lt;/strong&gt;：使用 SET resource_name my_random_value NX PX 30000。
&lt;ul&gt;
&lt;li&gt;NX：表示 Not eXists，只有 key 不存在时才设置成功（保证互斥性）。&lt;/li&gt;
&lt;li&gt;PX 30000：设置过期时间为 30 秒（防止宕机死锁）。&lt;/li&gt;
&lt;li&gt;my_random_value：必须是客户端唯一的随机 ID，解锁时通过 Lua 脚本比对这个值，保证“谁加的锁只有谁能解”，防止误删别人的锁。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;进阶版本 (Redisson)&lt;/strong&gt;：基础版本的锁如果业务执行时间太长，锁提前过期了怎么办？Redisson 框架提供了 &lt;strong&gt;看门狗 (Watch Dog)&lt;/strong&gt; 机制。加锁成功后，会开启一个后台线程，每隔 10 秒（默认超时时间 30s 的 1/3）检查一下业务是否还在执行，如果还在执行就将锁的过期时间续期回 30s。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;13-redis-和-mysql-如何保证双写一致性&#34;&gt;&lt;strong&gt;13. Redis 和 MySQL 如何保证双写一致性？&lt;/strong&gt;
&lt;/h3&gt;&lt;p&gt;这是面试高频必杀题。标准的处理模式是 &lt;strong&gt;Cache Aside Pattern（旁路缓存模式）&lt;/strong&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;标准操作&lt;/strong&gt;：&lt;strong&gt;先更新数据库，再删除缓存&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;为什么不能先更新缓存再更新 DB？&lt;/strong&gt; 如果 DB 更新失败，缓存就是&lt;strong&gt;脏数据&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;为什么不能先删缓存再更新 DB？&lt;/strong&gt; 在并发环境下，线程 A 删了缓存还没更新 DB，线程 B 进来查缓存没命中，去 DB 读到了旧数据并写入缓存。然后 A 更新了 DB。导致缓存里永远是&lt;strong&gt;旧数据&lt;/strong&gt;。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;先更新 DB 再删缓存，有没有可能出问题？&lt;/strong&gt; 有。A 查 DB 读到旧数据（还未写缓存），B 更新 DB 并删缓存，A 将刚才的旧数据写入缓存。但这种情况概率极低（要求写操作比读操作还快）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;为什么是删除缓存而不是更新缓存？&lt;/strong&gt; 因为更新缓存需要保证原子性（更新 DB 和更新缓存必须是一个原子操作），而 Redis 没有提供这样的事务机制。删除缓存后，下一次读请求会去 DB 读到最新数据并写入缓存。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解决方案&lt;/strong&gt;：
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;加分布式锁&lt;/strong&gt;：在更新 DB 和删除缓存的过程中加锁，保证同一时间只有一个线程能操作这个 key。缺点是性能较差，增加了复杂度。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;逻辑过期&lt;/strong&gt;：不设置物理过期时间，而是在 value 内部维护一个逻辑过期时间字段。更新 DB 后，直接更新缓存并重置逻辑过期时间。读请求发现逻辑过期时，异步开启一个线程去更新缓存，当前请求先返回旧数据。缺点是可能会有短暂的脏数据窗口。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;终极保障方案（延迟双删 / 消息队列）&lt;/strong&gt;：
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;延迟双删&lt;/strong&gt;：先删缓存 -&amp;gt; 更新 DB -&amp;gt; 睡眠（如 500ms） -&amp;gt; 再次删缓存。确保把读请求可能产生的脏缓存删掉。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;基于 Canal + 消息队列（推荐）&lt;/strong&gt;：业务代码只管更新数据库。通过 Canal 伪装成 MySQL 从节点监听 binlog，提取出修改的数据后扔到 MQ 中，消费者订阅 MQ 去异步且可靠地删除 Redis 缓存。&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;六-高可用与集群架构&#34;&gt;&lt;strong&gt;六、 高可用与集群架构&lt;/strong&gt;
&lt;/h2&gt;&lt;h3 id=&#34;14-主从复制的原理是什么&#34;&gt;&lt;strong&gt;14. 主从复制的原理是什么？&lt;/strong&gt;
&lt;/h3&gt;&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;全量同步&lt;/strong&gt;：当从节点第一次连接主节点时。主节点执行 bgsave 生成 RDB 文件发送给从节点，从节点加载。期间主节点的新写命令会存入 replication buffer，RDB 发送完后再把 buffer 里的命令发给从节点。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;增量同步&lt;/strong&gt;：网络断开重连后，主节点根据从节点上报的 offset，从 &lt;strong&gt;repl_backlog_buffer&lt;/strong&gt;（环形缓冲区）中把断开期间的命令发给从节点，无需重新全量同步。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;15-什么是哨兵模式-sentinel&#34;&gt;&lt;strong&gt;15. 什么是哨兵模式 (Sentinel)？&lt;/strong&gt;
&lt;/h3&gt;&lt;p&gt;主从复制无法自动故障转移。哨兵就是用来&lt;strong&gt;监控主从节点&lt;/strong&gt;的：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;监控&lt;/strong&gt;：不断向主从节点发送 PING 检查是否在线（主观下线、客观下线）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;故障转移 (Failover)&lt;/strong&gt;：主节点挂了，哨兵集群会通过 Raft 算法选举出一个 Leader 哨兵，由它在从节点中选出一个新的主节点（根据优先级、复制偏移量 offset、RunID 选举）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;通知&lt;/strong&gt;：将新的主节点信息通知给客户端和其他从节点。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&#34;16-redis-cluster-集群的原理什么是哈希槽-hash-slot&#34;&gt;&lt;strong&gt;16. Redis Cluster 集群的原理？什么是哈希槽 (Hash Slot)？&lt;/strong&gt;
&lt;/h3&gt;&lt;p&gt;哨兵模式解决了高可用，但无法解决单机内存上限和写并发能力瓶颈。Redis Cluster 提供了**分布式（分片）**方案。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;哈希槽&lt;/strong&gt;：Redis 集群没有使用一致性 Hash，而是引入了 16384 个哈希槽。集群的每个主节点负责一部分槽。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;寻址过程&lt;/strong&gt;：当客户端发送命令时，对 key 使用 CRC16 算法取模 16384，计算出该 key 属于哪个槽。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;去中心化&lt;/strong&gt;：集群中没有中心节点，节点之间通过 &lt;strong&gt;Gossip 协议&lt;/strong&gt;交换彼此的状态和槽信息。如果客户端请求打到了错误的节点，节点会返回 MOVED 重定向指令，让客户端去正确的节点操作。&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        <item>
        <title>Redis基础学习文档</title>
        <link>https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/</link>
        <pubDate>Tue, 24 Mar 2026 17:05:27 +0800</pubDate>
        
        <guid>https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/</guid>
        <description>&lt;img src="https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/bg.png" alt="Featured image of post Redis基础学习文档" /&gt;&lt;h1 id=&#34;redis基础学习文档&#34;&gt;Redis基础学习文档
&lt;/h1&gt;&lt;h2 id=&#34;基础篇&#34;&gt;基础篇
&lt;/h2&gt;&lt;h2 id=&#34;redis数据结构介绍&#34;&gt;Redis数据结构介绍
&lt;/h2&gt;&lt;p&gt;Redis是一个key-value的数据库，key一般是String类型，value的类型多种多样：
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/dataType.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/dataType.png&#34; alt=&#34;Redis的数据类型&#34; width=&#34;1654&#34; height=&#34;845&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;195&#34; data-flex-basis=&#34;469px&#34;&gt;&lt;/a&gt;

我们可以在官网（https://redis.io/commands）查看不同的命令用法。同时我们也可以在命令行通过help指令来查找命令。&lt;/p&gt;
&lt;h2 id=&#34;redis的通用命令&#34;&gt;Redis的通用命令
&lt;/h2&gt;&lt;p&gt;通用命令是部分数据类型的，都可以使用的命令，常见的有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;KEYS&lt;/code&gt;：查看符合模板的所有key。模糊查询的效率不高，又因为Redis是单线程的，所以&lt;strong&gt;不建议在生产环境设备上使用&lt;/strong&gt;
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/KEYS.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/KEYS.png&#34; alt=&#34;KEYS命令用法&#34; width=&#34;631&#34; height=&#34;352&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;179&#34; data-flex-basis=&#34;430px&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;DEL&lt;/code&gt;：删除一个或多个指定的key
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/DEL.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/DEL.png&#34; alt=&#34;DEL命令用法&#34; width=&#34;457&#34; height=&#34;806&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;56&#34; data-flex-basis=&#34;136px&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;EXISTS&lt;/code&gt;：检查一个或多个key是否存在
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/EXISTS.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/EXISTS.png&#34; alt=&#34;EXISTS命令用法&#34; width=&#34;481&#34; height=&#34;488&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;98&#34; data-flex-basis=&#34;236px&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;EXPIRE&lt;/code&gt;：为一个key设置有效期（过期时间），单位为秒，有效期到期时，key会被自动删除&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;TTL&lt;/code&gt;：查看一个key的剩余有效期，单位为秒
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/EXPIRE_TTL.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/EXPIRE_TTL.png&#34; alt=&#34;EXPIRE和TTL命令用法&#34; width=&#34;604&#34; height=&#34;939&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;64&#34; data-flex-basis=&#34;154px&#34;&gt;&lt;/a&gt;

注意：当一个key设置了过期时间后，如果在过期时间到期之前再次设置了过期时间，那么原来的过期时间会被覆盖掉，新的过期时间会重新计算。并且过期后TTL命令会返回-2，表示key不存在了；如果一个key没有设置过期时间，那么TTL命令会返回-1，表示这个key是永久有效的。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;string类型&#34;&gt;String类型
&lt;/h2&gt;&lt;p&gt;String类型是Redis中最基本的数据类型，key和value都是字符串类型。不过根据字符串的格式不同，String类型又可以分为以下几种：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;普通字符串：普通的字符串类型，可以存储任何文本数据，最大长度为512MB。&lt;/li&gt;
&lt;li&gt;数字字符串：可以存储整数或浮点数，可以进行数学运算和自增操作。&lt;/li&gt;
&lt;li&gt;二进制字符串：可以存储二进制数据，如图片、音频等非文本数据。&lt;/li&gt;
&lt;li&gt;JSON字符串：可以存储JSON格式的数据，可以方便地进行数据交换和存储复杂的数据结构。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不管是哪种格式，底层都是字节数组形式存储，只不过是编码方式不同。字符串类型的最大空间不能超过512MB，如果超过了这个限制，Redis会返回错误。
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/String.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/String.png&#34; alt=&#34;String类型的不同格式&#34; width=&#34;1262&#34; height=&#34;272&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;463&#34; data-flex-basis=&#34;1113px&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;p&gt;String类型的常用命令有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;SET&lt;/code&gt;：设置一个key的值，如果key已经存在，则覆盖原来的值&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET&lt;/code&gt;：获取一个key的值，如果key不存在，则返回nil&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MSET&lt;/code&gt;：同时设置多个key的值&lt;/li&gt;
&lt;li&gt;&lt;code&gt;MGET&lt;/code&gt;：同时获取多个key的值
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/SET_GET.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/SET_GET.png&#34; alt=&#34;SET、GET、MSET、MGET命令用法&#34; width=&#34;545&#34; height=&#34;378&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;144&#34; data-flex-basis=&#34;346px&#34;&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;INCR&lt;/code&gt;：将一个key的值加1，如果key不存在，则先将其设置&lt;/li&gt;
&lt;li&gt;&lt;code&gt;INCRBY&lt;/code&gt;：将一个key的值加上指定的整数，如果key不存在，则先将其设置。也可以实现自减的效果。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;INCRBYFLOAT&lt;/code&gt;：将一个key的值加上指定的浮点数，如果key不存在，则先将其设置
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/INCR.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/INCR.png&#34; alt=&#34;INCR、INCRBY、INCRBYFLOAT命令用法&#34; width=&#34;436&#34; height=&#34;349&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;124&#34; data-flex-basis=&#34;299px&#34;&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DECR&lt;/code&gt;：将一个key的值减1，如果key不存在，则先将其设置&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DECRBY&lt;/code&gt;：将一个key的值减去指定的整数，如果key不存在，则先将其设置
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/DECR.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/DECR.png&#34; alt=&#34;DECR、DECRBY命令用法&#34; width=&#34;364&#34; height=&#34;186&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;195&#34; data-flex-basis=&#34;469px&#34;&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SETNX&lt;/code&gt;：只有当key不存在时才设置key的值，如果key已经存在，则不做任何操作
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/SETNX.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/SETNX.png&#34; alt=&#34;SETNX命令用法&#34; width=&#34;412&#34; height=&#34;256&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;160&#34; data-flex-basis=&#34;386px&#34;&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;SETEX&lt;/code&gt;：设置一个key的值，并为key设置过期时间，单位为秒
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/SETEX.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/SETEX.png&#34; alt=&#34;SETEX命令用法&#34; width=&#34;471&#34; height=&#34;343&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;137&#34; data-flex-basis=&#34;329px&#34;&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PSETEX&lt;/code&gt;：设置一个key的值，并为key设置过期时间，单位为毫秒&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;key的层级结构&#34;&gt;KEY的层级结构
&lt;/h2&gt;&lt;p&gt;Redis的key是一个字符串，可以包含任何字符，包括空格和特殊字符。为了方便管理和组织key，Redis没有提供真正的层级结构，但我们可以通过在key中使用分隔符（如冒号:）来模拟层级结构。
例如，我们有一个项目叫heima，有user和product两种不同类型的数据，我们可以这样定义key：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;user相关的key：heima:user:1、heima:user:2、heima:user:3等&lt;/li&gt;
&lt;li&gt;product相关的key：heima:product:1、heima:product:2、heima:product:3等&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;如果value是一个对象，例如一个user对象，我们可以将其序列化成JSON字符串存储在Redis中，这样就可以方便地进行数据交换和存储复杂的数据结构。
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/eg1.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/eg1.png&#34; alt=&#34;&#34; width=&#34;1255&#34; height=&#34;214&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;586&#34; data-flex-basis=&#34;1407px&#34;&gt;&lt;/a&gt;

&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/eg2.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/eg2.png&#34; alt=&#34;&#34; width=&#34;1336&#34; height=&#34;696&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;191&#34; data-flex-basis=&#34;460px&#34;&gt;&lt;/a&gt;

&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/KEYLAYER.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/KEYLAYER.png&#34; alt=&#34;KEY的层级结构&#34; width=&#34;743&#34; height=&#34;798&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;93&#34; data-flex-basis=&#34;223px&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;h2 id=&#34;hash类型&#34;&gt;Hash类型
&lt;/h2&gt;&lt;p&gt;Hash类型，也叫散列，其value是一个无序字典，类似于C++中的unordered_map。Hash类型的key是一个字符串，而value是一个包含多个field和value的字典。每个field都是一个字符串，每个value也是一个字符串。主要特征有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Hash类型的元素是无序的，不能通过索引访问&lt;/li&gt;
&lt;li&gt;Hash类型的元素是唯一的，不能重复&lt;/li&gt;
&lt;li&gt;Hash类型的元素可以在字典中添加或删除&lt;/li&gt;
&lt;li&gt;查询速度快，适合于需要频繁查询的场景，例如用户信息、商品信息等。
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/Hash.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/Hash.png&#34; alt=&#34;Hash类型的结构&#34; width=&#34;1203&#34; height=&#34;687&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;175&#34; data-flex-basis=&#34;420px&#34;&gt;&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hash类型的常用命令有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;HSET key field value&lt;/code&gt;：设置hash表key中field的值为value，如果key不存在，则创建一个新的hash表；如果field已经存在，则覆盖原来的值&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;HGET key field&lt;/code&gt;：获取hash表key中field的值，如果key不存在或field不存在，则返回nil&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;HMSET key field1 value1 field2 value2 ...&lt;/code&gt;：同时设置hash表key中多个field的值，如果key不存在，则创建一个新的hash表；如果field已经存在，则覆盖原来的值&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;HMGET key field1 field2 ...&lt;/code&gt;：同时获取hash表key中多个field的值，如果key不存在或field不存在，则返回nil
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/eg3.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/eg3.png&#34; alt=&#34;&#34; width=&#34;1549&#34; height=&#34;653&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;237&#34; data-flex-basis=&#34;569px&#34;&gt;&lt;/a&gt;

&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/HSET_HGET.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/HSET_HGET.png&#34; alt=&#34;HSET、HGET、HMSET、HMGET命令用法&#34; width=&#34;1172&#34; height=&#34;690&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;169&#34; data-flex-basis=&#34;407px&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;HGETALL key&lt;/code&gt;：获取hash表key中所有field和value的值，如果key不存在，则返回nil&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;HKEYS key&lt;/code&gt;：获取hash表key中所有field的值，如果key不存在，则返回nil&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;HVALS key&lt;/code&gt;：获取hash表key中所有value的值，如果key不存在，则返回nil
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/HGETALL.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/HGETALL.png&#34; alt=&#34;HGETALL、HKEYS、HVALS命令用法&#34; width=&#34;656&#34; height=&#34;538&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;121&#34; data-flex-basis=&#34;292px&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;HDEL key field1 field2 ...&lt;/code&gt;：删除hash表key中指定的field，如果key不存在或field不存在，则不做任何操作&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;HLEN key&lt;/code&gt;：获取hash表key中field的数量，如果key不存在，则返回0
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/HDEL_HLEN.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/HDEL_HLEN.png&#34; alt=&#34;HDEL、HLEN命令用法&#34; width=&#34;521&#34; height=&#34;376&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;138&#34; data-flex-basis=&#34;332px&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;HEXISTS key field&lt;/code&gt;：检查hash表key中是否存在field，如果key不存在或field不存在，则返回0；如果存在，则返回1
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/HEXISTS.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/HEXISTS.png&#34; alt=&#34;HEXISTS命令用法&#34; width=&#34;472&#34; height=&#34;218&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;216&#34; data-flex-basis=&#34;519px&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;HINCRBY key field increment&lt;/code&gt;：将hash表key中field的值加上指定的整数increment，如果key不存在，则先创建一个新的hash表；如果field不存在，则先将其设置为0；如果field的值不是一个整数，则返回错误&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;HSETNX key field value&lt;/code&gt;：只有当hash表key中field不存在时才设置field的值为value，如果key不存在，则先创建一个新的hash表；如果field已经存在，则不做任何操作
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/HINCRBY_HSETNX.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/HINCRBY_HSETNX.png&#34; alt=&#34;HINCRBY、HSETNX命令用法&#34; width=&#34;552&#34; height=&#34;472&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;116&#34; data-flex-basis=&#34;280px&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;list类型&#34;&gt;List类型
&lt;/h2&gt;&lt;p&gt;Redis的List类型与C++中的std::list类似，是一个&lt;strong&gt;双向链表&lt;/strong&gt;。List类型的key是一个字符串，而value是一个包含多个元素的列表，每个元素都是一个字符串。特征也与std::list类似：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;List类型的元素是有序的，可以通过索引访问&lt;/li&gt;
&lt;li&gt;List类型的元素可以重复&lt;/li&gt;
&lt;li&gt;List类型的元素可以在头部或尾部添加或删除&lt;/li&gt;
&lt;li&gt;查询速度一般，适合于需要频繁插入和删除的场景，例如消息队列、任务列表等。
常用来存储一个有序数据，例如朋友圈点赞列表、微博评论列表等。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;List类型的常用命令有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;LRANGE key start stop&lt;/code&gt;：获取列表key中指定范围内的元素，start和stop都是索引，索引从0开始，负数表示从列表尾部开始计算，例如-1表示最后一个元素，-2表示倒数第二个元素，以此类推。如果key不存在，则返回nil；如果start或stop超出范围，则返回空列表
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/LRANGE.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/LRANGE.png&#34; alt=&#34;LRANGE命令用法&#34; width=&#34;384&#34; height=&#34;195&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;196&#34; data-flex-basis=&#34;472px&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;LPUSH key value1 value2 ...&lt;/code&gt;：将一个或多个值插入到列表key的头部，如果key不存在，则创建一个新的列表；如果key存在但不是列表类型，则返回错误&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;LPOP key&lt;/code&gt;：移除并返回列表key的头部元素，如果key不存在或列表为空，则返回nil&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;RPUSH key value1 value2 ...&lt;/code&gt;：将一个或多个值插入到列表key的尾部，如果key不存在，则创建一个新的列表；如果key存在但不是列表类型，则返回错误&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;RPOP key&lt;/code&gt;：移除并返回列表key的尾部元素，如果key不存在或列表为空，则返回nil
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/LPUSH_RPUSH.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/LPUSH_RPUSH.png&#34; alt=&#34;LPUSH、RPUSH命令用法&#34; width=&#34;453&#34; height=&#34;696&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;65&#34; data-flex-basis=&#34;156px&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;LLEN key&lt;/code&gt;：获取列表key中元素的数量，如果key不存在，则返回0&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;LINDEX key index&lt;/code&gt;：获取列表key中指定索引位置的元素，如果key不存在或索引超出范围，则返回nil&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;LSET key index value&lt;/code&gt;：设置列表key中指定索引位置的元素为value，如果key不存在或索引超出范围，则返回错误
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/LLEN_LINDEX_LSET.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/LLEN_LINDEX_LSET.png&#34; alt=&#34;LLEN、LINDEX、LSET命令用法&#34; width=&#34;406&#34; height=&#34;313&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;129&#34; data-flex-basis=&#34;311px&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;BLPOP key [key ...] timeout&lt;/code&gt;：移除并返回一个或多个列表key的头部元素，如果key不存在或列表为空，则返回nil；如果timeout为0，表示永远等待；如果timeout为正整数，表示等待指定的秒数，如果在等待期间有元素被添加到列表中，则立即返回；如果在等待期间没有元素被添加到列表中，则返回nil&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;BRPOP key [key ...] timeout&lt;/code&gt;：移除并返回一个或多个列表key的尾部元素，如果key不存在或列表为空，则返回nil；如果timeout为0，表示永远等待；如果timeout为正整数，表示等待指定的秒数，如果在等待期间有元素被添加到列表中，则立即返回；如果在等待期间没有元素被添加到列表中，则返回nil
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/BLPOP_BRPOP.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/BLPOP_BRPOP.png&#34; alt=&#34;BLPOP、BRPOP命令用法&#34; width=&#34;391&#34; height=&#34;499&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;78&#34; data-flex-basis=&#34;188px&#34;&gt;&lt;/a&gt;

&lt;strong&gt;BLPOP和BRPOP命令常用于实现消息队列的功能，例如生产者将消息推送到列表中，消费者从列表中弹出消息进行处理。如果消费者在等待期间没有收到消息，可以设置一个超时时间来避免无限等待。&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;set类型&#34;&gt;Set类型
&lt;/h2&gt;&lt;p&gt;Redis的Set类型是一种无序集合，类似于C++中的std::unordered_set，可以看作是一个value为null的Hash类型。因为也是一个hash表，所以具备与Hash类型相似的特征：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Set类型的元素是无序的，不能通过索引访问&lt;/li&gt;
&lt;li&gt;Set类型的元素是唯一的，不能重复&lt;/li&gt;
&lt;li&gt;Set类型的元素可以在集合中添加或删除&lt;/li&gt;
&lt;li&gt;查询速度快，适合于需要频繁查询的场景，例如标签系统、好友关系等。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Set类型的常用命令有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;SADD key member1 member2 ...&lt;/code&gt;：将一个或多个成员添加到集合key中，如果key不存在，则创建一个新的集合；如果key存在但不是集合类型，则返回错误&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;SREM key member1 member2 ...&lt;/code&gt;：从集合key中移除一个或多个成员，如果key不存在或成员不存在，则不做任何操作&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;SCARD key&lt;/code&gt;：获取集合key中成员的数量，如果key不存在，则返回0
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/SADD_SREM_SCARD.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/SADD_SREM_SCARD.png&#34; alt=&#34;SADD、SREM、SCARD命令用法&#34; width=&#34;396&#34; height=&#34;250&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;158&#34; data-flex-basis=&#34;380px&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;SISMEMBER key member&lt;/code&gt;：检查集合key中是否存在成员，如果key不存在或成员不存在，则返回0；如果存在，则返回1&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;SMEMBERS key&lt;/code&gt;：获取集合key中所有成员的值，如果key不存在，则返回nil
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/SISMEMBER_SMEMBERS.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/SISMEMBER_SMEMBERS.png&#34; alt=&#34;SISMEMBER、SMEMBERS命令用法&#34; width=&#34;406&#34; height=&#34;219&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;185&#34; data-flex-basis=&#34;444px&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;SINTER key1 key2 ...&lt;/code&gt;：获取一个或多个集合key的交集，如果key不存在，则返回nil；如果key存在但不是集合类型，则返回错误&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;SUNION key1 key2 ...&lt;/code&gt;：获取一个或多个集合key的并集，如果key不存在，则返回nil；如果key存在但不是集合类型，则返回错误&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;SDIFF key1 key2 ...&lt;/code&gt;：获取一个或多个集合key的差集，如果key不存在，则返回nil；如果key存在但不是集合类型，则返回错误
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/SINTER_SUNION_SDIFF.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/SINTER_SUNION_SDIFF.png&#34; alt=&#34;SINTER、SUNION、SDIFF命令用法&#34; width=&#34;489&#34; height=&#34;534&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;91&#34; data-flex-basis=&#34;219px&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;sorted-set类型&#34;&gt;Sorted Set类型
&lt;/h2&gt;&lt;p&gt;Redis的SortedSet类型是一个可排序的set几何，与C++中的std::set类似，但底层数据结构却差别很大。SortedSet中的每一个元素都带有一个分数（score），Redis会根据分数来对元素进行排序。底层实现是一个跳表（skip list），&lt;strong&gt;跳表是一种基于链表的数据结构，通过增加多级索引来提高查询效率&lt;/strong&gt;。SortedSet具备以下特性：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SortedSet类型的元素是有序的，可以通过索引访问&lt;/li&gt;
&lt;li&gt;SortedSet类型的元素是唯一的，不能重复&lt;/li&gt;
&lt;li&gt;SortedSet类型的元素可以在集合中添加或删除&lt;/li&gt;
&lt;li&gt;查询速度快，适合于需要频繁查询的场景，例如排行榜、社交网络等。
因为SortedSet的可排序特性，经常被用来实现排行榜这样的功能。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;SortedSet类型的常用命令有：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ZADD key score1 member1 [score2 member2 ...]&lt;/code&gt;：将一个或多个成员添加到有序集合key中，并为每个成员设置分数，如果key不存在，则创建一个新的有序集合；如果key存在但不是有序集合类型，则返回错误；如果成员已经存在，则更新其分数&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ZREM key member1 member2 ...&lt;/code&gt;：从有序集合key中移除一个或多个成员，如果key不存在或成员不存在，则不做任何操作&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ZSCORE key member&lt;/code&gt;：获取有序集合key中成员的分数，如果key不存在或成员不存在，则返回nil
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/ZADD_ZREM_ZSCORE.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/ZADD_ZREM_ZSCORE.png&#34; alt=&#34;ZADD、ZREM、ZSCORE命令用法&#34; width=&#34;442&#34; height=&#34;630&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;70&#34; data-flex-basis=&#34;168px&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ZRANK key member&lt;/code&gt;：获取有序集合key中成员的排名，排名从0开始，如果key不存在或成员不存在，则返回nil&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ZREVRANK key member&lt;/code&gt;：获取有序集合key中成员的反向排名，排名从0开始，如果key不存在或成员不存在，则返回nil&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ZCARD key&lt;/code&gt;：获取有序集合key中成员的数量，如果key不存在，则返回0
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/ZRANK_ZREVRANK_ZCARD.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/ZRANK_ZREVRANK_ZCARD.png&#34; alt=&#34;ZRANK、ZREVRANK、ZCARD命令用法&#34; width=&#34;401&#34; height=&#34;241&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;166&#34; data-flex-basis=&#34;399px&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ZCOUNT key min max&lt;/code&gt;：获取有序集合key中分数在min和max之间的成员数量，如果key不存在，则返回0；如果key存在但不是有序集合类型，则返回错误&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ZINCRBY key increment member&lt;/code&gt;：将有序集合key中成员的分数增加increment，如果key不存在，则先创建一个新的有序集合；如果成员不存在，则先将其设置为0；如果成员的分数不是一个数字，则返回错误
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/ZCOUNT_ZINCRBY.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/ZCOUNT_ZINCRBY.png&#34; alt=&#34;ZCOUNT、ZINCRBY命令用法&#34; width=&#34;403&#34; height=&#34;500&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;80&#34; data-flex-basis=&#34;193px&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ZRANGE key start stop [WITHSCORES]&lt;/code&gt;：获取有序集合key中指定范围内的成员，start和stop都是索引，索引从0开始，负数表示从集合尾部开始计算，例如-1表示最后一个成员，-2表示倒数第二个成员，以此类推。如果key不存在，则返回nil；如果start或stop超出范围，则返回空列表；如果指定了WITHSCORES选项，则返回成员和分数的列表&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ZREVRANGE key start stop [WITHSCORES]&lt;/code&gt;：获取有序集合key中指定范围内的成员，start和stop都是索引，索引从0开始，负数表示从集合尾部开始计算，例如-1表示最后一个成员，-2表示倒数第二个成员，以此类推。如果key不存在，则返回nil；如果start或stop超出范围，则返回空列表；如果指定了WITHSCORES选项，则返回成员和分数的列表&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ZRANGEBYSCORE key min max [WITHSCORES]&lt;/code&gt;：获取有序集合key中分数在min和max之间的成员，如果key不存在，则返回nil；如果key存在但不是有序集合类型，则返回错误；如果指定了WITHSCORES选项，则返回成员和分数的列表
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/ZRANGE_ZREVRANGE_ZRANGEBYSCORE.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/ZRANGE_ZREVRANGE_ZRANGEBYSCORE.png&#34; alt=&#34;ZRANGE、ZREVRANGE、ZRANGEBYSCORE命令用法&#34; width=&#34;514&#34; height=&#34;382&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;134&#34; data-flex-basis=&#34;322px&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ZINTER key numkeys key1 key2 ...&lt;/code&gt;：获取一个或多个有序集合key的交集，如果key不存在，则返回nil；如果key存在但不是有序集合类型，则返回错误；如果指定了WITHSCORES选项，则返回成员和分数的列表&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ZUNION key numkeys key1 key2 ...&lt;/code&gt;：获取一个或多个有序集合key的并集，如果key不存在，则返回nil；如果key存在但不是有序集合类型，则返回错误；如果指定了WITHSCORES选项，则返回成员和分数的列表&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ZDIFF key numkeys key1 key2 ...&lt;/code&gt;：获取一个或多个有序集合key的差集，如果key不存在，则返回nil；如果key存在但不是有序集合类型，则返回错误；如果指定了WITHSCORES选项，则返回成员和分数的列表
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/ZINTER_ZUNION_ZDIFF.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/ZINTER_ZUNION_ZDIFF.png&#34; alt=&#34;ZINTER、ZUNION、ZDIFF命令用法&#34; width=&#34;464&#34; height=&#34;857&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;54&#34; data-flex-basis=&#34;129px&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ZINTERSTORE destination numkeys key1 key2 ...&lt;/code&gt;：计算一个或多个有序集合key的交集，并将结果存储在destination中，如果destination已经存在，则覆盖原来的值；如果key不存在，则返回nil；如果key存在但不是有序集合类型，则返回错误&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ZUNIONSTORE destination numkeys key1 key2 ...&lt;/code&gt;：计算一个或多个有序集合key的并集，并将结果存储在destination中，如果destination已经存在，则覆盖原来的值；如果key不存在，则返回nil；如果key存在但不是有序集合类型，则返回错误&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;ZDIFFSTORE destination numkeys key1 key2 ...&lt;/code&gt;：计算一个或多个有序集合key的差集，并将结果存储在destination中，如果destination已经存在，则覆盖原来的值；如果key不存在，则返回nil；如果key存在但不是有序集合类型，则返回错误
&lt;a href=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/ZINTERSTORE_ZUNIONSTORE_ZDIFFSTORE.png&#34; target=&#34;_blank&#34; rel=&#34;noopener noreferrer&#34;&gt;&lt;img src=&#34;https://SymphonyW.github.io/zh-cn/p/redis%E5%9F%BA%E7%A1%80%E5%AD%A6%E4%B9%A0%E6%96%87%E6%A1%A3/ZINTERSTORE_ZUNIONSTORE_ZDIFFSTORE.png&#34; alt=&#34;ZINTERSTORE、ZUNIONSTORE、ZDIFFSTORE命令用法&#34; width=&#34;557&#34; height=&#34;956&#34; loading=&#34;lazy&#34; decoding=&#34;async&#34; class=&#34;gallery-image&#34; data-flex-grow=&#34;58&#34; data-flex-basis=&#34;139px&#34;&gt;&lt;/a&gt;
&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</description>
        </item>
        
    </channel>
</rss>
