关键词搜索

源码搜索 ×
×

Jedis相关操作总结

发布2017-03-07浏览940次

详情内容

文章虽已久,况味尝自知。原文来自:http://www.cnblogs.com/olinux/p/5179174.html

Jedis 是 Redis 官方首选的 Java 客户端开发包。

OSchina Jedis API:http://tool.oschina.net/apidocs/apidoc?api=jedis-2.1.0

Github:https://github.com/xetorthio/jedis

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

【分布式的id生成器】

【分布式锁【watch】【multi】】

【redis分布式】

Pipeline

官方的说明是: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适用于批处理。当有大量的操作需要一次性执行的时候,可以用管道。
示例:

  1. Jedis jedis = new Jedis(String, int);
  2. Pipeline p = jedis.pipelined();
  3. p.set(key,value);//每个操作都发送请求给redis-server
  4. p.get(key,value);
  5. p.sync();//这段代码获取所有的response

这里我进行了20w次连续操作(10w读,10w写),不用pipeline耗时:187242ms,用pipeline耗时:1188ms,可见使用管道后的性能上了一个台阶。看了代码了解到,管道通过一次性写入请求,然后一次性读取响应。也就是说jedis是:request response,request response,...;pipeline则是:request request... response response的方式。这样无需每次请求都等待server端的响应。

跨jvm的id生成器 

谈到这个话题,首先要知道redis-server端是单线程来处理client端的请求的。
这样来实现一个id生成器就非常简单了,只要简单的调用jdeis.incr(key);就搞定了。
你或许会问,incr是原子操作吗,能保证不会出现并发问题吗,前面说过,server端是单线程处理请求的。

跨jvm的锁实现【watch】【multi】】

首先说下这个问题的使用场景,有些时候我们业务逻辑是在不同的jvm进程甚至是不同的物理机上的jvm处理的。这样如何来实现不同jvm上的同步问题呢,其实我们可以基于redis来实现一个锁。
具体事务和监听请参考文章:redis学习笔记之事务 暂时找到三种实现方式:
1. 通过jedis.setnx(key,value)实现

  1. import java.util.Random;
  2. import org.apache.commons.pool.impl.GenericObjectPool.Config;
  3. import redis.clients.jedis.Jedis;
  4. import redis.clients.jedis.JedisPool;
  5. import redis.clients.jedis.Transaction;
  6. /**
  7. * @author Teaey
  8. */
  9. public class RedisLock {
  10. //加锁标志
  11. public static final String LOCKED = "TRUE";
  12. public static final long ONE_MILLI_NANOS = 1000000L;
  13. //默认超时时间(毫秒)
  14. public static final long DEFAULT_TIME_OUT = 3000;
  15. public static JedisPool pool;
  16. public static final Random r = new Random();
  17. //锁的超时时间(秒),过期删除
  18. public static final int EXPIRE = 5 * 60;
  19. static {
  20. pool = new JedisPool(new Config(), "host", 6379);
  21. }
  22. private Jedis jedis;
  23. private String key;
  24. //锁状态标志
  25. private boolean locked = false;
  26. public RedisLock(String key) {
  27. this.key = key;
  28. this.jedis = pool.getResource();
  29. }
  30. public boolean lock(long timeout) {
  31. long nano = System.nanoTime();
  32. timeout *= ONE_MILLI_NANOS;
  33. try {
  34. while ((System.nanoTime() - nano) < timeout) {
  35. if (jedis.setnx(key, LOCKED) == 1) {
  36. jedis.expire(key, EXPIRE);
  37. locked = true;
  38. return locked;
  39. }
  40. // 短暂休眠,nano避免出现活锁
  41. Thread.sleep(3, r.nextInt(500));
  42. }
  43. } catch (Exception e) {
  44. }
  45. return false;
  46. }
  47. public boolean lock() {
  48. return lock(DEFAULT_TIME_OUT);
  49. }
  50. // 无论是否加锁成功,必须调用
  51. public void unlock() {
  52. try {
  53. if (locked)
  54. jedis.del(key);
  55. } finally {
  56. pool.returnResource(jedis);
  57. }
  58. }
  59. }

  2. 通过事务(multi)实现由于采纳第一张方法,第二种跟第三种实现只贴了关键代码,望谅解。^_^

  1. public boolean lock_2(long timeout) {
  2. long nano = System.nanoTime();
  3. timeout *= ONE_MILLI_NANOS;
  4. try {
  5. while ((System.nanoTime() - nano) < timeout) {
  6. Transaction t = jedis.multi();
  7. // 开启事务,当server端收到multi指令
  8. // 会将该client的命令放入一个队列,然后依次执行,知道收到exec指令
  9. t.getSet(key, LOCKED);
  10. t.expire(key, EXPIRE);
  11. String ret = (String) t.exec().get(0);
  12. if (ret == null || ret.equals("UNLOCK")) {
  13. return true;
  14. }
  15. // 短暂休眠,nano避免出现活锁
  16. Thread.sleep(3, r.nextInt(500));
  17. }
  18. } catch (Exception e) {
  19. }
  20. return false;
  21. }

3. 通过事务+监听实现

  1. public boolean lock_3(long timeout) {
  2. long nano = System.nanoTime();
  3. timeout *= ONE_MILLI_NANOS;
  4. try {
  5. while ((System.nanoTime() - nano) < timeout) {
  6. jedis.watch(key);
  7. // 开启watch之后,如果key的值被修改,则事务失败,exec方法返回null
  8. String value = jedis.get(key);
  9. if (value == null || value.equals("UNLOCK")) {
  10. Transaction t = jedis.multi();
  11. t.setex(key, EXPIRE, LOCKED);
  12. if (t.exec() != null) {
  13. return true;
  14. }
  15. }
  16. jedis.unwatch();
  17. // 短暂休眠,nano避免出现活锁
  18. Thread.sleep(3, r.nextInt(500));
  19. }
  20. } catch (Exception e) {
  21. }
  22. return false;
  23. }

    最终采用第一种实现,因为加锁只需发送一个请求,效率最高。

【redis分布式】

    最后一个话题,jedis的分布式。在jedis的源码里发现了两种hash算法(MD5,MURMUR Hash(默认)),也可以自己实现redis.clients.util.Hashing接口扩展。
   

  1. List<JedisShardInfo> hosts = new ArrayList<JedisShardInfo>();
  2. //server1
  3. JedisShardInfo host1 = new JedisShardInfo("", 6380, 2000);
  4. //server2
  5. JedisShardInfo host2 = new JedisShardInfo("", 6381, 2000);
  6. hosts.add(host1);
  7. hosts.add(host2);
  8. ShardedJedis jedis = new ShardedJedis(hosts);
  9. jedis.set("key", "");


相关技术文章

点击QQ咨询
开通会员
返回顶部
×
微信扫码支付
微信扫码支付
确定支付下载
请使用微信描二维码支付
×

提示信息

×

选择支付方式

  • 微信支付
  • 支付宝付款
确定支付下载