初始分布式

认识分布式

常见概念

  • 单机结构

    • 一个app即可完成所有操作,适用于业务量小的项目

      食客 厨师 点单 上菜 食客 厨师
  • 集群结构

    • 多个单机结构的集合

    • 物理上增加额外的机器

      食客1 厨师1 食客2 厨师2 点单 上菜 点单 上菜 食客1 厨师1 食客2 厨师2
  • 分布式

    • 分布式结构就是将一个完整的系统,按照业务功能,拆分成一个个独立的子系统,在分布式结构中,每个子系统就被称为“服务”。这些子系统能够独立运行在web容器中,它们之间通过RPC方式通信。

    • 操作模式的改变

      配菜1 厨师1 配菜2 厨师2 洗菜切菜 洗菜切菜 配菜1 厨师1 配菜2 厨师2
  • 节点

    • 可以独立按照分布式协议完成一定逻辑的程序
  • 副本机制

    • 在不同节点上持久化同一份数据,当其中一个节点数据丢失,则可以种副本上读取数据
    • 数据副本是分布式系统中解决数据丢失的方法
  • 中间件

    • 应用河系统之间为开发者提供通讯处理的一类软件

架构演进

  • 以电商为例,模块为 用户商品支付

单应用

  • 将整个项目作为整体进行部署

    1559632134693

应用与数据库分离

  • 将应用与数据分离至两台服务器上

1559632149030

应用集群

  • 多个应用服务器

    1559632239910

读写分离

  • 两个数据库分别承担读、写 ,写数据库需要向读数据库进行数据提交

1559632340710

搜索索引

  • 电商场景下 模糊搜索很多,提升搜索的性能使用ES

1559632500117

缓存引入

  • redis 存储经常使用数据或这其他数据

1559632708743

数据库拆分

  • 水平拆分:同一个表的数据拆分到更多的表或数据库中
  • 垂直拆分:把不同业务数据拆分到不同数据库中,下图:将商品作为业务进行拆分

1559632986263

应用拆分

  • 用户商品交易拆分成独立应用

1559633062459

通讯协议

TCP/IP

发送请求 传输层 网络层 数据链路层 物理层 TCP头、http请求报文 +IP头 +MAC头 二进制 发送请求 传输层 网络层 数据链路层 物理层
  • TCP

    • 目标端口号
  • IP

    • 源ip地址
    • 目标ip地址

三次握手

服务器A 服务器B SYN/Seq,服务器A:SYN-SEND SYN/ACK/Seq/ack,服务器B:SYN-RCVD ACK/SEQ: 服务器A、服务器B:esta-bleshed 服务器A 服务器B
四次挥手
服务器A 服务器B FIN=1 关闭连接,服务器A:fin_wait_1 ACK ,服务器B:close_wati,服务器A:fin_wait_2 FIN ,服务器B:last_ack ACK,服务器A在接收FIN状态time_wait 服务器A 服务器B

简单socket

  • ClientSocketDemo
public class ClientSocketDemo {

    public static void main(String[] args) throws IOException {
        Socket socket = null;

        try {
            socket = new Socket("127.0.0.1", 8080);
            PrintWriter printWriter = new PrintWriter(socket.getOutputStream(),true);
            printWriter.println("hello");
        } catch (Exception e) {

        } finally {
            if (socket != null) {
                socket.close();
            }
        }
    }
}

  • ServerSocketDemo
public class ServerSocketDemo {

    public static void main(String[] args) throws IOException {
        ServerSocket serverSocket = null;
        BufferedReader bufferedReader = null;

        try {
            serverSocket = new ServerSocket(8080);
            // 等待客户端连接
            Socket accept = serverSocket.accept();
            // inputstream
            bufferedReader = new BufferedReader(new InputStreamReader(accept.getInputStream()));
            // 写出
            System.out.println(bufferedReader.readLine());

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bufferedReader != null) {
                bufferedReader.close();
            }

            if (serverSocket != null) {
                serverSocket.close();
            }
        }


    }
}
简单UDP
  • UdpClientDemo
public class UdpClientDemo {

    public static void main(String[] args) throws Exception {
        InetAddress address = InetAddress.getByName("localhost");
        byte[] sendData = "hello".getBytes();
        DatagramPacket datagramPacket = new DatagramPacket(sendData, sendData.length, address,
                9999);

        DatagramSocket datagramSocket = new DatagramSocket();
        datagramSocket.send(datagramPacket);
        datagramSocket.close();
    }

}
  • UdpServerDemo
public class UdpServerDemo {

    public static void main(String[] args) {
        DatagramSocket datagramSocket = null;
        DatagramPacket datagramPacket = null;
        try {
            datagramSocket = new DatagramSocket(9999);
            byte[] receiveData = new byte[1024];
            datagramPacket = new DatagramPacket(receiveData, receiveData.length);
            datagramSocket.receive(datagramPacket);

            System.out.println(new String(receiveData, 0, datagramPacket.getLength()));


        } catch (Exception e) {

        } finally {
            if (datagramSocket != null) {
                datagramSocket.close();
            }
        }

    }
}

http

方法
  • GET
    • 请求指定的页面信息,并返回实体主体。
  • POST
    • 请求服务器接受所指定的文档作为对所标识的URI的新的从属实体。
  • PUT
    • 从客户端向服务器传送的数据取代指定的文档的内容。
  • DELETE
    • 请求服务器删除指定的页面。
  • OPTIONS
    • 允许客户端查看服务器的性能。
  • HEAD
    • 只请求页面的首部。
特点
  1. HTTP无状态

    • 解决技术:cookie + session

      浏览器 服务器 创建一个session,sessionId 将sessionId 放入cookie 将cookie 携带发送请求 浏览器 服务器
  2. 数据明文

    • 解决技术:https协议
      • ssl/tls
      • tcp
      • ip

https

通讯原理
  • 基础模型

    客户端向服务端发送一段文本信息。

client server 发送一个文本信息 client server
  • 客户端加密

    对称加密

    client密钥 server密钥 发送一个文本信息 client密钥 server密钥
  
  - 对称加密的坏处:一个密钥可以解密所有信息
    ```mermaid
    sequenceDiagram
    clientA、密钥A-->>server密钥A:请求
    clientB、密钥A-->>server密钥A:请求
  clientC、密钥A-->>server密钥A:非发请求
  • 一个客户端一个密钥

    • 问题,客户端如何知道这个密钥
    clientA、密钥A server clientB、密钥B clientC、密钥C 请求 请求 请求 clientA、密钥A server clientB、密钥B clientC、密钥C
  • 非对称加密

    • 公钥+私钥
    • 公钥获取形式?
    clientA、公钥 server私钥 clientB、公钥 clientC、公钥 请求 请求 请求 clientA、公钥 server私钥 clientB、公钥 clientC、公钥

    问题概述图

    client 拦截者 server 请求 转发请求种的公钥 公钥+数据 拦截者创建一个公钥 , 此时client不知道公钥的正确性 client 拦截者 server
  • 第三方加密

    client 拦截者 server 第三方 请求 转发请求种的公钥 server密钥加密公钥 第三方返回加密后的公钥 第三方加密公钥+数据 拦截者创建一个公钥 client 拦截者 server 第三方
    • 第三方创建数字证书

      • server公钥(加密后)
    • 问题

      1. 客户端如何解密第三方加密的数字证书

      2. 第三方可以将证书发放给任意一个客户端,如何避免?

        serverA 第三方 serverB 申请证书 申请证书,这个是一个坏人。这样又可以替换证书了 serverA 第三方 serverB
  • 证书有效性的验证

    • 数字证书改进

      • 证书唯一编号

      • 唯一编号算法

      • server公钥(加密后)

      • 其他信息

    server 数字证书A 拦截者 数字证书B client 通过ca生产证书 通过ca生产证书 获取证书 获取证书 server 数字证书A 拦截者 数字证书B client
    • 通过加密算法进行一次加密计算,比对加密算法结果和证书唯一编号进行对比是否相等
  • 总结

    服务端 CA机构 客户端 服务端公钥发送给CA机构 返回证书 服务端生产公钥私钥 服务端保存私钥 公钥发送给CA机构 CA机构内置的公钥 私钥,CA机构加密服 务端公钥生产数字前面 返回给客户端,CA根证 书内置在浏览器中 TCP,发起请求,客户端随机值,客户端加密算法 接受请求,返回CA机构基于自身公钥私钥的算法后的证书,服务端随机值 CA证书可受信任,有效期,数字签名,所有者 loop [ 证书校验 ] 加密算法(客户端随机值+服务端随机值) 客户端随机值+服务端随机值,验证成功船舰Session-Key loop [ 解密信息 ] 后续使用session-key 服务端 CA机构 客户端

序列化与反序列化

序列化的意义

  • 两个服务之间传输实体
  • 磁盘数据转换成实体
实体1 serverA 通讯 serverB 实体2 实体2 序列化 网络通讯 接收信息 反序列化 实体1 serverA 通讯 serverB 实体2 实体2

Serialization

  1. 数据大
  2. 语言限制

java序列化

public class MySerializerImpl implements MySerializer {

    @Override
    public <T> byte[] serializer(T obj) throws IOException {
        ObjectOutputStream oos = null;
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            oos = new ObjectOutputStream(bos);
            oos.writeObject(obj);
            return bos.toByteArray();

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (oos != null) {
                oos.close();
            }
            bos.close();
        }
        return null;
    }

    @Override
    public <T> T deSerializer(byte[] data, Class<T> clazz) throws IOException {
        ByteArrayInputStream bis = new ByteArrayInputStream(data);
        ObjectInputStream ois = null;

        try {
            ois = new ObjectInputStream(bis);
            return (T) ois.readObject();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            if (ois != null) {
                ois.close();
            }
            bis.close();
        }

        return null;
    }
}


public class TestRun {


    public static void main(String[] args) throws IOException {
        User user = new User();
        user.setName("张三");
        MySerializer mySerializer = new MySerializerImpl();

        byte[] serializer = mySerializer.serializer(user);
        User user1 = mySerializer.deSerializer(serializer, User.class);
        System.out.println(user1);


    }


    private static class User implements Serializable {

        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            final StringBuilder sb = new StringBuilder("{");
            sb.append("\"name\":\"")
                    .append(name).append('\"');
            sb.append('}');
            return sb.toString();
        }
    }

}
  • 静态变量不参与序列化

常见序列化技术

XML形式
  • webservice soap (http+xml)
json
  • Jackson

  • FastJson

  • GSON

hessian
Protobuf
  • 独立语言,独立平台
  • 空间占用少

protobuf

syntax ="proto3";


package com.huifer.jdk.serializer.proto;
option java_outer_classname="UserProto";


message MyUser{
    string name=1;
    int32 age=2;
}

.\protoc.exe --java_out=./ ./MyUser.proto
  • Maven 插件

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.huifer</groupId>
        <artifactId>jdk</artifactId>
        <version>1.0-SNAPSHOT</version>
        <properties>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
            <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
            <java.version>1.9</java.version>
        </properties>
    
    
    
    
    
        <dependencies>
            <dependency>
                <groupId>io.grpc</groupId>
                <artifactId>grpc-all</artifactId>
                <version>0.13.2</version>
            </dependency>
        </dependencies>
    
    
        <build>
            <extensions>
                <extension>
                    <groupId>kr.motd.maven</groupId>
                    <artifactId>os-maven-plugin</artifactId>
                    <version>1.4.1.Final</version>
                </extension>
            </extensions>
    
    
            <plugins>
    
                <plugin>
                    <groupId>org.xolstice.maven.plugins</groupId>
                    <artifactId>protobuf-maven-plugin</artifactId>
                    <version>0.5.0</version>
                    <configuration>
                        <protoSourceRoot>${basedir}/src/main/resources</protoSourceRoot><!--默认的proto文件路径-->
                        <protocArtifact>com.google.protobuf:protoc:3.8.0:exe:${os.detected.classifier}</protocArtifact>
                        <pluginId>grpc-java</pluginId>
                        <pluginArtifact>io.grpc:protoc-gen-grpc-java:0.13.2:exe:${os.detected.classifier}</pluginArtifact>
                    </configuration>
                    <executions>
                        <execution>
                            <goals>
                                <goal>compile</goal>
                                <goal>compile-custom</goal>
                            </goals>
                        </execution>
                    </executions>
                </plugin>
    
    
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <configuration>
                        <source>9</source>
                        <target>9</target>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    
    
    
    
    
    </project>
    

1560218050594

  • 上图还需要将文件复制到项目的具体包下,有点不方便进行如下改进。

    <protoSourceRoot>${basedir}/src/main/resources
    </protoSourceRoot><!--默认的proto文件路径-->
    <outputDirectory>${basedir}/src/main/java/com/huifer/jdk/serializer/proto
    </outputDirectory><!--默认的proto文件路径-->
    <clearOutputDirectory>false</clearOutputDirectory>
    
    • protoSourceRoot:proto文件存放位置
    • outputDirectory:java文件输出位置
    • clearOutputDirectory:是否清空outputDirectory
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.huifer</groupId>
  <artifactId>jdk</artifactId>
  <version>1.0-SNAPSHOT</version>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
    <java.version>1.9</java.version>
    <protobuf.version>3.8.0</protobuf.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>com.google.protobuf</groupId>
      <artifactId>protobuf-java</artifactId>
      <version>${protobuf.version}</version>
    </dependency>


    <dependency>
      <groupId>io.grpc</groupId>
      <artifactId>grpc-all</artifactId>
      <version>0.13.2</version>
    </dependency>
  </dependencies>

  <build>
    <extensions>
      <extension>
        <groupId>kr.motd.maven</groupId>
        <artifactId>os-maven-plugin</artifactId>
        <version>1.4.1.Final</version>
      </extension>
    </extensions>


    <plugins>
      <plugin>
        <groupId>org.xolstice.maven.plugins</groupId>
        <artifactId>protobuf-maven-plugin</artifactId>
        <version>0.5.0</version>
        <configuration>
          <protoSourceRoot>${basedir}/src/main/resources
          </protoSourceRoot><!--默认的proto文件路径-->
          <!--                    <outputDirectory>${basedir}/src/main/java/com/huifer/jdk/serializer/proto                    </outputDirectory>&lt;!&ndash;默认的proto文件路径&ndash;&gt;-->
          <outputDirectory>${basedir}/src/main/java</outputDirectory><!--默认的proto文件路径-->
          <clearOutputDirectory>false</clearOutputDirectory>
          <protocArtifact>com.google.protobuf:protoc:3.8.0:exe:${os.detected.classifier}
          </protocArtifact>
          <pluginId>grpc-java</pluginId>
          <pluginArtifact>
            io.grpc:protoc-gen-grpc-java:0.13.2:exe:${os.detected.classifier}
          </pluginArtifact>
        </configuration>
        <executions>
          <execution>
            <goals>
              <goal>compile</goal>
              <goal>compile-custom</goal>
            </goals>
          </execution>
        </executions>
      </plugin>


      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
          <source>9</source>
          <target>9</target>
        </configuration>
      </plugin>
    </plugins>
  </build>

</project>

1560218245177

成功放入具体包下

public class ProtoDemo {

    public static void main(String[] args) throws Exception {
        UserProto.MyUser myUser = UserProto.MyUser.newBuilder().setAge(10).setName("zhangsan").build();

        ByteString bytes = myUser.toByteString();

        System.out.println(bytes);

        UserProto.MyUser myUser1 = UserProto.MyUser.parseFrom(bytes);
        System.out.println(myUser1);
    }

}
<ByteString@7c53a9eb size=12>
name: "zhangsan"
age: 10

源码

本文代码及可视化代码均放在 GITHUB 欢迎star & fork

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值