Redis操作手册

一、Redis简介

1.1 NoSQL

NoSQL,泛指非关系型数据库,NoSQL数据库分为四大类:键值存储数据库(RedisVoldemortOracle BDB)、列存储数据库(HBaseRiak)、文档型数据库(CouchDBMongoDB)、图形数据库(Neo4JInfoGridInfinite Graph)。

1.2 非关系型数据库特点

  • 数据模型比较简单
  • 需要灵活性更强的IT系统
  • 对数据库性能要求较高
  • 不需要高度的数据一致性
  • 对于给定key,比较容易映射复杂值的环境

1.3 Redis

是以key-value形式存储,和传统的关系型数据库不一样,不一定遵循传统数据库的一些基本要求。

优点:

  • 对数据高并发读写
  • 对海量数据的高效率存储和访问
  • 对数据的可扩展性和高可用性

缺点:

  • RedisACID处理非常简单)
  • 无法做到太复杂的关系数据库模型

Redis是以key-value存储的,键可以包含:字符串(string)、哈希、链表(list)、集合(set)、有序集合(zet)。这些数据集合都支持push/pop、add/remove及取交集和并集以及更丰富的操作,Redis支持各种不同的方式排序,为了保证效率,数据都是缓存在内存中,它可以周期性的把更新的数据写入磁盘或者把修改操作写入追加到文件。

 Redis有三种集群方式,主从模式、哨兵模式、集群模式。

二、Redis安装与部署

下载地址:http://redis.io/download

首先说明一下,以下安装是在CentOS 7环境下进行的。

安装步骤:

  1. 首先需要安装gcc,把下载好的redis-4.0.1.tar.gz 放到自己指定的文件夹下(/usr/software)

  2. 进行解压,将Redis解压到/usr/local/文件夹下
    [root@localhost software]# tar -zxvf redis-4.0.1.tar.gz -C /usr/local/
  3. 进入到redis-4.0.1目录下,进行编译make

    [root@localhost local]# cd redis-4.0.1/
    [root@localhost redis-4.0.1]# make
  4. 进入到src下进行安装 make install  验证(ll 查看src下的目录,有redis-server redis-cil即可)

    [root@localhost redis-4.0.1]# cd src/
    [root@localhost src]# make install
  5. 建立俩个文件夹存放redis命令和配置文件

    [root@localhost local]# mkdir -p /usr/local/redis/etc
    [root@localhost local]# mkdir -p /usr/local/redis/bin
  6. redis-4.0.1下的redis.conf 复制到/usr/local/redis/etc

    [root@localhost local]# cp /usr/local/redis-4.0.1/redis.conf /usr/local/redis/etc/
  7. redis-4.0.1/src里的mkreleasehdr.shredis-benchmarkredis-check-aofredis-check-dumpredis-cliredis-server

    文件移动到bin

    [root@localhost local]# cd redis-4.0.1/src/
    [root@localhost src]# mv mkreleasehdr.sh redis-benchmark redis-check-aof redis-check-rdb redis-cli redis-server /usr/local/redis/bin
  8. 启动时并指定配置文件:./redis-server /usr/local/redis/etc/redis.conf(注意要使用后台启动,所以修改redis.conf里的daemonize 改为yes)

    [root@localhost local]# /usr/local/redis/bin/redis-server /usr/local/redis/etc/redis.conf 

    或者进入/usr/local/redis/bin/目录下

    [root@localhost local]# ./redis-server /usr/local/redis/etc/redis.conf

     前台启动成功:

    进入/usr/local/redis/etc/目录下,修改redis.conf配置文件,将daemonize选项改为yes,表示默认为后台启动

    ################################# GENERAL #####################################
    
    # By default Redis does not run as a daemon. Use 'yes' if you need it.
    # Note that Redis will write a pid file in /var/run/redis.pid when daemonized.
    daemonize yes

     设置将数据文件放到指定的目录文件夹:

    复制代码
    # The filename where to dump the DB
    dbfilename dump.rdb
    
    # The working directory.
    #
    # The DB will be written inside this directory, with the filename specified
    # above using the 'dbfilename' configuration directive.
    #
    # The Append Only File will also be created inside this directory.
    #
    # Note that you must specify a directory here, not a file name.
    dir /usr/local/redis/etc/
    复制代码
  9. 再次启动,则为后台启动
    复制代码
    [root@localhost local]# cd redis/bin/
    [root@localhost bin]# ./redis-server /usr/local/redis/etc/redis.conf 
    13322:C 19 Aug 09:37:02.450 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
    13322:C 19 Aug 09:37:02.450 # Redis version=4.0.1, bits=64, commit=00000000, modified=0, pid=13322, just started
    13322:C 19 Aug 09:37:02.450 # Configuration loaded
    [root@localhost bin]# 
    复制代码
  10. 使用命令 ps -ef | grep redis 查看是否有redis服务 或者 查看端口:netstat -tunpl | grep 6379

    [root@localhost bin]# ps -ef|grep 6379
    root      13323      1  0 09:37 ?        00:00:00 ./redis-server 127.0.0.1:6379
    root      13345   2732  0 09:38 pts/0    00:00:00 grep --color=auto 6379

    只要显示为以上情况则为启动成功。

  11. 进入redis客户端 ./redis-cli 退出客户端quit

    [root@localhost bin]# ./redis-cli 
    127.0.0.1:6379> 
  12. 退出redis服务

    1pkill redis-server 

    2kill 进程号

    3/usr/local/redis/bin/redis-cli shutdown

 三、使用Redis Desktop Manager连接Redis

如果就以上面的配置情况使用Desktop Manager连接Redis的话,发现根本连接不上:

1、因为Redis默认端口是6379,所以首先查看6379端口是否开启

[root@localhost bin]# firewall-cmd --query-port=6379/tcp
yes

如果返回结果为no,那么证明6379端口确实没有开启,需要使用命令开启6379端口

[root@localhost bin]# firewall-cmd --add-port=6379/tcp
success

返回success表示已经成功开启该端口。

2、修改redis.conf配置文件,注释掉 bind 127.0.0.1以及设置自己的密码 requirepass "root",这里的密码是自己随便设置的。

复制代码
################################## NETWORK #####################################

# By default, if no "bind" configuration directive is specified, Redis listens
# for connections from all the network interfaces available on the server.
# It is possible to listen to just one or multiple selected interfaces using
# the "bind" configuration directive, followed by one or more IP addresses.
#
# Examples:
#
# bind 192.168.1.100 10.0.0.1
# bind 127.0.0.1 ::1
复制代码
复制代码
################################## SECURITY ###################################

# Require clients to issue AUTH <PASSWORD> before processing any other
# commands.  This might be useful in environments in which you do not trust
# others with access to the host running redis-server.
#
# This should stay commented out for backward compatibility and because most
# people do not need auth (e.g. they run their own servers).
#
# Warning: since Redis is pretty fast an outside user can try up to
# 150k passwords per second against a good box. This means that you should
# use a very strong password otherwise it will be very easy to break.
#
requirepass "root"
复制代码

注:设置密码 为了安全一定要设,而且这里如果不绑定ip也不设密码的话,redis是默认保护模式,只能本虚拟机访问,不允许其他ip访问

重新启动Redis服务

[root@localhost bin]# ./redis-server /usr/local/redis/etc/redis.conf

再次使用Redis Desktop Manager 连接Redis服务,可以成功连接。

但是现在又会有另外一个问题,当我们想使用 ./redis-cli命令登陆客户端使用Redis命令时,发现会没有权限操作。

[root@localhost bin]# ./redis-cli 
127.0.0.1:6379> keys *
(error) NOAUTH Authentication required.
127.0.0.1:6379> 

这是因为我们给Redis添加了密码保护,需要输入密码登陆才能对其进行操作。

方式一:

[root@localhost bin]# ./redis-cli -a root
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> 

方式二:

复制代码
[root@localhost bin]# ./redis-cli 
127.0.0.1:6379> auth root
OK
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> 
复制代码

到此为止,使用Redis Desktop Manager连接Redis的问题已经全部解决。

redis.conf 的配置信息

1、daemonize 如果需要在后台运行,把该项改为yes
2、pidfile 配置多个pid的地址 默认在/var/run/redis.pid
3、bind 绑定ip,设置后只接受来自该ip的请求
4、port 监听端口,默认是6379
5、loglevel 分为4个等级:debug verbose notice warning
6、logfile 用于配置log文件地址
7、databases 设置数据库个数,默认使用的数据库为0
8、save 设置redis进行数据库镜像的频率。
9、rdbcompression 在进行镜像备份时,是否进行压缩
10、dbfilename 镜像备份文件的文件名
11、Dir 数据库镜像备份的文件放置路径
12、Slaveof 设置数据库为其他数据库的从数据库
13、Masterauth 主数据库连接需要的密码验证
14、Requriepass 设置 登陆时需要使用密码
15、Maxclients 限制同时使用的客户数量
16、Maxmemory 设置redis能够使用的最大内存
17、Appendonly 开启append only模式
18、Appendfsync 设置对appendonly.aof文件同步的频率(对数据进行备份的第二种方式)
19、vm-enabled 是否开启虚拟内存支持 (vm开头的参数都是配置虚拟内存的)
20、vm-swap-file 设置虚拟内存的交换文件路径
21、vm-max-memory 设置redis使用的最大物理内存大小
22、vm-page-size 设置虚拟内存的页大小
23、vm-pages 设置交换文件的总的page数量
24、vm-max-threads 设置VM IO同时使用的线程数量
25、Glueoutputbuf 把小的输出缓存存放在一起
26、hash-max-zipmap-entries 设置hash的临界值
27、Activerehashing 重新hash

四、Redis集群搭建

 第一步:创建文件夹

 在/usr/local下,创建存放redis集群的文件夹(redis-cluster)

[root@localhost local]# mkdir redis-cluster
[root@localhost local]# cd redis-cluster/

然后进入redis-cluster文件夹下创建留个集群文件夹,分别存放各个节点自己的配置文件

复制代码
[root@localhost local]# cd redis-cluster/
[root@localhost redis-cluster]# mkdir 7001
[root@localhost redis-cluster]# mkdir 7002
[root@localhost redis-cluster]# mkdir 7003
[root@localhost redis-cluster]# mkdir 7004
[root@localhost redis-cluster]# mkdir 7005
[root@localhost redis-cluster]# mkdir 7006
[root@localhost redis-cluster]# ls
7001  7002  7003  7004  7005  7006
复制代码

第二步:修改配置文件

拷贝redis.conf配置文件到 700* 文件夹中:

复制代码
[root@localhost redis-cluster]# cd ../redis-4.0.1/
[root@localhost 7001]# cp redis.conf /usr/local/redis-cluster/7001
[root@localhost 7001]# cp redis.conf /usr/local/redis-cluster/7002
[root@localhost 7001]# cp redis.conf /usr/local/redis-cluster/7003
[root@localhost 7001]# cp redis.conf /usr/local/redis-cluster/7004
[root@localhost 7001]# cp redis.conf /usr/local/redis-cluster/7005
[root@localhost 7001]# cp redis.conf /usr/local/redis-cluster/7006
复制代码

修改配置文件:

  1. daemonize yes
  2. port 700* (分别对每台机器的端口进行设置)
  3. bind 192.168.1.122 (必须要绑定当前机器的ip
  4. dir /usr/local/redis-cluster/700*/ (指定数据文件存放位置,必须要指定不同的目录位置,不然会丢失数据)
  5. cluster-enabled yes(启动集群模式)
  6. cluster-config-file nodes-700*.conf(这里700*最好和port对应上)
  7. cluster-node-timeout 5000
  8. appendonly yes

第三步:修改各个对应结点的配置文件

按照以上的配置,修改对应的ipport(700*)端口号和cluster-config-file nodes-700*.conf配置文件即可。

第四步:由于redis集群需要使用ruby命令,所以我们需要安装ruby

[root@localhost redis-cluster]# yum install ruby
[root@localhost redis-cluster]# yum install rubygems
[root@localhost redis-cluster]# gem install redis

第五步:分别启动6redis实例,然后检查是否启动成功

[root@localhost local]# /usr/local/redis/bin/redis-server /usr/local/redis-cluster/700*/redis.conf

查看是否启动成功 

[root@localhost local]# ps aux|grep redis

第六步:首先到redis4.0.1的安装目录下,然后执行redis-trib.rb命令

[root@localhost local]# cd redis-4.0.1/src/
[root@localhost src]# ./redis-trib.rb create --replicas 1 192.168.1.122:7001 192.168.1.122:7002 192.168.1.122:7003 192.168.1.122:7004 192.168.1.122:7005 192.168.1.122:7006

第七步:进行验证

  1. 连接任意一个客户端即可:./redis-cli -c -h -p-c表示集群模式,指定IP地址和端口号),如:/usr/local/redis/bin/redis-cli -c -h 192.168.1.122 -p 700*
  2. 进行验证cluster info(查看集群信息)、cluster nodes(查看节点列表)
  3. 进行数据操作验证
  4. 关闭集群则需要逐个关闭,使用命令:
[root@localhost 7001]# /usr/local/redis/bin/redis-cli -c -h 192.168.1.122 -p 700* shutdown

友情提示:当出现集群无法启动时,删除临时的数据文件,再次重新启动每一个redis服务,然后重新构造集群环境。

第八步:创建快速启动脚本和快速关闭脚本

创建快速全部开启脚本 startall.sh:

复制代码
[root@localhost redis-cluster]# vim startall.sh 

cd /usr/local/redis/bin/redis-server
./redis-server /usr/local/redis-cluster/7001/redis.conf
cd /usr/local/redis/bin/redis-server
./redis-server /usr/local/redis-cluster/7002/redis.conf
cd /usr/local/redis/bin/redis-server
./redis-server /usr/local/redis-cluster/7003/redis.conf
cd /usr/local/redis/bin/redis-server
./redis-server /usr/local/redis-cluster/7004/redis.conf
cd /usr/local/redis/bin/redis-server
./redis-server /usr/local/redis-cluster/7005/redis.conf
cd /usr/local/redis/bin/redis-server
./redis-server /usr/local/redis-cluster/7006/redis.conf
复制代码

创建快速全部关闭脚本shutdown.sh:

复制代码
[root@localhost redis-cluster]# vim shutdown.sh 

cd /usr/local/redis/bin/
redis-cli -p 7001 shutdown
redis-cli -p 7002 shutdown
redis-cli -p 7003 shutdown
redis-cli -p 7004 shutdown
redis-cli -p 7005 shutdown
redis-cli -p 7006 shutdown
复制代码

给两个新建的脚本赋可执行权限:

[root@localhost redis-cluster]# chmod +x startall.sh
[root@localhost redis-cluster]# chmod +x shutdown.sh

之后直接启动脚本即可:

[root@localhost redis-cluster]# ./startall.sh
[root@localhost redis-cluster]# ./shutdown.sh

五、Redis基础数据类型详解

参考:https://www.cnblogs.com/lizhenghn/p/5322887.html

Redis目前支持5种数据类型,分别是:

  1. String(字符串)
  2. List(列表)
  3. Hash(字典)
  4. Set(集合)
  5. Sorted Set(有序集合)

1、String(字符串)

String是简单的 key-value 键值对,value 不仅可以是 String,也可以是数字。String在redis内部存储默认就是一个字符串,被redisObject所引用,当遇到incr,decr等操作时会转成数值型进行计算,此时redisObject的encoding字段为int。

String在redis内部存储默认就是一个字符串,被redisObject所引用,当遇到incr,decr等操作时会转成数值型进行计算,此时redisObject的encoding字段为int。

应用场景

String是最常用的一种数据类型,普通的key/value存储都可以归为此类,这里就不所做解释了。

相关命令
复制代码
SET key value                   设置key=value
GET key                         或者键key对应的值
GETRANGE key start end          得到字符串的子字符串存放在一个键
GETSET key value                设置键的字符串值,并返回旧值
GETBIT key offset               返回存储在键位值的字符串值的偏移
MGET key1 [key2..]              得到所有的给定键的值
SETBIT key offset value         设置或清除该位在存储在键的字符串值偏移
SETEX key seconds value         键到期时设置值
SETNX key value                 设置键的值,只有当该键不存在
SETRANGE key offset value       覆盖字符串的一部分从指定键的偏移
STRLEN key                      得到存储在键的值的长度
MSET key value [key value...]   设置多个键和多个值
MSETNX key value [key value...] 设置多个键多个值,只有在当没有按键的存在时
PSETEX key milliseconds value   设置键的毫秒值和到期时间
INCR key                        增加键的整数值一次
INCRBY key increment            由给定的数量递增键的整数值
INCRBYFLOAT key increment       由给定的数量递增键的浮点值
DECR key                        递减键一次的整数值
DECRBY key decrement            由给定数目递减键的整数值
APPEND key value                追加值到一个键
复制代码
使用示例
复制代码
redis 127.0.0.1:6379> set baidu http://www.baidu
OK
redis 127.0.0.1:6379> append baidu .com
(integer) 20
redis 127.0.0.1:6379> get baidu
"http://www.baidu.com"
redis 127.0.0.1:6379> set visitors 0
OK
redis 127.0.0.1:6379> incr visitors
(integer) 1
redis 127.0.0.1:6379> incr visitors
(integer) 2
redis 127.0.0.1:6379> get visitors
"2"
redis 127.0.0.1:6379> incrby visitors 100
(integer) 102
redis 127.0.0.1:6379> get visitors
"102"
redis 127.0.0.1:6379> type baidu
string
redis 127.0.0.1:6379> type visitors
string
redis 127.0.0.1:6379> ttl baidu
(integer) -1
redis 127.0.0.1:6379> rename baidu baidu-site
OK
redis 127.0.0.1:6379> get baidu
(nil)
redis 127.0.0.1:6379> get baidu-site
"http://www.baidu.com"
复制代码

2、Hash(哈希)

Redis Hash对应Value内部实际就是一个HashMap,实际这里会有2种不同实现,这个Hash的成员比较少时Redis为了节省内存会采用类似一维数组的方式来紧凑存储,而不会采用真正的HashMap结构,对应的value redisObject的encoding为zipmap,当成员数量增大时会自动转成真正的HashMap,此时encoding为ht。

应用场景

假设有多个用户及对应的用户信息,可以用来存储以用户ID为key,将用户信息序列化为比如json格式做为value进行保存。

相关命令
复制代码
HDEL key field[field...] 删除对象的一个或几个属性域,不存在的属性将被忽略
HEXISTS key field 查看对象是否存在该属性域
HGET key field 获取对象中该field属性域的值
HGETALL key 获取对象的所有属性域和值
HINCRBY key field value 将该对象中指定域的值增加给定的value,原子自增操作,只能是integer的属性值可以使用
HINCRBYFLOAT key field increment 将该对象中指定域的值增加给定的浮点数
HKEYS key 获取对象的所有属性字段
HVALS key 获取对象的所有属性值
HLEN key 获取对象的所有属性字段的总数
HMGET key field[field...] 获取对象的一个或多个指定字段的值
HSET key field value 设置对象指定字段的值
HMSET key field value [field value ...] 同时设置对象中一个或多个字段的值
HSETNX key field value 只在对象不存在指定的字段时才设置字段的值
HSTRLEN key field 返回对象指定field的value的字符串长度,如果该对象或者field不存在,返回0.
HSCAN key cursor [MATCH pattern] [COUNT count] 类似SCAN命令
复制代码
使用示例
复制代码
127.0.0.1:6379> hset person name jack
(integer) 1
127.0.0.1:6379> hset person age 20
(integer) 1
127.0.0.1:6379> hset person sex famale
(integer) 1
127.0.0.1:6379> hgetall person
1) "name"
2) "jack"
3) "age"
4) "20"
5) "sex"
6) "famale"
127.0.0.1:6379> hkeys person
1) "name"
2) "age"
3) "sex"
127.0.0.1:6379> hvals person
1) "jack"
2) "20"
3) "famale"
复制代码

3、List(列表)

Redis列表是简单的字符串列表,可以类比到C++中的std::list,简单的说就是一个链表或者说是一个队列。可以从头部或尾部向Redis列表添加元素。列表的最大长度为2^32 - 1,也即每个列表支持超过40亿个元素。

Redis list的实现为一个双向链表,即可以支持反向查找和遍历,更方便操作,不过带来了部分额外的内存开销,Redis内部的很多实现,包括发送缓冲队列等也都是用的这个数据结构。

应用场景

Redis list的应用场景非常多,也是Redis最重要的数据结构之一,比如twitter的关注列表、粉丝列表等都可以用Redis的list结构来实现,再比如有的应用使用Redis的list类型实现一个简单的轻量级消息队列,生产者push,消费者pop/bpop。

相关命令
复制代码
BLPOP key1 [key2 ] timeout 取出并获取列表中的第一个元素,或阻塞,直到有可用
BRPOP key1 [key2 ] timeout 取出并获取列表中的最后一个元素,或阻塞,直到有可用
BRPOPLPUSH source destination timeout 从列表中弹出一个值,它推到另一个列表并返回它;或阻塞,直到有可用
LINDEX key index 从一个列表其索引获取对应的元素
LINSERT key BEFORE|AFTER pivot value 在列表中的其他元素之后或之前插入一个元素
LLEN key 获取列表的长度
LPOP key 获取并取出列表中的第一个元素
LPUSH key value1 [value2] 在前面加上一个或多个值的列表
LPUSHX key value 在前面加上一个值列表,仅当列表中存在
LRANGE key start stop 从一个列表获取各种元素
LREM key count value 从列表中删除元素
LSET key index value 在列表中的索引设置一个元素的值
LTRIM key start stop 修剪列表到指定的范围内
RPOP key 取出并获取列表中的最后一个元素
RPOPLPUSH source destination 删除最后一个元素的列表,将其附加到另一个列表并返回它
RPUSH key value1 [value2] 添加一个或多个值到列表
RPUSHX key value 添加一个值列表,仅当列表中存在
复制代码
使用示例
复制代码
redis 127.0.0.1:6379> lpush list1 redis
(integer) 1
redis 127.0.0.1:6379> lpush list1 hello
(integer) 2
redis 127.0.0.1:6379> rpush list1 world
(integer) 3
redis 127.0.0.1:6379> llen list1
(integer) 3
redis 127.0.0.1:6379> lrange list1 0 3
1) "hello"
2) "redis"
3) "world"
redis 127.0.0.1:6379> lpop list1
"hello"
redis 127.0.0.1:6379> rpop list1
"world"
redis 127.0.0.1:6379> lrange list1 0 3
1) "redis"
复制代码

4、Set(集合)

可以理解为一堆值不重复的列表,类似数学领域中的集合概念,且Redis也提供了针对集合的求交集、并集、差集等操作。

set 的内部实现是一个 value永远为null的HashMap,实际就是通过计算hash的方式来快速排重的,这也是set能提供判断一个成员是否在集合内的原因。

应用场景

Redis set对外提供的功能与list类似是一个列表的功能,特殊之处在于set是可以自动排重的,当你需要存储一个列表数据,又不希望出现重复数据时,set是一个很好的选择,并且set提供了判断某个成员是否在一个set集合内的重要接口,这个也是list所不能提供的。

又或者在微博应用中,每个用户关注的人存在一个集合中,就很容易实现求两个人的共同好友功能。

相关命令
复制代码
SADD key member [member ...] 添加一个或者多个元素到集合(set)里
SCARD key 获取集合里面的元素数量
SDIFF key [key ...] 获得队列不存在的元素
SDIFFSTORE destination key [key ...] 获得队列不存在的元素,并存储在一个关键的结果集
SINTER key [key ...] 获得两个集合的交集
SINTERSTORE destination key [key ...] 获得两个集合的交集,并存储在一个集合中
SISMEMBER key member 确定一个给定的值是一个集合的成员
SMEMBERS key 获取集合里面的所有key
SMOVE source destination member 移动集合里面的一个key到另一个集合
SPOP key [count] 获取并删除一个集合里面的元素
SRANDMEMBER key [count] 从集合里面随机获取一个元素
SREM key member [member ...] 从集合里删除一个或多个元素,不存在的元素会被忽略
SUNION key [key ...] 添加多个set元素
SUNIONSTORE destination key [key ...] 合并set元素,并将结果存入新的set里面
SSCAN key cursor [MATCH pattern] [COUNT count] 迭代set里面的元素
复制代码
使用示例
复制代码
redis> SADD myset "Hello"
(integer) 1
redis> SADD myset "World"
(integer) 1
redis> SMEMBERS myset
1) "World"
2) "Hello"
redis> SADD myset "one"
(integer) 1
redis> SISMEMBER myset "one"
(integer) 1
redis> SISMEMBER myset "two"
(integer) 0
复制代码

使用集合数据结构的典型用例是朋友名单的实现:

复制代码
redis 127.0.0.1:6379> sadd friends:leto ghanima paul chani jessica
(integer) 4
redis 127.0.0.1:6379> sadd friends:duncan paul jessica alia
(integer) 3
redis 127.0.0.1:6379> sismember friends:leto jessica
(integer) 1   #不管一个用户有多少个朋友,我们都能高效地(O(1)时间复杂度)识别出用户X是不是用户Y的朋友
redis 127.0.0.1:6379> sismember friends:leto vladimir
(integer) 0
redis 127.0.0.1:6379> sinter friends:leto friends:duncan    #我们可以查看两个或更多的人是不是有共同的朋友
1) "paul"
2) "jessica"
redis 127.0.0.1:6379> sinterstore friends:leto_duncan friends:leto friends:duncan # 可以在一个新的关键字里存储结果
(integer) 2
复制代码

5、zset(sorted set:有序集合)

Redis有序集合类似Redis集合,不同的是增加了一个功能,即集合是有序的。一个有序集合的每个成员带有分数,用于进行排序。

Redis有序集合添加、删除和测试的时间复杂度均为O(1)(固定时间,无论里面包含的元素集合的数量)。列表的最大长度为2^32- 1元素(4294967295,超过40亿每个元素的集合)。

Redis sorted set的内部使用HashMap和跳跃表(SkipList)来保证数据的存储和有序,HashMap里放的是成员到score的映射,而跳跃表里存放的是所有的成员,排序依据是HashMap里存的score,使用跳跃表的结构可以获得比较高的查找效率,并且在实现上比较简单。

使用场景

Redis sorted set的使用场景与set类似,区别是set不是自动有序的,而sorted set可以通过用户额外提供一个优先级(score)的参数来为成员排序,并且是插入有序的,即自动排序。当你需要一个有序的并且不重复的集合列表,那么可以选择sorted set数据结构,比如twitter 的public timeline可以以发表时间作为score来存储,这样获取时就是自动按时间排好序的。

又比如用户的积分排行榜需求就可以通过有序集合实现。还有上面介绍的使用List实现轻量级的消息队列,其实也可以通过Sorted Set实现有优先级或按权重的队列。

相关命令
复制代码
ZADD key score1 member1 [score2 member2] 添加一个或多个成员到有序集合,或者如果它已经存在更新其分数
ZCARD key 得到的有序集合成员的数量
ZCOUNT key min max 计算一个有序集合成员与给定值范围内的分数
ZINCRBY key increment member 在有序集合增加成员的分数
ZINTERSTORE destination numkeys key [key ...] 多重交叉排序集合,并存储生成一个新的键有序集合。
ZLEXCOUNT key min max 计算一个给定的字典范围之间的有序集合成员的数量
ZRANGE key start stop [WITHSCORES] 由索引返回一个成员范围的有序集合(从低到高)
ZRANGEBYLEX key min max [LIMIT offset count]返回一个成员范围的有序集合(由字典范围)
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT] 返回有序集key中,所有 score 值介于 min 和 max 之间(包括等于 min 或 max )的成员,有序集成员按 score 值递增(从小到大)次序排列
ZRANK key member 确定成员的索引中有序集合
ZREM key member [member ...] 从有序集合中删除一个或多个成员,不存在的成员将被忽略
ZREMRANGEBYLEX key min max 删除所有成员在给定的字典范围之间的有序集合
ZREMRANGEBYRANK key start stop 在给定的索引之内删除所有成员的有序集合
ZREMRANGEBYSCORE key min max 在给定的分数之内删除所有成员的有序集合
ZREVRANGE key start stop [WITHSCORES] 返回一个成员范围的有序集合,通过索引,以分数排序,从高分到低分
ZREVRANGEBYSCORE key max min [WITHSCORES] 返回一个成员范围的有序集合,以socre排序从高到低
ZREVRANK key member 确定一个有序集合成员的索引,以分数排序,从高分到低分
ZSCORE key member 获取给定成员相关联的分数在一个有序集合
ZUNIONSTORE destination numkeys key [key ...] 添加多个集排序,所得排序集合存储在一个新的键
ZSCAN key cursor [MATCH pattern] [COUNT count] 增量迭代排序元素集和相关的分数
复制代码
使用示例
复制代码
redis 127.0.0.1:6379> zadd dbs 100 redis
(integer) 1
redis 127.0.0.1:6379> zadd dbs 98 memcached
(integer) 1
redis 127.0.0.1:6379> zadd dbs 99 mongodb
(integer) 1
redis 127.0.0.1:6379> zadd dbs 99 leveldb
(integer) 1
redis 127.0.0.1:6379> zcard dbs
(integer) 4
redis 127.0.0.1:6379> zcount dbs 10 99
(integer) 3
redis 127.0.0.1:6379> zrank dbs leveldb
(integer) 1
redis 127.0.0.1:6379> zrank dbs other
(nil)
redis 127.0.0.1:6379> zrangebyscore dbs 98 100
1) "memcached"
2) "leveldb"
3) "mongodb"
4) "redis"
复制代码

六、Redis高级命令

复制代码
DEL key                         如果存在删除键
DUMP key                        返回存储在指定键的值的序列化版本
EXISTS key                      此命令检查该键是否存在
EXPIRE key seconds              指定键的过期时间
EXPIREAT key timestamp          指定的键过期时间。在这里,时间是在Unix时间戳格式
PEXPIRE key milliseconds        设置键以毫秒为单位到期
PEXPIREAT key milliseconds-timestamp        设置键在Unix时间戳指定为毫秒到期
KEYS pattern                    查找与指定模式匹配的所有键
MOVE key db                     移动键到另一个数据库
PERSIST key                     移除过期的键
PTTL key                        以毫秒为单位获取剩余时间的到期键。
TTL key                         获取键到期的剩余时间。
RANDOMKEY                       从Redis返回随机键
RENAME key newkey               更改键的名称
RENAMENX key newkey             重命名键,如果新的键不存在
TYPE key                        返回存储在键的数据类型的值。
复制代码

七、RedisJava的使用

 1、单机版API测试

复制代码
package com.taotao.rest.jedis;

import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.junit.Test;

import redis.clients.jedis.Jedis;

public class TestRedis
{
    private static Jedis jedis = new Jedis("192.168.1.122", 6379);
    
    @Test
    public void testRedis()
    {
        jedis.auth("root"); // 如果设置了密码才需要这一行,没有设置密码则不需要这行
        jedis.set("sex", "man");
        System.out.println(jedis);
        
        List<String> list = jedis.mget("name", "age", "sex");
        for (Iterator iterator = list.iterator(); iterator.hasNext();)
        {
            String string = (String)iterator.next();
            System.out.println(string);
        }
        
        Map<String, String> user = new HashMap<String, String>();
        user.put("name", "huangyuxuan");
        user.put("age", "0.5");
        user.put("sex", "男");
        jedis.hmset("user", user);
        
        List<String> rsmap = jedis.hmget("user", "name", "age", "sex");
        System.out.println(rsmap);
        
        jedis.hdel("user", "age");
        System.out.println(jedis.hmget("user", "age")); // 因为删除了,所以返回的是null
        System.out.println(jedis.hlen("user")); // 返回key为user的键中存放的值的个数2
        System.out.println(jedis.exists("user"));// 是否存在key为user的记录 返回true
        System.out.println(jedis.hkeys("user"));// 返回map对象中的所有key
        System.out.println(jedis.hvals("user"));// 返回map对象中的所有value
        
        testStr();
        testList();
        testSet();
        
        Iterator<String> iter = jedis.hkeys("user").iterator();
        while (iter.hasNext())
        {
            String key = iter.next();
            System.out.println(key + ":" + jedis.hmget("user", key));
        }
    }
    
    public static void testStr()
    {
        // -----添加数据----------
        jedis.set("name", "treee");// 向key-->name中放入了value-->xinxin
        System.out.println(jedis.get("name"));// 执行结果:xinxin
        
        jedis.append("name", " is my lover"); // 拼接
        System.out.println(jedis.get("name"));
        
        jedis.del("name"); // 删除某个键
        System.out.println(jedis.get("name"));
        // 设置多个键值对
        jedis.mset("name", "treee", "age", "27", "qq", "174754613");
        jedis.incr("age"); // 进行加1操作
        System.out.println(jedis.get("name") + "-" + jedis.get("age") + "-" + jedis.get("qq"));
        
    }
    
    public static void testList()
    {
        // 开始前,先移除所有的内容
        jedis.del("java framework");
        System.out.println(jedis.lrange("java framework", 0, -1));
        // 先向key java framework中存放三条数据
        jedis.lpush("java framework", "spring");
        jedis.lpush("java framework", "struts");
        jedis.lpush("java framework", "hibernate");
        // 再取出所有数据jedis.lrange是按范围取出,
        // 第一个是key,第二个是起始位置,第三个是结束位置,jedis.llen获取长度 -1表示取得所有
        System.out.println(jedis.lrange("java framework", 0, -1));
        
        jedis.del("java framework");
        jedis.rpush("java framework", "spring");
        jedis.rpush("java framework", "struts");
        jedis.rpush("java framework", "hibernate");
        System.out.println(jedis.lrange("java framework", 0, -1));
    }
    
    public static void testSet()
    {
        // 添加
        jedis.sadd("user1", "liuling");
        jedis.sadd("user1", "xinxin");
        jedis.sadd("user1", "ling");
        jedis.sadd("user1", "zhangxinxin");
        jedis.sadd("user1", "who");
        // 移除noname
        jedis.srem("user1", "who");
        System.out.println(jedis.smembers("user1"));// 获取所有加入的value
        System.out.println(jedis.sismember("user1", "who"));// 判断 who 是否是user集合的元素
        System.out.println(jedis.srandmember("user1"));
        System.out.println(jedis.scard("user1"));// 返回集合的元素个数
    }
}
复制代码

2、单机版连接池

复制代码
package com.taotao.rest.jedis;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisShardInfo;
import redis.clients.jedis.Pipeline;
import redis.clients.jedis.ShardedJedis;
import redis.clients.jedis.ShardedJedisPipeline;
import redis.clients.jedis.ShardedJedisPool;
import redis.clients.jedis.Transaction;

public class TestSingleRedis
{
    private static Jedis jedis;
    
    private static ShardedJedis shard;
    
    private static ShardedJedisPool pool;
    
    @BeforeClass
    public static void setUpBeforeClass() throws Exception
    {
        // 单个节点
        jedis = new Jedis("192.168.1.122", 6379);
        jedis.auth("root"); // 设置密码了才需要添加这一行
        // 分片
        List<JedisShardInfo> shards = Arrays.asList(new JedisShardInfo("192.168.1.122", 6379));
        shard = new ShardedJedis(shards);
        
        GenericObjectPoolConfig goConfig = new GenericObjectPoolConfig();
        goConfig.setMaxTotal(100);
        goConfig.setMaxIdle(20);
        goConfig.setMaxWaitMillis(-1);
        goConfig.setTestOnBorrow(true);
        pool = new ShardedJedisPool(goConfig, shards);
    }
    
    @AfterClass
    public static void tearDownAfterClass() throws Exception
    {
        jedis.disconnect();
        shard.disconnect();
        pool.destroy();
    }
    
    @Test
    public void testString()
    {
        // -----添加数据----------
        jedis.set("name", "treee");// 向key-->name中放入了value-->xinxin
        System.out.println(jedis.get("name"));// 执行结果:xinxin
        
        jedis.append("name", " is my lover"); // 拼接
        System.out.println(jedis.get("name"));
        
        jedis.del("name"); // 删除某个键
        System.out.println(jedis.get("name"));
        // 设置多个键值对
        jedis.mset("name", "treee", "age", "27", "qq", "174754613");
        jedis.incr("age"); // 进行加1操作
        System.out.println(jedis.get("name") + "-" + jedis.get("age") + "-" + jedis.get("qq"));
    }
    
    /**
     * redis操作Map
     */
    @Test
    public void testMap()
    {
        // -----添加数据----------
        Map<String, String> map = new HashMap<String, String>();
        map.put("name", "xinxin");
        map.put("age", "22");
        map.put("qq", "123456");
        jedis.hmset("user", map);
        // 取出user中的name,执行结果:[minxr]-->注意结果是一个泛型的List
        // 第一个参数是存入redis中map对象的key,后面跟的是放入map中的对象的key,后面的key可以跟多个,是可变参数
        List<String> rsmap = jedis.hmget("user", "name", "age", "qq");
        System.out.println(rsmap);
        // 删除map中的某个键值
        jedis.hdel("user", "age");
        System.out.println(jedis.hmget("user", "age")); // 因为删除了,所以返回的是null
        System.out.println(jedis.hlen("user")); // 返回key为user的键中存放的值的个数2
        System.out.println(jedis.exists("user"));// 是否存在key为user的记录 返回true
        System.out.println(jedis.hkeys("user"));// 返回map对象中的所有key
        System.out.println(jedis.hvals("user"));// 返回map对象中的所有value
        
        Iterator<String> iter = jedis.hkeys("user").iterator();
        while (iter.hasNext())
        {
            String key = iter.next();
            System.out.println(key + ":" + jedis.hmget("user", key));
        }
    }
    
    /**
     * jedis操作List
     */
    @Test
    public void testList()
    {
        // 开始前,先移除所有的内容
        jedis.del("java framework");
        System.out.println(jedis.lrange("java framework", 0, -1));
        // 先向key java framework中存放三条数据
        jedis.lpush("java framework", "spring");
        jedis.lpush("java framework", "struts");
        jedis.lpush("java framework", "hibernate");
        // 再取出所有数据jedis.lrange是按范围取出,
        // 第一个是key,第二个是起始位置,第三个是结束位置,jedis.llen获取长度 -1表示取得所有
        System.out.println(jedis.lrange("java framework", 0, -1));
        
        jedis.del("java framework");
        jedis.rpush("java framework", "spring");
        jedis.rpush("java framework", "struts");
        jedis.rpush("java framework", "hibernate");
        System.out.println(jedis.lrange("java framework", 0, -1));
    }
    
    /**
     * jedis操作Set
     */
    @Test
    public void testSet()
    {
        // 添加
        jedis.sadd("user", "liuling");
        jedis.sadd("user", "xinxin");
        jedis.sadd("user", "ling");
        jedis.sadd("user", "zhangxinxin");
        jedis.sadd("user", "who");
        // 移除noname
        jedis.srem("user", "who");
        System.out.println(jedis.smembers("user"));// 获取所有加入的value
        System.out.println(jedis.sismember("user", "who"));// 判断 who 是否是user集合的元素
        System.out.println(jedis.srandmember("user"));
        System.out.println(jedis.scard("user"));// 返回集合的元素个数
    }
    
    @Test
    public void testRLpush() throws InterruptedException
    {
        // jedis 排序
        // 注意,此处的rpush和lpush是List的操作。是一个双向链表(但从表现来看的)
        jedis.del("a");// 先清除数据,再加入数据进行测试
        jedis.rpush("a", "1");
        jedis.lpush("a", "6");
        jedis.lpush("a", "3");
        jedis.lpush("a", "9");
        System.out.println(jedis.lrange("a", 0, -1));// [9, 3, 6, 1]
        System.out.println(jedis.sort("a")); // [1, 3, 6, 9] //输入排序后结果
        System.out.println(jedis.lrange("a", 0, -1));
    }
    
    @Test
    public void testTrans()
    {
        long start = System.currentTimeMillis();
        Transaction tx = jedis.multi();
        for (int i = 0; i < 1000; i++)
        {
            tx.set("t" + i, "t" + i);
        }
        // System.out.println(tx.get("t1000").get());
        
        List<Object> results = tx.exec();
        long end = System.currentTimeMillis();
        System.out.println("Transaction SET: " + ((end - start) / 1000.0) + " seconds");
    }
    
    @Test
    public void testPipelined()
    {
        Pipeline pipeline = jedis.pipelined();
        long start = System.currentTimeMillis();
        for (int i = 0; i < 1000; i++)
        {
            pipeline.set("p" + i, "p" + i);
        }
        // System.out.println(pipeline.get("p1000").get());
        List<Object> results = pipeline.syncAndReturnAll();
        long end = System.currentTimeMillis();
        System.out.println("Pipelined SET: " + ((end - start) / 1000.0) + " seconds");
    }
    
    @Test
    public void testPipelineTrans()
    {
        long start = System.currentTimeMillis();
        Pipeline pipeline = jedis.pipelined();
        pipeline.multi();
        for (int i = 0; i < 100000; i++)
        {
            pipeline.set("" + i, "" + i);
        }
        pipeline.exec();
        List<Object> results = pipeline.syncAndReturnAll();
        long end = System.currentTimeMillis();
        System.out.println("Pipelined transaction SET: " + ((end - start) / 1000.0) + " seconds");
    }
    
    @Test
    public void testShard()
    {
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++)
        {
            String result = shard.set("shard" + i, "n" + i);
        }
        long end = System.currentTimeMillis();
        System.out.println("shard SET: " + ((end - start) / 1000.0) + " seconds");
    }
    
    @Test
    public void testShardpipelined()
    {
        ShardedJedisPipeline pipeline = shard.pipelined();
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++)
        {
            pipeline.set("sp" + i, "p" + i);
        }
        List<Object> results = pipeline.syncAndReturnAll();
        long end = System.currentTimeMillis();
        System.out.println("shardPipelined SET: " + ((end - start) / 1000.0) + " seconds");
    }
    
    @Test
    public void testShardPool()
    {
        ShardedJedis sj = pool.getResource();
        
        long start = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++)
        {
            String result = sj.set("spn" + i, "n" + i);
        }
        long end = System.currentTimeMillis();
        pool.returnResource(sj);
        System.out.println("shardPool SET: " + ((end - start) / 1000.0) + " seconds");
    }
}
复制代码

3、集群Java操作

复制代码
package com.taotao.rest.jedis;

import java.util.HashSet;
import java.util.Set;

import org.junit.Test;

import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisPoolConfig;

public class TestClusterRedis
{
    @Test
    public void testCluster()
    {
        Set<HostAndPort> jedisClusterNode = new HashSet<HostAndPort>();
        jedisClusterNode.add(new HostAndPort("192.168.1.122", 7001));
        jedisClusterNode.add(new HostAndPort("192.168.1.122", 7002));
        jedisClusterNode.add(new HostAndPort("192.168.1.122", 7003));
        jedisClusterNode.add(new HostAndPort("192.168.1.122", 7004));
        jedisClusterNode.add(new HostAndPort("192.168.1.122", 7005));
        jedisClusterNode.add(new HostAndPort("192.168.1.122", 7006));
        // GenericObjectPoolConfig goConfig = new GenericObjectPoolConfig();
        // JedisCluster jc = new JedisCluster(jedisClusterNode,2000,100, goConfig);
        JedisPoolConfig cfg = new JedisPoolConfig();
        cfg.setMaxTotal(100);
        cfg.setMaxIdle(20);
        cfg.setMaxWaitMillis(-1);
        cfg.setTestOnBorrow(true);
        JedisCluster jc = new JedisCluster(jedisClusterNode, 6000, 1000, cfg);
        
        System.out.println(jc.set("age", "20"));
        System.out.println(jc.set("sex", "男"));
        System.out.println(jc.get("name"));
        System.out.println(jc.get("name"));
        System.out.println(jc.get("name"));
        System.out.println(jc.get("name"));
        System.out.println(jc.get("name"));
        System.out.println(jc.get("name"));
        System.out.println(jc.get("name"));
        System.out.println(jc.get("name"));
        System.out.println(jc.get("age"));
        System.out.println(jc.get("sex"));
        jc.close();
    }
}
复制代码

 

八、Redis集群与Spring的整合

 1、redis单机版与Spring整合

复制代码
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd 
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">

    <!-- 连接池配置 -->
    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <!-- 最大连接数 -->
        <property name="maxTotal" value="30" />
        <!-- 最大空闲连接数 -->
        <property name="maxIdle" value="10" />
        <!-- 每次释放连接的最大数目 -->
        <property name="numTestsPerEvictionRun" value="1024" />
        <!-- 释放连接的扫描间隔(毫秒) -->
        <property name="timeBetweenEvictionRunsMillis" value="30000" />
        <!-- 连接最小空闲时间 -->
        <property name="minEvictableIdleTimeMillis" value="1800000" />
        <!-- 连接空闲多久后释放, 当空闲时间>该值 且 空闲连接>最大空闲连接数 时直接释放 -->
        <property name="softMinEvictableIdleTimeMillis" value="10000" />
        <!-- 获取连接时的最大等待毫秒数,小于零:阻塞不确定的时间,默认-1 -->
        <property name="maxWaitMillis" value="1500" />
        <!-- 在获取连接的时候检查有效性, 默认false -->
        <property name="testOnBorrow" value="false" />
        <!-- 在空闲时检查有效性, 默认false -->
        <property name="testWhileIdle" value="true" />
        <!-- 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true -->
        <property name="blockWhenExhausted" value="false" />
    </bean>

    <!-- redis单机 通过连接池 -->
    <bean id="jedisPool" class="redis.clients.jedis.JedisPool" destroy-method="close">
        <constructor-arg name="poolConfig" ref="jedisPoolConfig" />
        <constructor-arg name="host" value="192.168.1.122" />
        <constructor-arg name="port" value="6379" />
    </bean>

</beans>
    
复制代码

使用Java测试:

复制代码
@Test
    public void testSpringJedisSingle()
    {
        ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:spring/applicationContext-*.xml");
        JedisPool pool = (JedisPool)ac.getBean("jedisPool");
        Jedis jedis = pool.getResource();
        jedis.auth("root");
        String str = jedis.get("key1");
        System.out.println(str);
        jedis.close();
        pool.close();
    }
复制代码

2、Redis集群版与Spring整合

复制代码
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
    http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd 
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">

    <!-- 连接池配置 -->
    <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
        <!-- 最大连接数 -->
        <property name="maxTotal" value="30" />
        <!-- 最大空闲连接数 -->
        <property name="maxIdle" value="10" />
        <!-- 每次释放连接的最大数目 -->
        <property name="numTestsPerEvictionRun" value="1024" />
        <!-- 释放连接的扫描间隔(毫秒) -->
        <property name="timeBetweenEvictionRunsMillis" value="30000" />
        <!-- 连接最小空闲时间 -->
        <property name="minEvictableIdleTimeMillis" value="1800000" />
        <!-- 连接空闲多久后释放, 当空闲时间>该值 且 空闲连接>最大空闲连接数 时直接释放 -->
        <property name="softMinEvictableIdleTimeMillis" value="10000" />
        <!-- 获取连接时的最大等待毫秒数,小于零:阻塞不确定的时间,默认-1 -->
        <property name="maxWaitMillis" value="1500" />
        <!-- 在获取连接的时候检查有效性, 默认false -->
        <property name="testOnBorrow" value="false" />
        <!-- 在空闲时检查有效性, 默认false -->
        <property name="testWhileIdle" value="true" />
        <!-- 连接耗尽时是否阻塞, false报异常,ture阻塞直到超时, 默认true -->
        <property name="blockWhenExhausted" value="false" />
    </bean>
    
    <!-- redis集群 -->
    <bean id="jedisCluster" class="redis.clients.jedis.JedisCluster">
        <constructor-arg index="0">
            <set>
                <bean class="redis.clients.jedis.HostAndPort">
                    <constructor-arg index="0" value="192.168.1.122"></constructor-arg>
                    <constructor-arg index="1" value="7001"></constructor-arg>
                </bean>
                <bean class="redis.clients.jedis.HostAndPort">
                    <constructor-arg index="0" value="192.168.1.122"></constructor-arg>
                    <constructor-arg index="1" value="7002"></constructor-arg>
                </bean>
                <bean class="redis.clients.jedis.HostAndPort">
                    <constructor-arg index="0" value="192.168.1.122"></constructor-arg>
                    <constructor-arg index="1" value="7003"></constructor-arg>
                </bean>
                <bean class="redis.clients.jedis.HostAndPort">
                    <constructor-arg index="0" value="192.168.1.122"></constructor-arg>
                    <constructor-arg index="1" value="7004"></constructor-arg>
                </bean>
                <bean class="redis.clients.jedis.HostAndPort">
                    <constructor-arg index="0" value="192.168.1.122"></constructor-arg>
                    <constructor-arg index="1" value="7005"></constructor-arg>
                </bean>
                <bean class="redis.clients.jedis.HostAndPort">
                    <constructor-arg index="0" value="192.168.1.122"></constructor-arg>
                    <constructor-arg index="1" value="7006"></constructor-arg>
                </bean>
            </set>
        </constructor-arg>
        <constructor-arg index="1" ref="jedisPoolConfig"></constructor-arg>
    </bean>

</beans>
    
复制代码

Java代码测试集群:

复制代码
@Test
    public void testSpringJedisCluster() throws IOException
    {
        ApplicationContext ac = new ClassPathXmlApplicationContext("classpath:spring/applicationContext-*.xml");
        JedisCluster jedisCluster = (JedisCluster)ac.getBean("jedisCluster");
        String str = jedisCluster.get("key1");
        System.out.println(str);
        jedisCluster.close();
    }
复制代码

 

九、TomcatRedissession共享


redis.conf配置文件说明

复制代码
# Redis 配置文件

# 当配置中需要配置内存大小时,可以使用 1k, 5GB, 4M 等类似的格式,其转换方式如下(不区分大小写)
#
# 1k =>
1000 bytes
# 1kb => 1024 bytes
# 1m => 1000000 bytes
# 1mb =>
1024*1024 bytes
# 1g => 1000000000 bytes
# 1gb => 1024*1024*1024
bytes
#
# 内存配置大小写是一样的.比如 1gb 1Gb 1GB 1gB

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

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

# 指定redis运行的端口,默认是6379
port 6379

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

# Specify the path for the unix socket that will be used to listen for
#
incoming connections. There is no default, so Redis will not listen
# on a
unix socket when not specified.
#
# unixsocket /tmp/redis.sock
#
unixsocketperm 755

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

# 指定日志记录级别
# Redis总共支持四个级别:debug、verbose、notice、warning,默认为verbose
#
debug  记录很多信息,用于开发和测试
# varbose 有用的信息,不像debug会记录那么多
#
notice 普通的verbose,常用于生产环境
# warning 只有非常重要或者严重的信息会记录到日志
loglevel
debug

# 配置log文件地址
# 默认值为stdout,标准输出,若后台模式会输出到/dev/null
#logfile
stdout
logfile /var/log/redis/redis.log

# To enable logging to the system logger, just set 'syslog-enabled' to
yes,
# and optionally update the other syslog parameters to suit your
needs.
# syslog-enabled no

# Specify the syslog identity.
# syslog-ident redis

# Specify the syslog facility.  Must be USER or between LOCAL0-LOCAL7.
#
syslog-facility local0

# 可用数据库数
# 默认值为16,默认数据库为0,数据库范围在0-(database-1)之间
databases 16

################################ 快照  
#################################
#
# 保存数据到磁盘,格式如下:
#
#   save
<seconds> <changes>
#
#   
指出在多长时间内,有多少次更新操作,就将数据同步到数据文件rdb。
#   相当于条件触发抓取快照,这个可以多个条件配合
#   
#   
比如默认配置文件中的设置,就设置了三个条件
#
#   save 900 1  900秒内至少有1个key被改变
#   save 300
10  300秒内至少有300个key被改变
#   save 60 10000  60秒内至少有10000个key被改变

save 900 1
save 300 10
save 60 10000

# 存储至本地数据库时(持久化到rdb文件)是否压缩数据,默认为yes
rdbcompression yes

# 本地持久化数据库文件名,默认值为dump.rdb
dbfilename dump.rdb

# 工作目录
#
# 数据库镜像备份的文件放置的路径。
#
这里的路径跟文件名要分开配置是因为redis在进行备份时,先会将当前数据库的状态写入到一个临时文件中,等备份完成时,
#
再把该该临时文件替换为上面所指定的文件,而这里的临时文件和上面所配置的备份文件都会放在这个指定的路径当中。
#
#
AOF文件也会存放在这个目录下面
#
# 注意这里必须制定一个目录而不是文件
dir ./

################################# 复制
#################################

# 主从复制. 设置该数据库为其他数据库的从数据库.
#
设置当本机为slav服务时,设置master服务的IP地址及端口,在Redis启动时,它会自动从master进行数据同步
#
# slaveof
<masterip> <masterport>

# 当master服务设置了密码保护时(用requirepass制定的密码)
# slav服务连接master的密码
#
#
masterauth <master-password>


# 当从库同主机失去连接或者复制正在进行,从机库有两种运行方式:
#
# 1)
如果slave-serve-stale-data设置为yes(默认设置),从库会继续相应客户端的请求
#
# 2)
如果slave-serve-stale-data是指为no,出去INFO和SLAVOF命令之外的任何请求都会返回一个
#    错误"SYNC with
master in progress"
#
slave-serve-stale-data yes

# 从库会按照一个时间间隔向主库发送PINGs.可以通过repl-ping-slave-period设置这个时间间隔,默认是10秒
#
#
repl-ping-slave-period 10

# repl-timeout 设置主库批量数据传输时间或者ping回复时间间隔,默认值是60秒
#
一定要确保repl-timeout大于repl-ping-slave-period
# repl-timeout 60

################################## 安全
###################################

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

# 命令重命名.
#
# 在一个共享环境下可以重命名相对危险的命令。比如把CONFIG重名为一个不容易猜测的字符。
#
#
举例:
#
# rename-command CONFIG
b840fc02d524045429941cc15f59e41cb7be6c52
#
#
如果想删除一个命令,直接把它重命名为一个空字符""即可,如下:
#
# rename-command CONFIG ""

################################### 约束
####################################

# 设置同一时间最大客户端连接数,默认无限制,Redis可以同时打开的客户端连接数为Redis进程可以打开的最大文件描述符数,
# 如果设置
maxclients 0,表示不作限制。
# 当客户端连接数到达限制时,Redis会关闭新的连接并向客户端返回max number of clients
reached错误信息
#
# maxclients 128

# 指定Redis最大内存限制,Redis在启动时会把数据加载到内存中,达到最大内存后,Redis会先尝试清除已到期或即将到期的Key
#
Redis同时也会移除空的list对象
#
#
当此方法处理后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作
#
#
注意:Redis新的vm机制,会把Key存放内存,Value会存放在swap区
#
#
maxmemory的设置比较适合于把redis当作于类似memcached的缓存来使用,而不适合当做一个真实的DB。
#
当把Redis当做一个真实的数据库使用的时候,内存使用将是一个很大的开销
# maxmemory <bytes>

# 当内存达到最大值的时候Redis会选择删除哪些数据?有五种方式可供选择
#
# volatile-lru ->
利用LRU算法移除设置过过期时间的key (LRU:最近使用 Least Recently Used )
# allkeys-lru ->
利用LRU算法移除任何key
# volatile-random -> 移除设置过过期时间的随机key
#
allkeys->random -> remove a random key, any key
# volatile-ttl ->
移除即将过期的key(minor TTL)
# noeviction -> 不移除任何可以,只是返回一个写错误
#
#
注意:对于上面的策略,如果没有合适的key可以移除,当写的时候Redis会返回一个错误
#
#       写命令包括: set setnx
setex append
#       incr decr rpush lpush rpushx lpushx linsert lset
rpoplpush sadd
#       sinter sinterstore sunion sunionstore sdiff sdiffstore
zadd zincrby
#       zunionstore zinterstore hset hsetnx hmset hincrby incrby
decrby
#       getset mset msetnx exec sort
#
# 默认是:
#
#
maxmemory-policy volatile-lru

# LRU 和 minimal TTL 算法都不是精准的算法,但是相对精确的算法(为了节省内存),随意你可以选择样本大小进行检测。
#
Redis默认的灰选择3个样本进行检测,你可以通过maxmemory-samples进行设置
#
# maxmemory-samples
3

############################## AOF ###############################


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

appendonly no

# AOF文件名称 (默认: "appendonly.aof")
# appendfilename appendonly.aof

# Redis支持三种同步AOF文件的策略:
#
# no: 不进行同步,系统去操作 . Faster.
# always:
always表示每次有写操作都进行同步. Slow, Safest.
# everysec: 表示对写操作进行累积,每秒同步一次.
Compromise.
#
# 默认是"everysec",按照速度和安全折中这是最好的。
#
如果想让Redis能更高效的运行,你也可以设置为"no",让操作系统决定什么时候去执行
#
或者相反想让数据更安全你也可以设置为"always"
#
# 如果不确定就用 "everysec".

# appendfsync always
appendfsync everysec
# appendfsync no

# AOF策略设置为always或者everysec时,后台处理进程(后台保存或者AOF日志重写)会执行大量的I/O操作
#
在某些Linux配置中会阻止过长的fsync()请求。注意现在没有任何修复,即使fsync在另外一个线程进行处理
#
#
为了减缓这个问题,可以设置下面这个参数no-appendfsync-on-rewrite
#
# This means that while
another child is saving the durability of Redis is
# the same as "appendfsync
none", that in pratical terms means that it is
# possible to lost up to 30
seconds of log in the worst scenario (with the
# default Linux
settings).
#
# If you have latency problems turn this to "yes". Otherwise
leave it as
# "no" that is the safest pick from the point of view of
durability.
no-appendfsync-on-rewrite no

# Automatic rewrite of the append only file.
# AOF 自动重写
#
当AOF文件增长到一定大小的时候Redis能够调用 BGREWRITEAOF 对日志文件进行重写
#
#
它是这样工作的:Redis会记住上次进行些日志后文件的大小(如果从开机以来还没进行过重写,那日子大小在开机的时候确定)
#
#
基础大小会同现在的大小进行比较。如果现在的大小比基础大小大制定的百分比,重写功能将启动
#
同时需要指定一个最小大小用于AOF重写,这个用于阻止即使文件很小但是增长幅度很大也去重写AOF文件的情况
# 设置 percentage
为0就关闭这个特性

auto-aof-rewrite-percentage 100
auto-aof-rewrite-min-size 64mb

################################## SLOW LOG
###################################

# Redis Slow Log 记录超过特定执行时间的命令。执行时间不包括I/O计算比如连接客户端,返回结果等,只是命令执行时间
#
#
可以通过两个参数设置slow log:一个是告诉Redis执行超过多少时间被记录的参数slowlog-log-slower-than(微妙),
#
另一个是slow log 的长度。当一个新命令被记录的时候最早的命令将被从队列中移除

# 下面的时间以微妙微单位,因此1000000代表一分钟。
#
注意制定一个负数将关闭慢日志,而设置为0将强制每个命令都会记录
slowlog-log-slower-than 10000

# 对日志长度没有限制,只是要注意它会消耗内存
# 可以通过 SLOWLOG RESET
回收被慢日志消耗的内存
slowlog-max-len 1024

################################ VM ###############################

### WARNING! Virtual Memory is deprecated in Redis 2.4
### The use of
Virtual Memory is strongly discouraged.

# Virtual Memory allows Redis to work with datasets bigger than the
actual
# amount of RAM needed to hold the whole dataset in memory.
# In
order to do so very used keys are taken in memory while the other keys
# are
swapped into a swap file, similarly to what operating systems do
# with
memory pages.
#
# To enable VM just set 'vm-enabled' to yes, and set the
following three
# VM parameters accordingly to your needs.

vm-enabled no
# vm-enabled yes

# This is the path of the Redis swap file. As you can guess, swap
files
# can't be shared by different Redis instances, so make sure to use a
swap
# file for every redis process you are running. Redis will complain if
the
# swap file is already in use.
#
# The best kind of storage for the
Redis swap file (that's accessed at random)
# is a Solid State Disk
(SSD).
#
# *** WARNING *** if you are using a shared hosting the default
of putting
# the swap file under /tmp is not secure. Create a dir with access
granted
# only to Redis user and configure Redis to create the swap file
there.
vm-swap-file /tmp/redis.swap

# vm-max-memory configures the VM to use at max the specified amount
of
# RAM. Everything that deos not fit will be swapped on disk *if* possible,
that
# is, if there is still enough contiguous space in the swap
file.
#
# With vm-max-memory 0 the system will swap everything it can. Not
a good
# default, just specify the max amount of RAM you can in bytes, but
it's
# better to leave some margin. For instance specify an amount of
RAM
# that's more or less between 60 and 80% of your free
RAM.
vm-max-memory 0

# Redis swap files is split into pages. An object can be saved using
multiple
# contiguous pages, but pages can't be shared between different
objects.
# So if your page is too big, small objects swapped out on disk will
waste
# a lot of space. If you page is too small, there is less space in the
swap
# file (assuming you configured the same number of total swap file
pages).
#
# If you use a lot of small objects, use a page size of 64 or 32
bytes.
# If you use a lot of big objects, use a bigger page size.
# If
unsure, use the default :)
vm-page-size 32

# Number of total memory pages in the swap file.
# Given that the page
table (a bitmap of free/used pages) is taken in memory,
# every 8 pages on
disk will consume 1 byte of RAM.
#
# The total swap size is vm-page-size *
vm-pages
#
# With the default of 32-bytes memory pages and 134217728 pages
Redis will
# use a 4 GB swap file, that will use 16 MB of RAM for the page
table.
#
# It's better to use the smallest acceptable value for your
application,
# but the default is large in order to work in most
conditions.
vm-pages 134217728

# Max number of VM I/O threads running at the same time.
# This threads
are used to read/write data from/to swap file, since they
# also encode and
decode objects from disk to memory or the reverse, a bigger
# number of
threads can help with big objects even if they can't help with
# I/O itself
as the physical device may not be able to couple with many
# reads/writes
operations at the same time.
#
# The special value of 0 turn off threaded
I/O and enables the blocking
# Virtual Memory
implementation.
vm-max-threads 4

############################### ADVANCED CONFIG
###############################

# 当hash中包含超过指定元素个数并且最大的元素没有超过临界时,
#
hash将以一种特殊的编码方式(大大减少内存使用)来存储,这里可以设置这两个临界值
# Redis
Hash对应Value内部实际就是一个HashMap,实际这里会有2种不同实现,
#
这个Hash的成员比较少时Redis为了节省内存会采用类似一维数组的方式来紧凑存储,而不会采用真正的HashMap结构,对应的value
redisObject的encoding为zipmap,
#
当成员数量增大时会自动转成真正的HashMap,此时encoding为ht。
hash-max-zipmap-entries
512
hash-max-zipmap-value 64

# list数据类型多少节点以下会采用去指针的紧凑存储格式。
#
list数据类型节点值大小小于多少字节会采用紧凑存储格式。
list-max-ziplist-entries
512
list-max-ziplist-value 64

# set数据类型内部数据如果全部是数值型,且包含多少节点以下会采用紧凑格式存储。
set-max-intset-entries
512

# zsort数据类型多少节点以下会采用去指针的紧凑存储格式。
#
zsort数据类型节点值大小小于多少字节会采用紧凑存储格式。
zset-max-ziplist-entries
128
zset-max-ziplist-value 64

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

################################## INCLUDES
###################################

# 指定包含其它的配置文件,可以在同一主机上多个Redis实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件
#
include /path/to/local.conf
# include /path/to/other.conf
复制代码

 

# Redis 配置文件
# 当配置中需要配置内存大小时,可以使用 1k, 5GB, 4M 等类似的格式,其转换方式如下(不区分大小写)## 1k =>1000 bytes# 1kb => 1024 bytes# 1m => 1000000 bytes# 1mb =>1024*1024 bytes# 1g => 1000000000 bytes# 1gb => 1024*1024*1024bytes## 内存配置大小写是一样的.比如 1gb 1Gb 1GB 1gB
# daemonize no 默认情况下,redis不是在后台运行的,如果需要在后台运行,把该项的值更改为yesdaemonizeyes
# 当redis在后台运行的时候,Redis默认会把pid文件放在/var/run/redis.pid,你可以配置到其他地址。#当运行多个redis服务时,需要指定不同的pid文件和端口pidfile /var/run/redis.pid
# 指定redis运行的端口,默认是6379port 6379
# 指定redis只接收来自于该IP地址的请求,如果不进行设置,那么将处理所有请求,# 在生产环境中最好设置该项# bind127.0.0.1
# Specify the path for the unix socket that will be used to listen for#incoming connections. There is no default, so Redis will not listen# on aunix socket when not specified.## unixsocket /tmp/redis.sock#unixsocketperm 755
# 设置客户端连接时的超时时间,单位为秒。当客户端在这段时间内没有发出任何指令,那么关闭该连接# 0是关闭此设置timeout0
# 指定日志记录级别# Redis总共支持四个级别:debug、verbose、notice、warning,默认为verbose#debug  记录很多信息,用于开发和测试# varbose 有用的信息,不像debug会记录那么多#notice 普通的verbose,常用于生产环境# warning 只有非常重要或者严重的信息会记录到日志logleveldebug
# 配置log文件地址# 默认值为stdout,标准输出,若后台模式会输出到/dev/null#logfilestdoutlogfile /var/log/redis/redis.log
# To enable logging to the system logger, just set 'syslog-enabled' toyes,# and optionally update the other syslog parameters to suit yourneeds.# syslog-enabled no
# Specify the syslog identity.# syslog-ident redis
# Specify the syslog facility.  Must be USER or between LOCAL0-LOCAL7.#syslog-facility local0
# 可用数据库数# 默认值为16,默认数据库为0,数据库范围在0-(database-1)之间databases 16
################################ 快照  ################################### 保存数据到磁盘,格式如下:##   save<seconds> <changes>##   指出在多长时间内,有多少次更新操作,就将数据同步到数据文件rdb。#   相当于条件触发抓取快照,这个可以多个条件配合#   #   比如默认配置文件中的设置,就设置了三个条件##   save 900 1  900秒内至少有1个key被改变#   save 30010  300秒内至少有300个key被改变#   save 60 10000  60秒内至少有10000个key被改变
save 900 1save 300 10save 60 10000
# 存储至本地数据库时(持久化到rdb文件)是否压缩数据,默认为yesrdbcompression yes
# 本地持久化数据库文件名,默认值为dump.rdbdbfilename dump.rdb
# 工作目录## 数据库镜像备份的文件放置的路径。#这里的路径跟文件名要分开配置是因为redis在进行备份时,先会将当前数据库的状态写入到一个临时文件中,等备份完成时,#再把该该临时文件替换为上面所指定的文件,而这里的临时文件和上面所配置的备份文件都会放在这个指定的路径当中。##AOF文件也会存放在这个目录下面## 注意这里必须制定一个目录而不是文件dir ./
################################# 复制#################################
# 主从复制. 设置该数据库为其他数据库的从数据库.#设置当本机为slav服务时,设置master服务的IP地址及端口,在Redis启动时,它会自动从master进行数据同步## slaveof<masterip> <masterport>
# 当master服务设置了密码保护时(用requirepass制定的密码)# slav服务连接master的密码##masterauth <master-password>

# 当从库同主机失去连接或者复制正在进行,从机库有两种运行方式:## 1)如果slave-serve-stale-data设置为yes(默认设置),从库会继续相应客户端的请求## 2)如果slave-serve-stale-data是指为no,出去INFO和SLAVOF命令之外的任何请求都会返回一个#    错误"SYNC withmaster in progress"#slave-serve-stale-data yes
# 从库会按照一个时间间隔向主库发送PINGs.可以通过repl-ping-slave-period设置这个时间间隔,默认是10秒##repl-ping-slave-period 10
# repl-timeout 设置主库批量数据传输时间或者ping回复时间间隔,默认值是60秒#一定要确保repl-timeout大于repl-ping-slave-period# repl-timeout 60
################################## 安全###################################
# 设置客户端连接后进行任何其他指定前需要使用的密码。#警告:因为redis速度相当快,所以在一台比较好的服务器下,一个外部的用户可以在一秒钟进行150K次的密码尝试,这意味着你需要指定非常非常强大的密码来防止暴力破解##requirepass foobared
# 命令重命名.## 在一个共享环境下可以重命名相对危险的命令。比如把CONFIG重名为一个不容易猜测的字符。##举例:## rename-command CONFIGb840fc02d524045429941cc15f59e41cb7be6c52##如果想删除一个命令,直接把它重命名为一个空字符""即可,如下:## rename-command CONFIG ""
################################### 约束####################################
# 设置同一时间最大客户端连接数,默认无限制,Redis可以同时打开的客户端连接数为Redis进程可以打开的最大文件描述符数,# 如果设置maxclients 0,表示不作限制。# 当客户端连接数到达限制时,Redis会关闭新的连接并向客户端返回max number of clientsreached错误信息## maxclients 128
# 指定Redis最大内存限制,Redis在启动时会把数据加载到内存中,达到最大内存后,Redis会先尝试清除已到期或即将到期的Key#Redis同时也会移除空的list对象##当此方法处理后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作##注意:Redis新的vm机制,会把Key存放内存,Value会存放在swap区##maxmemory的设置比较适合于把redis当作于类似memcached的缓存来使用,而不适合当做一个真实的DB。#当把Redis当做一个真实的数据库使用的时候,内存使用将是一个很大的开销# maxmemory <bytes>
# 当内存达到最大值的时候Redis会选择删除哪些数据?有五种方式可供选择## volatile-lru ->利用LRU算法移除设置过过期时间的key (LRU:最近使用 Least Recently Used )# allkeys-lru ->利用LRU算法移除任何key# volatile-random -> 移除设置过过期时间的随机key#allkeys->random -> remove a random key, any key# volatile-ttl ->移除即将过期的key(minor TTL)# noeviction -> 不移除任何可以,只是返回一个写错误##注意:对于上面的策略,如果没有合适的key可以移除,当写的时候Redis会返回一个错误##       写命令包括: set setnxsetex append#       incr decr rpush lpush rpushx lpushx linsert lsetrpoplpush sadd#       sinter sinterstore sunion sunionstore sdiff sdiffstorezadd zincrby#       zunionstore zinterstore hset hsetnx hmset hincrby incrbydecrby#       getset mset msetnx exec sort## 默认是:##maxmemory-policy volatile-lru
# LRU 和 minimal TTL 算法都不是精准的算法,但是相对精确的算法(为了节省内存),随意你可以选择样本大小进行检测。#Redis默认的灰选择3个样本进行检测,你可以通过maxmemory-samples进行设置## maxmemory-samples3
############################## AOF ###############################

#默认情况下,redis会在后台异步的把数据库镜像备份到磁盘,但是该备份是非常耗时的,而且备份也不能很频繁,如果发生诸如拉闸限电、拔插头等状况,那么将造成比较大范围的数据丢失。#所以redis提供了另外一种更加高效的数据库备份及灾难恢复方式。# 开启appendonly模式之后,redis会把所接收到的每一次写操作请求都追加到appendonly.aof文件中,当redis重新启动时,会从该文件恢复出之前的状态。#但是这样会造成appendonly.aof文件过大,所以redis还支持了BGREWRITEAOF指令,对appendonly.aof 进行重新整理。#你可以同时开启asynchronous dumps 和 AOF
appendonly no
# AOF文件名称 (默认: "appendonly.aof")# appendfilename appendonly.aof
# Redis支持三种同步AOF文件的策略:## no: 不进行同步,系统去操作 . Faster.# always:always表示每次有写操作都进行同步. Slow, Safest.# everysec: 表示对写操作进行累积,每秒同步一次.Compromise.## 默认是"everysec",按照速度和安全折中这是最好的。#如果想让Redis能更高效的运行,你也可以设置为"no",让操作系统决定什么时候去执行#或者相反想让数据更安全你也可以设置为"always"## 如果不确定就用 "everysec".
# appendfsync alwaysappendfsync everysec# appendfsync no
# AOF策略设置为always或者everysec时,后台处理进程(后台保存或者AOF日志重写)会执行大量的I/O操作#在某些Linux配置中会阻止过长的fsync()请求。注意现在没有任何修复,即使fsync在另外一个线程进行处理##为了减缓这个问题,可以设置下面这个参数no-appendfsync-on-rewrite## This means that whileanother child is saving the durability of Redis is# the same as "appendfsyncnone", that in pratical terms means that it is# possible to lost up to 30seconds of log in the worst scenario (with the# default Linuxsettings).## If you have latency problems turn this to "yes". Otherwiseleave it as# "no" that is the safest pick from the point of view ofdurability.no-appendfsync-on-rewrite no
# Automatic rewrite of the append only file.# AOF 自动重写#当AOF文件增长到一定大小的时候Redis能够调用 BGREWRITEAOF 对日志文件进行重写##它是这样工作的:Redis会记住上次进行些日志后文件的大小(如果从开机以来还没进行过重写,那日子大小在开机的时候确定)##基础大小会同现在的大小进行比较。如果现在的大小比基础大小大制定的百分比,重写功能将启动#同时需要指定一个最小大小用于AOF重写,这个用于阻止即使文件很小但是增长幅度很大也去重写AOF文件的情况# 设置 percentage为0就关闭这个特性
auto-aof-rewrite-percentage 100auto-aof-rewrite-min-size 64mb
################################## SLOW LOG###################################
# Redis Slow Log 记录超过特定执行时间的命令。执行时间不包括I/O计算比如连接客户端,返回结果等,只是命令执行时间##可以通过两个参数设置slow log:一个是告诉Redis执行超过多少时间被记录的参数slowlog-log-slower-than(微妙),#另一个是slow log 的长度。当一个新命令被记录的时候最早的命令将被从队列中移除
# 下面的时间以微妙微单位,因此1000000代表一分钟。#注意制定一个负数将关闭慢日志,而设置为0将强制每个命令都会记录slowlog-log-slower-than 10000
# 对日志长度没有限制,只是要注意它会消耗内存# 可以通过 SLOWLOG RESET回收被慢日志消耗的内存slowlog-max-len 1024
################################ VM ###############################
### WARNING! Virtual Memory is deprecated in Redis 2.4### The use ofVirtual Memory is strongly discouraged.
# Virtual Memory allows Redis to work with datasets bigger than theactual# amount of RAM needed to hold the whole dataset in memory.# Inorder to do so very used keys are taken in memory while the other keys# areswapped into a swap file, similarly to what operating systems do# withmemory pages.## To enable VM just set 'vm-enabled' to yes, and set thefollowing three# VM parameters accordingly to your needs.
vm-enabled no# vm-enabled yes
# This is the path of the Redis swap file. As you can guess, swapfiles# can't be shared by different Redis instances, so make sure to use aswap# file for every redis process you are running. Redis will complain ifthe# swap file is already in use.## The best kind of storage for theRedis swap file (that's accessed at random)# is a Solid State Disk(SSD).## *** WARNING *** if you are using a shared hosting the defaultof putting# the swap file under /tmp is not secure. Create a dir with accessgranted# only to Redis user and configure Redis to create the swap filethere.vm-swap-file /tmp/redis.swap
# vm-max-memory configures the VM to use at max the specified amountof# RAM. Everything that deos not fit will be swapped on disk *if* possible,that# is, if there is still enough contiguous space in the swapfile.## With vm-max-memory 0 the system will swap everything it can. Nota good# default, just specify the max amount of RAM you can in bytes, butit's# better to leave some margin. For instance specify an amount ofRAM# that's more or less between 60 and 80% of your freeRAM.vm-max-memory 0
# Redis swap files is split into pages. An object can be saved usingmultiple# contiguous pages, but pages can't be shared between differentobjects.# So if your page is too big, small objects swapped out on disk willwaste# a lot of space. If you page is too small, there is less space in theswap# file (assuming you configured the same number of total swap filepages).## If you use a lot of small objects, use a page size of 64 or 32bytes.# If you use a lot of big objects, use a bigger page size.# Ifunsure, use the default :)vm-page-size 32
# Number of total memory pages in the swap file.# Given that the pagetable (a bitmap of free/used pages) is taken in memory,# every 8 pages ondisk will consume 1 byte of RAM.## The total swap size is vm-page-size *vm-pages## With the default of 32-bytes memory pages and 134217728 pagesRedis will# use a 4 GB swap file, that will use 16 MB of RAM for the pagetable.## It's better to use the smallest acceptable value for yourapplication,# but the default is large in order to work in mostconditions.vm-pages 134217728
# Max number of VM I/O threads running at the same time.# This threadsare used to read/write data from/to swap file, since they# also encode anddecode objects from disk to memory or the reverse, a bigger# number ofthreads can help with big objects even if they can't help with# I/O itselfas the physical device may not be able to couple with many# reads/writesoperations at the same time.## The special value of 0 turn off threadedI/O and enables the blocking# Virtual Memoryimplementation.vm-max-threads 4
############################### ADVANCED CONFIG###############################
# 当hash中包含超过指定元素个数并且最大的元素没有超过临界时,#hash将以一种特殊的编码方式(大大减少内存使用)来存储,这里可以设置这两个临界值# RedisHash对应Value内部实际就是一个HashMap,实际这里会有2种不同实现,#这个Hash的成员比较少时Redis为了节省内存会采用类似一维数组的方式来紧凑存储,而不会采用真正的HashMap结构,对应的valueredisObject的encoding为zipmap,#当成员数量增大时会自动转成真正的HashMap,此时encoding为ht。hash-max-zipmap-entries512hash-max-zipmap-value 64
# list数据类型多少节点以下会采用去指针的紧凑存储格式。#list数据类型节点值大小小于多少字节会采用紧凑存储格式。list-max-ziplist-entries512list-max-ziplist-value 64
# set数据类型内部数据如果全部是数值型,且包含多少节点以下会采用紧凑格式存储。set-max-intset-entries512
# zsort数据类型多少节点以下会采用去指针的紧凑存储格式。#zsort数据类型节点值大小小于多少字节会采用紧凑存储格式。zset-max-ziplist-entries128zset-max-ziplist-value 64
# Redis将在每100毫秒时使用1毫秒的CPU时间来对redis的hash表进行重新hash,可以降低内存的使用##当你的使用场景中,有非常严格的实时性需要,不能够接受Redis时不时的对请求有2毫秒的延迟的话,把这项配置为no。##如果没有这么严格的实时性要求,可以设置为yes,以便能够尽可能快的释放内存activerehashing yes
################################## INCLUDES###################################
# 指定包含其它的配置文件,可以在同一主机上多个Redis实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件#include /path/to/local.conf# include /path/to/other.conf

分类:  Redis

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值