Redis5.x 的 README 文档译文

Redis5.X快速启动文档

注:readme文件中除了c语言的源码部分的文件解释,其他的部分已被本人通读并翻译,请放心食用。
Linux下常用启动Redis服务器的命令:
redis-server & #后台启动使用默认配置
redis-server #直接启动
停止Redis服务器:
redis-cli -a 密码 -h 127.0.0.1 -p 6379 shutdown
没有密码:
redis-cli -h 127.0.0.1 -p 6379 shutdown

CentOS默认配置Redis自启动(参考redis生成环境下的安装):
Selected config:
Port : 6379
Config file : /etc/redis/6379.conf
Log file : /var/log/redis_6379.log
Data dir : /var/lib/redis/6379
Executable : /usr/local/bin/redis-server
Cli Executable : /usr/local/bin/redis-cli


一.Redis 是什么?


Redis通常被称为 data structures 服务器。这意味着Redis通过一组命令提供对可变数据结构的访问,这些命令使用带有TCP套接字的server-client模型和一个简单的协议发送。因此,不同的流程可以以共享的方式查询和修改相同的数据结构。

在Redis中实现的数据结构有一些特殊的属性:

  • Redis关心将它们存储在磁盘上,即使它们总是被服务并修改到服务器内存中。这意味着Redis速度快,但数据也不容易丢失。
  • 数据结构的实现强调内存效率,因此与使用高级编程语言建模的相同数据结构相比,Redis内部的数据结构可能使用更少的内存。
  • Redis提供了许多在数据库中很自然可以找到的特性,比如复制、可调持久性级别、集群和高可用性。

另一个很好的例子是将Redis看作memcached的一个更复杂的版本,在这个版本中,操作不仅仅是set和get,而是处理复杂数据类型(如列表、集合、有序数据结构等)的操作。

如果你想知道更多,这是一个列表的选择起点:


二.构建 Redis


Redis可以在Linux、OSX、OpenBSD、NetBSD、FreeBSD上编译和使用。我们支持大端和小端架构,以及32位和64位系统。
它可以在Solaris派生的系统上编译(例如SmartOS),但是我们对这个平台的支持是“best effort”,而且Redis不能保证在Linux、OSX和*BSD中工作得那么好。

这很简单:

% make

你可以运行32位Redis二进制使用:

% make 32bit

在构建Redis之后,最好使用以下工具进行测试:

% make test

三.修复依赖项或缓存的生成选项的生成问题


Redis有一些依赖关系,包括在’deps’目录中。即使依赖项源代码中的某些内容发生更改,make也不会自动重新生成依赖项。

当您使用’git pull’更新源代码或以任何其他方式修改依赖关系树中的代码时,请确保使用以下命令,以便真正地清理所有内容并从头开始重新构建:

make distclean

这将清理:jemalloc、lua、hiredis、linenoise.

此外,如果强制执行某些构建选项,如32位目标、没有C编译器优化(用于调试)和其他类似的构建时选项,这些选项将无限期缓存,直到发出make distclean命令。


四.修复构建32位二进制文件的问题


如果在用32位目标构建Redis之后,需要用64位目标重新构建它,或者反过来,需要在Redis发行版的根目录中执行make distclean命令。

如果构建一个32位的Redis二进制文件时出现错误,请尝试以下步骤:

  • Install the packages libc6-dev-i386 (also try g+±multilib).
  • 尝试使用以下命令行代替make 32bit’:
    make CFLAGS="-m32 -march=native" LDFLAGS="-m32"

五.Allocator


在构建Redis时选择非默认内存分配器是通过设置‘MALLOC’环境变量来完成的。默认情况下,除了jemalloc是Linux系统上的默认值外,Redis是针对libc malloc编译和链接的。之所以选择这个默认值,是因为jemalloclibc malloc有更少的碎片问题。

要强制针对libc malloc编译,请使用:

% make MALLOC=libc

要在Mac OS X系统上针对jemalloc编译,请使用:

% make MALLOC=jemalloc

六.详细的构建


默认情况下,Redis将构建一个用户友好的彩色输出。如果您想看到更详细的输出,请使用以下命令:

% make V=1

七.Running Redis


要用默认配置运行Redis,只需输入:

% cd src
% ./redis-server

如果你想提供你的 redis.conf,你必须使用一个额外的参数(配置文件的路径)来运行它:

% cd src
% ./redis-server /path/to/redis.conf

通过使用命令行将参数直接作为选项传递,可以更改Redis配置。例子:

% ./redis-server --port 9999 --replicaof 127.0.0.1 6379
% ./redis-server /etc/redis/6379.conf --loglevel debug

redis.conf 中的所有选项都支持使用命令行作为选项,它们的名称完全相同。


八.Redis 的使用


您可以使用 Redis-cli 来使用Redis。启动一个 redis-server 的实例,然后在另一个终端尝试以下操作:

'ping’命令用来检验redis服务器是否正常,服务器正常则返回一个‘PONG’。

% cd src
% ./redis-cli
redis> ping
PONG
redis> set foo bar
OK
redis> get foo
"bar"
redis> incr mycounter
(integer) 1
redis> incr mycounter
(integer) 2
redis>

你可以在 “http://redis.io/commands” 找到所有可用命令的列表。


九.安装 Redis


为了在 /usr/local/bin 中安装Redis的二进制文件,只需使用:

% make install

如果你希望Redis安装到自己指定的目录中可以使用命令 make PREFIX=/some/other/directory install

Make install 只会在你的系统中安装二进制文件,不会在适当的位置配置初始化脚本和配置文件。如果你只是想体验一下redis就不用特地去安装二进制文件了,官网会提供一个online版的redis让你体验,但是如果你是要使用正确的方式安装redis的生产系统,我们为Ubuntu和Debian系统提供一个专门的脚本:

% cd utils
% ./install_server.sh

该脚本将询问您几个问题,并将正确运行Redis所需的一切设置为后台守护进程,该守护进程将在系统重新启动时重新启动。

你能够使用名为 /etc/init.d/redis_<portnumber> 的脚本文件停止和启动Redis,例如/etc/init.d/redis_6379.


十.Code contributions(贡献代码)


Note: by contributing code to the Redis project in any form, including sending
a pull request via Github, a code fragment or patch via private email or
public discussion groups, you agree to release your code under the terms
of the BSD license that you can find in the COPYING file included in the Redis
source distribution.

Please see the CONTRIBUTING file in this source distribution for more
information.


十一.Redis internals(Redis 内部)


如果你正在阅读README文件,其实你离源码只有一步之遥,我们在这里将解释Redis源代码布局、每个文件中的一般概念、Redis服务器中最重要的函数和结构,等等。这里会面向一个较高层次而不深入细节进行讨论。


十二.Source code layout(源码的布局)


Redis 的 root 目录只包含这个 README 文件,在src目录中调用真正的Makefile的Makefile,以及Redis和Sentinel(哨兵)的示例配置。您可以找到一些用于执行Redis、Redis集群和
Redis Sentinel的单元测试,它是在“test”目录中实现的。

在根目录中有以下重要目录:

  • src:包含用C语言编写的Redis实现。
  • tests: 包含用Tcl实现的单元测试
  • deps: 包含Redis使用的库。编译Redis所需的一切都在这个目录中;你的系统只需要提供libc,一个POSIX兼容的接口和一个C编译器。值得注意的是,deps包含一个jemalloc副本,这是Linux下Redis的默认分配器。注意,在deps下面还有一些东西是从Redis项目开始的,但是主要存储库不是antirez/redis。这条规则的一个例外是deps/geohash-int,它是Redis使用的低层地址解析库:它起源于一个不同的项目,但在这一点上,它的分歧如此之大,以至于它被开发为直接位于Redis存储库中的一个独立实体。

还有一些目录,但是它们对我们的目标不是很重要。我们将主要关注“src”,其中包含Redis实现,研究每个文件中包含什么。文件公开的顺序是逻辑上的顺序,以便逐步公开不同层次的复杂性。

Note: Redis被重构了很多。函数名和文件名已更改,因此您可能会发现此文档反映了unstable分支更紧密。例如,在Redis 3.0的server.cserver.h文件名为redis.credis.h。但是整体结构是一样的。请记住,所有新的开发和pull请求都应该针对unstable分支执行。


十三.server.h


理解程序如何工作的最简单方法是理解它使用的数据结构。我们将从redis 的主头文件(main header file)开始,也就是“server.h”文件。

所有的服务器配置以及通常所有的共享状态都定义在一个名为“server”的全局结构中,类型为“struct redisServer”。
这个结构中的几个重要fields是:

  • server.db 是Redis databases的一个数据存储的数组。
  • server.commands 是命令表.
  • server.clients 是连接到服务器的client的linked list。
  • server.master 如果master实例是一个副本,则是一个特殊的client。

还有很多其他的 fields。大多数字段直接在结构定义中注释。

另一个重要的Redis数据结构是定义一个客户端,过去叫redisClient,现在叫client。结构有很多字段,这里我们只显示主要的字段:

struct client {
    int fd;
    sds querybuf;
    int argc;
    robj **argv;
    redisDb *db;
    int flags;
    list *reply;
    char buf[PROTO_REPLY_CHUNK_BYTES];
    ... many other fields ...
}

客户端结构定义了一个“connected client”:

  • “fd”字段是客户端套接字文件描述符。
  • “argc”和“argv”由客户机正在执行的命令填充,以便实现给定Redis命令的函数可以读取参数。
  • querybuf收集来自客户机的请求,这些请求由Redis服务器根据Redis协议进行解析,并通过调用客户机正在执行的命令的实现来执行。
  • ’ reply ‘和’ buf '是动态和静态缓冲区,用于累积服务器发送给客户机的响应。只要文件描述符是可写的,这些缓冲区就会增量地写入套接字。

正如您在上面的客户机结构中看到的,命令中的参数被描述为“robj”结构。 下面是完整的“robj”结构,它定义了一个Redis Object:

typedef struct redisObject {
    unsigned type:4;
    unsigned encoding:4;
    unsigned lru:LRU_BITS; /* lru time (relative to server.lruclock) */
    int refcount;
    void *ptr;
} robj;

基本上,这个结构可以表示所有基本的Redis数据类型,比如字符串、列表、集、排序集等等。有趣的是,它有一个“type”字段,这样就可以知道给定对象的类型,还有一个“refcount”,这样同一个对象就可以在多个地方引用,而不需要多次分配它。最后,“ptr”字段指向对象的实际表示,即使对于相同的类型,它也可能会根据使用的“编码”而有所不同。

Redis objects在Redis内部被广泛使用,但是为了避免间接访问的开销,最近在很多地方我们只使用没有封装在Redis Object中的普通动态字符串。


十四.server.c


这是Redis服务器的入口点,在这里定义了’ main() '函数。为了启动Redis服务器,以下是最重要的步骤:

  • initServerConfig() setups the default values of the server structure.
  • initServer() allocates the data structures needed to operate, setup the listening socket, and so forth.
  • aeMain() starts the event loop which listens for new connections.

事件循环周期调用两个特殊函数:

  1. serverCron() is called periodically (according to server.hz frequency), and performs tasks that must be performed from time to time, like checking for timedout clients.
  2. beforeSleep() is called every time the event loop fired, Redis served a few requests, and is returning back into the event loop.

在 server.c 中,你可以找到处理Redis服务器其他重要事情的代码:

  • call() is used in order to call a given command in the context of a given client.
  • activeExpireCycle() handles eviciton of keys with a time to live set via the EXPIRE command.
  • freeMemoryIfNeeded() is called when a new write command should be performed but Redis is out of memory according to the maxmemory directive.
  • The global variable redisCommandTable defines all the Redis commands, specifying the name of the command, the function implementing the command, the number of arguments required, and other properties of each command.

十五.networking.c


该文件定义了与clients、masters和replicas(副本)一起使用的所有I/O函数(在Redis中,这只是一些特殊的client):

  • createClient() allocates and initializes a new client.
  • the addReply*() family of functions are used by commands implementations in order to append data to the client structure, that will be transmitted to the client as a reply for a given command executed.
  • writeToClient() transmits the data pending in the output buffers to the client and is called by the writable event handler sendReplyToClient().
  • readQueryFromClient() is the readable event handler and accumulates data from read from the client into the query buffer.
  • processInputBuffer() is the entry point in order to parse the client query buffer according to the Redis protocol. Once commands are ready to be processed, it calls processCommand() which is defined inside server.c in order to actually execute the command.
  • freeClient() deallocates, disconnects and removes a client.

十六.aof.c and rdb.c


从名称中可以猜到,这些文件实现了Redis的RDB和AOF持久性。Redis使用基于“fork()”系统调用的持久性模型来创建具有与主Redis线程相同(共享)内存内容的线程。This secondary thread dumps the content
of the memory on disk. This is used by rdb.c to create the snapshots
on disk and by aof.c in order to perform the AOF rewrite when the
append only file gets too big.

The implementation inside aof.c has additional functions in order to
implement an API that allows commands to append new commands into the AOF
file as clients execute them.

The call() function defined inside server.c is responsible to call
the functions that in turn will write the commands into the AOF.


十七.db.c


某些Redis命令操作特定的数据类型,其他的是通用的。泛型命令的例子有“DEL”和“EXPIRE”。它们对键进行操作,而不是对它们的值进行操作。所有这些通用命令都在"db.c"中定义。

Moreover db.c implements an API in order to perform certain operations
on the Redis dataset without directly accessing the internal data structures.

The most important functions inside db.c which are used in many commands
implementations are the following:

  • lookupKeyRead() and lookupKeyWrite() are used in order to get a pointer to the value associated to a given key, or NULL if the key does not exist.
  • dbAdd() and its higher level counterpart setKey() create a new key in a Redis database.
  • dbDelete() removes a key and its associated value.
  • emptyDb() removes an entire single database or all the databases defined.

文件的其余部分实现了向客户机公开的通用命令。


十八.object.c


The robj structure defining Redis objects was already described. Inside
object.c there are all the functions that operate with Redis objects at
a basic level, like functions to allocate new objects, handle the reference
counting and so forth. Notable functions inside this file:

  • incrRefcount() and decrRefCount() are used in order to increment or decrement an object reference count. When it drops to 0 the object is finally freed.
  • createObject() allocates a new object. There are also specialized functions to allocate string objects having a specific content, like createStringObjectFromLongLong() and similar functions.

这个文件还实现了“OBJECT”命令。


十九.replication.c


这是Redis中最复杂的文件之一,建议您在稍微熟悉了代码库的其余部分之后再进行处理。
在这个文件中,实现了Redis的主角色和副本角色。

One of the most important functions inside this file is replicationFeedSlaves() that writes commands to the clients representing replica instances connected
to our master, so that the replicas can get the writes performed by the clients:
this way their data set will remain synchronized with the one in the master.

这个文件还实现了“SYNC”和“PSYNC”命令,这些命令用于在 主服务器 和 副本 之间执行第一次同步,或者在断开连接后继续复制


二十.其他 C 文件


  • t_hash.c, t_list.c, t_set.c, t_string.c and t_zset.c contains the implementation of the Redis data types. They implement both an API to access a given data type, and the client commands implementations for these data types.
  • ae.c implements the Redis event loop, it’s a self contained library which is simple to read and understand.
  • sds.c is the Redis string library, check http://github.com/antirez/sds for more information.
  • anet.c is a library to use POSIX networking in a simpler way compared to the raw interface exposed by the kernel.
  • dict.c is an implementation of a non-blocking hash table which rehashes incrementally.
  • scripting.c implements Lua scripting. It is completely self contained from the rest of the Redis implementation and is simple enough to understand if you are familar with the Lua API.
  • cluster.c implements the Redis Cluster. Probably a good read only after being very familiar with the rest of the Redis code base. If you want to read cluster.c make sure to read the Redis Cluster specification.

二十一.Redis命令的剖析


All the Redis commands are defined in the following way:

void foobarCommand(client *c) {
    printf("%s",c->argv[1]->ptr); /* Do something with the argument. */
    addReply(c,shared.ok); /* Reply something to the client. */
}

The command is then referenced inside server.c in the command table:

{"foobar",foobarCommand,2,"rtF",0,NULL,0,0,0,0,0},

In the above example 2 is the number of arguments the command takes,
while "rtF" are the command flags, as documented in the command table
top comment inside server.c.

After the command operates in some way, it returns a reply to the client,
usually using addReply() or a similar function defined inside networking.c.

在Redis源代码中有大量的命令实现,可以作为实际命令实现的示例。编写一些玩具命令(toy command)是熟悉代码库的一个很好的练习。

还有许多其他文件没有在这里描述,但是没有必要涵盖所有内容。我们只是想帮助你迈出第一步。最终,您将找到进入Redis代码库的方法 ?

Enjoy!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值