1)性能好:采用缓存性能会比数据库好很多。
2)可扩展:采用缓存可以很容易扩展,能够通过增加节点来扩展容量和性能,这在解决大流量,高并发的网站性能时是非常关键的。
3)丰富的存储结构:如果只有以上两点,那么跟memcached也没什么区别,相比memcached,redis可以存储MAP,SET,LIST等集合类型,在处理复杂数据时,能够提升性能。
4)可持久化:redis提供了两种持久化机制 AOP和RDB。
5)主备:支持1个master n个slave的模式,同步性能非常好。
6)集群:在redis3.x版本中,已经全面支持集群功能。当master失效之后,Sentinel会自动从slave中选举一个成为master。
7)客户端工具支持:有良好的客户端工具,可以实时查看缓存中的数据,检测缓存的运行情况。
二、redis安装篇
1)windows版
下载地址: https://github.com/MSOpenTech/redis/releases/download/win-2.8.2104/Redis-x64-2.8.2104.zip
下载解压就可以了。
服务端启动命令: redis-server.exe redis.windows.conf
客户端链接命令: redis-cli.exe -h localhost -p 6379
2)linux版
下载地址: http://download.redis.io/releases/redis-3.0.4.tar.gz
(1)下载后解压 tar -xvf redis-3.0.4.tar.gz
(2)然后切换到src目录(redis-3.0.4/src),输入命令:make && makeinstall
如果报错 error: jemalloc/jemalloc.h: No such file or directory
解决方法 make MALLOC=libc
(3)新建一个目录bin作为运行目录,在编译完之后,将当前目录的redis.conf和子目录src中的redis-server, redis-cli拷贝到bin中。
(4)修改权限,chmod 777 redis*
(5)服务端启动命令:./redis-server ./redis.conf
客户端链接命令:./redis-cli -h localhost -p 6379
当然也可以使用windows的客户端连接。
三、redis开发篇
1)客户端采用jedis是个不错的选择。最新版2.7.2兼容redis 2.x 和 3.x。
jedis下载地址:https://codeload.github.com/xetorthio/jedis/zip/jedis-2.7.2
2) redis的命令基本上分几大类: 字符串处理类,MAP处理类,SET处理类,LIST处理类等。命令参考文档: http://redisdoc.com/。
这些命令既可以在客户端中运行,也对应jedis的API方法,对,就这么好用。
说这么多,给点示例吧.
package cn.gov.zjport.learning.redis.redis; import java.util.HashMap; import java.util.Map; import org.junit.Before; import org.junit.Test; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; /** * @author: zhenggm */ public class RedisDemo { private static final int DEFAULT_PORT=6379; private static final int DEFAULT_TIMEOUT=2000; JedisPool pool; Jedis jedis; @Before public void setUp() { pool = new JedisPool(new JedisPoolConfig(), "localhost", DEFAULT_PORT, DEFAULT_TIMEOUT, "123456");//new JedisPool(new JedisPoolConfig(), "localhost"); jedis = pool.getResource(); } /** * Redis存储初级的字符串 * CRUD */ @Test public void testString(){ //-----添加数据---------- //向key-->name中放入了value-->zhenggm jedis.set("name","zhenggm"); //执行结果:zhenggm System.out.println(jedis.get("name")); //-----修改数据---------- //将key-->name的value改为zhangsan jedis.set("name","zhangsan"); //执行结果:zhangsan System.out.println(jedis.get("name")); //-----删除数据---------- //删除key对应的记录 jedis.del("name"); //执行结果:null System.out.println(jedis.get("name")); /** * mset(multi set) 相当于 * jedis.set("name","zhenggm"); * jedis.set("company","zjport.gov.cn"); */ jedis.mset("name","zhenggm","company","zjport.gov.cn"); /** * mget(multi get) * 执行结果: [zhenggm, zjport.gov.cn] */ System.out.println(jedis.mget("name","company")); } /** * jedis操作Map */ //@Test public void testMap(){ Mapuser=new HashMap (); user.put("name","zhenggm"); user.put("company","zjport.gov.cn"); //将map集合保存到缓存中 jedis.hmset("user",user); //获取user的name字段 System.out.println(jedis.hmget("user", "name")); //获取user的全部字段 System.out.println(jedis.hgetAll("user")); //删除用户 jedis.del("user"); } /** * jedis操作List */ //@Test public void testList(){ //先向缓存中插入数据 jedis.lpush("lname","zhangsan"); jedis.lpush("lname","lisi"); jedis.lpush("lname","wangwu"); //再取出所有数据jedis.lrange是按范围取出, // 第一个是key,第二个是起始位置,第三个是结束位置,jedis.llen获取长度 -1表示取得所有 System.out.println(jedis.lrange("lname",0,-1)); //删除list jedis.del("lname"); } /** * jedis操作Set */ //@Test public void testSet(){ jedis.sadd("sname","zhangsan"); jedis.sadd("sname","lisi"); jedis.sadd("sname","wangwu"); System.out.println(jedis.smembers("sname"));//获取所有加入的value //删除某一个 jedis.srem("sname", "lisi"); //删除整个set jedis.del("sname"); //批量添加 jedis.sadd("sname", "zhangsan", "lisi","wangwu"); } //@Test public void test() throws InterruptedException { //返回当前库中所有的key System.out.println(jedis.keys("*")); //返回当前db的key数量 System.out.println(jedis.dbSize()); //设置"sname" 10秒后过期,过期的数据会被自动删除 jedis.expire("sname", 10); //清空当前数据库数据 jedis.flushDB(); //更改DB,1个redis server默认拥有16个DB,所有DB数据物理隔离 jedis.select(1); //清空所有DB jedis.flushAll(); jedis.select(0); jedis.sadd("sname", "zhangsan","lisi","wangwu"); //将sname从db0转移至db1 jedis.move("sname", 1); //返回当前db(db0)的key数量 System.out.println(jedis.dbSize()); //返回db1的key数量 jedis.select(1); System.out.println(jedis.dbSize()); } }
以上示例的连接池是最简单的,在实际使用中,JedisPoolConfig还有很多属性可以设置。
//控制一个pool可分配多少个jedis实例,通过pool.getResource()来获取;如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted。 private Integer maxTotal; //控制一个pool最多有多少个状态为idle(空闲)的jedis实例; private Integer maxIdle; //控制一个pool最少有多少个状态为idle(空闲)的jedis实例; private Integer minIdle; //表示当borrow一个jedis实例时,最大的等待时间,如果超过等待时间,则直接抛出JedisConnectionException; private Integer maxWaitMillis; //在获取连接的时候检查有效性 private Boolean testOnBorrow;
四、redis维护篇
主要涉及redis.conf的设置
1)设置redis server的访问密码为123456: requirepass "123456"
2)建议同时开启rdb和aop的持久化策略,rdb由于每次save都需要全量持久化,因此建议不要频繁持久化,导致性能问题。aop由于每次是增量写日志,因此可以比较频繁的写出,但是文件比较大,且相对容易坏,建议每秒写一次。
3)默认是不开启aop持久化的,如果要开启,需要将appendonly 改为yes.
4)maxmemory不要大于系统内存,且要比预估的业务最大容量大一些,因为redis有一部分空间是需要用作同步或者写入磁盘的预留。设置了maxmemory,当业务量超过阀值时,会将设置了过期时间的key,按照最近最少使用的策略删除,如果这些key也删除了,但仍超出,redis可能会崩溃(我用的windows版本出现过)。
5)有一些重要的命令,如flushall, flushdb, 如果让人不小心执行了,那数据就丢失了,可以在配置文件中使用rename-command flushall "" ,将命令禁用。
6)主从设置特别简单,主服务器的配置与没有主从配置是一模一样。从服务器的配置也就是使用 slaveof master的地址 master的端口 即可。由于redis的主从同步是另起线程进行的,因此不影响redis-master的服务性能。值得注意的是,由于redis的主从同步是非常快的,因此主服务器如果宕机或其他误操作导致内存丢失,一定要将从服务器的主从同步关闭。否则主服务器一启动,从服务器马上也会同步,导致内存丢失。关闭命令 slaveof no one
7)如果master设置了密码, 那么还需要设置 masterauth "123456"。
8)后台运行 daemonize yes
9)记录日志 logfile "redis.log"
10)如果主服务器宕机,可以不用停服务修改redis配置。使用客户端工具连上之后,使用config get命令可以看到配置文件中的每个配置项。使用config set命令设置其中的配置项。修改之后,记得使用config rewrite命令,将修改的内容同步到物理配置文件中,这样重启之后,配置也不会丢失。
11)info命令可以看缓存的实时状态。
12)monitor命令可以监控缓存的实时运行命令。
13)如果要关闭server,不要直接kill或者在windows中关闭server窗口,这样会造成还未持久化的数据丢失。可以使用客户端连上之后,敲命令 shutdown.
14)查看哪些客户端连着, client list
15) 慢查询统计
CONFIG SET slowlog-log-slower-than 10000 设置记录操作10000us的慢操作
CONFIG SET slowlog-max-len 128 最大记录128条慢操作日志
SLOWLOG LEN 统计当前记录了多少条慢操作日志
SLOWLOG RESET 重设置慢操作日志
SLOWLOG GET 100 获取前100条慢操作日志

返回值每个条目由4个字段构成:
(1)用于表示该条slow log的唯一id
(2)以unix时间戳表示的日志记录时间
(3)命令执行时间,单位:微秒
(4)执行的具体命令
16) 服务器命令统计
info commandstats 可以查看服务器命令的执行数,执行总时间,命令平均时间
CONFIG RESETSTAT 重置统计结果
五、常见问题
1、提示 "ERROR: 磁盘空间不足"
原因:可能客户端连接数超出了redis服务器设置最大连接数,默认最大连接数1w.