最近阅读了Redis6.2源码,添加了一些注释,感兴趣的同学可以看下。
https://github.com/neohope/NeoRedisSrc
Category Archives: Redis
Redis与Tomcat集群集成
在网站访问量急剧上升时,通常需要使用集群的方法进行横向扩展。
对于没有状态的应用来说,直接用nginx进行处理即可。
但对于有状态的应用来说,比如登录状态等,除了使用nginx进行扩展外,就需要考虑到Session共享的问题了。
大家知道可以用apache+tomcat来实现Session共享,但效率太低了,而且容易出错。
今天说的主要是用nginx+tomcat+redis+tomcat-redis-session-manager的方式实现共享。
原理比较简单:
1、tomcat-redis-session-manage扩展了 org.apache.catalina.valves.ValveBase; org.apache.catalina.session.ManagerBase; org.apache.catalina.session.StandardSession; 并通过Tomcat配置,替代了这几个类。 2、Set属性时,用session id作为key,将Tomcat的整个Session拆分为SessionSerializationMetadata+RedisSession然后序列化为byte[],存放到Redis。 3、Get属性时,用session id作为key,从Redis获取byte[],然后反序列化为SessionSerializationMetadata+RedisSession,供Tomcat使用。
配置也很简单:
1、从github下载源码tomcat-redis-session-manager
2、用gradle进行编译
#master分支下面,要把signing段和uploadArchives段删掉,才能正常编译 #release就不需要了 gradle build
3、将三个Jar包拷贝到Tomcat的lib文件夹下
#%TOMCAT_HOME%/lib tomcat-redis-session-manager-master-2.0.0.jar commons-pool2-2.2.jar jedis-2.5.2.jar
4、修改context.xml配置文件,新增下面内容就搞定咯
<!--%TOMCAT_HOME%/conf/context.xml--> <Valve className="com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" /> <Manager className="com.orangefunction.tomcat.redissessions.RedisSessionManager" host="localhost" port="6379" database="0" maxInactiveInterval="60"/>
好处是:不需要修改应用
坏处是:要耗费一定的时间来(序列化+保存到Redis)、(反序列化+从Redis读取)。
Redis分片(Jedis)
Redis的分片技术一般是通过客户端或代理来实现的
1、用jedis实现分片的时候,服务端不需要做任何配置即可
package com.djhu.redis.test; import java.util.ArrayList; import java.util.List; import redis.clients.jedis.JedisShardInfo; import redis.clients.jedis.ShardedJedis; public class JedisShardTest { public static void main(String[] args) { List<JedisShardInfo> jedisShardInfoList = new ArrayList<JedisShardInfo>(); jedisShardInfoList.add(new JedisShardInfo("172.16.172.4", 6379)); jedisShardInfoList.add(new JedisShardInfo("172.16.172.4", 6380)); ShardedJedis sharded = new ShardedJedis(jedisShardInfoList); sharded.set("key01", "a"); sharded.set("key02", "b"); sharded.set("key03", "c"); sharded.set("key04", "d"); sharded.set("key05", "e"); System.out.println(sharded.get("key03")); } }
2、用Jedis连接池实现分片
package com.djhu.redis.test; import java.util.ArrayList; import java.util.List; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisShardInfo; import redis.clients.jedis.ShardedJedis; import redis.clients.jedis.ShardedJedisPool; import redis.clients.jedis.JedisPoolConfig; import redis.clients.util.Hashing; import redis.clients.util.Sharded; public class JedisSharedFactory { // 最大可用连接数,默认值为8,如果赋值为-1则表示不限制 private static int MAX_TOTAL = 256; // 最大空闲连接数,默认值为8 private static int MAX_IDLE = 32; // 最小空闲连接数 private static int MIN_IDLE = 4; // 最大等待连接毫秒数,默认值为-1表示永不超时 private static int MAX_WAIT = 3000; // 连接redis超时时间 private static int TIMEOUT = 3000; // true表示验证连接 private static boolean TEST_ON_BORROW = true; //连接池 private static ShardedJedisPool jedisPool = null; public static void initJedisPool() { try { JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(MAX_TOTAL); config.setMaxIdle(MAX_IDLE); config.setMinIdle(MIN_IDLE); config.setMaxWaitMillis(MAX_WAIT); config.setTestOnBorrow(TEST_ON_BORROW); List<JedisShardInfo> jedisShardInfoList = new ArrayList<JedisShardInfo>(); jedisShardInfoList.add(new JedisShardInfo("172.16.172.4", 6379)); jedisShardInfoList.add(new JedisShardInfo("172.16.172.4", 6380)); jedisPool = new ShardedJedisPool(config, jedisShardInfoList,Hashing.MURMUR_HASH,Sharded.DEFAULT_KEY_TAG_PATTERN); } catch (Exception e) { e.printStackTrace(); } } public synchronized static ShardedJedis getConnection() { try { if (jedisPool != null) { ShardedJedis resource = jedisPool.getResource(); return resource; } else { return null; } } catch (Exception e) { e.printStackTrace(); return null; } } public static void returnResource(final ShardedJedis jedis) { if (jedis != null) { jedis.close(); } } public static void main(String[] args) { initJedisPool(); ShardedJedis redis = getConnection(); redis.set("key10", "j"); redis.set("key11", "k"); redis.set("key12", "l"); redis.set("key13", "m"); redis.set("key14", "n"); System.out.print(redis.get("key12")); returnResource(redis); } }
Jedis连接Redis3 Cluster
1、源码如下
package com.djhu.redis.test; import java.util.Set; import java.util.HashSet; import redis.clients.jedis.HostAndPort; import redis.clients.jedis.JedisCluster; public class JedisClusterTest { public static void main(String[] args) { Set<HostAndPort> jedisClusterNodes = new HashSet<HostAndPort>(); jedisClusterNodes.add(new HostAndPort("172.16.172.4", 6379)); jedisClusterNodes.add(new HostAndPort("172.16.172.4", 6380)); jedisClusterNodes.add(new HostAndPort("172.16.172.4", 6381)); jedisClusterNodes.add(new HostAndPort("172.16.172.4", 6382)); jedisClusterNodes.add(new HostAndPort("172.16.172.4", 6383)); jedisClusterNodes.add(new HostAndPort("172.16.172.4", 7384)); //JedisCluster cluster = new JedisCluster(jedisClusterNodes,3000,1000); JedisCluster cluster = new JedisCluster(jedisClusterNodes); cluster.set("key10", "j"); cluster.set("key11", "k"); cluster.set("key12", "l"); cluster.set("key13", "m"); cluster.set("key14", "n"); System.out.println(cluster.get("key12")); } }
2、如果遇到下面错误,主要是因为建立cluster时,ip用了127.0.0.1。用其他ip重建一下cluster,就可以解决了。
Exception in thread "main" redis.clients.jedis.exceptions.JedisClusterMaxRedirectionsException: Too many Cluster redirections? at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:34) at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:68) at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:85) at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:68) at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:85) at redis.clients.jedis.JedisClusterCommand.runWithRetries(JedisClusterCommand.java:68) at redis.clients.jedis.JedisClusterCommand.run(JedisClusterCommand.java:29) at redis.clients.jedis.JedisCluster.set(JedisCluster.java:75)
Redis3重建Cluster
1、关闭cluster全部节点
2、删除所有nodes.conf文件
3、开启全部节点
4、依次flushall
5、重建集群即可
Redis3配置Cluster
1、redis3的cluster是基于ruby的,所以要安装好ruby,然后安装redis的gem
gem install redis
2、然后配置6份redis,修改配置如下
节点 | ||||||
dbm6379 | dbm6380 | dbm6381 | dbs6382 | dbm6383 | dbm6384 | |
配置文件 | dbm6379/conf/redis.conf | dbm6380/conf/redis.conf | dbm6381/conf/redis.conf | dbs6382/conf/redis.conf | dbm6383/conf/redis.conf | dbm6384/conf/redis.conf |
port | 6379 | 6380 | 6381 | 6382 | 6383 | 6384 |
logfile | “/home/neohope/DB/redis-3.0.4/cluster/dbm6379/logs/redis_log.log” | “/home/neohope/DB/redis-3.0.4/cluster/dbm6380/logs/redis_log.log” | “/home/neohope/DB/redis-3.0.4/cluster/dbm6381/logs/redis_log.log” | “/home/neohope/DB/redis-3.0.4/cluster/dbm6382/logs/redis_log.log” | “/home/neohope/DB/redis-3.0.4/cluster/dbm6383/logs/redis_log.log” | “/home/neohope/DB/redis-3.0.4/cluster/dbm6384/logs/redis_log.log” |
dir | “/home/neohope/DB/redis-3.0.4/cluster/dbm6379/data” | “/home/neohope/DB/redis-3.0.4/cluster/dbm6380/data” | “/home/neohope/DB/redis-3.0.4/cluster/dbm6381/data” | “/home/neohope/DB/redis-3.0.4/cluster/dbm6382/data” | “/home/neohope/DB/redis-3.0.4/cluster/dbm6383/data” | “/home/neohope/DB/redis-3.0.4/cluster/dbm6384/data” |
cluster-enabled | yes | yes | yes | yes | yes | yes |
cluster-config-file | nodes-6379.conf | nodes-6380.conf | nodes-6381.conf | nodes-6382.conf | nodes-6383.conf | nodes-6384.conf |
cluster-node-timeout | 15000 | 15000 | 15000 | 15000 | 15000 | 15000 |
cluster-migration-barrier | 1 | 1 | 1 | 1 | 1 | 1 |
cluster-require-full-coverage | yes | yes | yes | yes | yes | yes |
3、启动redis
#!/bin/sh ~/DB/redis-3.0.4/bin/redis-server ~/DB/redis-3.0.4/cluster/dbm6379/conf/redis.conf & echo $! & ~/DB/redis-3.0.4/bin/redis-server ~/DB/redis-3.0.4/cluster/dbm6380/conf/redis.conf & echo $! & ~/DB/redis-3.0.4/bin/redis-server ~/DB/redis-3.0.4/cluster/dbm6381/conf/redis.conf & echo $! & ~/DB/redis-3.0.4/bin/redis-server ~/DB/redis-3.0.4/cluster/dbs6382/conf/redis.conf & echo $! & ~/DB/redis-3.0.4/bin/redis-server ~/DB/redis-3.0.4/cluster/dbs6383/conf/redis.conf & echo $! & ~/DB/redis-3.0.4/bin/redis-server ~/DB/redis-3.0.4/cluster/dbs6384/conf/redis.conf & echo $!
4、配置cluster
#!/bin/sh #这里最好不要用127.0.0.1做地址 ~/DB/redis-3.0.4/bin/redis-trib.rb create --replicas 1 127.0.0.1:6379 127.0.0.1:6380 127.0.0.1:6381 127.0.0.1:6382 127.0.0.1:6383 127.0.0.1:6384
5、测试redis cluster
~/DB/redis-3.0.4/bin/redis-cli -c -p 6379 set key01 a set key02 b set key03 c set key04 d dbsize keys * get key03
6、关闭redis
#!/bin/sh ~/DB/redis-3.0.4/bin/redis-cli -p 6379 shutdown ~/DB/redis-3.0.4/bin/redis-cli -p 6380 shutdown ~/DB/redis-3.0.4/bin/redis-cli -p 6381 shutdown ~/DB/redis-3.0.4/bin/redis-cli -p 6382 shutdown ~/DB/redis-3.0.4/bin/redis-cli -p 6383 shutdown ~/DB/redis-3.0.4/bin/redis-cli -p 6384 shutdown
Redis主从数据库(Shell)
1、基本配置如下
数据库 | master | slave01 | slave02 |
配置文件 | redis.master.conf | redis.slave01.conf | redis.slave02.conf |
ip地址 | localhost | localhost | localhost |
端口 | 6379 | 6380 | 6381 |
logfile | “D:/Database/Redis2.8/mirror/master/logs/redis_log.txt” | “D:/Database/Redis2.8/mirror/slave01/logs/redis_log.txt” | “D:/Database/Redis2.8/mirror/slave02/logs/redis_log.txt” |
dir | “D:/Database/Redis2.8/mirror/master/data/” | “D:/Database/Redis2.8/mirror/slave01/data/” | “D:/Database/Redis2.8/mirror/slave02/data/” |
slaveof | – | localhost 6379 | localhost 6379 |
slave-serve-stale-data | – | yes | yes |
slave-read-only | – | yes | yes |
slave-priority | – | 100 | 100 |
maxheap | – | 1073741824 | 1073741824 |
heapdir | – | D:\Database\Redis2.8\mirror\slave01\heap | D:\Database\Redis2.8\mirror\slave02\heap |
2、启动
redis-server.exe D:\Database\Redis2.8\mirror\redis.master.conf redis-server.exe D:\Database\Redis2.8\mirror\redis.slave01.conf redis-server.exe D:\Database\Redis2.8\mirror\redis.slave02.conf
3、测试
D:\Database\Redis2.8>redis-cli 127.0.0.1:6379> dbsize (integer) 0 127.0.0.1:6379> set key01 a OK 127.0.0.1:6379> exit D:\Database\Redis2.8>redis-cli -p 6380 127.0.0.1:6380> get key01 "a" 127.0.0.1:6380> set key02 b (error) READONLY You can't write against a read only slave. 127.0.0.1:6380> exit D:\Database\Redis2.8>redis-cli -p 6381 127.0.0.1:6381> get key01 "a" 127.0.0.1:6381> set key02 b (error) READONLY You can't write against a read only slave. 127.0.0.1:6381> exit
4、关闭
redis-cli -p 6380 shutdown redis-cli -p 6381 shutdown redis-cli -p 6379 shutdown
redis-server注册为服务(Shell)
1、注册服务
#loglevel 分为debug, notice, warning三级 redis-server.exe --service-install D:\Database\Redis2.8\db\redis.windows.conf --loglevel notice
2、启动服务
redis-server --service-start
3、停止服务
redis-server --service-stop
4、卸载服务
redis-server --service-uninstall
Jedis使用连接池(Java)
package com.djhu.redis.test; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; public class JedisFactory { // 最大可用连接数,默认值为8,如果赋值为-1则表示不限制 private static int MAX_TOTAL = 256; // 最大空闲连接数,默认值为8 private static int MAX_IDLE = 32; // 最小空闲连接数 private static int MIN_IDLE = 4; // 最大等待连接毫秒数,默认值为-1表示永不超时 private static int MAX_WAIT = 3000; // 连接redis超时时间 private static int TIMEOUT = 3000; // true表示验证连接 private static boolean TEST_ON_BORROW = true; //连接池 private static JedisPool jedisPool = null; public static void initJedisPool(String IP, int port, String password) { try { JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(MAX_TOTAL); config.setMaxIdle(MAX_IDLE); config.setMinIdle(MIN_IDLE); config.setMaxWaitMillis(MAX_WAIT); config.setTestOnBorrow(TEST_ON_BORROW); jedisPool = new JedisPool(config, IP, port, TIMEOUT, password); } catch (Exception e) { e.printStackTrace(); } } public synchronized static Jedis getConnection() { try { if (jedisPool != null) { Jedis resource = jedisPool.getResource(); return resource; } else { return null; } } catch (Exception e) { e.printStackTrace(); return null; } } public static void returnResource(final Jedis jedis) { if (jedis != null) { jedis.close(); } } public static void main(String[] args) { initJedisPool("localhost",6379,null); Jedis redis = getConnection(); redis.select(1); //redis.set("key01", "a"); //redis.set("key02", "b"); //redis.set("key03", "c"); System.out.print(redis.dbSize()); returnResource(redis); } }
Redis入门之增删改查(Java)
1、下载驱动
jedis驱动源码地址
jedis驱动下载地址
2、测试代码
package com.djhu.redis.test; import java.util.HashMap; import java.util.List; import java.util.Map; import redis.clients.jedis.Jedis; public class ConnectionTest { public static Jedis getConnection(String ip, int port) { Jedis jedis = new Jedis(ip, port); //jedis.auth("password"); return jedis; } public static void cleanAll(Jedis jedis) { jedis.flushDB(); } public static void stringTest(Jedis jedis) { jedis.set("key01", "a"); jedis.set("key02", "b"); jedis.set("key03", "c"); jedis.mset("key04", "d", "key05", "e", "key06", "f"); jedis.del("key04"); System.out.println("key01 is " + jedis.get("key01")); System.out.println("key04 is " + jedis.get("key04")); } public static void mapTest(Jedis jedis) { Map<String, String> map = new HashMap<String, String>(); map.put("username", "hansen"); map.put("usersex", "male"); jedis.hmset("mapkey01", map); map.put("username", "neohope"); map.put("usersex", "male"); jedis.hmset("mapkey02", map); map.put("username", "tuzi"); map.put("usersex", "female"); jedis.hmset("mapkey03", map); List<String> rsmap = jedis.hmget("mapkey03", "username", "usersex"); System.out.println("query for hmget(\"mapkey03\", \"username\", \"usersex\") is " + rsmap); jedis.hdel("mapkey02", "usersex"); System.out.println("query for hmget jedis.hmget(\"mapkey02\", \"username\") is "+jedis.hmget("mapkey02", "username")); System.out.println("query for jedis.hmget(\"mapkey02\", \"usersex\") is " + jedis.hmget("mapkey02", "usersex")); System.out.println("query for jedis.hlen(\"mapkey01\") is " + jedis.hlen("mapkey01")); System.out.println("query for jedis.exists(\"mapkey01\") is " + jedis.exists("mapkey01")); System.out.println("query for jedis.hkeys(\"mapkey01\") is " + jedis.hkeys("mapkey01")); System.out.println("query for jedis.hvals(\"mapkey01\") is " + jedis.hvals("mapkey01")); } public static void listTest(Jedis jedis) { jedis.lpush("keylist01", "a"); jedis.lpush("keylist01", "b"); jedis.lpush("keylist01", "c"); System.out.println("keylist01 is " + jedis.lrange("keylist01", 0, -1)); } public static void setTest(Jedis jedis) { jedis.sadd("keyset01", "01"); jedis.sadd("keyset01", "02"); jedis.sadd("keyset01", "03"); jedis.sadd("keyset01", "04"); jedis.sadd("keyset01", "05"); System.out.println("query for jedis.smembers(\"keyset01\") is " + jedis.smembers("keyset01")); System.out.println("query for jedis.sismember(\"keyset01\", \"06\") is " + jedis.sismember("keyset01", "06")); System.out.println("query for jedis.scard(\"keyset01\") is " + jedis.scard("keyset01")); } public static void sortTest(Jedis jedis) { jedis.rpush("keylist02", "16"); jedis.lpush("keylist02", "8"); jedis.lpush("keylist02", "4"); jedis.lpush("keylist02", "2"); jedis.lpush("keylist02", "1"); System.out.println("keylist02 is " + jedis.lrange("keylist02", 0, -1)); jedis.sort("keylist02"); System.out.println("after sort keylist02 is " + jedis.lrange("keylist02", 0, -1)); } public static void main(String[] args) { Jedis jedis = getConnection("localhost", 6379); cleanAll(jedis); stringTest(jedis); mapTest(jedis); listTest(jedis); sortTest(jedis); setTest(jedis); jedis.close(); } }