从本篇文章开始(命名为Redis分析系列),将会通过分析Redis的源代码(以Redis 2.2.0 RC1为准),来对它的内部实现做一些探讨。本文主要介绍Redis启动加载过程,总体上可以分为如下几步:
1. 初始化全局服务器配置
2. 加载配置文件(如果指定了配置文件,否则使用默认配置)
3. 初始化服务器
4. 加载数据库
5. 网络监听
整个启动加载过程如下图所示:
下面对于上图中的各个步骤一些介绍,有些部分(如数据库加载、网络监听)会在后面单独用一篇文章详细说明。
初始化全局服务器配置
初始化全局服务器配置通过initServerConfig()函数完成,主要是初始化server变量,它是一个redisServer的结构类型:
struct redisServer server;
初始化的内容包括下面几个方面:
1. 网络监听相关,如绑定地址,TCP端口等
2. 虚拟内存相关,如swap文件、page大小等
3. 保存机制,多长时间内有多少次更新才进行保存
4. 复制相关,如是否是slave,master地址、端口
5. Hash相关设置
6. 初始化命令表
如其中的保存机制中,服务器初始化策略为:
// 1小时内1次更新
appendServerSaveParams(60*60,1);
// 5分钟内100次更新
appendServerSaveParams(300,100);
// 1分钟内10000次更新
appendServerSaveParams(60,10000);
如果在启动服务器时,指定了配置文件,则会在下面的“加载配置文件”步骤中,根据配置文件内容,更改其中的某些服务器配置。
加载配置文件
如果指定了配置文件,Redis使用loadServerConfig()函数加载配置文件,整个过程没什么可以说的,无非是使用标准I/O库打开配置文件,循环读取每一行然后覆盖上一步进行的默认配置。
这里有一点需要注意的是,下载Redis后代码包中有一个默认配置文件,如果启动Redis服务器时,不指定配置文件,Redis不会使用这个默认文件的配置,而是使用上一步“初始化全局服务器配置”中的配置。在默认配置文件中提供的配置项与上一步默认初始化的配置有些事不一样的,所以如果没有指定配置文件,千万不能认为Redis的行为会按照默认配置文件进行,最典型的一个例子,在默认配置文件中的数据保存策略是:
# 15分钟内1次更新
save 900 1
# 5分钟内100次更新
save 300 10
# 1分钟内10000次更新
save 60 10000
而默认初始化的全局配置中数据保存策略:
// 1小时内1次更新
appendServerSaveParams(60*60,1);
// 5分钟内100次更新
appendServerSaveParams(300,100);
// 1分钟内10000次更新
appendServerSaveParams(60,10000);
初始化服务器
初始化服务器的工作在initServer()函数中,主要是完成前面未完成的工作,继续对server变量初始化,如设置信号处理、创建clients、slaves列表,创建Pub/Sub通道列表,同时还会创建共享对象:
shared.crlf = createObject(REDIS_STRING,sdsnew("\r\n"));
shared.ok = createObject(REDIS_STRING,sdsnew("+OK\r\n"));
shared.err = createObject(REDIS_STRING,sdsnew("-ERR\r\n"));
shared.emptybulk = createObject(REDIS_STRING,sdsnew("$0\r\n\r\n"));
最后,如果启用了虚拟内存机制,还需要初始化虚拟内存相关,如Thread I/O等。
加载数据库
在完成了上面的所有的初始化工作之后,Redis开始加载数据到内存中,如果启用了appendonly了(不知道这个参数做什么的,请先看配置文件篇),则Redis从appendfile加载数据,否则就从dbfile加载数据。
1. 从appendfile中加载数据:loadAppendOnlyFile()函数
在此之前,我们先来看一下appendfile里面保存了什么,如我执行了下面两条命令(记得在配置文件中开启appendonly):
redis> SET mykey001 myvalue001
OK
redis> GET mykey001
"myvalue001"
使用cat命令查看appendonly.aof文件内容:
$ cat appendonly.aof
*2
$6
SELECT
$1
0
*3
$3
SET
$8
mykey001
$10
myvalue001
嗯,相信大家都能看明白(看不明白的请先看这篇文章),在appendonly.aof文件中保存的正是从客户端发过来的请求命令,还可以看到对于GET命令,并没有保存。既然appendonly.aof中保存了所有写入数据的请求命令,那么在加载数据的时候只要重新执行一遍这些命令即可。
事实上Redis也正是这么做的,在开始加载之前暂时关闭appendonly,然后Redis创建一个假的Redis客户端:
server.appendonly = 0;
fakeClient = createFakeClient();
startLoading(fp);
然后读取appendonly.aof文件中的命令,在假的Redis客户端上下文中执行,同时服务器也不对该客户端做任何应答:
fakeClient->argc = argc;
fakeClient->argv = argv;
cmd->proc(fakeClient);
/* The fake client should not have a reply */
redisAssert(fakeClient->bufpos == 0 && listLength(fakeClient->reply) == 0);
如果加载过程中物理内存不够用,并且Redis开启了VM,则还需要处理swap操作,最后加载完成后重新设置appendonly标志。
2. 从dbfile中加载数据:rdbLoad()函数
如果Redis没有开启appendonly,就需要从数据库文件中加载数据到内存,基本步骤如下:
a. 处理SELECT命令,即选择数据库
b. 读取key
c. 读取value
d. 检测key是否过期
e. 添加新的对象到哈希表
f. 设置过期时间(如果需要)
g. 如果开启了VM,处理swap操作
网络监听
在完成了初始化配置和数据加载后,Redis启动监听。Redis的网络库没有使用libevent或者libev,而是作者自己实现的一个非常轻量级的库(主要实现在ae.c文件中),这部分内容在后面分析Redis的网络库的时候单独写篇文章。
通过本文,介绍了Redis的启动加载过程,希望对大家有所帮助。
相关推荐
5. **网络监听服务启动前的准备工作**:在此步骤中,Redis会进行一系列准备操作,确保服务能够正常监听客户端请求。 6. **开启事件监听**:最后,Redis启动事件循环,开始处理客户端的请求。 #### 三、Redis数据...
本文将对Redis服务器的启动过程进行深入分析,包括初始化全局配置、加载配置文件、初始化服务器、加载数据和开始网络监听等关键步骤。 首先,Redis的启动始于Redis.c文件中的main函数。整个启动过程可以分为几个...
### Redis 学习与实战应用 #### 一、Redis 概述 Redis 是一款非常流行的非关系型(NoSQL)数据库。...同时,结合 Spring Data Redis 或 Jedis 这样的高级客户端,能够进一步简化 Redis 的使用过程,提升开发效率。
- **使用场景**:Redis更适合用作高速缓存或实时数据分析,而传统数据库适用于复杂的数据查询和事务处理。 #### 2. Redis支持的数据结构有哪些?请简要介绍每种数据结构的特点和用途。 - **字符串(String)**:...
- **启动**:使用`redis-server`命令启动Redis服务。 - **停止**:使用`redis-cli -p port shutdown`命令关闭Redis服务。 - **查看和修改配置**:通过`redis-cli config set`命令修改运行时配置。 - **批量执行操作*...
- **sweet-framework-core**:核心组件,负责定义Sweet应用的启动方式、配置加载方式以及模块化加载方式。简化业务逻辑开发,聚焦于业务本身。 - **sweet-framework-common**:提供大量常用的方法、工具类和类库,...
4. **最大内容绘制时间**(Largest Contentful Paint, LCP):页面加载过程中最大的内容绘制事件发生的时间点。LCP反映了页面主要内容的加载速度,对提升用户体验至关重要。 除了以上指标外,还有许多其他性能指标...
服务提供者在应用启动时加载,并且可以控制框架的初始化过程。 数据库模块是 Web 应用中最为常见的需求。Laravel 提供了基于 Eloquent ORM 的数据库抽象层,使得数据库操作变得简单。Eloquent ORM 支持复杂的查询...
### Spring Boot概要介绍与分析 #### 一、Spring Boot简介 Spring Boot 是由 Pivotal 团队推出的一款全新的框架,旨在简化基于 Spring 的应用的初始搭建和开发过程。通过采用一系列默认配置、内嵌的 Web 服务器等...
在`AbstractRegistryFactory`中,通常会根据不同的注册中心类型(如ZK、Redis等)加载相应的配置,然后创建对应的注册表实例。这使得Dubbo可以轻松地支持多种注册中心,增强了系统的可扩展性。 总的来说,`...
Guns是一款高效、易用的Java快速开发框架,旨在通过一系列自动化工具和规范化的架构设计,帮助开发者快速构建高质量的企业级应用。本解析将从文档的标题、描述、标签及部分内容出发,深入挖掘其中的关键知识点和技术...
2. **类加载机制**:了解Java的类加载过程,包括双亲委托模型、类加载器的生命周期,以及类的加载、链接和初始化。这有助于优化类的加载性能,尤其是在大规模应用中。 3. **JVM性能调优**:包括JVM启动参数设置,如...
- **服务提供者**:阐述了服务提供者的作用机制和使用方法,包括注册服务、绑定依赖注入容器、启动服务等过程。 - **服务容器**:讲解了Laravel的核心服务容器的工作原理,包括依赖注入、服务绑定和服务注册等内容。...
在系统启动时预加载常用数据,减少初次查询延迟。 5. 使用数据库内置功能:如SQL Server的索引视图、物化视图,Oracle的materialized view等,可以预先计算并存储结果。 总结,SQL性能测试是数据库管理的重要环节...
1. **访问速度慢**:可以通过优化前端资源加载顺序、开启Gzip压缩等方式提升加载速度。 2. **数据库连接超时**:增加连接池大小或优化SQL语句减少查询次数。 3. **内存溢出**:适当增大JVM堆内存大小,并进行代码...
20. **其他知识点**:还包括线程池的拒绝策略、Spring Bean的初始化方式、Redis Sorted Set的数据结构、过期键的删除策略、分片技术、高可用策略、JVM参数、JWT原理、聚簇索引、类加载器机制、Future和FutureTask、...
- 使用EXPLAIN分析SQL执行计划:帮助理解SQL语句的执行过程,从而找出性能瓶颈。 - 合理使用JOIN:避免不必要的JOIN操作,减少数据检索时间。 - 分区表:对于非常大的表,分区可以帮助提高查询效率。 ### 其他...
- **java.util.concurrent**:提供了一系列用于并发编程的工具类,如`ExecutorService`、`CountDownLatch`等。 4. **Spring** - **启动**:通过ApplicationContext或BeanFactory初始化Spring容器。 - **时间**:...