《架构师训练营》-第八周-网络与数据库

网络通信协议

一次Web请求的网络通信历程

在这里插入图片描述

OSI七层模型和TCP/IP四层模型

OSI七层模型TCP/IP四层模型功能
应用层(Application Layer)应用层(Application Layer)为用户的应用提供服务并支持网络访问
表示层(Presentation Layer)应用层(Application Layer)负责转化数据格式,并处理数据加密和数据压缩
会话层(Session Layer)应用层(Application Layer)负责管理网络中计算之间的通信,提供传输层不具备的链接功能
传输层(Transport Layer)传输层(Transport Layer)提供端对端的接口
网络层(Network Layer)网络互联层(Internet Layer)为数据包选择路由
数据链路层(Data Link Layer)网络访问(链路)层(Network Access (Link) Layer)传输有地址的帧以及错误检测功能
物理层(Physical Layer)网络访问(链路)层(Network Access (Link) Layer)在物理媒介上传输二进制格式数据

数据包格式

在这里插入图片描述

物理层

负责数据的物理传输,计算机输入的只能是二进制数据,在通信线路中有光纤、电缆、无线各种设备。光信号、电信号以及无线电磁信号在物理上是完全不同的,如何让这些不同的设备能够理解、处理相同的二进制数据,这就是物理层要解决的问题。

链路层

链路层就是将数据进行封装后交给物理层进行传输,主要就是将数据封装成数据帧,以帧为单位通过物理层进行通信,有了帧,就可以在帧上进行数据校验,进行流量控制。

链路层会定义帧的大小,这个大小也被称为最大传输单元。像HTTP要在传输的数据上添加一个HTTP头一样,数据链路层也会将封装好的帧添加一个帧头,帧头里记录的一个重要信息就是发送者和接受者的MAC地址。MAC地址是网卡的设备标识符,是唯一的,数据帧通过这个信息确保数据送达到正确的目标机器。

数据链路层的负载均衡

在这里插入图片描述

应用服务器集群的IP地址都是一样的,所以每台应用服务器都会收到请求,链路层会校验MAC地址是否发给自己的,如果不是则拒收。

网络层(IP协议)

网际互连协议(IP,Internet Protocol),是TCP/IP体系中的网络层协议。根据端到端的设计原则,IP只为主机提供一种无连接、不可靠的、尽力而为的数据报传输服务。

网络层IP协议使得互联网应用根据IP地址就能访问到目标服务器,请求利凯App后,到达运营服务商的交换机,交换机会根据这个IP地址进行路由转发,可能中间会经过很多个转发节点,最后数据到达目标服务器。

网络层的数据要交给链路层进行处理,而链路层帧的大小定义了最大传输单元,网络层的IP数据包必须要小于最大传输单元才能进行网络传输,这个数据包也有一个IP头,主要包括的就是发送者和接受者的IP地址。

IP负载均衡

在这里插入图片描述

传输层(TCP协议)

传输控制协议(TCP,Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793 [1] 定义。

IP协议不是一个可靠的通信协议,不会建立稳定的通信链路,并不会确保数据一定送达。要保证通信的稳定可靠,需要传输层协议TCP。
TCP协议是一种面向连接的、可靠的、基于字节流的传输层协议。TCP作为一个比较基础的通讯协议,有很多重要的机制保证了TCP协议的可靠性和强壮性:

  1. 使用序号对收到的TCP报文段进行排序和检测重复的数据
  2. 无错传输,使用校验和检测报文段的错误
  3. 使用确认和计时器来检测和纠正丢包或者延时
  4. 流量控制,避免主机分组发送得过快而使接收方来不及完全手下
  5. 拥塞控制,发送方根据网络承载情况控制分组的发送量,以获得高性能同时避免拥塞崩溃丢失包的重传
TCP建立连接的三次握手过程

在这里插入图片描述

  1. APP先发送SYN=1,Seq=X的报文,表示请求建立连接,X是个随机数;
  2. 服务器收到这个报文后,应答SYN=1,ACK=X+1,Seq=Y的报文,表示同意建立连接
  3. APP收到这个报文后,检查ACK的值为自己发送的Seq值+1,确认建立连接。并发送ACK=Y+1的报文给服务器;服务器收到这个报文后检查ACK值为自己发送的Seq值+1,确认建立连接。至此,App和服务器建立起TCP连接,就可以进行数据传输了
TCP关闭连接4次挥手

在这里插入图片描述

  1. 客户端向服务端发送一个FIN,请求关闭数据传输
  2. 当服务器接收到客户端的FIN时,向客户端发送一个ACK,其中ACK的值等于FIN+SEQ
  3. 然后服务器向客户端发送一个FIN告诉客户端应用程序关闭
  4. 当客户端收到服务器端的FIN时,回复一个ACK给服务器端。其中ACK的值等于FIN+SEQ

应用层(HTTP协议)

超文本传输协议( HTTP,Hyper Text Transfer Protocol)

HTTP请求的7种方法
序号方法描述
1GET【幂等】发送请求来获得服务器上的资源,请求体中不会包含请求数据,请求数据放在协议头中
2POST【非幂等】向服务器提交资源让服务器处理。提交的资源放在请求体中
3HEAD本质和GET一样,但是响应中没有呈现数据,而是http的头信息
4PUT【幂等】上传资源到指定位置。提交的资源放在请求体中
5DELETE【幂等】请求服务器删除某资源
6TRACE回显服务器收到的请求
7OPTIONS获取http服务器支持的http请求方法
HTTP响应的5种状态
序号方法描述
1GET【幂等】发送请求来获得服务器上的资源,请求体中不会包含请求数据,请求数据放在协议头中
2POST【非幂等】向服务器提交资源让服务器处理。提交的资源放在请求体中
3HEAD本质和GET一样,但是响应中没有呈现数据,而是http的头信息
4PUT【幂等】上传资源到指定位置。提交的资源放在请求体中
5DELETE【幂等】请求服务器删除某资源
6TRACE回显服务器收到的请求
7OPTIONS获取http服务器支持的http请求方法
HTTP协议发展
  • HTTP1.0
    每次请求都要建立新的TCP连接,都要进行三次握手。
    在这里插入图片描述
  • HTTP1.1
    并行使用多个TCP协议。
    在这里插入图片描述
  • HTTP2
    引入流的概念,可以使浏览器复用TCP连接。
    在这里插入图片描述
  • HTTP3
    使用QUIC协议,QUIC协议的传输由TCP换成UDP。UDP传输只保证数据有序发送,不关心客户端是否完全接收,需要QUIC协议来进行数据完整性校验,如果不完整则会要求重发。

非阻塞网络I/O

计算机之间如何进行网络通信

通过Socket进行连接

Socket工作原理

在这里插入图片描述

  1. 通过网络协议传输数据包达到网卡,网卡通过解析数据包的信息,确认是否接收(判断条件:mac地址是不是本机地址)
  2. 确认接收后,对数据包进行一层一层解包,将TCP数据部分拷贝到Socket的接收缓冲区
  3. 直到拷贝完成后,才会唤醒等待线程A

阻塞I/O

服务端与客户端

在这里插入图片描述

  1. 服务端监听指定端口,等待客户端连接(线程阻塞)
  2. 与客户端建立连接后,获取Socket接收缓冲区的内容(线程阻塞)
  3. 往Socket发送缓冲区写内容(线程阻塞)

多线程服务器与客户端

在这里插入图片描述

代码
  • 服务端
package cn.hgy.week8;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;

/**
 * @author guoyu.huang
 * @since 2020-08-16
 */
public class Server {

    public static void main(String[] args) throws IOException {

        ServerSocket serverSocket = new ServerSocket(8080);
        while (true) {
            System.out.println("阻塞点:accept");
            final Socket socket = serverSocket.accept();

            new Thread(() -> {
                try {
                    System.out.println("阻塞点:接收缓冲池");
                    InputStream inputStream = socket.getInputStream();
                    byte[] content = new byte[1024];
                    int len;
                    StringBuilder sb = new StringBuilder();
                    while ((len = inputStream.read(content)) != -1) {
                        sb.append(new String(content, 0, len));
                    }
                    System.out.println(sb.toString());
                    Thread.sleep(5000L);

                    OutputStream outputStream = socket.getOutputStream();
                    outputStream.write("接收成功".getBytes());
                    System.out.println("阻塞点:发送缓冲池");
                    outputStream.flush();
                    socket.shutdownOutput();
                } catch (IOException e) {
                    e.printStackTrace();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}

  • 客户端
package cn.hgy.week8;

import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;

/**
 * @author guoyu.huang
 * @since 2020-08-16
 */
public class Client {

    public static void main(String[] args) throws IOException, InterruptedException {

        Socket socket = new Socket("127.0.0.1", 8080);

        // 阻塞5秒输出
        Thread.sleep(5000L);
        socket.getOutputStream().write("client".getBytes());
        socket.shutdownOutput();

        // 输入
        InputStream inputStream = socket.getInputStream();
        byte[] content = new byte[1024];
        int len;
        StringBuilder sb = new StringBuilder();
        while ((len = inputStream.read(content)) != -1) {
            sb.append(new String(content, 0, len));
        }
        System.out.println(sb.toString());
    }
}

线程池服务器

在这里插入图片描述

总结

  1. 获取接收缓冲区数据时,如果没有数据则会发生阻塞
  2. 往发送缓冲区写数据时,如果缓冲区已经满了则会发生阻塞

非阻塞I/O

非阻塞I/O是指IO操作立即返回,发起线程不会阻塞等待。

  • 非阻塞IO读的操作
  1. Socket接收缓冲区有数据,读N个数据(不保证数据被读完整,因此可能需要多次读取)
  2. Socket接收缓冲区没有数据,直接返回失败(不会等待)
  • 非阻塞IO写的操作
  1. Socket发送缓冲区满,直接返回失败(不会等待)
  2. Socket发送缓冲区不满,写N个数据(不保证数据一次性被全部写入,因此可能需要多次写)

JAVA NIO (NEW I/O)

关键类信息

在这里插入图片描述

  1. Selector:不断的轮询注册在其上的Channel,如果某个Channel上面发送读或者写事件,这个Channel就处于就绪状态,会被Selector轮询出来,然后通过SelectionKey可以获取就绪Channel的集合,进行后续的I/O操作。
  2. Buffer:在NIO中,所有的数据都是用缓冲区处理的,读取数据时,它是从通道(Channel)直接读到缓冲区中,在写入数据时,也是从缓冲区写入到通道。
  3. Channel:网络数据通过Channel读取和写入。通道和流的不同之处在于通道是双向的(通道可以用于读、写后者二者同时进行),流只是在一个方向上移动。
  4. SelectionKey:四种操作类型,可以快速获取channel,selector
工作原理

在这里插入图片描述

代码实例
  • 服务端
package cn.hgy.week8;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * @author guoyu.huang
 * @since 2020-08-16
 */
public class NewServer {

    public static void main(String[] args) throws IOException, InterruptedException {
        InetSocketAddress address = new InetSocketAddress(8080);
        ServerSocketChannel server = ServerSocketChannel.open();
        server.bind(address);
        server.configureBlocking(false);

        // 监听ACCEPT
        Selector selector = Selector.open();
        server.register(selector, SelectionKey.OP_ACCEPT);

        while (true) {
            selector.select();

            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey selectionKey = iterator.next();

                if (selectionKey.isAcceptable()) {

                    System.out.println("----- accept -----");
                    ServerSocketChannel serverSocketChannel = (ServerSocketChannel) selectionKey.channel();
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    socketChannel.configureBlocking(false);

                    // 监听读
                    socketChannel.register(selector, SelectionKey.OP_READ);

                } else if (selectionKey.isReadable()) {

                    System.out.println("----- read -----");
                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                    SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                    socketChannel.read(byteBuffer);
                    System.out.println(new String(byteBuffer.array()));

                    socketChannel.register(selector, SelectionKey.OP_WRITE);
                } else if (selectionKey.isWritable()) {

                    System.out.println("----- write -----");

                    SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                    ByteBuffer byteBuffer = ByteBuffer.wrap("接收成功".getBytes());
                    socketChannel.write(byteBuffer);

                    selectionKey.cancel();

                }

                iterator.remove();
            }

        }
    }
}

  • 客户端
package cn.hgy.week8;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**
 * 客户端发起连接
 *
 * @author guoyu.huang
 * @since 2020-08-16
 */
public class NewClient {

    public static void main(String[] args) throws IOException, InterruptedException {
        SocketChannel channel = SocketChannel.open();
        channel.configureBlocking(false);

        Selector selector = Selector.open();
        channel.connect(new InetSocketAddress("127.0.0.1", 8080));
        channel.register(selector, SelectionKey.OP_CONNECT);

        while (true) {
            selector.select();

            Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
            while (iterator.hasNext()) {
                SelectionKey selectionKey = iterator.next();

                if (selectionKey.isConnectable()) {

                    System.out.println("----- connect -----");
                    SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                    if (channel.isConnectionPending()) {
                        channel.finishConnect();
                    }
                    // 监听写
                    socketChannel.register(selector, SelectionKey.OP_WRITE);

                } else if (selectionKey.isReadable()) {

                    System.out.println("----- read -----");
                    ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                    SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                    socketChannel.read(byteBuffer);
                    System.out.println(new String(byteBuffer.array()));

                    socketChannel.register(selector, SelectionKey.OP_WRITE);
                } else if (selectionKey.isWritable()) {

                    System.out.println("----- write -----");
                    Thread.sleep(8000);
                    SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                    ByteBuffer byteBuffer = ByteBuffer.wrap("new client".getBytes());
                    socketChannel.write(byteBuffer);

                    // 监听读
                    socketChannel.register(selector, SelectionKey.OP_READ);
                }

                iterator.remove();
            }
        }
    }
}

扩展 - 操作系统

在NIO中selector.select()函数会调用操作系统函数,该函数会发生阻塞。不同操作系统实现方式也不同,有:select,poll,epoll。

I/O复用方式

在这里插入图片描述

select/poll 的read

在这里插入图片描述
所有Socket关联同一个线程A,当Socket触发事件时,唤醒线程A,线程A轮询所有的Socket,判断哪些Socket是有事件要触发。

epoll

在这里插入图片描述

eventpoll会关联线程A,所有Socket如果有事件触发,会添加到eventpoll中,同时唤醒线程A。

数据库架构原理

数据库架构

在这里插入图片描述

连接器

在这里插入图片描述

语法分析器

在这里插入图片描述

语义分析与优化器

在这里插入图片描述

PrepareStatement

两种SQL执行方式:
在这里插入图片描述

防止SQL攻击

在这里插入图片描述

MYSQL索引数据结构:B+树

在这里插入图片描述

聚簇索引与非聚簇索引

在这里插入图片描述

数据库事务

在这里插入图片描述

数据库事务日志

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

瑾析编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值