Jedis使用总结

红太狼 2024-02-17 14:42 118阅读 0赞
  1. Jedis使用总结
  2. 前段时间细节的了解了Jedis的使用,Jedisredisjava版本的客户端实现。
  3. 本文做个总结,主要分享如下内容:
  4. pipeline】【分布式的id生成器】【分布式锁【watch】【multi】】【redis分布式】
  5. 好了,一个一个来。
  6. 一、 Pipeline
  7. 官方的说明是:starts a pipeline,which is a very efficient way to send lots of command and read all the responses when you finish sending them。简单点说pipeline适用于批处理。当有大量的操作需要一次性执行的时候,可以用管道。
  8. 示例:
  9. Jedis jedis = new Jedis(String, int);
  10. Pipeline p = jedis.pipelined();
  11. p.set(key,value);//每个操作都发送请求给redis-server
  12. p.get(key,value);
  13. p.sync();//这段代码获取所有的response
  14. 这里我进行了20w次连续操作(10w读,10w写),不用pipeline耗时:187242ms,用pipeline耗时:1188ms,可见使用管道后的性能上了一个台阶。看了代码了解到,管道通过一次性写入请求,然后一次性读取响应。也就是说jedis是:request responserequest response,...;pipeline则是:request request... response response的方式。这样无需每次请求都等待server端的响应。
  15. 二、 jvmid生成器
  16. 谈到这个话题,首先要知道redis-server端是单线程来处理client端的请求的。
  17. 这样来实现一个id生成器就非常简单了,只要简单的调用jdeis.incr(key);就搞定了。
  18. 你或许会问,incr是原子操作吗,能保证不会出现并发问题吗,不是说了吗,server端是单线程处理请求的。
  19. 三、 【跨jvm的锁实现【watch】【multi】】
  20. 首先说下这个问题的使用场景,有些时候我们业务逻辑是在不同的jvm进程甚至是不同的物理机上的jvm处理的。这样如何来实现不同jvm上的同步问题呢,其实我们可以基于redis来实现一个锁。
  21. 具体事务和监听请参考文章:redis学习笔记之事务
  22. 暂时找到三种实现方式:
  23. 1. 通过jedis.setnx(key,value)实现
  24. import java.util.Random;
  25. import org.apache.commons.pool.impl.GenericObjectPool.Config;
  26. import redis.clients.jedis.Jedis;
  27. import redis.clients.jedis.JedisPool;
  28. import redis.clients.jedis.Transaction;
  29. /**
  30. * @author Teaey
  31. */
  32. public class RedisLock {
  33. //加锁标志
  34. public static final String LOCKED = "TRUE";
  35. public static final long ONE_MILLI_NANOS = 1000000L;
  36. //默认超时时间(毫秒)
  37. public static final long DEFAULT_TIME_OUT = 3000;
  38. public static JedisPool pool;
  39. public static final Random r = new Random();
  40. //锁的超时时间(秒),过期删除
  41. public static final int EXPIRE = 5 * 60;
  42. static {
  43. pool = new JedisPool(new Config(), "host", 6379);
  44. }
  45. private Jedis jedis;
  46. private String key;
  47. //锁状态标志
  48. private boolean locked = false;
  49. public RedisLock(String key) {
  50. this.key = key;
  51. this.jedis = pool.getResource();
  52. }
  53. public boolean lock(long timeout) {
  54. long nano = System.nanoTime();
  55. timeout *= ONE_MILLI_NANOS;
  56. try {
  57. while ((System.nanoTime() - nano) < timeout) {
  58. if (jedis.setnx(key, LOCKED) == 1) {
  59. jedis.expire(key, EXPIRE);
  60. locked = true;
  61. return locked;
  62. }
  63. // 短暂休眠,nano避免出现活锁
  64. Thread.sleep(3, r.nextInt(500));
  65. }
  66. } catch (Exception e) {
  67. }
  68. return false;
  69. }
  70. public boolean lock() {
  71. return lock(DEFAULT_TIME_OUT);
  72. }
  73. // 无论是否加锁成功,必须调用
  74. public void unlock() {
  75. try {
  76. if (locked)
  77. jedis.del(key);
  78. } finally {
  79. pool.returnResource(jedis);
  80. }
  81. }
  82. }
  83. 2. 通过事务(multi)实现
  84. 由于采纳第一张方法,第二种跟第三种实现只贴了关键代码,望谅解。^_^
  85. public boolean lock_2(long timeout) {
  86. long nano = System.nanoTime();
  87. timeout *= ONE_MILLI_NANOS;
  88. try {
  89. while ((System.nanoTime() - nano) < timeout) {
  90. Transaction t = jedis.multi();
  91. // 开启事务,当server端收到multi指令
  92. // 会将该client的命令放入一个队列,然后依次执行,知道收到exec指令
  93. t.getSet(key, LOCKED);
  94. t.expire(key, EXPIRE);
  95. String ret = (String) t.exec().get(0);
  96. if (ret == null || ret.equals("UNLOCK")) {
  97. return true;
  98. }
  99. // 短暂休眠,nano避免出现活锁
  100. Thread.sleep(3, r.nextInt(500));
  101. }
  102. } catch (Exception e) {
  103. }
  104. return false;
  105. }
  106. 3. 通过事务+监听实现
  107. public boolean lock_3(long timeout) {
  108. long nano = System.nanoTime();
  109. timeout *= ONE_MILLI_NANOS;
  110. try {
  111. while ((System.nanoTime() - nano) < timeout) {
  112. jedis.watch(key);
  113. // 开启watch之后,如果key的值被修改,则事务失败,exec方法返回null
  114. String value = jedis.get(key);
  115. if (value == null || value.equals("UNLOCK")) {
  116. Transaction t = jedis.multi();
  117. t.setex(key, EXPIRE, LOCKED);
  118. if (t.exec() != null) {
  119. return true;
  120. }
  121. }
  122. jedis.unwatch();
  123. // 短暂休眠,nano避免出现活锁
  124. Thread.sleep(3, r.nextInt(500));
  125. }
  126. } catch (Exception e) {
  127. }
  128. return false;
  129. }
  130. 最终采用第一种实现,因为加锁只需发送一个请求,效率最高。
  131. 四、 redis分布式】
  132. 最后一个话题,jedis的分布式。在jedis的源码里发现了两种hash算法(MD5MURMUR Hash(默认)),也可以自己实现redis.clients.util.Hashing接口扩展。
  133. List<JedisShardInfo> hosts = new ArrayList<JedisShardInfo>();
  134. //server1
  135. JedisShardInfo host1 = new JedisShardInfo("", 6380, 2000);
  136. //server2
  137. JedisShardInfo host2 = new JedisShardInfo("", 6381, 2000);
  138. hosts.add(host1);
  139. hosts.add(host2);
  140. ShardedJedis jedis = new ShardedJedis(hosts);
  141. jedis.set("key", "");

发表评论

表情:
评论列表 (有 0 条评论,118人围观)

还没有评论,来说两句吧...

相关阅读

    相关 Jedis使用总结

    Jedis使用总结 前段时间细节的了解了Jedis的使用,Jedis是redis的java版本的客户端实现。 本文做个总结,主要分享如下内容:

    相关 jedis使用

    一、Redis Client介绍 1.1、简介 Jedis Client是Redis官网推荐的一个面向java客户端,库文件实现了对各类API进行封装调用。 Jedis源

    相关 Jedis使用示例

      Jedis 是 Redis 官方首选的 Java 客户端开发包。 工作过程总结的一个示例,贴出来,如下: Java代码   ![收藏代码][icon_star.png