<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    jinfeng_wang

    G-G-S,D-D-U!

    BlogJava 首頁 新隨筆 聯系 聚合 管理
      400 Posts :: 0 Stories :: 296 Comments :: 0 Trackbacks
    https://blog.huachao.me/2016/2/%E6%B7%B1%E5%85%A5Jedis/?utm_source=tuicool&utm_medium=referral

    Redis客戶端與服務器端的通信協議是如此簡單

    RESP協議

    RESP(REdis Serialization Protocol)是redis server與redis client的通信協議。

    • TCP Port 6379
    • Request-Response模型。2個例外,1)pipeline;2)pub/sub
    • 5種DataType,Simple String(+);Errors(-);Integers(:);Bulk String($);Arrays(*)
    • \r\n(CRLF)是結束符
    • Simple String 例子:"+OK\r\n"
    • Errors 例子:-WRONGTYPE Operation against a key holding the wrong kind of value
    • Integer 例子:":1000\r\n"
    • Bulk String 例子:"$6\r\nfoobar\r\n" 6表示后面有6個byte的長度
    • Null 例子:"$-1\r\n"
    • Arrays 例子:"*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n" 2表示有2個元素; "*0\r\n"表示空數組
    • 客戶端發送命令:就是Bulk String。例子:llen mylist -> *2\r\n$4\r\nllen\r\n$6\r\nmylist\r\n
    • redis服務器回答RESP DataType。例子::48293\r\n

    Jedis對RESP協議的抽象

    Jedis類圖

    • Protocol是實現上述RESP協議的主要類,其中可以看到sendCommand(final RedisOutputStream os, final byte[] command, final byte[]... args)是如何根據協議拼接字符串發送到redis server,Object read(final RedisInputStream is)是如何接收redis server的返回,并且轉換為Java Object。
    • BinaryXxxCommands <- BinaryJedis, XxxCommands <- Jedis 用來抽象所有通過二進制流來發送的Redis命令
    • XxxCommands <- Jedis用來抽象類似ClusterCommands的命令,最終都是走的二進制流,去掉Binary一層估計是作者覺得厭煩了。不對之處還請賜教。
    • Commands, Connection <- BinaryClient <- Client抽象了網絡發送命令和接收回復,其中Client將參數encode為byte[],然后調用BinaryClient的方法;BinaryClient調用Connection#sendCommand;sendCommand調用connect(),構造RedisInputStream和RedisOutputStream,用Protocol.sendCommand來發送命令;client.getXxxReply()首先將outputstream中的內容flush出去,然后調用Protocol.read來處理接收到的返回值。

      /* 發送命令 Connection.java */
      protected Connection sendCommand(final ProtocolCommand cmd, final byte[]... args) {
      try {
      connect();
      Protocol.sendCommand(outputStream, cmd, args);
      pipelinedCommands++;
      return this;
      } catch (JedisConnectionException ex) {
      // Any other exceptions related to connection?
      broken = true;
      throw ex;
      }
      }

      public void connect() {
      if (!isConnected()) {
      try {
      socket = new Socket();
      // ->@wjw_add
      socket.setReuseAddress(true);
      socket.setKeepAlive(true); // Will monitor the TCP connection is
      // valid
      socket.setTcpNoDelay(true); // Socket buffer Whetherclosed, to
      // ensure timely delivery of data
      socket.setSoLinger(true, 0); // Control calls close () method,
      // the underlying socket is closed
      // immediately
      // <-@wjw_add

      socket.connect(new InetSocketAddress(host, port), connectionTimeout);
      socket.setSoTimeout(soTimeout);
      outputStream = new RedisOutputStream(socket.getOutputStream());
      inputStream = new RedisInputStream(socket.getInputStream());
      } catch (IOException ex) {
      broken = true;
      throw new JedisConnectionException(ex);
      }
      }
      }

      /* 接收回復 */
      public String getBulkReply() {
      final byte[] result = getBinaryBulkReply();
      if (null != result) {
      return SafeEncoder.encode(result);
      } else {
      return null;
      }
      }

      public byte[] getBinaryBulkReply() {
      flush();
      pipelinedCommands--;
      return (byte[]) readProtocolWithCheckingBroken();
      }

      protected Object readProtocolWithCheckingBroken() {
      try {
      return Protocol.read(inputStream);
      } catch (JedisConnectionException exc) {
      broken = true;
      throw exc;
      }
      }
    • Jedis通過Pipeline這個類來對redis的pipeline進行抽象,jedis.pipelined()返回一個Pipeline實例,并且這個Pipeline實例的client就是當前jedis實例的client;調用pipeline.a_redis_command()的時候會有一個responseList,用來記錄每個command應該對應的response;pipeline.syncAndReturnAll()會調用client.getAll()將所有command一次flush()出去,然后拿回List<Object>,再將這些Object填充到responseList中。

    Jedis使用注意事項

    • Jedis instance本身不是線程安全的!要用JedisPool

      //將JedisPool定義為spring單例
      JedisPool pool = new JedisPool(new JedisPoolConfig(), "localhost");

      Jedis jedis = null;
      try {
      jedis = pool.getResource();
      /// ... do stuff here ... for example
      jedis.set("foo", "bar");
      String foobar = jedis.get("foo");
      jedis.zadd("sose", 0, "car"); jedis.zadd("sose", 0, "bike");
      Set<String> sose = jedis.zrange("sose", 0, -1);
      } finally {
      if (jedis != null) {
      jedis.close();
      }
      }
      /// ... when closing your application:
      pool.destroy();
    • JedisPool是一個包裝模式,內部就是Apache Common Pool 2, Pool里面裝的是Jedis。Jedis之所以不是線程安全的主要是由于Jedis類中的fields(client, pipeline, transaction)沒有做同步。如果每個thread都有一份Jedis實例,其實也不存在線程安全問題,就是要注意使用完了需要jedis.close()。JedisPool和DBCP的Pool一樣,就是用來創建Jedis實例,然后提供給線程使用,Pool技術能夠復用已經標記為IDLE的Jedis,以此來提供內存利用率和減小開銷。

    小結

    • Redis的通信協議簡單容易實現
    • Jedis在實現協議的時候用的Client將Connection和Command解耦,中規中矩,值得學習
    • JedisPool用了Apache Common Pool來做到ThreadSafe
    posted on 2016-12-20 15:07 jinfeng_wang 閱讀(188) 評論(0)  編輯  收藏 所屬分類: 2016-REDIS
    主站蜘蛛池模板: 91九色老熟女免费资源站| 午夜亚洲www湿好大| 四虎永久在线观看免费网站网址 | jizz日本免费| 亚洲乱妇老熟女爽到高潮的片| 亚洲人成电影在线天堂| 久久久久国产成人精品亚洲午夜| 最新仑乱免费视频| 免费在线观看h片| 老司机69精品成免费视频| 九九久久精品国产免费看小说| 在线观看亚洲AV每日更新无码| 亚洲福利秒拍一区二区| 国产成人精品日本亚洲| 亚洲人成网站在线播放vr| 中文字幕在亚洲第一在线| 免费又黄又爽的视频| 四虎成人免费大片在线| 人成午夜免费视频在线观看| 最近免费中文字幕mv在线电影| 日韩精品无码免费专区午夜| 中文字幕视频免费在线观看| 青青青视频免费观看| 视频一区二区三区免费观看| 亚洲狠狠婷婷综合久久蜜芽| 亚洲中文无码永久免费| 亚洲一区二区三区在线| 亚洲午夜成激人情在线影院| 亚洲国产精品午夜电影 | 97在线视频免费播放| 无码免费一区二区三区免费播放| 免费无码又爽又刺激网站| a毛片在线还看免费网站| 好吊色永久免费视频大全| 久久久久久国产a免费观看不卡| 国产日韩精品无码区免费专区国产 | 国产亚洲精品影视在线| jiz zz在亚洲| 午夜亚洲国产理论片二级港台二级 | 中国一级特黄高清免费的大片中国一级黄色片 | 四虎精品成人免费视频|