zoukankan      html  css  js  c++  java
  • Redis Java客户端之Jedis

    依赖项:

    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>2.9.0</version>
    </dependency>

    一、 jedis对应redis的四种工作模式

    Jedis,JedisCluster,JedisSentinel和ShardedJedis对应了Redis的四种工作模式:Redis Standalone(单节点模式),Redis Cluster(集群模式),Redis Sentinel(哨兵模式)和Redis Sharding(分片模式)。

    二、jedis的三种请求模式

    每个jedis实例对应一个Redis节点,我们对jedis实例的每个操作,都相当于redis-cli启动客户端的直接操作,无论是集群模式,哨兵模式,还是分片模式,内部均为对Jedis实例的操作。
    Jedis实例有3种请求模式,Pipeline,Transaction和Client。 

    jedis实例通过Socket建立客户端与服务端的长连接,往outputStream发送命令,从inputStream读取回复。

    Client模式就是常用的所见即所得,客户端发送一个命令,阻塞等待服务端执行,然后读取返回结果。

    Pipeline模式是一次性发送多个命令,最后一次取回所有的返回结果,这种模式通过减少网络的往返时间和io读写次数,大幅度提高通信性能,但pipeline不支持原子性,要想保证原子性,可同时开启事物模式。

    Transaction模式即开启Redis的事务管理,事务模式开启后,所有的命令(除了exec,discard,multi和watch)到达服务端以后不会立即执行,会进入一个等待队列,等待收到下述四个命令时执行不同操作:
    • EXEC命令执行时,服务器以先进先出FIFO的方式执行事务队列中的命令,当事务队列的所有命令被执行完之后,将回复队列作为自己的执行结果返回给客户端,客户端从事务状态返回到非事务状态。
    • DISCARD命令用于取消一个事务,它清空客户端的整个事务队列,然后将客户端从事务状态调整到非事务状态。最后返回字符串 OK 给客户端, 说明事务已被取消。
    • Redis 的事务是不可嵌套的, 当客户端已经处于事务状态, 而客户端又再向服务器发送MULTI时, 服务器只是简单地向客户端发送一个错误, 然后继续等待其他命令的入队。 MULTI命令的发送不会造成整个事务失败, 也不会修改事务队列中已有的数据。
    • WATCH只能在客户端进入事务状态之前执行, 在事务状态下发送 WATCH命令会引发一个错误, 但它不会造成整个事务失败, 也不会修改事务队列中已有的数据(和前面处理 MULTI的情况一样)。
    jedis以输入的命令参数是否为二进制,将处理请求的具体实现部署在两个类中,Jedis和BinaryJedis, Client和BinaryClient。与Redis服务器的连接信息(Socket,host, port)封装在Client的基类Connection中,BinaryJedis类中提供了Client,Pipeline和Transaction变量,对应三种请求模式。

    三、Jedis的初始化流程

    Jedis jedis = new Jedis("localhost", 6379, 15000);
    Transaction t = jedis.multi();
    Pipeline pipeline = jedis.pipelined();
    ​Jedis通过传入Redis服务器地址(host,port)开始初始化,然后在BinaryJedis里实例化Client。Client通过Socket维持客户端与Redis服务器的连接与沟通。
    Transaction和Pipeline很相似,他们继承同一个基类MultiKeyPipelineBase。区别在于Transaction在实例化的时候,会自动发送MULTI命令,开启事务模式,而Pipeline则按情况手动开启,他们都是依靠Client发送命令,下面通过发送一个get key的命令,看看这三种模式是如何运转的。
    //BinaryJedis类
    public Transaction multi() {
        client.multi();
        transaction = new Transaction(client);
        return transaction;
    }
    public Pipeline pipelined() {
        pipeline = new Pipeline();
        pipeline.setClient(client);
        return pipeline;
    }

    四、jedis工作模式的调用流程

    Client模式的调用流程

    从上图可以看出,在每次发送命令之前,会先通过connect()方法判断是否已经连接,如果未连接则:

    • 实例化Socket,并配置。
    • 连接Socket,获取OutputStream和InputStream。
    • 如果是SSL连接,通过SSLSocketFactory创建socket连接
      • Protocol是一个通讯工具类,将Redis的各类执行关键字存储为静态变量,比如Protocol.Command.GET, 同时将命令包装成符合Redis的统一请求协议,回复消息的处理也是在这个类进行,它先通过通讯协议提取出当次请求的回复消息,将Object类型的消息转化为String,List 等具体类型,如果回复消息有Error则以异常的形式抛出。

    五、Java代码示例

    单机模式

    有两种方式:new Jedis() 和 基于JedisPool。一般是使用JedisPool,如下:

    String host = "127.0.0.1";
    int port = 6379;
    // JedisPoolConfig 继承了GenericObjectPoolConfig
    JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
    JedisPool jedisPool = new JedisPool(jedisPoolConfig, host, port);
    Jedis jedis = jedisPool.getResource();
    jedis.set("a","b");
    System.out.println(jedis.get("a"));
    分片模式

    ShardedJedisPool是redis没有集群功能之前客户端实现的一个数据分布式方案,redis3.0提供集群之后,客户端则采用JedisCluster实现连接redis集群环境。
    ShardedJedisPool使用的是JedisShardInfo的instance的顺序或者name来做的一致性哈希 。JedisCluster使用的是CRC16算法来做的哈希槽。

    GenericObjectPoolConfig config = new GenericObjectPoolConfig();
    config.setMaxIdle(32);
    config.setMinIdle(12);
    config.setTestOnBorrow(true);
    config.setTestOnReturn(true);
    config.setTestWhileIdle(true);
    // 可以一个或多个
    List<JedisShardInfo> shards = new ArrayList();
    shards.add(new JedisShardInfo("127.0.0.1", 6379, 200));
    // 构造池
    ShardedJedisPool shardedJedisPool = new ShardedJedisPool(config, shards, Hashing.MURMUR_HASH, Sharded.DEFAULT_KEY_TAG_PATTERN);
    ShardedJedis jedis = shardedJedisPool.getResource();
    jedis.set("abc", "blili");
    System.out.println(jedis.get("abc"));
    集群模式(since 3.0)
    // 集群的IP和端口
    String[] hostAndPorts = new String[]{"127.0.0.1:7000", "127.0.0.1:7001", "127.0.0.1:7002", "127.0.0.1:7003", "127.0.0.1:7004", "127.0.0.1:7005"};
    Set<HostAndPort> clusterHostAndPortSet = new HashSet();
    for (String hdp : hostAndPorts) {
        String[] arr = hdp.split(":");
        clusterHostAndPortSet.add(new HostAndPort(arr[0], Integer.parseInt(arr[1])));
    }
    // 超时时间设置为200ms
    JedisCluster cluster = new JedisCluster(clusterHostAndPortSet, 200);
    cluster.set("cluster", "jedis cluster");
    System.out.println(cluster.get("cluster"));
    哨兵模式
    //1.设置sentinel 各个节点集合, 可以有多个哨兵
    Set<String> sentinelSet = new HashSet<>();
    sentinelSet.add("127.0.0.1:26379");
    
    //2.设置jedispool 连接池配置文件
    JedisPoolConfig config = new JedisPoolConfig();
    config.setMaxTotal(10);
    config.setMaxWaitMillis(1000);
    
    //3.设置mastername,sentinelNode集合,配置文件等
    JedisSentinelPool jedisSentinelPool = new JedisSentinelPool("mymaster", sentinelSet, config);
    Jedis jedis = null;
    try {
        jedis = jedisSentinelPool.getResource();
        jedis.set("hello", "kiki");
        //获取Redis中key=hello的值
        String value = jedis.get("hello");
        System.out.println(value);
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        if (jedis != null) {
            jedis.close();
        }
    }

    参考:

    https://www.jianshu.com/p/6e8af34219c9

    时刻与技术进步,每天一点滴,日久一大步!!! 本博客只为记录,用于学习,如有冒犯,请私信于我。
  • 相关阅读:
    使用layui报错:Uncaught TypeError: Cannot create property 'LAY_TABLE_INDEX' on number '2
    mongodb安装教程
    PDF,Word,Markdown,HTML ,Doc文件格式的相互转换
    Go To Oracle
    spark、standalone集群 (2)集群zookeeper 热备
    spark、standalone集群 (1)
    tomcat8.0部署启动
    mysql5.7以上安装
    spark单击 搭建
    自定义标签
  • 原文地址:https://www.cnblogs.com/myitnews/p/13721489.html
Copyright © 2011-2022 走看看