数据系统

数据库、缓存与消息系统。

专题分组

下级分类

2 个下级
redis-发布与订阅机制-1
数据库与缓存
14 分钟

redis-发布与订阅机制-1

这篇笔记聚焦 Redis Pub/Sub 的发布订阅机制,核心定位是低延迟广播而非队列消费:发布者把消息写入 Channel,Redis 通过 SUBSCRIBE、PSUBSCRIBE 建立的订阅关系,将消息推送给所有当前在线的订阅连接。正文用 live_room:123 这类房间频道说明了订阅、发布、接收、取消订阅以及 PUBSUB 查询命令的基本用法,并给出 FastAPI 多进程房间广播示例:各节点订阅 live_room:*,收到消息后解析频道中的房间号,再调用本地 WebSocket 广播函数。文章特别强调每个订阅者在 Redis 端都是独立 TCP 长连接,发布时 Redis 执行 Fan-out,遍历同一频道下所有活跃连接并各发送一份完整消息,因此它不是“谁抢到谁处理”的负载均衡模型。需要注意的是,Pub/Sub 不持久化消息,也没有 ACK、重试、死信队列或回放能力,订阅连接断开、阻塞或不可读时就可能丢失该连接上的消息。文末将它与 RabbitMQ/Kafka 的队列、Topic 和消费者组机制对比,给出选型边界:在线聊天、游戏广播、房间通知等可容忍丢失的中小规模实时场景适合 Redis Pub/Sub;若要求可靠投递、复杂路由、审计回溯或海量吞吐,则应使用专业 MQ。

数据库与缓存
10 分钟

mysql错误码 2013 解决方案

这篇笔记聚焦脚本长时间持续写入 MySQL 时出现的 2013 错误,即客户端已建立连接并发起 SQL 后,在查询执行过程中与服务端断开。正文先梳理常见诱因,包括慢 SQL 超过 net_read_timeout 或 net_write_timeout、网络或容器中断、MySQL 被重启或 kill、连接池复用失效连接,以及空闲连接被 wait_timeout、interactive_timeout 回收。作者进一步指出自己的场景并非典型慢查询或服务端异常,而是纯 SQL 脚本中每个函数都手动 connect 和 close,导致连接建立、认证、释放过于频繁,可能触发连接数压力、连接未就绪即查询、或查询尚未结束就关闭连接等问题。解决方案采用全局 DBManager 管理单例 SyncMySQLSDK 连接,通过 get_dsn_sdk 按需创建并复用连接,避免在大量函数签名中补传 session,降低改造和测试成本。管理器还提供 check_and_release 按空闲时间释放连接、force_release_all 在脚本退出时强制清理,并用 threading.Lock 保护多线程场景下的连接状态。该方案适合爬取、报表、批处理等长时间运行且频繁读写数据库的脚本,可减少连接抖动和资源消耗,但仍应结合超时配置、慢查询、服务端稳定性与网络状态一起排查。

数据库与缓存
9 分钟

乐观锁和悲观锁

这篇笔记梳理了悲观锁与乐观锁两类并发控制策略,重点放在数据库业务中“先读后改”时如何避免数据被并发覆盖、重复扣减或状态错乱。悲观锁的核心是假设冲突一定会发生,需要在事务内先通过 SELECT ... FOR UPDATE 查询并锁定记录,再由应用层完成余额、库存、订单状态等判断和更新,直到提交或回滚前其他事务不能修改该行。它适合库存扣减、积分余额变更、任务领取、名额抢占、订单状态流转等写冲突高且强一致要求明确的场景,但代价是锁等待、死锁风险和更高的数据库压力。乐观锁则默认冲突较少,不在读取时加锁,而是在提交更新时用 version 或 updated_at 等字段校验数据是否仍是读取时的版本,若 UPDATE 影响行数为 0,就说明发生冲突,需要失败提示或重试。文章特别强调前端或调用方必须把读取到的 version 一并提交,否则后端无法判断并发修改;如果只能由后端再查版本,会增加一次数据库 IO,也削弱乐观锁的优势。版本字段选择上,int 自增最常用且 SQL 简单高效,timestamp 可读但可能受精度影响,uuid 虽不可猜但更新逻辑复杂,一般不适合作为版本号。整体内容适合后端开发者在配置管理、内容编辑、用户资料修改、非关键订单更新等读多写少场景中选择乐观锁,也能帮助判断何时应为金融、电商、调度类关键数据改用悲观锁。

数据库与缓存
11 分钟

mysql中的锁

这篇笔记梳理 MySQL 在并发读写中的锁机制,先从锁的目的切入,说明它用于保障多用户访问时的数据一致性与完整性,并区分表锁、行锁、页锁等物理层锁,以及乐观锁、悲观锁这类通常由业务或事务语句体现的控制方式。内容重点放在 InnoDB 与 MyISAM 的差异:MyISAM 更常见表级锁,而 InnoDB 默认支持行级锁,UPDATE、DELETE 按索引命中目标行时通常只加排他行锁,INSERT 一般也不会阻塞已有数据。文章提醒,行锁并不等于永远只锁一行,如果 WHERE 条件没有使用索引或无法命中索引,InnoDB 可能出现范围锁、间隙锁,甚至表现得接近表级阻塞,这是排查更新慢和并发冲突时的重要线索。它还解释了 SELECT FOR UPDATE、显式事务与自动提交的关系:即使没有手写 BEGIN,单条 UPDATE 也会在 InnoDB 内部以隐式事务执行,语句完成后自动提交并释放锁,所以很多场景下不容易观察到阻塞。后半部分聚焦 ALTER TABLE、增删字段、同步建索引等 DDL 操作,说明这类操作需要表级排他访问,会等待已有事务释放相关锁,并可能阻塞后续 SELECT、UPDATE、INSERT、DELETE。对于后端开发和运维人员,这篇笔记的价值在于建立一套判断加锁范围、锁释放时机和 DDL 卡住原因的基础框架,并给出生产环境避开高峰、考虑 pt-online-schema-change 或 gh-ost 等在线 DDL 工具的实践提醒。

数据库与缓存
10 分钟

数据库预热-介绍

这篇笔记围绕 FastAPI 等 Web 服务的数据库预热展开,核心问题是应用启动后即使配置了 SQLAlchemy、asyncpg 等连接池,首个真实请求仍可能因为懒加载连接、TCP/TLS 握手、认证和首次轻量查询而明显变慢。正文把预热定义为在启动阶段主动建立数据库连接或执行 `SELECT 1` 之类的轻量 SQL,使连接池中提前拥有可复用连接,从而降低对外 API、性能敏感服务的首请求延迟。连接机制部分梳理了 PostgreSQL 从 TCP 端口连接、StartupMessage、SSLRequest、TLS 协商到用户名密码认证的流程,并强调 TLS 握手只发生在新连接建立时,连接池维护的持久 TCP/TLS 连接在未超时或关闭前可以反复复用。文章还提到 pgbouncer、asyncpg + SQLAlchemy 内建连接池和 OS 层 keepalive 等方案,用于在不同层面减少重复建连和连接过早断开的问题。实践部分给出在 FastAPI `lifespan` 钩子中创建 `AsyncSessionLocal` 并执行 `SELECT 1` 的写法,启动时记录预热结果,退出时通过 `engine.dispose()` 释放连接池。需要注意的是,`yield` 之后的清理逻辑只在 Ctrl+C 或 `kill -TERM` 等优雅退出场景可靠执行,热重载、崩溃或强制终止通常不会触发关闭流程;这篇内容适合后端开发者和运维人员理解首请求变慢的来源,并为服务启动、健康检查和连接池配置提供操作依据。

数据库与缓存
14 分钟

主键id设计

围绕数据库主键 ID 的选型,内容从自增 ID、传统 UUID、雪花算法和 UUIDv7 四类方案展开,重点放在唯一性、顺序性、分布式适配和索引写入性能的取舍上。自增 ID 在单库单实例中简单、可读、范围查询友好,但会暴露业务增长、存在中心化生成瓶颈,并不适合多节点高并发场景。文章解释了聚簇索引和 B+Tree 的存储特性:主键顺序会影响数据物理组织,随机 UUID 作为主键容易造成页分裂、碎片化和更大的索引体积,因此更适合作为业务唯一标识而非数据库主键。雪花算法通过时间戳、机器 ID 和序列号组合实现趋势递增与高并发生成,但需要处理机器时钟回拨、节点配置和生命周期限制。UUIDv7 被作为重点方案分析,它用 48 bit 毫秒时间戳作为前缀,后缀保留随机熵,在保持标准 UUID 128 bit 格式和全局唯一性的同时,让插入更接近顺序写入,尤其适合 PostgreSQL 原生 uuid 类型存储。需要注意的是,同一毫秒内 UUIDv7 仍可能发生局部乱序,但影响通常远小于 UUIDv4;如果业务需要精确按时间筛选或频繁使用时间条件,仍建议保留 create_time 字段及索引。整体适合后端开发和数据库设计人员在单库、分布式、高并发写入等不同场景下评估主键策略。

数据库与缓存
16 分钟

elasticsearch简单使用

这篇笔记面向 Elasticsearch 入门实践,围绕本地开发环境搭建、核心存储概念和中文检索示例展开。正文先给出基于 Docker 的 Elasticsearch 8.0.0 启动方式,说明 9200 REST API 端口、9300 节点通信端口、single-node 单节点模式以及关闭 xpack 安全验证的用途,并补充 Kibana 8.0.0 的安装和 5601 可视化访问入口。概念部分用 MySQL 作类比解释 index、document、field、mapping 的关系,强调 Elasticsearch 是面向文档的 NoSQL 数据库,文档以 JSON 存储,字段结构可以灵活变化,但业务上仍应让同一索引保存同类数据。文章还列出常见字段类型,包括 text、keyword、integer、date、boolean 等,并指出动态映射虽然方便,但手机号等关键字段若被默认识别为 text 可能不符合预期,因此需要提前通过 mapping 指定类型。示例部分创建 books 索引,配置 title、content 使用 standard 分词器、price 使用 integer,随后写入书籍文档,并通过 match 查询和 _analyze API 查看字段分词结果。最后,笔记指出标准分词器对中文通常只能得到较粗或不理想的效果,因此演示在 Docker 容器内安装 analysis-ik 插件、重启验证插件列表,并创建使用 ik_smart 的索引来改善中文文本检索体验。

Redis简单的消息队列
数据库与缓存
14 分钟

Redis简单的消息队列

这篇笔记围绕用 Redis 列表实现一个轻量级消息队列展开,适合在不想引入 RabbitMQ、Kafka 等完整 MQ 组件时,用现有 Redis 承担简单异步任务分发。正文先补充 Redis 的基础定位:它是跨平台的 key-value 非关系型数据库,支持字符串、哈希、列表、集合、有序集合、Pub/Sub、Streams 等数据类型,并具备高性能、原子操作、持久化、主从复制和 Lua 脚本等能力。队列部分的关键在于利用 list 结构和阻塞弹出命令,生产者通过 Python 异步客户端将包含 answer_id、answer_data 的 JSON 任务 rpush 到队列,消费者则在 while True 循环中使用 blpop 阻塞等待任务、解析数据、调用 AI 生成逻辑并更新记录。文章还展示了一个基于 redis.asyncio、Django settings.REDIS_URL 和 asynccontextmanager 封装的 RedisClient,用于管理连接创建、复用和关闭。需要注意的是,这种方案需要自行编写并维护生产者、消费者、异常处理和进程运行方式,示例中生产者写入的 ai_report_task_queue 与消费者监听的 queue 并不一致,实际使用时必须统一队列名。读者可以从中获得 Redis 列表队列的最小实现思路,以及在简单后台任务、异步报告生成等场景下快速落地的基本代码结构。

rocketmq基本概念
消息队列
16 分钟

rocketmq基本概念

这份笔记系统梳理 RocketMQ 的基础消息模型,先从 NameServer、Broker、Producer、Consumer 的分工讲起,说明 NameServer 只负责 Topic 到 Broker 的路由发现,真正的消息接收、磁盘存储与转发由 Broker 完成。文章重点拆解 Broker 内部组件,包括追加写入消息的 CommitLog、按 Topic-Queue 建索引的 ConsumeQueue、按 Key 查询历史消息的 IndexFile,以及刷盘检查点、主从同步和网络请求处理等配套能力。核心术语部分覆盖 Topic、MessageQueue、Queue ID、Offset、Tag、Key 等概念,帮助读者理解消息如何被路由、过滤、定位和记录消费进度。消息模式部分进一步区分 Pull 与基于长轮询的 Push 体验,并说明顺序消息需要将同一业务 Key 路由到同一队列且串行消费,而并行消费依赖多队列提升吞吐但不保证全局顺序。对于事务消息和延迟消息,文章给出半消息、本地事务回查、delayTimeLevel、延迟队列再投递等实现思路,同时提示延迟精度受预设级别限制。最后围绕消费可靠性解释重试次数、死信队列和 ACK 返回状态的关系,强调取到消息不等于消费成功,只有返回 CONSUME_SUCCESS 才会推进消费进度,异常或 RECONSUME_LATER 会触发重试直至进入 DLQ,适合后端开发者建立 RocketMQ 入门认知和排障框架。

rocketmq 配置环境[python]
消息队列
9 分钟

rocketmq 配置环境[python]

这是一份面向 M1 Mac 本地用 Python 接入 RocketMQ 的环境配置与排错记录,核心问题是 rocketmq-client-python 依赖 RocketMQ C/C++ 动态库,而 Apache 官方 Darwin 包只提供 x86_64 版本,无法直接被原生 arm64 Python 加载。配置流程包括下载 rocketmq-client-cpp 2.0.0 的 darwin 压缩包,将头文件和 librocketmq.dylib 安装到 /usr/local/include/rocketmq 与 /usr/local/lib,并用 install_name_tool 修正动态库 ID,再通过 DYLD_LIBRARY_PATH 让 Python 能找到该 dylib。针对 M1 上常见的 incompatible architecture 报错,文章给出使用 Rosetta 启动 iTerm,并创建 CONDA_SUBDIR=osx-64 的 conda Python 3.10 环境来安装 rocketmq-client-python 的做法,验证重点是 platform.machine() 返回 x86_64 且能够导入 Producer。后半部分补充腾讯云 RocketMQ 的差异:NameServer 使用云厂商提供的专属地址,Topic 和 Group 必须先在控制台创建、授权,不支持像自建 Apache RocketMQ 那样自动创建 Topic。对于 No route info of this topic,排查路径集中在确认公网/私网地址是否匹配本地开发场景、Topic 队列是否正确绑定到当前集群 Broker、发送测试消息刷新 NameServer 路由缓存,以及用 telnet、ping 验证网络连通性。适合在 macOS Apple Silicon 上调试 RocketMQ Python SDK、同时接入腾讯云 RocketMQ 的后端开发者参考,尤其是需要区分架构兼容、动态库加载和云端路由配置三类问题时。