redis 入门介绍

一、Redis介绍

 

Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。从2010年3月15日起,Redis的开发工作由VMware主持。

 

Redis能运行在大多数POSIX(Linux, *BSD, OS X 和Solaris等)系统上,官方没有支持Windows的版本。目前最新的版本是2.2.11,这个版本主要是修复了一个2.2.7版本中遍历方式优化带来的一个bug。

 

和普通的Key-Value结构不同,Redis的Key支持灵活的数据结构,除了strings,还有hashes、lists、 sets 和sortedsets等结构。正是这些灵活的数据结构,丰富了Redis的应用场景,能满足更多业务上的灵活存储需求。

 

Redis的数据都保存在内存中,而且底层实现上是自己写了epollevent loop部分,而没有采用开源的libevent等通用框架,所以读写效率很高。为了实现数据的持久化,Redis支持定期刷新(可通过配置实现)或写日志的方式来保存数据到磁盘。

 

1、数据类型

作为Key-value型数据库,Redis也提供了键(Key)和键值(Value)的映射关系。但是,除了常规的数值或字符串,Redis的键值还可以是以下形式之一:

●Lists (列表)

●Sets (集合)

●Sorted sets (有序集合)

●Hashes (哈希表)

键值的数据类型决定了该键值支持的操作。Redis支持诸如列表、集合或有序集合的交集、并集、查集等高级原子操作;同时,如果键值的类型是普通数字,Redis则提供自增等原子操作。

 

下面我们就来简单说明一下它们各自的使用场景:

1.String——字符串

String 数据结构是简单的key-value 类型,value 不仅可以是 String,也可以是数字(当数字类型用 Long可以表示的时候encoding就是整型,其他都存储在 sdshdr 当做字符串)。使用 Strings 类型,可以完全实现目前Memcached 的功能,并且效率更高。还可以享受Redis 的定时持久化(可以选择 RDB 模式或者 AOF 模式),操作日志及Replication 等功能。除了提供与Memcached 一样的 get、set、incr、decr 等操作外,Redis 还提供了下面一些操作:

1.      LEN niushuai:O(1)获取字符串长度
2.APPEND niushuai redis:往字符串append 内容,而且采用智能分配内存(每次2倍)
3.设置和获取字符串的某一段内容
4.设置及获取字符串的某一位(bit)
5.批量设置一系列字符串的内容
6.原子计数器
7.GETSET 命令的妙用,请于清空旧值的同时设置一个新值,配合原子计数器使用

 

2.Hash——字典

在Memcached 中,我们经常将一些结构化的信息打包成hashmap,在客户端序列化后存储为一个字符串的值(一般是 JSON格式),比如用户的昵称、年龄、性别、积分等。这时候在需要修改其中某一项时,通常需要将字符串(JSON)取出来,然后进行反序列化,修改某一项的值, 再序列化成字符串(JSON)存储回去。简单修改一个属性就干这么多事情,消耗必定是很大的,也不适用于一些可能并发操作的场合(比如两个并发的操作都需 要修改积分)。而 Redis 的 Hash结构可以使你像在数据库中 Update 一个属性一样只修改某一项属性值。

存储、读取、修改用户属性

 

3.List——列表

List 说白了就是链表(redis 使用双端链表实现的 List),相信学过数据结构知识的人都应该能理解其结构。使用 List结构,我们可以轻松地实现最新消息排行等功能(比如新浪微博的TimeLine )。List 的另一个应用就是消息队列,可以利用 List 的*PUSH 操作,将任务存在 List 中,然后工作线程再用 POP 操作将任务取出进行执行。Redis 还提供了操作 List 中某一段元素的 API,你可以直接查询,删除 List 中某一段的元素。

1.      微博TimeLine

2.      消息队列

 

4. Set——集合

Set 就是一个集合,集合的概念就是一堆不重复值的组合。利用Redis 提供的 Set 数据结构,可以存储一些集合性的数据。比如在微博应用中,可以将一个用户所有的关注人存在一个集合中,将其所有粉丝存在一个集合。因为Redis 非常人性化的为集合提供了求交集、并集、差集等操作,那么就可以非常方便的实现如共同关注、共同喜好、二度好友等功能,对上面的所有集合操作,你还可以使 用不同的命令选择将结果返回给客户端还是存集到一个新的集合中。

1.共同好友、二度好友

2.利用唯一性,可以统计访问网站的所有独立 IP

3.好友推荐的时候,根据 tag 求交集,大于某个 threshold 就可以推荐

 

5.Sorted Set——有序集合

和Sets相比,Sorted Sets是将 Set 中的元素增加了一个权重参数 score,使得集合中的元素能够按score 进行有序排列,比如一个存储全班同学成绩的Sorted Sets,其集合 value 可以是同学的学号,而 score 就可以是其考试得分,这样在数据插入集合的时候,就已经进行了天然的排序。另外还可以用Sorted Sets 来做带权重的队列,比如普通消息的score 为1,重要消息的 score 为2,然后工作线程可以选择按 score 的倒序来获取工作任务。让重要的任务优先执行。

1.带有权重的元素,比如一个游戏的用户得分排行榜
2.比较复杂的数据结构,一般用到的场景不算太多

 

 

2、持久化

通常,Redis将数据存储于内存中,或被配置为使用虚拟内存。通过两种方式可以实现数据持久化:使用截图的方式,将内存中的数据不断写入磁盘;或使用类似MySQL的日志方式,记录每次更新的日志。前者性能较高,但是可能会引起一定程度的数据丢失;后者相反。

 

3、主从同步

  Redis支持将数据同步到多台从库上,这种特性对提高读取性能非常有益。

 

4、性能

  相比需要依赖磁盘记录每个更新的数据库,基于内存的特性无疑给Redis带来了非常优秀的性能。读写操作之间有显著的性能差异。

 

5、提供API的语言

  ●C

  ●C++

  ●C#

  ●Clojure

  ●CommonLisp

  ●Erlang

  ●Haskell

  ●Java

  ●JavaScript

  ●Lua

  ●Objective-C

  ●Perl

  ●PHP

  ●Python

  ●Ruby

  ●Scala

  ●Go

  ●Tcl

 

6、适用场合

毫无疑问,Redis开创了一种新的数据存储思路,使用Redis,我们不用在面对功能单调的数据库时,把精力放在如何把大象放进冰箱这样的问题上,而是利用Redis灵活多变的数据结构和数据操作,为不同的大象构建不同的冰箱。希望你喜欢这个比喻。

 

下面是Redis适用的一些场景:

取最新N个数据的操作

比如典型的取你网站的最新文章,通过下面方式,我们可以将最新的5000条评论的ID放在Redis的List集合中,并将超出集合部分从数据库获取。

使用LPUSHlatest.comments命令,向list集合中插入数据

插入完成后再用LTRIMlatest.comments 0 5000命令使其永远只保存最近5000个ID

然后我们在客户端获取某一页评论时可以用下面的逻辑

FUNCTION get_latest_comments(start,num_items):

 id_list =redis.lrange("latest.comments",start,start+num_items-1)

 IF id_list.length <num_items
id_list = SQL_DB("SELECT ... ORDER BY time LIMIT ...")

 END

RETURN id_list

END

如果你还有不同的筛选维度,比如某个分类的最新N条,那么你可以再建一个按此分类的List,只存ID的话,Redis是非常高效的。

排行榜应用,取TOP N操作

这个需求与上面需求的不同之处在于,前面操作以时间为权重,这个是以某个条件为权重,比如按顶的次数排序,这时候就需要我们的sortedset出马了,将你要排序的值设置成sortedset的score,将具体的数据设置成相应的value,每次只需要执行一条ZADD命令即可。

需要精准设定过期时间的应用

比如你可以把上面说到的sortedset的score值设置成过期时间的时间戳,那么就可以简单地通过过期时间排序,定时清除过期数据了,不仅是清除Redis中的过期数据,你完全可以把 Redis里这个过期时间当成是对数据库中数据的索引,用Redis来找出哪些数据需要过期删除,然后再精准地从数据库中删除相应的记录。

计数器应用

Redis的命令都是原子性的,你可以轻松地利用INCR,DECR命令来构建计数器系统。

(5) Uniq操作,获取某段时间所有数据排重值

这个使用Redis的set数据结构最合适了,只需要不断地将数据往set中扔就行了,set意为集合,所以会自动排重。

(6) 实时系统,反垃圾系统

通过上面说到的set功能,你可以知道一个终端用户是否进行了某个操作,可以找到其操作的集合并进行分析统计对比等。没有做不到,只有想不到。

(7) Pub/Sub构建实时消息系统

Redis的Pub/Sub系统可以构建实时的消息系统,比如很多用Pub/Sub构建的实时聊天系统的例子。

(8) 构建队列系统

使用list可以构建队列系统,使用sorted set甚至可以构建有优先级的队列系统。

(9) 缓存

这个不必说了,性能优于Memcached,数据结构更多样化。

 

 

二、Redis安装部署

Redis是一种高级key-value数据库。它跟memcached类似,不过 数据可以持久化,而且支持的数据类型很丰富。有字符串,链表,集 合和有序集合。支持在服务器端计算集合的并,交和补集(difference)等,还支持多种排序功能。所以Redis也可以被看成是一个数据结构服务 器。

Redis的所有数据都是保存在内存中,然后不定期的通过异步方式保存到磁盘上(这称为“半持久化模式”);也可以把每一次数据变化都写入到一个appendonly file(aof)里面(这称为“全持久化模式”)。

1.下载地址

$ wgethttp://download.redis.io/releases/redis-3.0.3.tar.gz

 

2.解压缩

$ tar -xzvf redis-3.0.3.tar.gz

 

3.编译

$ cd redis-3.0.3

$ make

$makeinstall

$cpredis.conf  /etc/

参数介绍:

makeinstall命令执行完成后,会在/usr/local/bin目录下生成可执行文件,分别是redis-server、redis-cli、 redis-benchmark、redis-check-aof、redis-check-dump,它们的作用如下:

redis-server:Redis服务器的daemon启动程序

redis-cli:Redis命令行操作工具。也可以用telnet根据其纯文本协议来操作

redis-benchmark:Redis性能测试工具,测试Redis在当前系统下的读写性能

redis-check-aof:数据修复

redis-check-dump:检查导出工具

 

4.修改系统配置文件,执行命令

a)echo vm.overcommit_memory=1 >> /etc/sysctl.conf

b)sysctl vm.overcommit_memory=1 或执行echovm.overcommit_memory=1 >>/proc/sys/vm/overcommit_memory

使用数字含义:

0,表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。

1,表示内核允许分配所有的物理内存,而不管当前的内存状态如何。

2,表示内核允许分配超过所有物理内存和交换空间总和的内存

 

5.修改redis配置文件

a) $cd /etc

b) viredis.conf

c) 修改daemonize yes---目的使进程在后台运行

参数介绍:

daemonize:是否以后台daemon方式运行

pidfile:pid文件位置

port:监听的端口号

timeout:请求超时时间

loglevel:log信息级别

logfile:log文件位置

databases:开启数据库的数量

save **:保存快照的频率,第一个*表示多长时间,第三个*表示执行多少次写操作。在一定时间内执行一定数量的写操作时,自动保存快照。可设置多个条件。

rdbcompression:是否使用压缩

dbfilename:数据快照文件名(只是文件名,不包括目录)

dir:数据快照的保存目录(这个是目录)

appendonly:是否开启appendonlylog,开启的话每次写操作会记一条log,这会提高数据抗风险能力,但影响效率。

appendfsync:appendonlylog如何同步到磁盘(三个选项,分别是每次写都强制调用fsync、每秒启用一次fsync、不调用fsync等待系统自己同步)

 

6.启动redis

a) $cd /usr/local/bin

b)./redis-server  /etc/redis.conf

 

7.检查是否启动成功

a) $ps -ef | grep redis

 

8.redis开机启动

其实github上很多老外写好的启动脚本,不过大部分都是ubuntu的,对于Centos,也有一份https://gist.github.com/1335694,经过修改,如下:

 

   ########################### 

[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. ###########################   
  2.   
  3.    PATH=/usr/local/bin:/sbin:/usr/bin:/bin   
  4.   
  5.           
  6.   
  7.     REDISPORT=6379   
  8.   
  9.    EXEC=/usr/local/bin/redis-server   
  10.   
  11.     REDIS_CLI=/usr/local/bin/redis-cli  //redis安装地址  
  12.   
  13.     CONF="/etc/redis.conf"  
  14.   
  15.    PIDFILE=/var/run/redis.pid   
  16.   
  17.        
  18.   
  19.     case "$1"in   
  20.   
  21.         start)   
  22.   
  23.             if [ -f $PIDFILE]   
  24.   
  25.             then   
  26.   
  27.                     echo"$PIDFILE exists, process is already running or crashed"   
  28.   
  29.             else   
  30.   
  31.                     echo"Starting Redis server..."   
  32.   
  33.                     $EXEC$CONF   
  34.   
  35.             fi   
  36.   
  37.             if ["$?"="0" ]    
  38.   
  39.             then    
  40.   
  41.                   echo"Redis is running..."   
  42.   
  43.             fi   
  44.   
  45.             ;;   
  46.   
  47.         stop)   
  48.   
  49.             if [ ! -f$PIDFILE ]   
  50.   
  51.             then   
  52.   
  53.                     echo"$PIDFILE does not exist, process is not running"   
  54.   
  55.             else   
  56.   
  57.                     PID=$(cat $PIDFILE)   
  58.   
  59.                     echo"Stopping ..."   
  60.   
  61.                    $REDIS_CLI -p $REDISPORT SHUTDOWN   
  62.   
  63.                     while [-x ${PIDFILE} ]   
  64.   
  65.                    do   
  66.   
  67.                         echo"Waiting for Redis to shutdown ..."   
  68.   
  69.                         sleep1   
  70.   
  71.                     done   
  72.   
  73.                     echo"Redis stopped"   
  74.   
  75.             fi   
  76.   
  77.             ;;   
  78.   
  79.       restart|force-reload)   
  80.   
  81.             ${0} stop   
  82.   
  83.             ${0} start   
  84.   
  85.             ;;   
  86.   
  87.       *)   
  88.   
  89.         echo "Usage:/etc/init.d/redis {start|stop|restart|force-reload}" >&2   
  90.   
  91.             exit 1   
  92.   
  93.     esac   
  94.   
  95.     ##############################    

   PATH=/usr/local/bin:/sbin:/usr/bin:/bin 

        

    REDISPORT=6379 

   EXEC=/usr/local/bin/redis-server 

    REDIS_CLI=/usr/local/bin/redis-cli  //redis安装地址

    CONF="/etc/redis.conf"

   PIDFILE=/var/run/redis.pid 

     

    case "$1"in 

        start) 

            if [ -f $PIDFILE] 

            then 

                    echo"$PIDFILE exists, process is already running or crashed" 

            else 

                    echo"Starting Redis server..." 

                    $EXEC$CONF 

            fi 

            if ["$?"="0" ]  

            then  

                  echo"Redis is running..." 

            fi 

            ;; 

        stop) 

            if [ ! -f$PIDFILE ] 

            then 

                    echo"$PIDFILE does not exist, process is not running" 

            else 

                    PID=$(cat $PIDFILE) 

                    echo"Stopping ..." 

                   $REDIS_CLI -p $REDISPORT SHUTDOWN 

                    while [-x ${PIDFILE} ] 

                   do 

                        echo"Waiting for Redis to shutdown ..." 

                        sleep1 

                    done 

                    echo"Redis stopped" 

            fi 

            ;; 

      restart|force-reload) 

            ${0} stop 

            ${0} start 

            ;; 

      *) 

        echo "Usage:/etc/init.d/redis {start|stop|restart|force-reload}" >&2 

            exit 1 

    esac 

    ############################## 

 

把上述代码存为redis, 放到/etc/init.d/下面

    chmod +x /etc/init.d/redis 

其实做成服务启动,也是调用redis-server,如果想让它在后台作为daemon运行,那么

需要修改redis.conf,将 daemonize no 改为 daemonize yes

 

8. 设定开机启动服务

sudo chkconfig redis on 

 

9. 启动, 停止redis

service redis start   #或者 /etc/init.d/redis start 

service redis stop   #或者 /etc/init.d/redis stop

 

三、配置Redis

使用配置文件启动:src/redis-server redis.conf

主要配置项:

Redis支持很多的参数,但都有默认值。

●daemonize:

默认情况下,redis不是在后台运行的,如果需要在后台运行,把该项的值更改为yes。

●pidfile

当Redis在后台运行的时候,Redis默认会把pid文件放在/var/run/redis.pid,你可以配置到其他地址。当运行多个redis服务时,需要指定不同的pid文件和端口。

●bind

指定Redis只接收来自于该IP地址的请求,如果不进行设置,那么将处理所有请求,在生产环境中最好设置该项。

●port

监听端口,默认为6379。

●timeout

设置客户端连接时的超时时间,单位为秒。当客户端在这段时间内没有发出任何指令,那么关闭该连接。

●loglevel

log等级分为4级,debug, verbose, notice, 和warning。生产环境下一般开启notice。

●logfile

配置log文件地址,默认使用标准输出,即打印在命令行终端的窗口上。

●databases

设置数据库的个数,可以使用SELECT 命令来切换数据库。默认使用的数据库是0。

●save

设置Redis进行数据库镜像的频率。

if(在60秒之内有10000个keys发生变化时){

  进行镜像备份

}else if(在300秒之内有10个keys发生了变化){

  进行镜像备份

}else if(在900秒之内有1个keys发生了变化){

  进行镜像备份

}

●rdbcompression

在进行镜像备份时,是否进行压缩。

●dbfilename

镜像备份文件的文件名。

●dir

数据库镜像备份的文件放置的路径。这里的路径跟文件名要分开配置是因为Redis在进行备份时,先会将当前数据库的状态写入到一个临时文件中,等备份完 成时,再把该该临时文件替换为上面所指定的文件,而这里的临时文件和上面所配置的备份文件都会放在这个指定的路径当中。

●slaveof

设置该数据库为其他数据库的从数据库。

●masterauth

当主数据库连接需要密码验证时,在这里指定。

●requirepass

设置客户端连接后进行任何其他指定前需要使用的密码。警告:因为redis速度相当快,所以在一台比较好的服务器下,一个外部的用户可以在一秒钟进行150K次的密码尝试,这意味着你需要指定非常非常强大的密码来防止暴力破解。

●maxclients

限制同时连接的客户数量。当连接数超过这个值时,redis将不再接收其他连接请求,客户端尝试连接时将收到error信息。

●maxmemory

设置redis能够使用的最大内存。 当内存满了的时候,如果还接收到set命令,redis将先尝试剔除设置过expire信息的key,而不管该key的过期时间还没有到达。在删除时,将 按照过期时间进行删除,最早将要被过期的key将最先被删除。如果带有expire信息的key都删光了,那么将返回错误。这样,redis将不再接收写 请求,只接收get请求。maxmemory的设置比较适合于把redis当作于类似memcached的缓存来使用。

●appendonly

默认情况下,redis会在后台异步的把数据库镜像备份到磁盘,但是该备份是非常耗时的,而且备份也不能很频繁,如果发生诸如拉闸限电、拔插头等状况, 那么将造成比较大范围的数据丢失。所以redis提供了另外一种更加高效的数据库备份及灾难恢复方式。开启append only模式之后,redis会把所接收到的每一次写操作请求都追加到appendonly.aof文件中,当redis重新启动时,会从该文件恢复出之 前的状态。但是这样会造成appendonly.aof文件过大,所以redis还支持了BGREWRITEAOF指令,对appendonly.aof 进行重新整理。所以我认为推荐生产环境下的做法为关闭镜像,开启appendonly.aof,同时可以选择在访问较少的时间每天对appendonly.aof进行重写一次。

●appendfsync

设置对appendonly.aof文件进行同步的频率。always表示每次有写操作都进行同步,everysec表示对写操作进行累积,每秒同步一次。这个需要根据实际业务场景进行配置。

●vm-enabled

是否开启虚拟内存支持。因为redis是一个内存数据库,而且当内存满的时候,无法接收新的写请求,所以在redis 2.0中,提供了虚拟内存的支持。但是需要注意的是,redis中,所有的key都会放在内存中,在内存不够时,只会把value值放入交换区。这样保证 了虽然使用虚拟内存,但性能基本不受影响,同时,你需要注意的是你要把vm-max-memory设置到足够来放下你的所有的key。

●vm-swap-file

设置虚拟内存的交换文件路径。

●vm-max-memory

这里设置开启虚拟内存之后,redis将使用的最大物理内存的大小。默认为0,redis将把他所有的能放到交换文件的都放到交换文件中,以尽量少的使用物理内存。在生产环境下,需要根据实际情况设置该值,最好不要使用默认的0。

●vm-page-size

设置虚拟内存的页大小,如果你的value值比较大,比如说你要在value中放置博客、新闻之类的所有文章内容,就设大一点,如果要放置的都是很小的内容,那就设小一点。

●vm-pages

设置交换文件的总的page数量,需要注意的是,page table信息会放在物理内存中,每8个page就会占据RAM中的1个byte。总的虚拟内存大小 = vm-page-size * vm-pages。

●vm-max-threads

设置VM IO同时使用的线程数量。因为在进行内存交换时,对数据有编码和解码的过程,所以尽管IO设备在硬件上本上不能支持很多的并发读写,但是还是如果你所保存的vlaue值比较大,将该值设大一些,还是能够提升性能的。

●glueoutputbuf

把小的输出缓存放在一起,以便能够在一个TCP packet中为客户端发送多个响应,具体原理和真实效果我不是很清楚。所以根据注释,你不是很确定的时候就设置成yes。

●hash-max-zipmap-entries

在redis 2.0中引入了hash数据结构。当hash中包含超过指定元素个数并且最大的元素没有超过临界时,hash将以一种特殊的编码方式(大大减少内存使用)来存储,这里可以设置这两个临界值。

●activerehashing

开启之后,redis将在每100毫秒时使用1毫秒的CPU时 间来对redis的hash表进行重新hash,可以降低内存的使用。当你的使用场景中,有非常严格的实时性需要,不能够接受Redis时不时的对请求有 2毫秒的延迟的话,把这项配置为no。如果没有这么严格的实时性要求,可以设置为yes,以便能够尽可能快的释放内存。

 

 

四、操作Redis

 

1、插入数据

  

[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. redis 127.0.0.1:6379> set name wwl  
  2.   
  3.   OK  

[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. </pre><p></p><p>  设置一个key-value对。</p><p> </p><p>2、查询数据</p><p>  redis 127.0.0.1:6379> get name</p><p>  "wwl"</p><p>  取出key所对应的value。</p><p> </p><p>3、删除键值</p><p>  redis 127.0.0.1:6379> del name</p><p>  删除这个key及对应的value。</p><p> </p><p>4、验证键是否存在</p><p>  redis 127.0.0.1:6379> exists name</p><p>  (integer) 0</p><p>  其中0,代表此key不存在;1代表存在。</p><p></p><p>5、查看redis信息</p><p>       redis 127.0.0.1:6379> info</p><p></p><p></p><p>6、查看redis key信息</p><p>       redis 127.0.0.1:6379> keys *</p><p>       redis 127.0.0.1:6379> keys prefix_*</p><p></p><p>6、批量删除redis key    </p><pre style="margin:0px 0px 10px;padding:5px;border:0px;font-size:14px;vertical-align:baseline;background-color:#EEEEEE;font-family:Consolas, Menlo, Monaco, 'Lucida Console', 'Liberation Mono', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', 'Courier New', monospace, serif;overflow:auto;width:auto;max-height:600px;word-wrap:normal;color:#000000;font-style:normal;font-variant:normal;font-weight:normal;letter-spacing:normal;line-height:18px;orphans:auto;text-align:left;text-indent:0px;text-transform:none;widows:auto;word-spacing:0px;-webkit-text-stroke-width:0px;background-position:initial initial;background-repeat:initial initial;"> redis-cli KEYS "126.com*" | xargs redis-cli DEL  

 

五、各类型的基本操作

 

1)strings

string是最简单的类型,你可以理解成与Memcached是一模一样的类型,一个key对应一个value,其上支持的操作与Memcached的操作类似。但它的功能更丰富。

string类型是二进制安全的。意思是redis的string可以包含任何数据,比如jpg图片或者序列化的对象。从内部实现来看其实string可以看作byte数组,最大上限是1G字节,下面是string类型的定义:

 struct sdshdr {

  long len;

  long free;

  char buf[];

  };

len是buf数组的长度。

free是数组中剩余可用字节数,由此可以理解为什么string类型是二进制安全的了,因为它本质上就是个byte数组,当然可以包含任何数据了

buf是个char数组用于存贮实际的字符串内容,其实char和c#中的byte是等价的,都是一个字节。

另外string类型可以被部分命令按int处理.比如incr等命令,如果只用string类型,redis就可以被看作加上持久化特性的memcached。当然redis对string类型的操作比memcached还是多很多的,具体操作方法如下:

 

1、set

  设置key对应的值为string类型的value。

  例如我们添加一个name= HongWan的键值对,可以这样做:

  redis 127.0.0.1:6379> set name HongWan

  OK

  redis 127.0.0.1:6379>

 

2、setnx

  设置key对应的值为string类型的value。如果key已经存在,返回0,nx是not exist的意思。

  例如我们添加一个name= HongWan_new的键值对,可以这样做:

  redis 127.0.0.1:6379> get name

  "HongWan"

  redis 127.0.0.1:6379> setnx name HongWan_new

  (integer) 0

  redis 127.0.0.1:6379> get name

  "HongWan"

  redis 127.0.0.1:6379>

  由于原来name有一个对应的值,所以本次的修改不生效,且返回码是0。

 

3、setex

  设置key对应的值为string类型的value,并指定此键值对应的有效期。

  例如我们添加一个haircolor= red的键值对,并指定它的有效期是10秒,可以这样做:

  redis 127.0.0.1:6379> setex haircolor 10 red

  OK

  redis 127.0.0.1:6379> get haircolor

  "red"

  redis 127.0.0.1:6379> get haircolor

  (nil)

  redis 127.0.0.1:6379>

  可见由于最后一次的调用是10秒以后了,所以取不到haicolor这个键对应的值。

 

4、setrange

  设置指定key的value值的子字符串。

  例如我们希望将HongWan的126邮箱替换为gmail邮箱,那么我们可以这样做:

  redis 127.0.0.1:6379> get name

  "HongWan@126.com"

  redis 127.0.0.1:6379> setrange name 8 gmail.com

  (integer) 17

  redis 127.0.0.1:6379> get name

  "HongWan@gmail.com"

  redis 127.0.0.1:6379>

  其中的8是指从下标为8(包含8)的字符开始替换

 

5、mset

  一次设置多个key的值,成功返回ok表示所有的值都设置了,失败返回0表示没有任何值被设置。

  redis 127.0.0.1:6379> mset key1 HongWan1 key2 HongWan2

  OK

  redis 127.0.0.1:6379> get key1

  "HongWan1"

  redis 127.0.0.1:6379> get key2

  "HongWan2"

  redis 127.0.0.1:6379>

 

6、msetnx

  一次设置多个key的值,成功返回ok表示所有的值都设置了,失败返回0表示没有任何值被设置,但是不会覆盖已经存在的key。

  redis 127.0.0.1:6379> get key1

  "HongWan1"

  redis 127.0.0.1:6379> get key2

  "HongWan2"

  redis 127.0.0.1:6379> msetnx key2 HongWan2_new key3 HongWan3

  (integer) 0

  redis 127.0.0.1:6379> get key2

  "HongWan2"

  redis 127.0.0.1:6379> get key3

  (nil)

  可以看出如果这条命令返回0,那么里面操作都会回滚,都不会被执行。

 

7、get

  获取key对应的string值,如果key不存在返回nil。

  例如我们获取一个库中存在的键name,可以很快得到它对应的value

  redis 127.0.0.1:6379> get name

  "HongWan"

  redis 127.0.0.1:6379>

  我们获取一个库中不存在的键name1,那么它会返回一个nil以表时无此键值对

  redis 127.0.0.1:6379> get name1

  (nil)

  redis 127.0.0.1:6379>

 

8、getset

  设置key的值,并返回key的旧值。

  redis 127.0.0.1:6379> get name

  "HongWan"

  redis 127.0.0.1:6379> getset name HongWan_new

  "HongWan"

  redis 127.0.0.1:6379> get name

  "HongWan_new"

  redis 127.0.0.1:6379>

  接下来我们看一下如果key不存的时候会什么样儿?

  redis 127.0.0.1:6379> getset name1 aaa

  (nil)

  redis 127.0.0.1:6379>

  可见,如果key不存在,那么将返回nil

 

9、getrange

  获取指定key的value值的子字符串。

  具体样例如下:

  redis 127.0.0.1:6379> get name

  "HongWan@126.com"

  redis 127.0.0.1:6379> getrange name 0 6

  "HongWan"

  redis 127.0.0.1:6379>

  字符串左面下标是从0开始的

  redis 127.0.0.1:6379> getrange name -7 -1

  "126.com"

  redis 127.0.0.1:6379>

  字符串右面下标是从-1开始的

  redis 127.0.0.1:6379> getrange name 7 100

  "@126.com"

  redis 127.0.0.1:6379>

  当下标超出字符串长度时,将默认为是同方向的最大下标

 

10、mget

  一次获取多个key的值,如果对应key不存在,则对应返回nil。

  具体样例如下:

  redis 127.0.0.1:6379> mget key1 key2 key3

  1) "HongWan1"

  2) "HongWan2"

  3) (nil)

  redis 127.0.0.1:6379>

  key3由于没有这个键定义,所以返回nil。

 

11、incr

  对key的值做加加操作,并返回新的值。注意incr一个不是int的value会返回错误,incr一个不存在的key,则设置key为1

  redis 127.0.0.1:6379> set age 20

  OK

  redis 127.0.0.1:6379> incr age

  (integer) 21

  redis 127.0.0.1:6379> get age

  "21"

  redis 127.0.0.1:6379>

 

12、incrby

  同incr类似,加指定值 ,key不存在时候会设置key,并认为原来的value是 0

  redis 127.0.0.1:6379> get age

  "21"

  redis 127.0.0.1:6379> incrby age 5

  (integer) 26

  redis 127.0.0.1:6379> get name

  "HongWan@gmail.com"

  redis 127.0.0.1:6379> get age

  "26"

  redis 127.0.0.1:6379>

 

13、decr

  对key的值做的是减减操作,decr一个不存在key,则设置key为-1

  redis 127.0.0.1:6379> get age

  "26"

  redis 127.0.0.1:6379> decr age

  (integer) 25

  redis 127.0.0.1:6379> get age

  "25"

  redis 127.0.0.1:6379>

 

14、decrby

  同decr,减指定值。

  redis 127.0.0.1:6379> get age

  "25"

  redis 127.0.0.1:6379> decrby age 5

  (integer) 20

  redis 127.0.0.1:6379> get age

  "20"

  redis 127.0.0.1:6379>

  decrby完全是为了可读性,我们完全可以通过incrby一个负值来实现同样效果,反之一样。

  redis 127.0.0.1:6379> get age

  "20"

  redis 127.0.0.1:6379> incrby age -5

  (integer) 15

  redis 127.0.0.1:6379> get age

  "15"

  redis 127.0.0.1:6379>

15、append

  给指定key的字符串值追加value,返回新字符串值的长度。例如我们向name的值追加一个@126.com字符串,那么可以这样做:

  redis 127.0.0.1:6379> append name @126.com

  (integer) 15

  redis 127.0.0.1:6379> get name

  "HongWan@126.com"

  redis 127.0.0.1:6379>

 

16、strlen

  取指定key的value值的长度。

  redis 127.0.0.1:6379> get name

  "HongWan_new"

  redis 127.0.0.1:6379> strlen name

  (integer) 11

  redis 127.0.0.1:6379> get age

  "15"

  redis 127.0.0.1:6379> strlen age

  (integer) 2

  redis 127.0.0.1:6379>

 

2)hash

Redis hash是一个string类型的field和value的映射表.它的添加、删除操作都是O(1)(平均)。hash特别适合用于存储对象。相较于将对象的每个字段存成单个string类型。将一个对象存储在hash类型中会占用更少的内存,并且可以更方便的存取整个对象。省内存的原因是新建一个hash对象时开始是用zipmap(又称为small hash)来存储的。这个zipmap其实并不是hash table,但是zipmap相比正常的hash实现可以节省不少hash本身需要的一些元数据存储开销。尽管zipmap的添加,删除,查找都是O(n),但是由于一般对象的field数量都不太多。所以使用zipmap也是很快的,也就是说添加删除平均还是O(1)。如果field或者value的大小超出一定限制后,Redis会在内部自动将zipmap替换成正常的hash实现. 这个限制可以在配置文件中指定

 

  hash-max-zipmap-entries 64 #配置字段最多64个。

  hash-max-zipmap-value 512 #配置value最大为512字节。

 

1、hset

  设置hash field为指定值,如果key不存在,则先创建。

  redis 127.0.0.1:6379> hset myhash field1 Hello

  (integer) 1

  redis 127.0.0.1:6379>

 

2、hsetnx

  设置hash field为指定值,如果key不存在,则先创建。如果field已经存在,返回0,nx是not exist的意思。

  redis 127.0.0.1:6379> hsetnx myhash field "Hello"

  (integer) 1

  redis 127.0.0.1:6379> hsetnx myhash field "Hello"

  (integer) 0

  redis 127.0.0.1:6379>

  第一次执行是成功的,但第二次执行相同的命令失败,原因是field已经存在了。

 

3、hmset

  同时设置hash的多个field。

  redis 127.0.0.1:6379> hmset myhash field1 Hello field2 World

  OK

  redis 127.0.0.1:6379>

 

4、hget

  获取指定的hash field。

  redis 127.0.0.1:6379> hget myhash field1

  "Hello"

  redis 127.0.0.1:6379> hget myhash field2

  "World"

  redis 127.0.0.1:6379> hget myhash field3

  (nil)

  redis 127.0.0.1:6379>

  由于数据库没有field3,所以取到的是一个空值nil。

 

5、hmget

  获取全部指定的hash filed。

  redis 127.0.0.1:6379> hmget myhash field1 field2 field3

  1) "Hello"

  2) "World"

  3) (nil)

  redis 127.0.0.1:6379>

  由于数据库没有field3,所以取到的是一个空值nil。

 

6、hincrby

  指定的hash filed 加上给定值。

  redis 127.0.0.1:6379> hset myhash field3 20

  (integer) 1

  redis 127.0.0.1:6379> hget myhash field3

  "20"

  redis 127.0.0.1:6379> hincrby myhash field3 -8

  (integer) 12

  redis 127.0.0.1:6379> hget myhash field3

  "12"

  redis 127.0.0.1:6379>

  在本例中我们将field3的值从20降到了12,即做了一个减8的操作。

 

7、hexists

  测试指定field是否存在。

  redis 127.0.0.1:6379> hexists myhash field1

  (integer) 1

  redis 127.0.0.1:6379> hexists myhash field9

  (integer) 0

  redis 127.0.0.1:6379>

  通过上例可以说明field1存在,但field9是不存在的。

 

8、hlen

  返回指定hash的field数量。

  redis 127.0.0.1:6379> hlen myhash

  (integer) 4

  redis 127.0.0.1:6379>

  通过上例可以看到myhash中有4个field。

 

9、hdel

  返回指定hash的field数量。

  redis 127.0.0.1:6379> hlen myhash

  (integer) 4

  redis 127.0.0.1:6379> hdel myhash field1

  (integer) 1

  redis 127.0.0.1:6379> hlen myhash

  (integer) 3

  redis 127.0.0.1:6379>

 

10、hkeys

  返回hash的所有field。

  redis 127.0.0.1:6379> hkeys myhash

  1) "field2"

  2) "field"

  3) "field3"

  redis 127.0.0.1:6379>

  说明这个hash中有3个field。

 

11、hvals

  返回hash的所有value。

  redis 127.0.0.1:6379> hvals myhash

  1) "World"

  2) "Hello"

  3) "12"

  redis 127.0.0.1:6379>

  说明这个hash中有3个field。

 

12、hgetall

  获取某个hash中全部的filed及value。

  redis 127.0.0.1:6379> hgetall myhash

  1) "field2"

  2) "World"

  3) "field"

  4) "Hello"

  5) "field3"

  6) "12"

  redis 127.0.0.1:6379>

  可见,一下子将myhash中所有的field及对应的value都取出来了。

 

3)list

 Redis的list类型其实就是一个每个子元素都是string类型的双向链表。链表的最大长度是(2的32次方)。我们可以通过push,pop操作从链表的头部或者尾部添加删除元素。这使得list既可以用作栈,也可以用作队列。

 

  有意思的是list的pop操作还有阻塞版本的,当我们[lr]pop一个list对象时,如果list是空,或者不存在,会立即返回nil。但是阻塞版本的b[lr]pop可以则可以阻塞,当然可以加超时时间,超时后也会返回nil。为什么要阻塞版本的pop呢,主要是为了避免轮询。举个简单的例子如果我们用list来实现一个工作队列。执行任务的thread可以调用阻塞版本的pop去获取任务这样就可以避免轮询去检查是否有任务存在。当任务来时候工作线程可以立即返回,也可以避免轮询带来的延迟。说了这么多,接下来看一下实际操作的方法吧:

 

1、lpush

  在key对应list的头部添加字符串元素:

redis 127.0.0.1:6379> lpush mylist "world"

(integer) 1

redis 127.0.0.1:6379> lpush mylist "hello"

(integer) 2

redis 127.0.0.1:6379> lrange mylist 0 -1

1) "hello"

2) "world"

redis 127.0.0.1:6379>

 

  在此处我们先插入了一个world,然后在world的头部插入了一个hello。其中lrange是用于取mylist的内容。

 

2、rpush

在key对应list的尾部添加字符串元素:

redis 127.0.0.1:6379> rpush mylist2 "hello"

(integer) 1

redis 127.0.0.1:6379> rpush mylist2 "world"

(integer) 2

redis 127.0.0.1:6379> lrange mylist2 0 -1

1) "hello"

2) "world"

redis 127.0.0.1:6379>

 

  在此处我们先插入了一个hello,然后在hello的尾部插入了一个world。

 

3、linsert

在key对应list的特定位置之前或之后添加字符串元素:

redis 127.0.0.1:6379> rpush mylist3 "hello"

(integer) 1

redis 127.0.0.1:6379> rpush mylist3 "world"

(integer) 2

redis 127.0.0.1:6379> linsert mylist3 before "world""there"

(integer) 3

redis 127.0.0.1:6379> lrange mylist3 0 -1

1) "hello"

2) "there"

3) "world"

redis 127.0.0.1:6379>

 

  在此处我们先插入了一个hello,然后在hello的尾部插入了一个world,然后又在world的前面插入了there。

 

4、lset

设置list中指定下标的元素值(下标从0开始):

redis 127.0.0.1:6379> rpush mylist4 "one"

(integer) 1

redis 127.0.0.1:6379> rpush mylist4 "two"

(integer) 2

redis 127.0.0.1:6379> rpush mylist4 "three"

(integer) 3

redis 127.0.0.1:6379> lset mylist4 0 "four"

OK

redis 127.0.0.1:6379> lset mylist4 -2 "five"

OK

redis 127.0.0.1:6379> lrange mylist4 0 -1

1) "four"

2) "five"

3) "three"

redis 127.0.0.1:6379>

 

  在此处我们依次插入了one,two,three,然后将标是0的值设置为four,再将下标是-2的值设置为five。

 

5、lrem

  从key对应list中删除count个和value相同的元素。

  count>0时,按从头到尾的顺序删除,具体如下:

redis 127.0.0.1:6379> rpush mylist5 "hello"

(integer) 1

redis 127.0.0.1:6379> rpush mylist5 "hello"

(integer) 2

redis 127.0.0.1:6379> rpush mylist5 "foo"

(integer) 3

redis 127.0.0.1:6379> rpush mylist5 "hello"

(integer) 4

redis 127.0.0.1:6379> lrem mylist5 2 "hello"

(integer) 2

redis 127.0.0.1:6379> lrange mylist5 0 -1

1) "foo"

2) "hello"

redis 127.0.0.1:6379>

 

  count<0时,按从尾到头的顺序删除,具体如下:

redis 127.0.0.1:6379> rpush mylist6 "hello"

(integer) 1

redis 127.0.0.1:6379> rpush mylist6 "hello"

(integer) 2

redis 127.0.0.1:6379> rpush mylist6 "foo"

(integer) 3

redis 127.0.0.1:6379> rpush mylist6 "hello"

(integer) 4

redis 127.0.0.1:6379> lrem mylist6 -2 "hello"

(integer) 2

redis 127.0.0.1:6379> lrange mylist6 0 -1

1) "hello"

2) "foo"

redis 127.0.0.1:6379>

 

  count=0时,删除全部,具体如下:

redis 127.0.0.1:6379> rpush mylist7 "hello"

(integer) 1

redis 127.0.0.1:6379> rpush mylist7 "hello"

(integer) 2

redis 127.0.0.1:6379> rpush mylist7 "foo"

(integer) 3

redis 127.0.0.1:6379> rpush mylist7 "hello"

(integer) 4

redis 127.0.0.1:6379> lrem mylist7 0 "hello"

(integer) 3

redis 127.0.0.1:6379> lrange mylist7 0 -1

1) "foo"

redis 127.0.0.1:6379>

 

6、ltrim

保留指定key 的值范围内的数据:

redis 127.0.0.1:6379> rpush mylist8 "one"

(integer) 1

redis 127.0.0.1:6379> rpush mylist8 "two"

(integer) 2

redis 127.0.0.1:6379> rpush mylist8 "three"

(integer) 3

redis 127.0.0.1:6379> rpush mylist8 "four"

(integer) 4

redis 127.0.0.1:6379> ltrim mylist8 1 -1

OK

redis 127.0.0.1:6379> lrange mylist8 0 -1

1) "two"

2) "three"

3) "four"

redis 127.0.0.1:6379>

 

7、lpop

从list的头部删除元素,并返回删除元素:

redis 127.0.0.1:6379> lrange mylist 0 -1

1) "hello"

2) "world"

redis 127.0.0.1:6379> lpop mylist

"hello"

redis 127.0.0.1:6379> lrange mylist 0 -1

1) "world"

redis 127.0.0.1:6379>

 

8、rpop

从list的尾部删除元素,并返回删除元素:

redis 127.0.0.1:6379> lrange mylist2 0 -1

1) "hello"

2) "world"

redis 127.0.0.1:6379> rpop mylist2

"world"

redis 127.0.0.1:6379> lrange mylist2 0 -1

1) "hello"

redis 127.0.0.1:6379>

 

9、rpoplpush

从第一个list的尾部移除元素并添加到第二个list的头部,最后返回被移除的元素值,整个操作是原子的.如果第一个list是空或者不存在返回nil:

redis 127.0.0.1:6379> lrange mylist5 0 -1

1) "three"

2) "foo"

3) "hello"

redis 127.0.0.1:6379> lrange mylist6 0 -1

1) "hello"

2) "foo"

redis 127.0.0.1:6379> rpoplpush mylist5 mylist6

"hello"

redis 127.0.0.1:6379> lrange mylist5 0 -1

1) "three"

2) "foo"

redis 127.0.0.1:6379> lrange mylist6 0 -1

1) "hello"

2) "hello"

3) "foo"

redis 127.0.0.1:6379>

 

10、lindex

返回名称为key的list中index位置的元素:

redis 127.0.0.1:6379> lrange mylist5 0 -1

1) "three"

2) "foo"

redis 127.0.0.1:6379> lindex mylist5 0

"three"

redis 127.0.0.1:6379> lindex mylist5 1

"foo"

redis 127.0.0.1:6379>

 

11、llen

返回key对应list的长度:

redis 127.0.0.1:6379> llen mylist5

(integer) 2

redis 127.0.0.1:6379>

4)sets

Redis的set是string类型的无序集合。set元素最大可以包含(2的32次方)个元素。

set的是通过hash table实现的,所以添加、删除和查找的复杂度都是O(1)。hash table会随着添加或者删除自动的调整大小。需要注意的是调整hash table大小时候需要同步(获取写锁)会阻塞其他读写操作,可能不久后就会改用跳表(skip list)来实现,跳表已经在sortedset中使用了。关于set集合类型除了基本的添加删除操作,其他有用的操作还包含集合的取并集(union),交集(intersection),差集(difference)。通过这些操作可以很容易的实现sns中的好友推荐和blog的tag功能。下面详细介绍set相关命令:

 

1、sadd

  向名称为key的set中添加元素:

  redis 127.0.0.1:6379> sadd myset "hello"

  (integer) 1

  redis 127.0.0.1:6379> sadd myset "world"

  (integer) 1

  redis 127.0.0.1:6379> sadd myset "world"

  (integer) 0

  redis 127.0.0.1:6379> smembers myset

  1) "world"

  2) "hello"

  redis 127.0.0.1:6379>

  本例中,我们向myset中添加了三个元素,但由于第三个元素跟第二个元素是相同的,所以第三个元素没有添加成功,最后我们用smembers来查看myset中的所有元素。

 

2、srem

  删除名称为key的set中的元素member:

  redis 127.0.0.1:6379> sadd myset2 "one"

  (integer) 1

  redis 127.0.0.1:6379> sadd myset2 "two"

  (integer) 1

  redis 127.0.0.1:6379> sadd myset2 "three"

  (integer) 1

  redis 127.0.0.1:6379> srem myset2 "one"

  (integer) 1

  redis 127.0.0.1:6379> srem myset2 "four"

  (integer) 0

  redis 127.0.0.1:6379> smembers myset2

  1) "three"

  2) "two"

  redis 127.0.0.1:6379>

  本例中,我们向myset2中添加了三个元素后,再调用srem来删除one和four,但由于元素中没有four所以,此条srem命令执行失败。

 

3、spop

  随机返回并删除名称为key的set中一个元素:

  redis 127.0.0.1:6379> sadd myset2 "one"

  (integer) 1

  redis 127.0.0.1:6379> sadd myset2 "two"

  (integer) 1

  redis 127.0.0.1:6379> sadd myset2 "three"

  (integer) 1

  redis 127.0.0.1:6379> srem myset2 "one"

  (integer) 1

  redis 127.0.0.1:6379> srem myset2 "four"

  (integer) 0

  redis 127.0.0.1:6379> smembers myset2

  1) "three"

  2) "two"

  redis 127.0.0.1:6379>

  本例中,我们向myset3中添加了三个元素后,再调用spop来随机删除一个元素,可以看到three元素被删除了。

 

4、sdiff

  返回所有给定key与第一个key的差集:

  redis 127.0.0.1:6379> sadd myset2 "one"

  (integer) 1

  redis 127.0.0.1:6379> sadd myset2 "two"

  (integer) 1

  redis 127.0.0.1:6379> sadd myset2 "three"

  (integer) 1

  redis 127.0.0.1:6379> srem myset2 "one"

  (integer) 1

  redis 127.0.0.1:6379> srem myset2 "four"

  (integer) 0

  redis 127.0.0.1:6379> smembers myset2

  1) "three"

  2) "two"

  redis 127.0.0.1:6379>

  本例中,我们可以看到myset2中的元素与myset3中不同的只是three,所以只有three被查出来了,而不是three和one,因为one是myset3的元素。

  我们也可以将myset2和myset3换个顺序来看一下结果:

  redis 127.0.0.1:6379> sdiff myset3 myset2

  1) "one"

  redis 127.0.0.1:6379>

  这个结果中只显示了,myset3中的元素与myset2中不同的元素。

 

5、sdiffstore

  返回所有给定key与第一个key的差集,并将结果存为另一个key:

  redis 127.0.0.1:6379> smembers myset2

  1) "three"

  2) "two"

  redis 127.0.0.1:6379> smembers myset3

  1) "two"

  2) "one"

  redis 127.0.0.1:6379> sdiffstore myset4 myset2 myset3

  (integer) 1

  redis 127.0.0.1:6379> smembers myset4

  1) "three"

  redis 127.0.0.1:6379>

 

6、sinter

  返回所有给定key的交集:

  redis 127.0.0.1:6379> smembers myset2

  1) "three"

  2) "two"

  redis 127.0.0.1:6379> smembers myset3

  1) "two"

  2) "one"

  redis 127.0.0.1:6379> sinter myset2 myset3

  1) "two"

  redis 127.0.0.1:6379>

  通过本例的结果可以看出, myset2和myset3的交集two被查出来了。

 

7、sinterstore

  返回所有给定key的交集,并将结果存为另一个key

  redis 127.0.0.1:6379> smembers myset2

  1) "three"

  2) "two"

  redis 127.0.0.1:6379> smembers myset3

  1) "two"

  2) "one"

  redis 127.0.0.1:6379> sinterstore myset5 myset2 myset3

  (integer) 1

  redis 127.0.0.1:6379> smembers myset5

  1) "two"

  redis 127.0.0.1:6379>

  通过本例的结果可以看出, myset2和myset3的交集被保存到myset5中了

 

8、sunion

  返回所有给定key的并集

  redis 127.0.0.1:6379> smembers myset2

  1) "three"

  2) "two"

  redis 127.0.0.1:6379> smembers myset3

  1) "two"

  2) "one"

  redis 127.0.0.1:6379> sunion myset2 myset3

  1) "three"

  2) "one"

  3) "two"

  redis 127.0.0.1:6379>

  通过本例的结果可以看出, myset2和myset3的并集被查出来了

 

9、sunionstore

  返回所有给定key的并集,并将结果存为另一个key

  redis 127.0.0.1:6379> smembers myset2

  1) "three"

  2) "two"

  redis 127.0.0.1:6379> smembers myset3

  1) "two"

  2) "one"

  redis 127.0.0.1:6379> sunionstore myset6 myset2 myset3

  (integer) 3

  redis 127.0.0.1:6379> smembers myset6

  1) "three"

  2) "one"

  3) "two"

  redis 127.0.0.1:6379>

  通过本例的结果可以看出, myset2和myset3的并集被保存到myset6中了

 

10、smove

  从第一个key对应的set中移除member并添加到第二个对应set中

  redis 127.0.0.1:6379> smembers myset2

  1) "three"

  2) "two"

  redis 127.0.0.1:6379> smembers myset3

  1) "two"

  2) "one"

  redis 127.0.0.1:6379> smove myset2 myset7 three

  (integer) 1

  redis 127.0.0.1:6379> smembers myset7

  1) "three"

  redis 127.0.0.1:6379>

  通过本例可以看到,myset2的three被移到myset7中了

 

11、scard

  返回名称为key的set的元素个数

  redis 127.0.0.1:6379> scard myset2

  (integer) 1

  redis 127.0.0.1:6379>

  通过本例可以看到,myset2的成员数量为1

 

12、sismember

  测试member是否是名称为key的set的元素

  redis 127.0.0.1:6379> smembers myset2

  1) "two"

  redis 127.0.0.1:6379> sismember myset2 two

  (integer) 1

  redis 127.0.0.1:6379> sismember myset2 one

  (integer) 0

  redis 127.0.0.1:6379>

  通过本例可以看到,two是myset2的成员,而one不是。

 

13、srandmember

 

  随机返回名称为key的set的一个元素,但是不删除元素

  redis 127.0.0.1:6379> smembers myset3

  1) "two"

  2) "one"

  redis 127.0.0.1:6379> srandmember myset3

  "two"

  redis 127.0.0.1:6379> srandmember myset3

  "one"

  redis 127.0.0.1:6379>

5)sorted sets

 和set一样sorted set也是string类型元素的集合,不同的是每个元素都会关联一个double类型的score。sorted set的实现是skip list和hash table的混合体。

当元素被添加到集合中时,一个元素到score的映射被添加到hash table中,所以给定一个元素获取score的开销是O(1),另一个score到元素的映射被添加到skip list,并按照score排序,所以就可以有序的获取集合中的元素。添加,删除操作开销都是O(log(N))和skip list的开销一致,redis的skip list实现用的是双向链表,这样就可以逆序从尾部取元素。sorted set最经常的使用方式应该是作为索引来使用.我们可以把要排序的字段作为score存储,对象的id当元素存储。下面是sorted set相关命令

 

1、zadd

  向名称为key的zset中添加元素member,score用于排序。如果该元素已经存在,则根据score更新该元素的顺序

  redis 127.0.0.1:6379> zadd myzset 1 "one"

  (integer) 1

  redis 127.0.0.1:6379> zadd myzset 2 "two"

  (integer) 1

  redis 127.0.0.1:6379> zadd myzset 3 "two"

  (integer) 0

  redis 127.0.0.1:6379> zrange myzset 0 -1 withscores

  1) "one"

  2) "1"

  3) "two"

  4) "3"

  redis 127.0.0.1:6379>

  本例中我们向myzset中添加了one和two,并且two被设置了2次,那么将以最后一次的设置为准,最后我们将所有元素都显示出来并显示出了元素的score。

 

2、zrem

  删除名称为key的zset中的元素member

  redis 127.0.0.1:6379> zrange myzset 0 -1 withscores

  1) "one"

  2) "1"

  3) "two"

  4) "3"

  redis 127.0.0.1:6379> zrem myzset two

  (integer) 1

  redis 127.0.0.1:6379> zrange myzset 0 -1 withscores

  1) "one"

  2) "1"

  redis 127.0.0.1:6379>

  可以看到two被删除了

 

3、zincrby

  如果在名称为key的zset中已经存在元素member,则该元素的score增加increment;否则向集合中添加该元素,其score的值为increment

  redis 127.0.0.1:6379> zadd myzset2 1 "one"

  (integer) 1

  redis 127.0.0.1:6379> zadd myzset2 2 "two"

  (integer) 1

  redis 127.0.0.1:6379> zincrby myzset2 2 "one"

  "3"

  redis 127.0.0.1:6379> zrange myzset2 0 -1 withscores

  1) "two"

  2) "2"

  3) "one"

  4) "3"

  redis 127.0.0.1:6379>

  本例中将one的score从1增加了2,增加到了3

 

4、zrank

  返回名称为key的zset中member元素的排名(按score从小到大排序)即下标

  redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores

  1) "one"

  2) "1"

  3) "two"

  4) "2"

  5) "three"

  6) "3"

  7) "five"

  8) "5"

  redis 127.0.0.1:6379> zrank myzset3 two

  (integer) 1

  redis 127.0.0.1:6379>

  本例,我这里取的是下标,而不是score

中将two的下标是1

 

5、zrevrank

  返回名称为key的zset中member元素的排名(按score从大到小排序)即下标

  redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores

  1) "one"

  2) "1"

  3) "two"

  4) "2"

  5) "three"

  6) "3"

  7) "five"

  8) "5"

  redis 127.0.0.1:6379> zrank myzset3 two

  (integer) 1

  redis 127.0.0.1:6379>

  按从大到小排序的话two是第三个元素,下标是2

 

6、zrevrange

 

  返回名称为key的zset(按score从大到小排序)中的index从start到end的所有元素

  redis 127.0.0.1:6379> zrevrange myzset3 0 -1 withscores

  1) "five"

  2) "5"

  3) "three"

  4) "3"

  5) "two"

  6) "2"

  7) "one"

  8) "1"

  redis 127.0.0.1:6379>

  首先按score从大到小排序,再取出全部元素

 

7、zrangebyscore

  返回集合中score在给定区间的元素

  redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores

  1) "one"

  2) "1"

  3) "two"

  4) "2"

  5) "three"

  6) "3"

  7) "five"

  8) "5"

  redis 127.0.0.1:6379> zrangebyscore myzset3 2 3 withscores

  1) "two"

  2) "2"

  3) "three"

  4) "3"

  redis 127.0.0.1:6379>

  本例中,返回了score在2~3区间的元素

 

8、zcount

  返回集合中score在给定区间的数量

  redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores

  1) "one"

  2) "1"

  3) "two"

  4) "2"

5) "three"

  6) "3"

  7) "five"

  8) "5"

  redis 127.0.0.1:6379> zcount myzset3 2 3

  (integer) 2

  redis 127.0.0.1:6379>

  本例中,计算了score在2~3之间的元素数目

 

9、zcard

  返回集合中元素个数

  redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores

  1) "one"

  2) "1"

  3) "two"

  4) "2"

  5) "three"

  6) "3"

  7) "five"

  8) "5"

  redis 127.0.0.1:6379> zcard myzset3

 

  (integer) 4

 

  redis 127.0.0.1:6379>

 

  从本例看出myzset3这个集全的元素数量是4

 

10、zscore

 

  返回给定元素对应的score

  redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores

 

  1) "one"

 

  2) "1"

 

  3) "two"

 

  4) "2"

 

  5) "three"

 

  6) "3"

 

  7) "five"

 

  8) "5"

 

  redis 127.0.0.1:6379> zscore myzset3 two

 

  "2"

 

  redis 127.0.0.1:6379>

 

  此例中我们成功的将two的score取出来了。

 

11、zremrangebyrank

  删除集合中排名在给定区间的元素

  redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores

  1) "one"

  2) "1"

  3) "two"

  4) "2"

  5) "three"

  6) "3"

  7) "five"

  8) "5"

  redis 127.0.0.1:6379> zremrangebyrank myzset3 3 3

  (integer) 1

  redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores

  1) "one"

  2) "1"

  3) "two"

  4) "2"

  5) "three"

  6) "3"

  redis 127.0.0.1:6379>

  在本例中我们将myzset3中按从小到大排序结果的下标为3的元素删除了。

 

12、zremrangebyscore

  删除集合中score在给定区间的元素

  redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores

  1) "one"

  2) "1"

  3) "two"

  4) "2"

  5) "three"

  6) "3"

  redis 127.0.0.1:6379> zremrangebyscore myzset3 1 2

  (integer) 2

  redis 127.0.0.1:6379> zrange myzset3 0 -1 withscores

  1) "three"

  2) "3"

  redis 127.0.0.1:6379>

  在本例中我们将myzset3中按从小到大排序结果的score在1~2之间的元素删除了。


redis 性能测试

[plain]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. Usage: redis-benchmark [-h <host>] [-p <port>] [-c <clients>] [-n <requests]> [-k <boolean>]    
  2.     
  3. -h <hostname>      Server hostname (default 127.0.0.1)    
  4. -p <port>          Server port (default 6379)    
  5. -s <socket>        Server socket (overrides host and port)    
  6. -c <clients>       Number of parallel connections (default 50)    
  7. -n <requests>      Total number of requests (default 10000)    
  8. -d <size>          Data size of SET/GET value in bytes (default 2)    
  9. -k <boolean>       1=keep alive 0=reconnect (default 1)    
  10. -r <keyspacelen>   Use random keys for SET/GET/INCR, random values for SADD    
  11.   Using this option the benchmark will get/set keys    
  12.   in the form mykey_rand:000000012456 instead of constant    
  13.   keys, the <keyspacelen> argument determines the max    
  14.   number of values for the random number. For instance    
  15.   if set to 10 only rand:000000000000 - rand:000000000009    
  16.   range will be allowed.    
  17. -P <numreq>        Pipeline <numreq> requests. Default 1 (no pipeline).    
  18. -q                 Quiet. Just show query/sec values 只显示每秒钟能处理多少请求数结果    
  19. --csv              Output in CSV format    
  20. -l                 Loop. Run the tests forever 永久测试    
  21. -t <tests>         Only run the comma separated list of tests. The test    
  22.                     names are the same as the ones produced as output.    
  23. -I                 Idle mode. Just open N idle connections and wait.    

实例:redis-benchmark -h 127.0.0.1 -p 6379 -q -d 100  
SET/GET 100 bytes 检测host为127.0.0.1 端口为6379的redis服务器性能


redis-benchmark -h 127.0.0.1 -p 6379 -c 5000 -n 100000 
5000个并发连接,100000个请求,检测host为127.0.0.1 端口为6379的redis服务器性能 


benchmark工具测试信息:
测试命令:
redis-benchmark -n 100000 -c 60
向redis服务器发送100000个请求,每个请求附带60个并发客户端
结果(部分):
====== SET ======
对集合写入测试
  100000 requests completed in 2.38 seconds
100000个请求在2.38秒内完成
  60 parallel clients
每次请求有60个并发客户端
  3 bytes payload
每次写入3个字节的数据
  keep alive: 1
保持一个连接,一台服务器来处理这些请求


93.06% <= 15 milliseconds
99.96% <= 31 milliseconds
99.98% <= 46 milliseconds
99.99% <= 62 milliseconds
100.00% <= 62 milliseconds
所有请求在62毫秒内完成
42105.26 requests per second
每秒处理42105.26次请求
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值