分享
  1. 首页
  2. 文章

『互联网架构』软件架构-redis的通信协议(protocol)(52)

IT人故事会 · · 1650 次点击 · · 开始浏览
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

原创文章,欢迎转载。转载请注明:转载自IT人故事会,谢谢!
原文链接地址:『互联网架构』软件架构-redis的通信协议(protocol)(52)

redis的通信协议是什么?双方约定了一种编码方式,客户端将要发送的命令进行编码,然后服务端收到后,使用同样的协议进行解码,服务端处理完成后,再次编码返回给客户端,客户端解码拿到返回结果,这样就完成了一次通信。

(一)协议介绍

https://redis.io/topics/protocol

  1. 易于实现
  2. 可以高效地被计算机分析(parse)
  3. 可以很容易地被人类读懂

(二)编码后的字符标记解释

  1. For Simple Strings the first byte of the reply is "+" 回复
  2. For Errors the first byte of the reply is "-" 错误
  3. For Integers the first byte of the reply is ":" 整数
  4. For Bulk Strings the first byte of the reply is "$" 字符串
  5. For Arrays the first byte of the reply is "*" 数组

(三)模拟Redis客户端&分片

  • 客户端

Jedis跟redis通讯很简单发送了socket,然后发送了resp这种‘暗语’进行通讯。

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
public class RedisClient {
 private Socket socket;
 private String host;
 private int port;
 public RedisClient() throws IOException {
 this.socket = new Socket("192.168.79.100",6379);
 }
 public RedisClient(String host, int port) {
 this.host = host;
 this.port = port;
 try {
 this.socket = new Socket(host,port);
 } catch (IOException e) {
 e.printStackTrace();
 }
 }
 //set wk 2018
 public String set( String key, String value) throws IOException {
 //"*3\r\n3ドル\r\nset\r\n2ドル\r\nwk\r\n4ドル\r\n2018"
 StringBuilder stringBuilder=new StringBuilder();
 stringBuilder.append("*3").append("\r\n");
 stringBuilder.append("$").append(CommandRedis.set.name().length()).append("\r\n");
 stringBuilder.append(CommandRedis.set).append("\r\n");
 stringBuilder.append("$").append(key.getBytes().length).append("\r\n");
 stringBuilder.append(key).append("\r\n");
 stringBuilder.append("$").append(value.getBytes().length).append("\r\n");
 stringBuilder.append(value).append("\r\n");
 socket.getOutputStream().write(stringBuilder.toString().getBytes());
 byte[] b=new byte[2048];
 socket.getInputStream().read(b);
 return new String(b);
 }
 public String get( String key) throws IOException {
 //"*3\r\n3ドル\r\nset\r\n2ドル\r\nwk\r\n4ドル\r\n2018"
 StringBuilder stringBuilder=new StringBuilder();
 stringBuilder.append("*2").append("\r\n");
 stringBuilder.append("$").append(CommandRedis.get.name().length()).append("\r\n");
 stringBuilder.append(CommandRedis.get).append("\r\n");
 stringBuilder.append("$").append(key.getBytes().length).append("\r\n");
 stringBuilder.append(key).append("\r\n");
 socket.getOutputStream().write(stringBuilder.toString().getBytes());
 byte[] b=new byte[2048];
 socket.getInputStream().read(b);
 return new String(b);
 }
 public String setnx(String key, String value) throws Exception {
 StringBuffer stringBuffer = new StringBuffer();
 stringBuffer.append("*3").append("\r\n");
 stringBuffer.append("5ドル").append("\r\n");
 stringBuffer.append("setnx").append("\r\n");
 stringBuffer.append("$").append(key.getBytes().length).append("\r\n");
 stringBuffer.append(key).append("\r\n");
 stringBuffer.append("$").append(value.getBytes().length).append("\r\n");
 stringBuffer.append(value).append("\r\n");
 socket.getOutputStream().write(stringBuffer.toString().getBytes());
 byte[] b = new byte[2048];
 socket.getInputStream().read(b );
 return new String(b);
 }
 // 管道
 public void pipeline(String key)throws Exception {
 StringBuffer stringBuffer = new StringBuffer();
 stringBuffer.append("*2").append("\r\n");
 stringBuffer.append("$"+CommandRedis.subscribe.name().length()).append("\r\n");
 stringBuffer.append(CommandRedis.subscribe).append("\r\n");
 stringBuffer.append("$").append(key.getBytes().length).append("\r\n");
 stringBuffer.append(key).append("\r\n");
 socket.getOutputStream().write(stringBuffer.toString().getBytes());
 InputStream inputStream = socket.getInputStream();
 while (true) {
 byte[] b = new byte[2048];
 inputStream.read(b );
 System.out.println(new String(b));
 }
 }
 //subscribe
 public void subscribe(String key)throws Exception {
 StringBuffer stringBuffer = new StringBuffer();
 stringBuffer.append("*2").append("\r\n");
 stringBuffer.append("$"+CommandRedis.subscribe.name().length()).append("\r\n");
 stringBuffer.append(CommandRedis.subscribe).append("\r\n");
 stringBuffer.append("$").append(key.getBytes().length).append("\r\n");
 stringBuffer.append(key).append("\r\n");
 socket.getOutputStream().write(stringBuffer.toString().getBytes());
 InputStream inputStream = socket.getInputStream();
 while (true) {
 byte[] b = new byte[2048];
 inputStream.read(b );
 System.out.println(new String(b));
 }
 }
 public void close(){
 if(socket != null){
 try {
 socket.close();
 } catch (IOException e) {
 e.printStackTrace();
 }
 }
 }
}

public enum CommandRedis {
 set,get,incr,subscribe
}
  • 分片

RedisClient分片方式,简单模拟,理解概念分片。

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class TestRedisClient {
 public static void main(String[] args) throws IOException {
 /* RedisClient redisClient=new RedisClient();
 System.out.println(redisClient.set("wk","悟空"));
 System.out.println(redisClient.get("wk"));*/
 List<RedisClient> pool=new ArrayList<>();
 pool.add(new RedisClient("192.168.0.12",6379));
 pool.add(new RedisClient("192.168.0.12",6380));
 pool.add(new RedisClient("192.168.0.12",6381));
 Crc16Sharding crc16Sharding=new Crc16Sharding(pool);
 for (int i=0;i<100;i++){
 String key="xx"+i;
 RedisClient redisClient=crc16Sharding.crc16(key);
 redisClient.set(key,i+"");
 System.out.println(redisClient.get(key));
 }
 }
}
import com.sun.org.apache.xerces.internal.impl.xpath.regex.Match;
import java.util.List;
public class Crc16Sharding {
 List<RedisClient> pool;
 public Crc16Sharding(List<RedisClient> pool) {
 this.pool = pool;
 }
 /**
 * 通过一个key可以定位到一块 节点
 * @param key
 * @return
 */
 public RedisClient crc16(String key){
 int num=Math.abs(key.hashCode()%pool.size());
 return pool.get(num);
 /* if(key.length()<3){
 return pool.get(0);
 }else if(key.length()<6){
 return pool.get(1);
 }else{
 return pool.get(2);
 }*/
 }
}
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class TestRedisClient {
 public static void main(String[] args) throws IOException {
 List<RedisClient> pool=new ArrayList<>();
 pool.add(new RedisClient("192.168.0.12",6379));
 pool.add(new RedisClient("192.168.0.12",6380));
 pool.add(new RedisClient("192.168.0.12",6381));
 Crc16Sharding crc16Sharding=new Crc16Sharding(pool);
 for (int i=0;i<100;i++){
 String key="xx"+i;
 RedisClient redisClient=crc16Sharding.crc16(key);
 redisClient.set(key,i+"");
 System.out.println(redisClient.get(key));;
 }
 }
}

(四)redis使用技巧

  1. 如果是订单表,取的话也是通过唯一的订单号来进行,不要通过循环去redis里面取。
  2. 开关类型的放到本地的jvm内存中,尽量减少redis的压力。
  3. 避免使用慢查询 hgetall
  4. 存储redis的购物车,有的人都是很多的好几M的,几百个商品,redis存储的内容的压缩。减少通信的宽带。优化存储内容。
  5. 少用字符串存储,可以存储map格式放入redis。获取redis里面的map,直接通过key就可以取到对应的值。

(五)监控&运维

  • Open-falcon

http://open-falcon.org/
open-falcon是小米开源监控系统,强大灵活的数据采集、采集、传输、绘制、查询、报警等。采用全部golang编写,portal和dashboard使用python编写。

  • Redis-migrate-tool

https://github.com/vipshop/redis-migrate-tool
2年多没更新了,可以了解下
Redis-migrate-tool是唯品会开源针对redis数据运维工具。
支持单独、twemproxy集群、redis custer、aof、rdb文件迁移。支持实时迁移、异构迁移、过滤等功能。

PS:介绍了运维工具,redis通信的内容拼接,redis存储的技巧,redis正常的时候没问题,并发量大的时候一定要注意,在大流量的情况下,代码的细节至关重要!


有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:IT人故事会

查看原文:『互联网架构』软件架构-redis的通信协议(protocol)(52)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信
1650 次点击
暂无回复
添加一条新回复 (您需要 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传

用户登录

没有账号?注册
(追記) (追記ここまで)

今日阅读排行

    加载中
(追記) (追記ここまで)

一周阅读排行

    加载中

关注我

  • 扫码关注领全套学习资料 关注微信公众号
  • 加入 QQ 群:
    • 192706294(已满)
    • 731990104(已满)
    • 798786647(已满)
    • 729884609(已满)
    • 977810755(已满)
    • 815126783(已满)
    • 812540095(已满)
    • 1006366459(已满)
    • 692541889

  • 关注微信公众号
  • 加入微信群:liuxiaoyan-s,备注入群
  • 也欢迎加入知识星球 Go粉丝们(免费)

给该专栏投稿 写篇新文章

每篇文章有总共有 5 次投稿机会

收入到我管理的专栏 新建专栏