JACIN Blog

深度的 AI 应用开发者

专注 AI 应用开发、Python 后端与工程实践,持续记录大模型落地、工具构建与真实项目经验。

183篇已发布
主题索引
查看全部分类
全部文章
183
数据库与缓存
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 列表队列的最小实现思路,以及在简单后台任务、异步报告生成等场景下快速落地的基本代码结构。

Python 开发
19 分钟

Alembic使用

这篇笔记围绕 FastAPI 项目中使用 SQLAlchemy 异步 ORM 与 PostgreSQL 时如何接入 Alembic 做数据库迁移展开,先说明 Alembic 通过迁移脚本和数据库中的 alembic_version 表来记录结构变更,并依靠 upgrade、downgrade 支持版本升级与回滚。配置部分重点放在 alembic.ini 的 script_location、初始化后生成的 env.py、versions 目录以及数据库连接地址,其中 env.py 需要手动接入项目配置、Base.metadata 和异步引擎,才能让 autogenerate 正确比对模型变化。文章给出一份异步迁移示例:加载项目根路径、读取 settings.DATABASE_URL、动态导入所有 models、使用 create_async_engine 和 connection.run_sync 执行在线迁移,同时在离线模式下生成 SQL。针对 FastAPI 与 Django 共用数据库的场景,示例通过 include_object 排除 django_session、auth_user、django_migrations 等 Django 相关表,避免 Alembic 误管理不属于当前服务的表结构。数据库层还记录了 DATABASE_URL 的拼接方式、Base 的作用、异步 Session 工厂以及 pool_size、max_overflow、pool_timeout、pool_recycle 等连接池参数。迁移命令部分覆盖 PYTHONPATH 设置、revision --autogenerate、upgrade head、history、upgrade/downgrade 指定版本和 downgrade base,并特别提醒迁移文件版本必须与数据库 alembic_version 对齐,新库初始化时不要混用旧版本文件。最后补充多环境迁移隔离思路,可通过不同 alembic 配置文件或在 env.py 中读取环境变量来切换版本目录,适合正在为异步 FastAPI 服务建立可控数据库版本管理流程的后端开发者参考。

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 的后端开发者参考,尤其是需要区分架构兼容、动态库加载和云端路由配置三类问题时。

消息队列
1 分钟

关于“消息队列”类别

“消息队列”类别用于归档围绕消息中间件、异步通信和事件驱动协作展开的内容,重点承担站点内主题分流和检索定位的作用。该类别的说明强调,使用分类时应先判断文章是否真正讨论消息队列相关问题,而不是仅在业务流程中偶然出现消息发送或通知机制。其边界需要从使用理由、与既有分类的差异、常见话题范围以及是否应合并等维度来界定,以避免同一类内容分散到架构、后端开发或运维等相邻栏目中。适合纳入的内容通常应围绕消息队列的选型、使用场景、可靠性、消费模型、削峰解耦、配置实践或问题排查等方向展开。它的价值不在于给出某个具体队列产品的教程,而是为后续文章建立一致的归档准则,帮助作者和读者快速判断相关内容应放在哪里。对于维护技术知识库或博客分类体系的人来说,这类说明有助于减少重复分类、模糊归档和后期合并成本。

数据库与缓存
1 分钟

关于“数据库与缓存数据库”类别

“数据库与缓存数据库”类别用于沉淀与数据存储、缓存型数据系统及其使用边界相关的内容,其核心作用是为后续文章提供清晰的归类依据,而不只是作为一个宽泛标签存在。该类别强调分类准则:为什么需要单独收纳这类主题、它承担什么检索与组织功能,以及在已有分类之间如何避免交叉和重复。说明重点包括适用话题范围、与相邻类别的区别、是否应独立保留,以及在内容规模或主题重叠时是否可以合并为其他类别或子类别。对于博客维护者来说,它的价值在于帮助数据库和缓存相关笔记形成稳定的知识入口,使读者能更快判断文章是否属于数据层、存储层或缓存体系的讨论范围。该类别更适合作为内容架构和分类治理的依据,而不是具体数据库产品、配置教程或问题排查本身。

文章归档
183