深入解析Redis:性能与应用

发表时间: 2019-08-22 09:41

Redis是一种NoSQL的基于内存的key-value数据库。数据存储在内存和硬盘上,Redis周期性把更新数据写入磁盘,把修改操作写入追加记录文件中。

很巧的是,知乎的日志系统kids pub/sub pattern is ported from Redis。另外,强烈推荐Redis设计与实现,图文并貌,讲解清楚。另,另外,Redis是典型的Server-client系统,看完_APUE_之后看单机数据库的实现理解会更加深刻。

##安装配置##

  1. 在官网下载源码。

2.解压后进入目录make即可。

/src下的redis-server和redis-cli分别是服务器和客户端应用程序,可直接调用。运行命令到用户bin目录下方便调用:

cp src/redis-* /usr/local/bin

服务器运行界面如下:

客户端运行如下:

##数据类型## Redis一共有五种数据类型:string,hash,list,set,zset。

string由sds.h/sds.c表示:

typedef char *sds;//结构提定义,len为数组长度,free为空闲大小。struct sdshdr { unsigned int len; unsigned int free; char buf[];};//内存向高地址增长,s是字符数组实际位置。得到结构体首地址,然后运算符取得string大小。static inline size_t sdslen(const sds s) { struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr))); return sh->len;}

启动redis-server和redis-cli,在redis-cli中输入:

127.0.0.1:6379> SET book "Advanced Programming in the UNIX Environment"

可以将book的键值设为string类型。

127.0.0.1:6379> GET book"Advanced Programming in the UNIX Environment"

list由adlist.h/adlist.c表示:

//可见list是一个双向链表typedef struct listNode { struct listNode *prev; struct listNode *next; void *value;} listNode;//遍历迭代器typedef struct listIter { listNode *next; int direction;} listIter;//定义一个head和tail,把list放在中间。typedef struct list { listNode *head; listNode *tail;//典型的函数指针,同OOP成员函数 void *(*dup)(void *ptr); void (*free)(void *ptr); int (*match)(void *ptr, void *key); unsigned long len;} list;match采用遍历,算法复杂度为0(n)。对比LRU缓存机制应用hashmap的0(1)算法。

在redis-cli中输入:

127.0.0.1:6379> RPUSH brands Apple Microsoft Google

即可为brands设置list类型的键值。

127.0.0.1:6379> Lpop brands"Apple"

hash由dict.h/dict.c表示:

typedef struct dictEntry { void *key; union { void *val; uint64_t u64; int64_t s64; double d; } v; struct dictEntry *next;} dictEntry;typedef struct dictht { dictEntry **table; unsigned long size; unsigned long sizemask; unsigned long used;} dictht;typedef struct dictType { unsigned int (*hashFunction)(const void *key); void *(*keyDup)(void *privdata, const void *key); void *(*valDup)(void *privdata, const void *obj); int (*keyCompare)(void *privdata, const void *key1, const void *key2); void (*keyDestructor)(void *privdata, void *key); void (*valDestructor)(void *privdata, void *obj);} dictType;typedef struct dict { dictType *type; void *privdata; dictht ht[2]; long rehashidx;  int iterators; } dict;

这么复杂的数据结构借助一张图可以清晰的捋清楚。

在redis-cli中输入:

127.0.0.1:6379> HSET cookbook type "source code analysis"

127.0.0.1:6379> HSET cookbook name "The design and implementation of Redis"

127.0.0.1:6379> HSET cookbook release-date "2013.3.8"

127.0.0.1:6379> HGETALL cookbook

1) "type"

2) "source code analysis"

3) "name"

4) "The design and implementation of Redis"

5) "release-date"

6) "2013.3.8"

hash类型键值的底层实现是hash表,hash表的常用寻址算法举例参见。
http://my.oschina.net/lvyi/blog/327314