程序员怎么用好内存数据库Redis?

时间:2022-12-22 11:17:02

程序员怎么用好内存数据库Redis?

前言:Redis是Remote Dictionary Server的缩写,意即远程字典服务器,但是更经常被用作内存数据库和缓存。在现代软件常用的微服务架构(MSA)中,Redis占有十分重要的地位,它是解决低响应时间和大并发数量的关键方法之一。因此,学好原理、用好细节成为程序员的必修课程。


1.源码分析和编译

1.1概述

Redis是Remote Dictionary Server的缩写,意即远程字典服务器。

(1)源码位置

其源码放在官网redis.io中,下载地址:https://redis.io/download

本文从gitee的副本克隆,地址:https://gitee.com/mirrors/redis.git克隆到目录F:\work\redis如下图,然后就可以使用gcc编译

程序员怎么用好内存数据库Redis?


如果使用vs2017编译,需要到这个地址下载:https://github.com/MicrosoftArchive/redis假设克隆到D:\microsoftredis目录下,如下图:

程序员怎么用好内存数据库Redis?

(2)Redis解释

Redis有不同的称呼,有的认为是内存数据库,有的还认为是缓存服务器,还有的认为是NoSql服务器,但是称为数据结构服务器也许是最准确的。因为Redis可以通过一组命令访问可变数据结构,这些命令使用带有TCP套接字和简单协议的服务器-客户端模型发送,不同的进程可以以共享的方式查询和修改相同的数据结构。

Redis主要特点如下:

  • 关注数据结构序列化:即使数据结构是在服务器内存中提供给使用者。这意味着Redis速度很快,但也是非易失性的。
  • 实现强调内存效率:与使用高级编程语言建模的相同数据结构相比,Redis内部的数据结构可能会使用更少的内存。
  • 具有数据库特性:提供了许多在数据库中很容易找到的特性,比如复制、可调的持久性、集群和高可用性。
  • 作为memcached复杂版本:支持的操作不仅仅是set和get,还是处理复杂数据类型(如list、SETs、有序数据结构等)的操作。​

参考链接:


1.2源码分析

下面分析Redis源代码布局,每个文件中的设计思想,内部最重要的函数和结构等等。Redis代码库会不断变化,但总体设计思想不会改变太多。源码分析的主要目的还是探索用好它的途径,这适用于JAVA/C++程序员;也可以学习内存操作和数据结构操纵的有效方法,这一般适用于C/C++程序员。


1.2.1源代码布局

Redis根目录主要包含README.MD,其他文件涉及版权、运行配置文件conf和编译配置文件Makefile,可以不用关心他们。因为在src目录中才调用真正的Makefile、Redis配置和Sentinel配置。根目录还有有关Redis、Redis集群、Redis哨兵(类似于看门狗)的单元测试脚本,这些测试在tests目录中实现。

根目录下包含如下重要目录:

  • src: 包含了用C语言编写的Redis实现
  • tests: 包含用Tcl实现的单元测试
  • deps: 包含Redis使用的库。编译Redis所需的一切都在这个目录中,但是不包括libc(POSIX兼容接口)和C编译器。值得注意的是,deps包含了jemalloc的副本,这是Linux下Redis的默认分配器。在deps下也有一些始于Redis项目的东西,但其主要内容放在其他地方。
  • utils: 提供一些工具

注意:最近Redis被重构了很多。函数名和文件名已经更改,因此代码分析针对7.x版本和unstable 分支。例如,在Redis 3.0中,server.c和server.h文件被命名为Redis .c和Redis .h。然而,整体结构是相同的。


1.2.2头文件server.h

程序=算法+数据结构,先理解数据结构比先理解算法更容易,入门也相对容易。所以代码分析从Redis的主头文件server.h开始。

所有服务器配置和所有共享状态都定义在一个称为server的全局结构中,类型为struct redisServer,如下:

struct redisServer {
/* 常用*/
pid_t pid; /* 主进程 pid. */
pthread_t main_thread_id; /* 主线程 id */
char *configfile; /* 配置文件绝对路径, 或 NULL */
char *executable; /* 执行文件绝对路径 */
char **exec_argv; /* 执行参数argv向量vector (copy). */
int dynamic_hz; /* 依客户端编码而变的hz值 */
int config_hz; /* 配置的 HZ值,如果dynamic-hz激活的话,可不同于实际的hz字段值 */
mode_t umask; /* 启动进程的umask 值 */
int hz; /* serverCron() 调用频率(单位赫兹) */
int in_fork_child; /* 分叉客户端的指示 */
redisDb *db;
dict *commands; /* 指令表 */
dict *orig_commands; /* 原始指令表 */
aeEventLoop *el;
rax *errors; /* 错误表 */

......

/* 本地环境 */
char *locale_collate;
};

其中有几个重要的字段:

  • server.db是Redis数据库的数组,数据就存储在server.db中
  • server.commands是指令表
  • server.clients是连接到服务器的客户端链表
  • server.master是一个特殊的客户端,即若本实例是副本,那么server.master指向master(主节点)

该结构还有很多其他字段,大多数字段都在结构定义中有注释。

另一个重要的结构是redisClient,用于定义客户端的数据结构。过去它叫redisClient,现在只叫client。这个结构也有很多字段,如下:

typedef struct client {
uint64_t id; /* 客户端递增统一编号 */
uint64_t flags; /* 客户端标志: CLIENT_* 宏 */
connection *conn;
int resp; /* 响应协议版本,可能是2或者3 */
redisDb *db; /* 目前选中的数据库的指针 */
robj *name; /* 客户端设置名称(SETNAME)的集合 */
sds querybuf; /* 用于客户端查询的缓冲区 */
size_t qb_pos; /* querybuf中的读取位置 */
size_t querybuf_peak; /* 最近100毫秒内querybuf大小的峰值 */
int argc; /* 当前指令的参数数量 */
robj **argv; /* 当前指令的参数 */

......

size_t buf_usable_size; /* 缓冲区的可用大小 */
char *buf;
} client;

client结构定义了一个可连接的客户端:

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

其中,argv被描述为robj结构下面是完整的robj结构,它来自redisObject:

typedef struct redisObject robj;
struct redisObject {
unsigned type:4;
unsigned encoding:4;
unsigned lru:LRU_BITS; /* LRU时间(相对于全局lru_clock)或LFU数据(最低8位频率和最多16位访问时间)*/
int refcount;
void *ptr;
};

基本上redisObject 可以表示所有基本的Redis数据类型,比如字符串、列表、集合、有序集合等等。它有一个type字段,这样就可以知道给定对象的类型,还有一个refcount,这样就可以在多个地方引用同一个对象,而无需多次分配它。最后,ptr字段指向对象的实际表示形式,即使是同一类型,根据使用的编码方式encoding ,也可能有所不同。
Redis对象(redisObject)在Redis内部被广泛使用,但是为了避免间接访问的开销,最近在许多地方只是使用普通的动态字符串,而不是包装在Redis对象中。


1.2.3服务器入口代码server.c

这个文件是Redis服务器的入口点,因为这里面定义了main()函数,这是C语言的入口函数。如下:

int main(int argc, char **argv) {
struct timeval tv;
int j;
char config_from_stdin = 0;

......

tzset(); /* 填充全局时区 */
zmalloc_set_oom_handler(redisOutOfMemoryHandler);
/* 为了实现熵,容器的time()和getpid()可以保持一致。但是tv_usec的值足够快,可以产生不同的结果 */
gettimeofday(&tv,NULL);
srand(time(NULL)^getpid()^tv.tv_usec);
srandom(time(NULL)^getpid()^tv.tv_usec);
init_genrand64(((long long) tv.tv_sec * 1000000 + tv.tv_usec) ^ getpid());
crc64_init();

......

redisSetCpuAffinity(server.server_cpulist);
setOOMScoreAdj(-1);
aeMain(server.el);
aeDeleteEventLoop(server.el);
return 0;
}

下面是执行Redis服务器最重要的函数:

  • initServerConfig()设置server结构的默认值
  • initServer()分配操作、设置监听套接字等所需的数据结构
  • aeMain()启动监听新连接的事件循环

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

  • serverCron()根据server.hz频率定期调用,并执行必须时常执行的任务,如检查超时的客户端.
  • beforeSleep() 在每次事件循环触发时调用,Redis处理了一些请求后返回到事件循环中

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

  • call() 用于在给定客户端的上下文中调用给定命令.
  • activeExpireCycle() 处理通过EXPIRE命令设置存活时间的键的回收.
  • performEvictions(),调用于根据maxmemory判断Redis内存不足而应该执行新的写命令之时
  • 全局变量redisCommandTable定义了所有的Redis命令,指定了命令的名称、实现该命令的函数、所需参数的数量以及每个命令的其他属性.

1.2.4指令元数据代码commands.c

commands.c文件由utils/generate-command-code.py自动生成,内容基于src/commands文件夹中的JSON文件是关于Redis指令和所有关于它们的元数据的唯一来源。JSON文件不给任何人直接使用元数据可以通过COMMAND命令获得。

内容片断如下:

......

/* Main command table */
struct redisCommand redisCommandTable[] = {
/* bitmap */
{"bitcount","Count set bits in a string","O(N)","2.6.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_BITMAP,BITCOUNT_History,BITCOUNT_tips,bitcountCommand,-2,CMD_READONLY,ACL_CATEGORY_BITMAP,{{NULL,CMD_KEY_RO|CMD_KEY_ACCESS,KSPEC_BS_INDEX,.bs.index={1},KSPEC_FK_RANGE,.fk.range={0,1,0}}},.args=BITCOUNT_Args},
{"bitfield","Perform arbitrary bitfield integer operations on strings","O(1) for each subcommand specified","3.2.0",CMD_DOC_NONE,NULL,NULL,COMMAND_GROUP_BITMAP,BITFIELD_History,BITFIELD_tips,bitfieldCommand,-2,CMD_WRITE|CMD_DENYOOM,ACL_CATEGORY_BITMAP,{{"This command allows both access and modification of the key",CMD_KEY_RW|CMD_KEY_UPDATE|CMD_KEY_ACCESS|CMD_KEY_VARIABLE_FLAGS,KSPEC_BS_INDEX,.bs.index={1},KSPEC_FK_RANGE,.fk.range={0,1,0}}},bitfieldGetKeys,.args=BITFIELD_Args},

......

1.2.5 网络IO代码networking.c

networking.c定义了所有的网络I/O函数,不管是客户端相关还是主节点和副本相关,主节点和副本在Redis只是特殊的客户端。片断截取如下:

......

#include "server.h"
#include "atomicvar.h"
#include "cluster.h"

......

client *createClient(connection *conn) {
client *c = zmalloc(sizeof(client));
/* 传递NULL作为conn可以创建一个非连接的客户端。这很有用,因为所有的命令在客户端上下文中都需要执行。当在其他上下文(例如一个Lua脚本)中执行命令时我们需要一个非连接客户端 */
if (conn) {
connEnableTcpNoDelay(conn);
if (server.tcpkeepalive)
connKeepAlive(conn,server.tcpkeepalive);
connSetReadHandler(conn, readQueryFromClient);
connSetPrivateData(conn, c);
}
c->buf = zmalloc(PROTO_REPLY_CHUNK_BYTES);
selectDb(c,0);

......

主要函数包括:

  • createClient() 分配并初始化一个新客户端
  • addReply*() 函数家族,用于为了添加数据到客户端结构的命令实现,将作为执行给定命令的应答传输到客户端
  • writeToClient() 将输出缓冲区中的挂起数据传输到客户端,并由可写事件处理程序sendReplyToClient()调用。
  • readQueryFromClient() 是可读的事件处理程序,将客户端读取的数据填充到查询缓冲区中
  • processInputBuffer() 是入口点,用于根据Redis协议解析客户端查询缓冲区。一旦准备好处理命令,它就调用server.c中定义的processCommand(),以便实际执行命令
  • freeClient() 释放、断开连接并删除客户端

1.2.6 持久化代码aof.c和rdb.c

aof.crdb.c文件实现了Redis的RDB(Redis Database,快照模式)和AOF(Append Only-file,追加或日志模式)两种持久化方式。Redis使用基于fork()系统调用的持久化模型来创建一个与主Redis进程具有相同(共享)内存内容的进程。这个辅助进程将内存内容转储到磁盘上。rdb.c在磁盘上创建快照,aof.c在追加文件太大时执行AOF重写。

aof.c内部的实现有额外的函数,允许在客户端执行时将新命令追加到AOF文件中。在server.c中定义的call()函数负责调用将命令轮流写入AOF的函数,Call()函数片断如下图:

void call(client *c, int flags) {
long long dirty;
uint64_t client_old_flags = c->flags;
struct redisCommand *real_cmd = c->realcmd;
/* 初始化:清除必须由命令按需设置的标志,并初始化数组以用于其他命令传递。 */
c->flags &= ~(CLIENT_FORCE_AOF|CLIENT_FORCE_REPL|CLIENT_PREVENT_PROP);

......

1.2.7 数据库操作代码db.c

某些Redis指令操作特定的数据类型;其他的指令则是一般性的。通用指令的例子是DEL和EXPIRE,对键进行操作,而不是对键的值进行操作。所有这些通用指令都在db.c中定义。

此外,db.c实现了API可以在不直接访问内部数据结构的情况下对Redis数据集执行某些操作。

db.c中在许多命令实现中使用的最重要的函数如下

  • lookupKeyRead() 和lookupKeyWrite() 用于获取与给定键相关的值的指针,如果键不存在则使用NULL
  • dbAdd() 和它的更高级别配对函数setKey()在Redis数据库中创建一个新键
  • dbDelete() 移除键和值
  • emptyDb() 移除单个数据库或者所有数据库db.c文件的其余部分实现向客户端公开的通用命令。

1.2.8 对象处理代码object.c

前面已经描述了定义Redis对象的robj结构。在object.c中,存在所有在基本级别上操作Redis对象的函数,比如分配新对象的函数,处理引用计数等等。该文件中的重要函数如下:

  • incrRefCount()和decrRefCount()用于增加或减少对象引用计数。当它降为0时,对象最终被释放
  • createObject()分配一个新对象。还有一些专门的函数来分配具有特定内容的字符串对象,如createStringObjectFromLongLong()和类似的函数.object.c也实现了OBJECT 指令.

1.2.9 副本处理代码replication.c

这是Redis中最复杂的文件之一,其中有Redis的主节点角色和副本角色的实现。

最重要的函数之一是replicationFeedSlaves(),它将命令写入到客户端,该客户端是连接到主服务器的副本实例,因此,副本可以获得客户端执行的写操作:这样它们的数据集将与主节点中的数据集保持同步。

还实现了SYNC和PSYNC命令,用于在主节点和副本之间执行第一次同步,或在断开连接后继续处理。


1.2.10 脚本处理模块

脚本处理模块包含:

  • script.c - 脚本与Redis的集成(命令执行,设置复制/响应,…),使用script_lua.c来执行Lua代码
  • script_lua.c - 负责执行Lua代码,使用script.c从Lua代码中与Redis交互
  • function_lua.c - 包含Lua引擎实现,
  • functions.c - 包含Redis函数实现(FUNCTION命令),如果它想调用的函数需要Lua引擎,那么应使用functions_lua.c
  • eval.c - 包含使用script_lua.c调用Lua代码的eval实现

1.2.11 数据类型、集群和事件

  • t_hash.c, t_list.c, t_set.c, t_string.c, t_zset.c 和t_stream.c 包含Redis数据类型的实现。它们实现了访问给定数据类型的API,以及这些数据类型的客户端命令实现
  • ae.c 实现了Redis事件循环,它是一个自包含的库,易于阅读和理解
  • sds.c 是Redis字符串库,参考链接:https://github.com/antirez/sds
  • anet.c是一个库,与内核公开的原始接口相比,它以一种更简单的方式使用POSIX网络
  • dict.c是一个增量式复用的非阻塞哈希表的实现。
  • cluster.c实现Redis集群。可能只有在非常熟悉Redis代码库的其余部分之后才会很好地读懂它. 建议先阅读如下文档: Redis Cluster specification(Redis集群规格说明书).

1.2.12 指令剖析

所有Redis指令都按如下格式定义:

voidfoobarCommand(client *c) {
printf("%s",c->argv[1]->ptr); /* 对参数做点什么事 */
addReply(c,shared.ok); /* 应答点什么给客户端 */
}

命令函数由JSON文件及其元数据引用,有关详细信息,请参阅上面描述的commands.c。命令标志记录在server.h中redisCommand结构上面的注释中。其他详细信息请参见COMMAND命令,相关文档:https://redis.io/commands/command/

在命令以某种方式操作后,它会向客户端返回一个应答,通常使用addReply()或在network .c中定义的类似函数。
在Redis源代码中有大量的命令实现,可以作为实际命令实现的示例(例如pingCommand)。编写一些测试命令可以作为熟悉代码库的良好练习。


1.3 Linux下源码编译

Redis可以在Linux, OSX, OpenBSD, NetBSD, FreeBSD上编译和使用。支持大endian 和小endian 架构,以及32位和64位系统。

可以在Solaris衍生系统上编译(例如SmartOS),但对这个平台的支持是尽力,Redis不能保证在Linux、OSX和*BSD上工作得一样好。

编译如此简单:

% make

要使用TLS支持构建,需要OpenSSL开发库(例如Debian/Ubuntu上的libssl-dev)并运行:

% make BUILD_TLS=yes

要使用systemd支持进行构建,需要systemd开发库(例如Debian/Ubuntu上的libsystemd-dev或CentOS上的system -devel)并运行:

% make USE_SYSTEMD=yes

构建一个32位的Redis二进制文件

% make 32bit

在构建Redis之后,使用它进行测试

% make test

如果构建了TLS,则在启用TLS的情况下运行测试(需要安装tcl-tls):

% ./utils/gen-test-certs.sh
% ./runtest --tls


1.4 Windows下源码编译

使用VS2017打开sln文件:

程序员怎么用好内存数据库Redis?

生成解决方案:

程序员怎么用好内存数据库Redis?

得到debug版的redis系统文件:

D:\redis-3.0.504\redis\msvs\x64\Debug

也有编译好的,下载网址:https://github.com/ServiceStack/redis-windows


2.Windows下运行


2.1环境变量和设置

在path中增加存放redis可执行文件的路径,例如:D:\redis-3.0.504\redis\msvs\x64\Debug。

进入该进入文件夹新增文件:redis.windows.conf。

加入文本内容:

程序员怎么用好内存数据库Redis?


2.2 Windows下启动和测试

启动redis:

程序员怎么用好内存数据库Redis?

启动redis-cli命令行:

程序员怎么用好内存数据库Redis?

测试:

启动第一个cmd窗口:

程序员怎么用好内存数据库Redis?

启动第二个cmd窗口:

程序员怎么用好内存数据库Redis?

回过头来看第一个cmd窗口:

程序员怎么用好内存数据库Redis?


3.Linux下运行


3.1通用运行指令

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

% cd src
% ./redis-server

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

% cd src
% ./redis-server /存放路径/redis.conf

使用命令行直接将参数作为选项来更改Redis配置。例如:

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

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


3.2 带TLS运行

使用TLS模式手动运行Redis服务器(假设调用了' gen-test-certs.sh ',因此示例证书/密钥可用):

TLS内置模式:

./src/redis-server --tls-port 6379 --port 0 \
--tls-cert-file ./tests/tls/redis.crt \
--tls-key-file ./tests/tls/redis.key \
--tls-ca-cert-file ./tests/tls/ca.crt

TLS模块模式:

./src/redis-server --tls-port 6379 --port 0 \
--tls-cert-file ./tests/tls/redis.crt \
--tls-key-file ./tests/tls/redis.key \
--tls-ca-cert-file ./tests/tls/ca.crt \
--loadmodule src/redis-tls.so

使用' Redis -cli '连接到这个Redis服务器:


./src/redis-cli --tls \
--cert ./tests/tls/redis.crt \
--key ./tests/tls/redis.key \
--cacert ./tests/tls/ca.crt

这将禁用TCP并在端口6379上启用TLS。TCP和TLS也可以同时使用,但需要分配不同的端口。

要让副本用TLS连接到主服务器,使用'--tls-replication yes',让Redis集群跨节点使用TLS采用如下命令'--tls-cluster yes


3.3 使用CLI

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

% 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>

命令列表参见第4章。


3.4安装

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

% make install

如果希望使用不同的目录,可以使用其他目录,则需要执行如下命令:

make PREFIX=/指定目录 install

make install 只会在系统中安装二进制文件,但不会在适当的位置配置init脚本和配置文件。如果只是想懂一点Redis,配置是不需要的,但如果为生产系统正确安装,那么为Ubuntu和Debian系统提供了一个脚本:

% cd utils
% ./install_server.sh

注意:install_server.sh不能在Mac OSX上运行;它仅为Linux构建。
脚本会问你一些问题,并将设置你需要正确运行Redis作为后台守护进程的一切事情,该守护进程将在系统重启时重新启动。

对于/etc/init.d/redis_6379实例,可以使用名为/etc/init.d/redis_<端口号>的脚本停止和启动Redis


4.常用指令


4.1连接命令


4.1.1启动

本地启动:redis-cli

远程启动:redis-cli -h host -p port -a password


4.1.2 AUTH password

验证密码是否正确


4.1.3 ECHO message

打印字符串


4.1.4 PING

查看服务是否运行


4.1.5 QUIT

关闭当前连接


4.1.6 SELECT index

切换到指定的数据库


4.2 keys命令


4.2.1 DEL key

DUMP key

序列化给定的key并返回序列化的值


4.2.2 EXISTS key

检查给定的key是否存在


4.2.3 EXPIRE key seconds

为key设置过期时间


4.2.4 EXPIRE key timestamp

用时间戳的方式给key设置过期时间


4.2.5 PEXPIRE key milliseconds

设置key的过期时间以毫秒计


4.2.6 KEYS pattern

查找所有符合给定模式的key


4.2.7 MOVE key db

将当前数据库的key移动到数据库db当中


4.2.8 PERSIST key

移除key的过期时间,key将持久保存


4.2.9 PTTL key

以毫秒为单位返回key的剩余过期时间


4.2.10 TTL key

以秒为单位,返回给定key的剩余生存时间


4.2.11 RANDOMKEY

从当前数据库中随机返回一个key


4.2.12 RENAME key newkey

修改key的名称


4.2.13 RENAMENX key newkey

仅当newkey不存在时,将key改名为newkey


4.2.14 TYPE key

返回key所存储的值的类型


4.3 KV字符串命令

1、SET key value

设置键值


2、GET key

得到键值


3、GETRANGE key start end

返回key中字符串值的子字符


4、GETSET key value

将给定key的值设为value,并返回key的旧值


5、GETBIT KEY OFFSET

对key所储存的字符串值,获取指定偏移量上的位


6、MGET KEY1 KEY2

获取一个或者多个给定key的值


7、SETBIT KEY OFFSET VALUE

对key所是存储的字符串值,设置或清除指定偏移量上的位


8、SETEX key seconds value

将值 value 关联到 key ,并将 key 的过期时间设为 seconds (以秒为单位)。


9、SETNX key value

只有在 key 不存在时设置 key 的值。


10、SETRANGE key offset value

用 value 参数覆写给定 key 所储存的字符串值,从偏移量 offset 开始。


11、STRLEN key

返回 key 所储存的字符串值的长度。


12、MSET key value [key value ...]

同时设置一个或多个 key-value 对。


13、MSETNX key value [key value ...]

同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在。


14、PSETEX key milliseconds value

这个命令和 SETEX 命令相似,但它以毫秒为单位设置 key 的生存时间,而不是像 SETEX 命令那样,以秒为单位。


15、INCR key

将 key 中储存的数字值增一。


16、INCRBY key increment

将 key 所储存的值加上给定的增量值(increment) 。


17、INCRBYFLOAT key increment

将 key 所储存的值加上给定的浮点增量值(increment) 。


18、DECR key

将 key 中储存的数字值减一。


19、DECRBY key decrement

key 所储存的值减去给定的减量值(decrement) 。


20、APPEND key value

如果 key 已经存在并且是一个字符串, APPEND 命令将 指定value 追加到改 key 原来的值(value)的末尾。


4.4 哈希命令

1、HDEL key field1 [field2]

删除一个或多个哈希表字段

2、HEXISTS key field

查看哈希表 key 中,指定的字段是否存在。

3、HGET key field

获取存储在哈希表中指定字段的值。

4、HGETALL key

获取在哈希表中指定 key 的所有字段和值

5、HINCRBY key field increment

为哈希表 key 中的指定字段的整数值加上增量 increment 。

6、HINCRBYFLOAT key field increment

为哈希表 key 中的指定字段的浮点数值加上增量 increment 。

7、HKEYS key

获取所有哈希表中的字段

8、HLEN key

获取哈希表中字段的数量

9、HMGET key field1 [field2]

获取所有给定字段的值

10、HMSET key field1 value1 [field2 value2 ]

同时将多个 field-value (域-值)对设置到哈希表 key 中。

11、HSET key field value

将哈希表 key 中的字段 field 的值设为 value 。

12、HSETNX key field value

只有在字段 field 不存在时,设置哈希表字段的值。

13、HVALS key

获取哈希表中所有值

14、HSCAN key cursor [MATCH pattern] [COUNT count]

迭代哈希表中的键值对。


4.5 列表命令

1、BLPOP key1 [key2 ] timeout

移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。

2、BRPOP key1 [key2 ] timeout

移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。

3、BRPOPLPUSH source destination timeout

从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。

4、LINDEX key index

通过索引获取列表中的元素

5、LINSERT key BEFORE|AFTER pivot value

在列表的元素前或者后插入元素

6、LLEN key

获取列表长度

7、LPOP key

移出并获取列表的第一个元素

8、LPUSH key value1 [value2]

将一个或多个值插入到列表头部

9、LPUSHX key value

将一个值插入到已存在的列表头部

10、LRANGE key start stop

获取列表指定范围内的元素

11、LREM key count value

移除列表元素

12、LSET key index value

通过索引设置列表元素的值

13、LTRIM key start stop

对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。

14、RPOP key

移除并获取列表最后一个元素

15、RPOPLPUSH source destination

移除列表的最后一个元素,并将该元素添加到另一个列表并返回

16、RPUSH key value1 [value2]

在列表中添加一个或多个值

17、RPUSHX key value

为已存在的列表添加值


4.6集合命令

1、SADD key member1 [member2]

向集合添加一个或多个成员

2、SCARD key

获取集合的成员数

3、SDIFF key1 [key2]

返回给定所有集合的差集

4、SDIFFSTORE destination key1 [key2]

返回给定所有集合的差集并存储在 destination 中

5、SINTER key1 [key2]

返回给定所有集合的交集

6、SINTERSTORE destination key1 [key2]

返回给定所有集合的交集并存储在 destination 中

7、SISMEMBER key member

判断 member 元素是否是集合 key 的成员

8、SMEMBERS key

返回集合中的所有成员

9、SMOVE source destination member

将 member 元素从 source 集合移动到 destination 集合

10、SPOP key

移除并返回集合中的一个随机元素

11、SRANDMEMBER key [count]

返回集合中一个或多个随机数

12、SREM key member1 [member2]

移除集合中一个或多个成员

13、SUNION key1 [key2]

返回所有给定集合的并集

14、SUNIONSTORE destination key1 [key2]

所有给定集合的并集存储在 destination 集合中

15、SSCAN key cursor [MATCH pattern] [COUNT count]

迭代集合中的元素


4.7有序集合命令

1、ZADD key score1 member1 [score2 member2]

向有序集合添加一个或多个成员,或者更新已存在成员的分数

2、ZCARD key

获取有序集合的成员数

3、ZCOUNT key min max

计算在有序集合中指定区间分数的成员数

4、ZINCRBY key increment member

有序集合中对指定成员的分数加上增量 increment

5、ZINTERSTORE destination numkeys key [key ...]

计算给定的一个或多个有序集的交集并将结果集存储在新的有序集合 key 中

6、ZLEXCOUNT key min max

在有序集合中计算指定字典区间内成员数量

7、ZRANGE key start stop [WITHSCORES]

通过索引区间返回有序集合成指定区间内的成员

8、ZRANGEBYLEX key min max [LIMIT offset count]

通过字典区间返回有序集合的成员

9、ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT]

通过分数返回有序集合指定区间内的成员

10、ZRANK key member

返回有序集合中指定成员的索引

11、ZREM key member [member ...]

移除有序集合中的一个或多个成员

12、ZREMRANGEBYLEX key min max

移除有序集合中给定的字典区间的所有成员

13、ZREMRANGEBYRANK key start stop

移除有序集合中给定的排名区间的所有成员

14、ZREMRANGEBYSCORE key min max

移除有序集合中给定的分数区间的所有成员

15、ZREVRANGE key start stop [WITHSCORES]

返回有序集中指定区间内的成员,通过索引,分数从高到底

16、ZREVRANGEBYSCORE key max min [WITHSCORES]

返回有序集中指定分数区间内的成员,分数从高到低排序

17、ZREVRANK key member

返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序

18、ZSCORE key member

返回有序集中,成员的分数值

19、ZUNIONSTORE destination numkeys key [key ...]

计算给定的一个或多个有序集的并集,并存储在新的 key 中

20、ZSCAN key cursor [MATCH pattern] [COUNT count]

迭代有序集合中的元素(包括元素成员和元素分值)


4.8发布订阅命令


4.8.1 PSUBSCRIBE pattern [pattern ...]

订阅一个或多个符合给定模式的频道。


4.8.2 PUBSUB subcommand [argument [argument ...]]

查看订阅与发布系统状态。


4.8.3 PUBLISH channel message

将信息发送到指定的频道。


4.8.4 PUNSUBSCRIBE [pattern [pattern ...]]

退订所有给定模式的频道。


4.8.5 SUBSCRIBE channel [channel ...]

订阅给定的一个或多个频道的信息。


4.8.6 UNSUBSCRIBE [channel [channel ...]]

指退订给定的频道。


4.9事务命令

1、DISCARD

取消事务,放弃执行事务块内的所有命令。

2、EXEC

执行所有事务块内的命令。

3、MULTI

标记一个事务块的开始。

4、UNWATCH

取消 WATCH 命令对所有 key 的监视。

5、WATCH key [key ...]

监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。


4.10脚本命令

1、EVAL script numkeys key [key ...] arg [arg ...]

执行 Lua 脚本。

2、EVALSHA sha1 numkeys key [key ...] arg [arg ...]

执行 Lua 脚本。

3、SCRIPT EXISTS script [script ...]

查看指定的脚本是否已经被保存在缓存当中。

4、SCRIPT FLUSH

从脚本缓存中移除所有脚本。

5、SCRIPT KILL

杀死当前正在运行的 Lua 脚本。

6、SCRIPT LOAD script

将脚本 script 添加到脚本缓存中,但并不立即执行这个脚本。


4.11服务器命令

1、BGREWRITEAOF

异步执行一个 AOF(AppendOnly File) 文件重写操作

2、BGSAVE

在后台异步保存当前数据库的数据到磁盘

3、CLIENT KILL [ip:port] [ID client-id]

关闭客户端连接

4、CLIENT LIST

获取连接到服务器的客户端连接列表

5、CLIENT GETNAME

获取连接的名称

6、CLIENT PAUSE timeout

在指定时间内终止运行来自客户端的命令

7、CLIENT SETNAME connection-name

设置当前连接的名称

8、CLUSTER SLOTS

获取集群节点的映射数组

9、COMMAND

获取 Redis 命令详情数组

10、COMMAND COUNT

获取 Redis 命令总数

11、COMMAND GETKEYS

获取给定命令的所有键

12、TIME

返回当前服务器时间

13、COMMAND INFO command-name [command-name ...]

获取指定 Redis 命令描述的数组

14、CONFIG GET parameter

获取指定配置参数的值

15、CONFIG REWRITE

对启动 Redis 服务器时所指定的 redis.conf 配置文件进行改写

16、CONFIG SET parameter value

修改 redis 配置参数,无需重启

17、CONFIG RESETSTAT

重置 INFO 命令中的某些统计数据

18、DBSIZE

返回当前数据库的 key 的数量

19、DEBUG OBJECT key

获取 key 的调试信息

20、DEBUG SEGFAULT

让 Redis 服务崩溃

21、FLUSHALL

删除所有数据库的所有key

22、FLUSHDB

删除当前数据库的所有key

23、INFO [section]

获取 Redis 服务器的各种信息和统计数值

24、LASTSAVE

返回最近一次 Redis 成功将数据保存到磁盘上的时间,以 UNIX 时间戳格式表示

25、MONITOR

实时打印出 Redis 服务器接收到的命令,调试用

26、ROLE

返回主从实例所属的角色

27、SAVE

同步保存数据到硬盘

28、SHUTDOWN [NOSAVE] [SAVE]

异步保存数据到硬盘,并关闭服务器

29、SLAVEOF host port

将当前服务器转变为指定服务器的从属服务器(slave server)

30、SLOWLOG subcommand [argument]

管理 redis 的慢日志

31、SYNC

用于复制功能(replication)的内部命令

32、 config set requirepass "123456"

设置密码为123456


更多请参考链接:https://redis.io/commands


5.同类对比


5.1和memchache对比

1、Redis和Memcache都是将数据存放在内存中,都是内存数据库。不过memcache还可用于缓存其他东西,例如图片、视频等等;

2、Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,hash等数据结构的存储;

3、虚拟内存--Redis当物理内存用完时,可以将一些很久没用到的value交换到磁盘;

4、过期策略--memcache在set时就指定,例如set key1 0 0 8,即永不过期。Redis可以通过例如expire 设定,例如expire name 10;

5、分布式--设定memcache集群,利用magent做一主多从;redis可以做一主多从,即都可以一主一从;

6、存储数据安全--memcache挂掉后,数据没了;redis可以定期保存到磁盘(持久化)

7、灾难恢复--memcache挂掉后,数据不可恢复; redis数据丢失后可以通过aof恢复;

8、Redis支持数据的备份,即master-slave模式的数据备份;

9、应用场景不一样:Redis出来作为NoSQL数据库使用外,还能用做消息队列、数据堆栈和数据缓存等;Memcached适合于缓存SQL语句、数据集、用户临时性数据、延迟查询数据和session等。

10、Redis使用最佳方式是全部数据in-memory。

Redis更多场景是作为Memcached的替代者来使用。

当需要除key/value之外的更多数据类型支持时,使用Redis更合适。

当存储的数据不能被剔除时,使用Redis更合适。


5.2和fastdb对比

fastdb是高效的关系型内存数据库系统,具备实时能力及便利的C++接口通过降低数据传输的开销和非常有效的锁机制提供了高速的查询并发访问数据库的同步机制通过原子指令实现,几乎不增加查询的开销。而Redis提供Java/C++接口。具体比较如下:

1、fastdb不支持C/S架构因而所有使用FastDB的应用程序必须运行在同一主机上;redis支持C/S架构,还支持集群。

2、fastdb假定整个数据库存在于RAM中,并且依据这个假定优化了查询算法和接口。Redis也是基于内存进行设计。

3、fastdb没有数据库缓冲管理开销,不需要在数据库文件和缓冲池之间传输数据。Redis采用订阅/发布模式,这需要缓冲管理。

4、整个fastdb的搜索算法和结构是建立在假定所有的数据都存在于内存中的,因此数据换出的效率不会很高。这个redis一样。

5、fastdb支持事务、在线备份以及系统崩溃后的自动恢复。Redis也支持事务、备份,不支持崩溃自动修复。

6、fastdb是一个面向应用的数据库,数据库表通过应用程序的类信息来构造redis不支持数据库表,也不支持SQL,而是支持NOSQL,是NOSQL数据库