0%

Redis Lua 脚本详解:原子性操作与高效执行

Redis 对 Lua 脚本的支持是其高级特性之一,通过将多个命令封装为脚本,可实现原子性执行减少网络往返开销,尤其适合复杂业务逻辑(如分布式锁、计数器累加等)。本文基于 Redis 6.0.10 版本,详解 Lua 脚本的使用方法、核心命令及最佳实践。

Lua 脚本在 Redis 中的价值

  1. 原子性保证:Lua 脚本在 Redis 中以单线程方式执行,执行期间不会被其他命令打断,确保多个命令的原子性(类似事务,但更灵活)。
  2. 减少网络开销:将多个命令合并为一个脚本,只需一次网络请求,降低延迟(尤其适用于跨机房部署)。
  3. 复用逻辑:脚本可被缓存,通过摘要(SHA1)重复调用,避免重复传输脚本内容。

Lua 基础:数据类型与语法

Redis 内嵌 Lua 解释器,支持 Lua 5.1 标准语法,核心数据类型如下:

类型 说明 示例
nil 空值(未赋值的变量默认为此类型)。 local aanil
字符串 单引号或双引号包裹,支持换行([[ 多行文本 ]])。 'hello'"redis"
数字 整数或浮点数(Lua 不区分 int 和 float)。 423.14
布尔值 truefalse(注意小写)。 local flag = true
表(table) 唯一复合类型,可表示数组、字典或对象(索引从 1 开始)。 {1, 2, 3}{name = "lua"}
函数 支持自定义函数,可作为参数或返回值。 local f = function(x) return x+1 end

核心命令:evalevalsha

eval:直接执行脚本

语法

1
eval script numkeys key1 [key2 ...] arg1 [arg2 ...]
  • script:Lua 脚本字符串。
  • numkeys:后续 key 参数的数量(必须为整数)。
  • key1...:Redis 键名,在脚本中通过 KEYS[1]KEYS[2] 访问(索引从 1 开始)。
  • arg1...:附加参数,在脚本中通过 ARGV[1]ARGV[2] 访问。

示例 1:简单脚本
返回键名和参数:

1
2
3
4
127.0.0.1:6379> eval "return {KEYS[1], KEYS[2], ARGV[1]}" 2 user:100 post:200 "hello"
1) "user:100"
2) "post:200"
3) "hello"
阅读全文 »

Lucene 中的段(Segment):增量索引与不可变设计的平衡

Lucene 的倒排索引一旦写入磁盘,其结构便难以修改(修改会导致大量磁盘 IO 和性能损耗)。为解决增量数据的索引问题,Lucene 引入了段(Segment) 的概念,通过 “多个不可变段的动态组合” 实现高效的增量索引和查询。

段的核心设计:不可变与增量并存

段的不可变性

  • 定义:每个段是一个独立的、完整的倒排索引片段,一旦写入磁盘,其数据和结构不可修改(只读)。
  • 优势:
    • 查询高效:不可变结构允许 Lucene 对段进行预优化(如倒排列表压缩、缓存热点数据),提升查询速度。
    • 线程安全:多个查询线程可同时读取同一网段,无需加锁,减少并发冲突。
    • 故障安全:段写入过程中若发生崩溃,仅需丢弃未完成的段,不影响已提交的段。

增量索引的实现

当有新文档需要索引时,Lucene 不会修改已有段,而是:

  1. 创建新段:新文档被写入新的临时段(先存于内存缓冲区)。
  2. 批量刷盘:当内存中的文档数量或时间达到阈值(如 index.max.bufferedDocsindex.flush.interval),临时段被批量写入磁盘,成为可查询的新段
  3. 逻辑组合:所有段通过 “提交点(Commit Point)” 被逻辑组合为一个完整索引,查询时 Lucene 会遍历所有段并合并结果。

示例

  • 初始索引包含段 S1(1000 文档)。
  • 新增 500 文档 → 生成新段 S2(500 文档),索引由 S1 + S2 组成。
  • 再新增 800 文档 → 生成新段 S3(800 文档),索引由 S1 + S2 + S3 组成。

段的合并:优化索引性能

随着增量索引的进行,段的数量会不断增加(如每次新增文档都生成新段),过多的段会导致:

阅读全文 »

Spring 引入外部属性文件的完整指南:从 XML 到注解配置

在 Spring 开发中,将数据库连接信息、API 密钥等配置项硬编码到配置文件中会导致维护困难(如切换环境时需修改大量配置)。通过引入外部属性文件(如 .properties.yml),可以实现 “配置与代码分离”,提升项目的可维护性。本文将详细讲解 Spring 引入外部属性文件的多种方式(XML 配置、注解配置)、底层原理及最佳实践。

外部属性文件的核心作用

外部属性文件(通常为 .properties 格式)用于存储键值对形式的配置信息,如:

1
2
3
4
5
# db.properties
db.url=jdbc:mysql://localhost:3306/test
db.username=root
db.password=123456
db.driver=com.mysql.cj.jdbc.Driver

引入外部属性文件的优势:

  1. 分离配置与代码:避免在 Spring 配置文件(XML / 注解)中硬编码环境相关信息;
  2. 多环境适配:不同环境(开发 / 测试 / 生产)可使用不同的属性文件,无需修改核心配置;
  3. 安全性:敏感信息(如密码)可单独管理,避免提交到代码仓库。

XML 配置方式:<context:property-placeholder>

这是传统 Spring 项目中引入外部属性文件的经典方式,通过 XML 标签 <context:property-placeholder> 实现。

1. 基本用法(单文件引入)

步骤 1:创建属性文件

src/main/resources 目录下创建 db.properties

阅读全文 »

MySQL 分区表:大规模数据的高效管理方案

MySQL 分区表是针对大表的一种优化方案,通过将表数据物理拆分到多个独立分区,实现数据的逻辑统一管理与物理分散存储。分区对应用透明(逻辑上仍是一张表),但能显著提升查询效率、简化数据维护。

分区表的核心概念

分区的本质

  • 逻辑统一性:应用访问分区表时,无需关心数据分布,SQL 语句与普通表一致。
  • 物理独立性:每个分区对应独立的数据文件(如 .ibd),可分布在不同磁盘,降低单文件大小限制。

分区的核心限制

  • 分区列约束:若表存在 PRIMARY KEYUNIQUE KEY,分区列必须是这些键的组成部分(确保数据唯一性可验证)。
  • 无全局索引:索引仅在分区内有效,跨分区查询需扫描所有相关分区。

分区类型及创建方式

MySQL 支持 4 种主要分区类型,适用于不同的数据分布场景:

RANGE 分区:按连续区间划分(最常用)

根据列值所在的连续区间分配数据,适合时间、ID 等有序数据(如按月份分区日志表)。

创建示例:
阅读全文 »