0%

Redis 命令解析流程:以 SET 命令为例

Redis 对命令的解析和执行是其核心功能之一,涉及协议解析、参数处理、命令路由等多个环节。本文以 SET 命令为例,详细解析 Redis 如何接收、解析并执行命令。

命令解析的整体流程

Redis 处理客户端命令的流程可概括为:
接收命令数据 → 协议解析 → 填充 client 结构体 → 路由到对应命令函数 → 执行命令 → 返回结果

其中,client 结构体是贯穿全程的核心载体,记录了命令的参数、客户端状态、连接信息等关键数据。

client 结构体:命令解析的核心载体

client 结构体是 Redis 描述客户端连接和命令请求的核心数据结构,与命令解析相关的关键字段如下:

字段名 作用
argc 命令参数的数量(包含命令名本身)。例如 SET key value 中,argc=3
argv 命令参数数组(robj* 类型,robj 是 Redis 通用对象结构)。argv[0] 为命令名(如 "SET"),argv[1...] 为命令参数(如 "key""value")。
querybuf 接收客户端命令的缓冲区(sds 类型,动态字符串),存储未解析的原始命令数据。
qb_pos querybuf 中已解析的位置,用于增量解析命令。
cmd 指向当前执行的命令结构体(redisCommand 类型),包含命令的处理函数、参数个数限制等元信息。

SET 命令解析:从代码看细节

setCommand 函数为例,解析 Redis 如何处理 SET 命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void setCommand(client *c) {
robj *expire = NULL; // 过期时间对象(如 EX 30 中的 30)
int unit = UNIT_SECONDS; // 时间单位(秒/毫秒,默认秒)
int flags = OBJ_NO_FLAGS; // 命令标志(如 NX、XX 等选项)

// 解析扩展参数(如 EX、PX、NX、XX 等)
if (parseExtendedStringArgumentsOrReply(c,&flags,&unit,&expire,COMMAND_SET) != C_OK) {
return; // 解析失败,返回错误
}

// 对 value 进行编码优化(如转为整数编码,节省内存)
c->argv[2] = tryObjectEncoding(c->argv[2]);

// 调用通用设置函数执行核心逻辑
setGenericCommand(c,flags,c->argv[1],c->argv[2],expire,unit,NULL,NULL);
}

步骤 1:解析扩展参数(parseExtendedStringArgumentsOrReply

SET 命令支持丰富的扩展选项(如 SET key value EX 30 NX),该函数的作用是解析这些选项:

阅读全文 »

Servlet 接口详解:Java Web 开发的基石

Servlet 是 Java Web 技术的核心组件,负责处理客户端请求并生成动态响应。它由 Servlet 容器管理,遵循标准化的生命周期,是构建 Java Web 应用的基础。本文将从 Servlet 的核心概念、接口方法、生命周期、配置方式及相关对象等方面,全面解析 Servlet 技术。

Servlet 与 Servlet 容器

1. 什么是 Servlet?

Servlet 是运行在 Web 服务器中的 Java 类,用于处理客户端(如浏览器)的 HTTP 请求并生成动态内容。它具有以下特点:

  • 平台无关:基于 Java 技术,可在任何支持 Java 的 Web 服务器上运行;
  • 由容器管理:生命周期(创建、初始化、服务、销毁)完全由 Servlet 容器控制;
  • 动态内容生成:通过接收请求参数、访问数据库等方式,生成个性化响应。

2. 什么是 Servlet 容器?

Servlet 容器是 Web 服务器(如 Tomcat、Jetty)的一部分,负责与 Servlet 交互并管理其生命周期。其核心功能包括:

  • 加载和实例化 Servlet 类;
  • 调用 Servlet 的生命周期方法(initservicedestroy);
  • 处理 HTTP 请求与响应的封装(将底层 TCP 数据转换为 HttpServletRequest/HttpServletResponse 对象);
  • 管理 Servlet 之间的共享资源(如 ServletContext)。

Servlet 接口核心方法

javax.servlet.Servlet 接口定义了 Servlet 与容器交互的标准协议,包含 5 个核心方法:

阅读全文 »

Nginx 日志配置详解:访问日志、错误日志与日志切割

Nginx 的日志系统是监控服务状态、排查问题的核心工具,主要分为访问日志(access_log)错误日志(error_log)。本文详细讲解日志的配置方法、格式自定义、级别设置及日志切割方案,帮助高效管理日志数据。

访问日志(access_log):记录客户端请求细节

访问日志用于记录客户端的每一次请求,包括请求来源、路径、响应状态等信息,是分析用户行为、排查接口问题的关键依据。

基础配置语法

1
2
3
4
5
6
7
8
9
10
# 完整语法(可省略可选参数)
access_log path [format [buffer=size] [gzip=level] [flush=time] [if=condition]];

# 示例:在server块中启用访问日志
server {
listen 80;
server_name example.com;
# 日志路径为/var/log/nginx/example.access.log,使用main格式
access_log /var/log/nginx/example.access.log main;
}

参数说明

  • path:日志文件路径(必填),如/var/log/nginx/access.log
  • format:日志格式名称(需通过log_format定义,默认使用combined格式);
  • buffer=size:日志写入缓存大小(默认 64k),减少磁盘 IO 次数;
  • gzip=level:日志写入前压缩(1-9 级,级别越高压缩率越高但速度越慢);
  • flush=time:缓存过期时间(如5s),超时后强制写入磁盘;
  • if=condition:条件判断(如if=$request_method=POST),满足条件才写入日志。

自定义日志格式(log_format)

通过log_format可定义个性化日志格式,灵活记录所需字段。语法如下:

阅读全文 »

MySQL 操作日志查看与数据恢复:从日志分析到误操作修复

当遇到数据不一致、疑似误删等问题时,MySQL 的二进制日志(binlog)是关键的排查与恢复依据。本文详细介绍如何通过 binlog 查看操作记录、定位误操作,并通过日志进行数据恢复。

二进制日志(binlog)的基本概念

二进制日志(binlog)是 MySQL 记录所有数据变更操作INSERT/UPDATE/DELETECREATE/ALTER 等)的日志文件,不记录查询操作(SELECT)。其核心作用包括:

  • 主从复制(Slave 通过 binlog 同步 Master 数据)。
  • 数据恢复(通过回放 binlog 恢复误操作前的状态)。
  • 审计追踪(记录所有数据变更的时间、用户、操作内容)。

查看 binlog 相关配置

确认 binlog 是否开启

1
2
-- 查看 binlog 启用状态(ON 为开启,OFF 为关闭)
show variables like 'log_bin';

若未开启(log_bin = OFF),则无法通过 binlog 追溯操作,需在 my.cnf 中配置开启(重启生效):

1
2
3
[mysqld]
log_bin = mysql-bin # 日志文件名前缀(如 mysql-bin.000001)
server-id = 1 # 必须配置,主从复制和 binlog 依赖唯一 server-id

查看当前 binlog 信息

阅读全文 »

Log4j2 配置详解:从基础到实战的完整指南

Log4j2 作为主流的日志实现框架,以其高性能、灵活的配置和丰富的功能(如异步日志、动态配置)被广泛应用。其配置文件通过 XML、JSON 或 YAML 定义日志的输出目的地、格式、滚动策略等。本文基于 XML 配置格式,详细解析 Log4j2 的配置结构与核心功能。

Log4j2 配置文件基本结构

Log4j2 配置文件的根元素为<Configuration>,包含两大核心子元素:<Appenders>(日志输出目的地)和<Loggers>(日志器,控制日志流向)。基本结构如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?xml version="1.0" encoding="UTF-8"?>
<!-- status:Log4j2自身日志级别(如WARN,避免过多内部日志);monitorInterval:自动检测配置文件变更的间隔(秒) -->
<Configuration status="WARN" monitorInterval="30">
<!-- 日志输出目的地集合 -->
<Appenders>
<!-- 具体的Appender(如控制台、文件、滚动文件等) -->
<Appender name="控制台" ...>
<!-- 过滤器(可选) -->
<Filters>...</Filters>
<!-- 日志格式(必填) -->
<PatternLayout .../>
<!-- 滚动策略(仅滚动文件Appender需要) -->
<Policies>...</Policies>
<!-- 滚动规则(仅滚动文件Appender需要) -->
<DefaultRolloverStrategy .../>
</Appender>
</Appenders>

<!-- 日志器集合 -->
<Loggers>
<!-- 特定类/包的日志器 -->
<Logger name="com.example" level="INFO" additivity="false">
<AppenderRef ref="控制台"/> <!-- 关联Appender -->
</Logger>
<!-- 根日志器(默认日志器) -->
<Root level="INFO">
<AppenderRef ref="控制台"/>
</Root>
</Loggers>
</Configuration>

Appenders:日志输出目的地

<Appenders>定义日志的输出位置(如控制台、文件),每个<Appender>需指定name(唯一标识)和具体类型(如ConsoleFileRollingFile)。

阅读全文 »