一、redis安装
1、安装
$ wget http://download.redis.io/releases/redis-2.8.17.tar.gz
$ tar xzf redis-2.8.17.tar.gz
$ cd redis-2.8.17
$ make
2、启动
$ ./redis-server
$ ./redis-server redis.conf指定配置文件启动
$ ./redis-server stop
$ ./redis-server restart
3、客户端连接
$ ./redis-cli -h localhost -p 6379
4、redis集群
1)redis自带集群功能,使用pingpong缓存机制容错,如果集群任意master挂掉且当前master没有slave或集群超过半数以上master挂掉集群进入fail状态,所以一般至少需要六个节点。如果在单机上部署集群,可以通过修改redis.conf文件的端口实现。
mkdir redis_cluster //创建集群目录
mkdir 7000 7001 7002 7003 7004 7005 //分别代表六个节点 其对应端口 7000 7001 7002 7003 7004 7005//创建7000节点为例,拷贝到7000目录
cp /usr/local/redis-3.2.1/redis.conf ./redis_cluster/7000/
//拷贝到7001目录
cp /usr/local/redis-3.2.1/redis.conf ./redis_cluster/7001/
//拷贝到7002目录
cp /usr/local/redis-3.2.1/redis.conf ./redis_cluster/7002/
//拷贝到7003目录
cp /usr/local/redis-3.2.1/redis.conf ./redis_cluster/7000/
//拷贝到7004目录
cp /usr/local/redis-3.2.1/redis.conf ./redis_cluster/7001/
//拷贝到7005目录
cp /usr/local/redis-3.2.1/redis.conf ./redis_cluster/7002/
2)启动
redis-server redis_cluster/7000/redis.conf
redis-server redis_cluster/7001/redis.conf
redis-server redis_cluster/7002/redis.conf
redis-server redis_cluster/7003/redis.conf
redis-server redis_cluster/7004/redis.conf
redis-server redis_cluster/7005/redis.conf
3)redis需要ruby环境,需要安装ruby依赖包
# yum -y install ruby ruby-devel rubygems rpm-build
使用ruby的工具包gem安装redis接口
gem install redis
运行/redis-trib.rb create --replicas 1 127.0.0.1:7000 127.0.0.1:7001 127.0.0.1:7003 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005
4)客户端连接集群
redis-cli -c -p 7000(任意一台)
二、redis数据类型和常用命令
1)select (0~5);keys *;randomkey;type key;exists key;del key;expire 1(过期时间,秒为单位);move key 2(库);dbsize;
2)字符串:set key value;get key;getrange key 开始 结束;mget key1 key2...someotherkey;strlen key;decr key(-1);decrby key value;append key value;
3)列表:lpush(rpush) key value;lrange key 开始 结束;lindex key index(左边第几个);llen key;lrem key count value(移除指定元素count个0所有);ltrim key 开始 结束
4)无序集合:sadd key value;smembers key;srem key value;不能重复
5)有序集合:zadd key 位 value;zrange key 开始 结束 withscres;zcard key 长度;zrem key value; zincrby key index 2 相当于arraylist
6)hash:hmset(hset) key name value;hgetall(hvals)key;hget key name;hmget k1 name1 name2;hkeys key;hlen key;hdel key field;hincrby key name 2;
redis脚本
事物:multi发起事物;discard 回滚;exec 执行;eval 用于执行redis脚本。
redis备份:save创建当前数据库备份,生成.rdb文件;bgsave在后台运行备份;redis.conf有两种备份方式rdb(多久保存)和aof(数据一修改就备份)
redis帮助文档:http://www.runoob.com/redis/sorted-sets-zadd.html
三、redis使用场景
1、缓存
redis缓存适用于一些改动不大或者访问率大的数据保存,设计模式有四种Cache aside,Read through,Write through,Write behind caching。
Cache aside:应用程序先从cache取数据,没有得到,则从数据库中取数据,成功后,放到缓存中,然后返回。先把数据存到数据库中,成功后,再让缓存失效;(常见)
Read through:在查询操作中当缓存失效的时候更新缓存,缓存服务自己来加载;
Write through:在更新数据时发生。当有数据更新的时候,如果没有命中缓存,直接更新数据库,然后返回。如果命中了缓存,则更新缓存,然后再由Cache自己更新数据库;
Write behind caching:又叫 Write Back,在更新数据的时候,只更新缓存,不更新数据库,而我们的缓存会异步地批量更新数据库。(微博等聊天服务缓存)
2、session共享
用户登录时将用户token作为key,用户信息作为value保存到redis。用户每次访问服务时使用监听器在redis查询token并将结果保存到request下(记得添加过期时间)。
3、分布式锁
加锁
String result = jedis.set(lockKey, requestId, SET_IF_NOT_EXIST, SET_WITH_EXPIRE_TIME, expireTime);
if (LOCK_SUCCESS.equals(result)) {
return true;
}
解锁
String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
Object result = jedis.eval(script, Collections.singletonList(lockKey), Collections.singletonList(requestId));
if (RELEASE_SUCCESS.equals(result)) {
return true;
}
详见:https://www.cnblogs.com/linjiqin/p/8003838.html
4、分布式计时器
获取系统时间:TIME命令返回当前时间
计时:SETEX KEY_NAME TIMEOUT VALUE
5、系统开关
在生产环境中为保证系统正常,往往需要通过后台管理系统控制管理生产系统的一些流程,这就要用到开关,为保证开关不影响系统正常工作,一般会使用redis缓存。
四、spring整合redis
spring整合redis有两种方式,直接用jedis构造函数和适用spring提供的整合工具,个人推荐前者,简单易操作,主要jedis方法和redis命令一致。
21 <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
22 <property name="maxIdle" value="${redis.maxIdle}"/>
23 <property name="maxTotal" value="${redis.maxActive}" />
24 <property name="maxWaitMillis" value="${redis.maxWait}" />
25 <property name="testOnBorrow" value="${redis.testOnBorrow}"/>
26 </bean>
.
.
.
58 <bean id="redisCluster" class="redis.clients.jedis.JedisCluster">
59 <constructor-arg name="jedisClusterNode">
60 <set>
28 <bean id="hostport1" class="redis.clients.jedis.HostAndPort">
29 <constructor-arg name="host" value="192.168.1.171" />
30 <constructor-arg name="port" value="7001" />
31 </bean>
.
.
.
67 </set>
68 </constructor-arg>
69 <constructor-arg name="connectionTimeout" value="6000" />
70 <constructor-arg name="soTimeout" value="2000" />
71 <constructor-arg name="maxAttempts" value="3" />
72 <constructor-arg name="password" value="123456" />
73 <constructor-arg name="poolConfig">
74 <ref bean="jedisPoolConfig"/>
75 </constructor-arg>
76 </bean>
附上单机版配置
<bean id = "jedisPool" class="redis.clients.jedis.JedisPool">
<constructor-arg index="0" ref="jedisPoolConfig"/>
<constructor-arg index="1" value="${redis.host}"/>
<constructor-arg index="2" value="${redis.port}" type="int"/>
<constructor-arg index="3" value="${redis.timeout}" type="int"/>
<constructor-arg index="4" value="${redis.password}"/>
</bean>
五、redis性能问题
1).Master写内存快照,save命令调度rdbSave函数,会阻塞主线程的工作,当快照比较大时对性能影响是非常大的,会间断性暂停服务,所以Master最好不要写内存快照。
2).Master AOF持久化,如果不重写AOF文件,这个持久化方式对性能的影响是最小的,但是AOF文件会不断增大,AOF文件过大会影响Master重启的恢复速度。Master最好不要做任何持久化工作,包括内存快照和AOF日志文件,特别是不要启用内存快照做持久化,如果数据比较关键,某个Slave开启AOF备份数据,策略为每秒同步一次。
3).Master调用BGREWRITEAOF重写AOF文件,AOF在重写的时候会占大量的CPU和内存资源,导致服务load过高,出现短暂服务暂停现象。
4).Redis主从复制的性能问题,为了主从复制的速度和连接的稳定性,Slave和Master最好在同一个局域网内
5).redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略(回收策略)。redis 提供 6种数据淘汰策略:
volatile-lru:从已设置过期时间的数据集(server.db[i].expires)中挑选最近最少使用的数据淘汰
volatile-ttl:从已设置过期时间的数据集(server.db[i].expires)中挑选将要过期的数据淘汰
volatile-random:从已设置过期时间的数据集(server.db[i].expires)中任意选择数据淘汰
allkeys-lru:从数据集(server.db[i].dict)中挑选最近最少使用的数据淘汰
allkeys-random:从数据集(server.db[i].dict)中任意选择数据淘汰
no-enviction(驱逐):禁止驱逐数据
六、常见问题
1、redis容错机制
1)RDB:relationalDB,使用save命令将rediskey持久化到磁盘,如save 900 1 900秒后修改了1次自动执行
2)AOF:Apend only file,把redis
所执行的写命令记录到数据库状态的AOF文件中。
2、redis过期淘汰机制
1)惰性删除:使用时检查,过期删除。
2)定期删除
redis采用惰性删除+定期删除的方式。减小使用过程中cpu开销。
3、缓存问题
1)缓存穿透:热点请求中的key在redis中不存在,每次请求都去mysql中获取。可以通过添加缓存锁解决,当从缓存中没有取到数数时,添加缓存锁,使其他线程阻塞住。
2)缓存击穿:缓存和数据库都不存在。可以通过规则过滤请求,或者设置null值key,下次请求直接返回null值。
3)缓存雪崩:redis重启或大量key同时时效。所有请求都去mysql中取数。使用随机过期时间策略。