1. Redis简介
redis简介:Redis(Remote Dictionary Server) 是一个由Salvatore Sanfilippo写的key-value存储系统。Redis 是完全开源免费的,遵守BSD协议,是一个高性能的key-value数据库。它通常被称为数据结构服务器,因为值(value)可以是 字符串(String), 哈希(Map), 列表(list), 集合(sets) 和 有序集合(sorted sets)等类型。Redis支持持久化,支持数据的备份。
Redis优点:
(1)性能极高:Redis读取速度能达到110000次/s,写的速度能达到81000次/s 。
(2)丰富的数据类型 :Redis支持二进制案例的 Strings, Lists, Hashes, Sets 及 Ordered Sets 数据类型操作。
(3)原子 :Redis的所有操作都是原子性的,同时Redis还支持对几个操作全并后的原子性执行。
(4)丰富的特性 :Redis还支持 publish/subscribe(发布订阅), 通知, key 过期等特性。
2. Redis在windows下安装、配置
Redis官方未提供windows版本, Microsoft Open Tech group在 GitHub上开发了一个Win64的版本。
Redis Windows版本下载地址:
Redis Linux版本下载地址:
打开windows版本下载地址,可以在页面中找到下图所示两个版本可供选择:
此处我们下载zip版本,将其解压到某一个目录,如D:/database,解压后的目录如下:
打开CMD命令窗口,进入刚才解压的目录,录入命令:redis-server redis.windows.conf启动Redis服务器;
重新打开一个cmd命令窗口,进入解压目录,录入命令:redis-cli ,默认连接本地redis服务器。如需连接远程服务器,使用命令redis-cli -h [ip] -p [port]进行连接,此处我们连接本地:redis-cli -h 127.0.0.1 -p 6379。如下图所示:
测试是否连接成功:输入set name zhangsan和get name命令进行确认
Redis服务器配置文件redis.windows.conf解释:
include /path/to | 引入其它配置文件 |
bind 127.0.0.1 | 绑定指定IP,只有该IP地址才能访问此服务器,默认绑定本机 |
protected-mode yes | 默认启用安全模式,安全模式下只允许本机访问,如果需要来自其他主机的客户端访问,需要将其关闭 |
port 6379 | 默认监听端口为6379 |
tcp-backlog 511 | 客户端连接队列值,这个值是socket里面listen函数的参数。如果服务器caps很高,需要把这个参数改大些。 |
timeout 0 | 客户端与服务端的连接超时时间,0为如不超时 |
tcp-keepalive 60 | 周期性的使用SO_KEEPALIVE检测客户端是否还处于健康状态,避免服务器一直阻塞,建议设为60 |
daemonize no | 默认情况,Redis不会以后台守护进程方式启动(windows下不支持此设置) |
supervised no | (不懂此设置,windows下不支持) |
pidfile /var/run | 当daemonize设置为yes时此设置有用(windows下不支持) |
loglevel notice | 定义日志级别,分别为debug、verbose、notice、warning |
logfile "" | 定义日志文件的位置 |
databases 16 | 定义数据库数量,默认为16个(0-15) |
save 900 1 | 意思是900秒内至少有1个key的值发生变化,则保存到磁盘中,如果注释save,则不保存到磁盘。 |
stop-writes-on-bgsave-error yes | 当redis在后台执行save操作失败后,停止接受写操作,以便于告知客户端不能持久化到磁盘 |
rdbcompression yes | 是否在 dump .rdb 数据库的时候使用 LZF 压缩字符串,如果设置为no保存子进程可以省点CPU,但会增大数据集 |
rdbchecksum yes | 是否检验rdb文件 |
dbfilename dump.rdb | 设置dump文件的位置 |
dir ./ | 工作目录 |
requirepass foobared | 设置服务器密码,默认为footbared |
slave-serve-stale-data yes | 当从属服务器与主服务器失去联系,或者正在复制的时候,如果设置此项为yes, 从属服务器仍然会响应客户端的请求,但可能返回请求超时,如果是第一次同步,可能返回为空;如果此项设置为no,除了执行info 和 slaveof命令,其它命令都将返回“SYNC with master in progress”的错误 |
slave-read-only yes | 从属服务器是否只读,默认为yes |
repl-diskless-sync no | 复制集同步策略,yes为磁盘,no为socket |
repl-diskless-sync-delay 5 | 基于socket同步时的延时设置 |
....更多配置请阅读配置文件注释 |
3. Redis数据类型
Redis支持五种数据类型:
(1) string(字符串)
string类型是Redis最基本的数据类型,一个key对应一个value。
string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。
(2) hash(哈希)
Redis hash 是一个键值对集合。
Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。
(3) list(列表)
Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。
(4) set(集合)
Redis的Set是string类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据。
(5) zset(Sort Set有序集合)
Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
zset的成员是唯一的,但分数(score)却可以重复。
4. Redis基础命令
注:此处只举例列出部分命令,更多命令请参考
服务器连接命令:
redis-cli | 连接本地redis服务 |
redis-cli -h host -p port -a password | 连接远程redis服务 |
redis-cli -h host -p port -c -a password | 以集群模式连接服务器 |
Key(键)相关命令:
del key | 当key存在时删除key |
Dump key | 序列化给定 key,并返回被序列化的值 |
EXISTS key | 检查给定 key 是否存在 |
EXPIRE key seconds | 为给定 key 设置过期时间 |
PERSIST key | 移除 key 的过期时间,key 将持久保持 |
TYPE key | 返回 key 所储存的值的类型 |
String(字符串)相关命令:
Set key value | 设置指定key的值 |
Get key | 获取指定key的值 |
Getrange key start end | 获取key对应字符串第start位到第end位的子字符串 |
Getset key value | 将key的值设为value,并返回key的旧值 |
Mget key1[key2...] | 获取一个或多个key的值 |
Decr key | 将key中存储的数字值减一,如果不是数字,则出错 |
Append key value | 如果key已经存在并且是字符串,则将value追加到原来的字符串尾部 |
Hash(哈希)相关命令:
HMSET key field1 value1 [field2 value2 ] | 同时将多个 field-value (域-值)对设置到哈希表 key 中 |
HSET key field value | 将哈希表 key 中的字段 field 的值设为 value |
HEXISTS key field | 查看哈希表 key 中,指定的字段是否存在 |
HGET key field | 获取存储在哈希表中指定字段的值 |
HGETALL key | 获取在哈希表中指定 key 的所有字段和值 |
HKEYS key | 获取所有哈希表中的字段 |
HLEN key | 获取哈希表中字段的数量 |
HMGET key field1 [field2] | 获取所有给定字段的值 |
List(列表)相关命令:
LPUSH key value1 [value2] | 将一个或多个值插入到列表头部 |
LPUSHX key value | 将一个或多个值插入到已存在的列表头部 |
RPUSH key value1 [value2] | 在列表中添加一个或多个值 |
LPOP key | 移出并获取列表的第一个元素 |
BLPOP key1 [key2 ] timeout | 移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止 |
BRPOP key1 [key2 ] timeout | 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止 |
Set(集合)相关命令:
SADD key member1 [member2] | 向集合添加一个或多个成员 |
SDIFF key1 [key2] | 返回给定所有集合的差集 |
SINTER key1 [key2] | 返回给定所有集合的交集 |
SMEMBERS key | 返回集合中的所有成员 |
SCARD key | 获取集合的成员数 |
SMOVE s1 s2member | 将 member 元素从 s1集合移动到 s2集合 |
SPOP key | 移除并返回集合中的一个随机元素 |
Sorted set(有序集合)相关命令:
ZADD key score1 member1 [score2 member2] | 向有序集合添加一个或多个成员,或者更新已存在成员的分数 |
ZCARD key | 获取有序集合的成员数 |
ZRANK key member | 返回有序集合中指定成员的索引 |
ZREM key member [member ...] | 移除有序集合中的一个或多个成员 |
ZSCORE key member | 返回有序集中,成员的分数值 |
Redis HyperLogLog:
2.8.9以上版本可用,用来做基数统计的算法,基数解释示例:比如有一个数据集{1, 2, 3, 2, 5, 3, 4},这个数据集的基数集为{1, 2, 3, 5, 4},基数为5
PFADD key element [element ...] | 添加指定元素到 HyperLogLog 中。 |
PFCOUNT key [key ...] | 返回给定 HyperLogLog 的基数估算值 |
PFMERGE destkey sourcekey [sourcekey ...] | 将多个 HyperLogLog 合并为一个 HyperLogLog |
Redis 发布订阅命令:
Redis 发布订阅(pub/sub)是一种消息通信模式:发送者(pub)发送消息,订阅者(sub)接收消息。Redis客户端可以订阅任意数量的频道。当发送者向某个频道发送消息时,订阅该频道的客户端都能接收到消息。
SUBSCRIBE channel [channel ...] | 订阅给定的一个或多个频道的信息 |
PUBLISH channel message | 将信息发送到指定的频道 |
UNSUBSCRIBE [channel [channel ...]] | 退订给定的频道 |
PUBSUB subcommand [argument [argument ...]] | 查看订阅与发布系统状态 |
PSUBSCRIBE pattern [pattern ...] | 订阅一个或多个符合给定模式的频道 |
PUNSUBSCRIBE [pattern [pattern ...]] | 退订所有给定模式的频道 |
Redis 事务:
Redis事务可以一次执行多个命令,事务中所有命令都会序列化、按顺序地执行,事务在执行的过程中,不会被其他客户端发送来的命令请求所打断(隔离性)。事务中的命令要么全部被执行,要么全部都不执行(原子性)。
MULTI | 标记一个事务块的开始 |
EXEC | 执行所有事务块内的命令 |
DISCARD | 取消事务,放弃执行事务块内的所有命令 |
UNWATCH | 取消 WATCH 命令对所有 key 的监视 |
WATCH key [key ...] | 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。 |
Redis 服务器相关命令:
BGSAVE | 在后台异步保存当前数据库的数据到磁盘 |
CLIENT KILL [ip:port] [ID client-id] | 关闭客户端连接 |
CLIENT LIST | 获取连接到服务器的客户端连接列表 |
COMMAND | 获取 Redis 命令详情数组 |
CLUSTER SLOTS | 获取集群节点的映射数组 |
CONFIG REWRITE | 对启动 Redis 服务器时所指定的 redis.conf 配置文件进行改写 |
DEBUG SEGFAULT | 让 Redis 服务崩溃 |
FLUSHALL | 删除所有数据库的所有key |
FLUSHDB | 删除当前数据库的所有key |
INFO [section] | 获取 Redis 服务器的各种信息和统计数值 |
SAVE | 异步保存数据到硬盘 |
5. Redis数据持久化
(1) 快照(snapshots)模式
默认情况下,Redis使用快照模式将数据保存到磁盘上的二进制文件中,文件名为dump.rdb,可以配置Redis的持久化策略,也可以手动调用命令save或bgsave。持久化策略配置在redis的配置文件中,主要由如下几个部分构成:
红色框内save 900 1表示每900秒内有1个key值发生改变就保存到磁盘
是否在 dump .rdb 数据库的时候使用 LZF 压缩字符串,如果设置为no保存子进程可以省点CPU,但会增大数据集
保存数据二进制文件的名字,默认为dump.rdb
二进制文件的存放目录
(2) AOF模式
快照模式并不十分健壮,当系统停止,或者无意中Redis被kill掉,最后写入Redis的数据就会丢失。对于可靠性要求高的系统来说,AOF模式是一个更好的选择。AOF是AppendOnly File的缩写,在AOF生成的文件中,将忠实记录发生在Redis的操作,从而达到在Redis服务器重启或者宕机之后,继续恢复之前数据状态的机制。AOF模式配置如下:
Aof模式默认关闭,将此处的配置为yes,打开aof模式
文件名称,默认为a
appendfsync :(a)当配置为no时,Redis不会主动调用fsync去将AOF日志内容同步到磁盘,所以这一切就完全依赖于操作系统的调试了。
(b)当配置为everysec时,Redis会默认每隔一秒进行一次fsync调用,将缓冲区中的数据写到磁盘。在特殊情况下,会隔两秒进行一次fsync调用。
(c)当设置为always时,每一次写操作都会调用一次fsync,这时数据是最安全的,当然,由于每次都会执行fsync,所以其性能也会受到影响。
快照模式和AOF模式可同时开启,互不影响。
(3) AOF 重写
在AOF的文件中,它忠实记录了发生在Redis上的操作,从而达到了还原数据的目的,但是有可能对于部分数据进行了大量的操作,在这种情况下就必定会产生大量的冗余操作记录,那么AOF文件的大小会不断的增加。当AOF文件满足一定条件时就需要对AOF进行rewrite,rewrite是根据当前内存数据库中的数据进行遍历写到一个临时的AOF文件,待写完后替换掉原来的AOF文件。
Redis触发AOF rewrite机制有三种:
1、Redis Server接收到客户端发送的BGREWRITEAOF指令请求,如果当前AOF/RDB数据持久化没有在执行,那么执行,反之,等当前AOF/RDB数据持久化结束后执行AOF rewrite;
2、在Redis配置文件redis.conf中,用户设置了auto-aof-rewrite-percentage和auto-aof-rewrite-min-size参数,并且当前AOF文件大小大于auto-aof-rewrite-min-size,同时AOF文件大小的增长率大于auto-aof-rewrite-percentage时,会自动触发AOF rewrite;
3、用户设置"config set appendonly yes"开启AOF的时,调用startAppendOnly函数会触发rewrite。
6. Windows下Redis集群简单配置
Redis集群介绍:
Redis 集群是一个提供在多个Redis间节点间共享数据的程序集,使用集群能大大提高Redis的并发性能,redis集群架构图如下:
架构细节:
(1)所有的redis节点彼此互联(PING-PONG机制),内部使用二进制协议优化传输速度和带宽.
(2)节点的fail是通过集群中超过半数的master节点检测失效时才生效.
(3)客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可
(4)redis-cluster把所有的物理节点映射到[0-16383]slot(哈希槽)上,cluster 负责维护node<->slot<->key
Redis 集群的主从复制模型:
为了使在部分节点失效或者部分节点无法通信的情况下集群仍然可用,所以集群使用了主从复制模型,每个节点都会有1到多个复制品.
假设有A,B,C三个节点的集群,在没有复制模型的情况下,如果节点B失败了,那么整个集群就会因为缺少节点B对应的哈希槽而不可用.
然而如果在集群创建的时候(或者过一段时间)我们为每个节点添加一个从节点A1,B1,C1,那么整个集群便有三个master节点和三个slave节点组成,这样在节点B失败后,集群便会将B1作为新的主节点继续服务,整个集群便不会因为槽找不到而不可用了。
准备工作:(1)Redis windows版本及linux版本下载并解压。
(2)Ruby安装:下载 64位的 RubyInstaller并安装, 地址 勾选下面三个选项后不用配置环境变量
(3) 安装RubyGems:下载地址,下载zip包,解压后运行即可安装成功。由于大陆墙的原因,ruby自带的源可能无法使用,将其更换为Ruby China的源,不然安装redis依赖会失败。CMD下执行以下命令:
gem sources --remove 删掉原来的源
gem sources -a 添加ruby china的源
gem sources -l 查看现有的源
gem install redis 安装redis依赖
注:如果第二行命令执行失败,更换为:gem sources -a
集群搭建:
(1) 找到windows版本redis根目录下的redis.windows.conf文件,修改如下配置:protected-mode no //关闭安全模式
cluster-enabled yes //启用集群模式
cluster-config-file nodes.conf //设定保存节点配置文件的路径
cluster-node-timeout 5000 //设定节点超时时间
appendonly yes
(2) 创建6个文件夹,以端口号命名,分别命名为7000、7001、7002、7003、7004、7005,将redis程序分别拷贝到这几个文件夹中,并分别修改redis.windows.conf文件中的port为文件夹名。此步骤旨在模拟不同主机上的redis服务器。
(3) 打开6个cmd命令窗口分别启动六个redis服务器,启动步骤在第2节(也可以自己编写bat文件,避免重复录入命令)
(4) 打开新的cmd命令窗口,进入linux版本redis下的src目录,运行如下命令redi create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
运行成功之后出现如下提示:
打印出配置信息,现在的master是 7000 7001 7002这三台机,redis会对key 做 CRC16 校验和后分别存储这三台机上。没问题就输入 yes。(前面准备工作中安装的ruby和rubygems就是为了执行redi命令做准备)
7. Java中Redis的使用
Redis的简单使用:
Java中使用Redis,除了确保已经有了redis服务器外,还需要Java Redis驱动,Redis官方现在推荐的有Jedis、lettuce和Redisson,关于他们之间的区别及下载请访问,我们使用Jedis进行演示。
新建一个Java项目,引入Jedis包,如下图所示:
测试代码如下:
public static void main(String[] args) {
//连接本地redis
Jedis jedis = new Jedis("127.0.0.1", 6379);
//查看服务是否运行
Sy("Server is running: "+jedis.ping());
Sy("++++++String类型测试开始+++++++");
jedis.set("name", "张三");
Sy("name:" + jedis.get("name"));
Sy("++++++String类型测试结束+++++++");
}
运行结果如下:
从运行结果可以看出已经成功连接到服务器
Ta+3整合Redis:
TA+3 3.13版本中已实现对Redis的整合,缓存管理器TaCacheManager通过实现Spring的CacheManager接口来对缓存进行管理,缓存管理器可管理多个缓存服务,缓存服务TaRedisCache实现Cache接口,这样就能统一的使用Cache接口对数据进行操作。
Spring整合Redis集群:
1. 引入相关依赖包,配置基础的spring框架
2. 新建Redis的配置文件redis.properties,内容如下:
redis.host=127.0.0.1 redis.port=7000 redis.timeout=100000 redis.maxIdle=300 redis.maxTotal=600 redis.timeBetweenEvictionRunsMillis=30000 redis.minEvictableIdleTimeMillis=30000 redis.testOnBorrow=true |
3. 新建一个Redis工厂类JedisClusterFactory ,代码如下:
public class JedisClusterFactory { private JedisCluster jedisCluster; public JedisCluster getJedisCluster() { return jedisCluster; } public JedisClusterFactory(JedisPoolConfig jedisPoolConfig,String host,int port){ Set<HostAndPort> jedisClusterNodes= new HashSet<HostAndPort>(); jedi(new HostAndPort(host,port)); jedisCluster=new JedisCluster(jedisClusterNodes,jedisPoolConfig); } } |
4. 在spring的配置文件a文件中配置该工厂类
<bean id="propertyConfigurer" class="org.;> <property name="location"> <value>classpa;/value> </property> </bean> <bean id="jedisPoolConfig" class="redis.clien;> <property name="maxTotal" value="${redis.maxTotal}" /> <property name="maxIdle" value="${redis.maxIdle}" /> <property name="timeBetweenEvictionRunsMillis" value="${redis.timeBetweenEvictionRunsMillis}" /> <property name="minEvictableIdleTimeMillis" value="${redis.minEvictableIdleTimeMillis}" /> <property name="testOnBorrow" value="${redis.testOnBorrow}" /> </bean> <bean id="jedisClusterFactory" class="com.yin; > <constructor-arg ref ="jedisPoolConfig"/> <constructor-arg name="host" value="${redis.host}"/> <constructor-arg name="port" value="${redis.port}"/> </bean> |
5. 以上步骤及完成了Spring和redis的简单整合,现在进行测试。新建工厂类的JUNIT测试类JedisClusterFactoryTest,此测试类比较了从Redis及Oracle中分别查询20条数据,测试条件为redis及oracle comments表中分别存入100万条数据,代码如下:
public class JedisClusterFactoryTest { private ApplicationContext applicationContext; @Before public void setUp() throws Exception { applicationContext = new FileSystemXmlApplicationContext("classpath:a"); } @Test public void test() { Long t1 = Sy(); JedisClusterFactory clusterFactory = (JedisClusterFactory("jedisClusterFactory"); JedisCluster cluster = clu(); /*写入100万条数据*/ /*for(int i = 0; i < 1000000; i++){ clu("comments", "这是第" + (i + 1) +"条数据"); Sy("第"+ (i+1)+"条"); }*/ Sy("+++++Redis查询开始+++++"); List<String> list = clu("comments", 500001, 500020); Sy("+++++Redis查询结束+++++"); Long t2 = Sy(); Sy("Redis查询数据共用时:"+(t2 - t1)+"ms"); /*for(int i = 0; i < li(); i ++){ Sy(i)); }*/ dbtest(); } public static void dbtest(){ String url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl"; Connection con = null; Statement stmt = null; ResultSet rs = null; try { Long start0 = Sy(); Class c = Cla("oracle.jdbc.driver.OracleDriver"); con = DriverManager.getConnection(url,"yhdb","yhdb"); Sy("连接成功"); StringBuilder sb = new StringBuilder(); (" SELECT *"); (" FROM comments"); (" WHERE commentid >= 500001"); (" AND commentid <= 500020"); (" ORDER BY commentid"); Long start = Sy(); PreparedStatement prst = con.prepareStatemen()); rs = (); Long end = Sy(); Sy("执行时间:"+ (end - start)); /*while ()) { Sy("ctext")); }*/ } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } } |
以上代码分别从oracle和redis中进行数据查询,查询时效在第8节给出
8. Redis性能简单测试
本次测试在个人电脑进行测试,测试结果仅供参考,使用oracle和redis进行性能比较,主要为了测试二者在查询数据上的性能,本次使用的oracle版本是11g,redis版本为3.2,使用了redis集群功能,在本机模拟了6台redis服务器。PC的基本配置如下表所示:
CPU | I5-2430M |
内存 | 4G DDR3 1333MHz |
硬盘 | 128G SSD |
本次测试通过java程序分别从oracle和redis总共1000000条数据中查询20条数据,共进行十次查询,查询用时如下表所示:
方式 用时(ms) 次序 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
ORACLE | 148 | 116 | 120 | 128 | 131 | 125 | 132 | 127 | 129 | 137 |
REDIS | 14 | 15 | 13 | 18 | 13 | 18 | 13 | 15 | 13 | 12 |
从上图可以看出,Redis查询数据性能大约为Oracle的7-11倍。