本章要点
- 发布与订阅
- 地理环境GEO
- 基数
- 分布式锁(推荐zk)
- Redis为什么快
1. 发布订阅
发布订阅命令主要包括:publish、subscribe、unsubscribe、psubscribe(正则匹配订阅)、punsubscribe(正则匹配取消订阅)等命令组成。
jedis代码如下:
2.GEO
redis在3.2版本以后新增了对GEO对支持,主要包括命令:geoadd、geodist、geohash、geopos、georadius、georadiusbymember等。
jedis代码:
public static Long geoadd(String key, double longitude, double latitude, final String member){
return redis.geoadd(key, longitude,latitude, member);
}
public static List<GeoCoordinate> geopos(String key, String... members){
return redis.geopos(key, members);
}
public static Double geodist( String key, String member1, String member2,GeoUnit unit){
return redis.geodist(key, member1, member2, unit);
}
public static List<GeoRadiusResponse> georadius(String key, double longitude, double latitude,
double radius, GeoUnit unit){
return redis.georadius(key, longitude, latitude, radius, unit);
}
public static List<GeoRadiusResponse> georadius(String key, double longitude, double latitude,
double radius, GeoUnit unit,GeoRadiusParam param){
return redis.georadius(key, longitude, latitude, radius, unit, param);
}
3.基数(HyperLogLog)
redis 在 2.8.9 版本添加了 HyperLogLog 结构,用来做基数统计的算法。主要包括“pfadd、pdcount、pfmerge等命令。
jedis代码:
public static Long pfadd(String key,String elements){
return redis.pfadd(key, elements);
}
public static Long pfcount(String key){
return redis.pfcount(key);
}
public static String pfmerge(String destkey, String... sourcekeys){
return redis.pfmerge(destkey, sourcekeys);
}
4.Redis分布式锁(Redlock)
- 分布式锁特性:
1)在分布式系统环境下,一个方法在同一时间只能被一个机器的的一个线程执行;
2)高可用的获取锁与释放锁;
3)高性能的获取锁与释放锁;
4)具备可重入特性;
5)具备锁失效机制,防止死锁;
6)具备非阻塞锁特性,即没有获取到锁将直接返回获取锁失败
public class RedisLock {
public static boolean lock(Jedis jedis, String lockKey, String requestId, int expireTime) {
String result = jedis.set(lockKey, requestId, "NX", "PX", expireTime);
if ("OK".equals(result)) {
return true;
}
return false;
}
public static boolean unlock(Jedis jedis, String lockKey, String requestId) {
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 ("1".equals(result)) {
return true;
}
return false;
}
}
- redis分布式锁,其实需要自己不断去尝试获取锁,比较消耗性能
- zk分布式锁,获取不到锁,注册个监听器即可,不需要不断主动尝试获取锁,性能开销较小
- 如果是redis获取锁的那个客户端bug了或者挂了,那么只能等待key过期之后才能释放锁;而zk的话,因为创建的是临时znode,只要客户端挂了,znode就没了,此时就自动释放锁
5. redis为什么快
1、协议简单,RESP是纯字符串,解析简单
2、完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1);
3、数据结构简单,对数据操作也简单,Redis中的数据结构是专门进行设计的;
4、采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗;
5、使用多路I/O复用模型,非阻塞IO;
6、Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求;