Featured image of post Tomcat与HTTP网络通讯

Tomcat与HTTP网络通讯

tomcat详解、tcp、http、https等介绍

Tomcat

Tomcat系统架构和原理剖析

Tomcat设计了两个核心组件连接器(Connector)和容器(Container)来完成Tomcat的两大核心功能

连接器:负责对外 交流,处理Socket连接,负责网络字节流与Request和Response对象的转换

容器:负责内部处理:加载和管理Servlet,以及具体处理Request请求。

  • http请求的处理过程

浏览器访问服务器使用的是http协议,http是应用层协议,用于定义数据通信的格式,具体的数据传输使用的是TCP/IP协议。

  • tomcat系统架构

Tomcat既按照servlet规范的要求去实现了servlet容器,同时它也具有Http服务器的功能。

  1. http服务器
  2. Tomcat是一个servlet容器。
  • Servlet容器的处理流程

  1. http服务器把请求使用ServletRequest对象封装起来
  2. 进一步去调用Servlet容器中某个具体的Servlet
  3. 在2中,Servlet拿到请求后,根据URL和Servlet的映射关系,找到相应的Servlet
  4. 如果Servlet还没有被加载,就用反射创建这个Servlet,并调用Servlet的init方法完成初始化
  5. 接着调用这个具体的Servlet的service方法来处理请求,请求处理结果使用ServletResponse对象封装
  6. 把ServletResponse对象返回给HTTP服务器,Http服务器会把响应发送给客户端

Tomcat连接器组件Coyote

Coyote是Tomcat中连接器的组件名称,是对外的接口。客户端通过Coyote与服务器建立连接,发送请求并接受响应。

  1. Coyote封装了底层的网络通信(Socket请求及响应处理)
  2. Coyote使Catalina容器与具体的请求协议及IO操作方式完全解耦
  3. Coyote将Socket输入转换封装为Request对象,进一步封装后交由Catalina容器进行处理,处理请求完成后,Catalina通过Coyote提供的Response对象将结果写入输出流
  4. Coyote负责的是具体协议(应用层)和IO(传输层)相关内容

  • 内部解析

  1. EndPoint:Coyote的通信端点,通信监听的接口,是具体的Socket接收和发送处理器,是传输层的抽象,因此EndPoint用来实现TCP/IP协议的
  2. Processor:Coyote协议处理接口,Processor用来实现HTTP协议,接收来自EndPoint的Socket,读取字节流解析成Tomcat Request和Response对象,并通过Adapter将其提交到容器处理。
  3. ProtocolHandler,Coyote协议接口,通过EndPoint和Processor,实现对具体协议的处理能力。Tomcat按照协议和IO通过了六种协议类:AjpNioProtocol,AjpAprProtocol,AjpNio2Protocol,Http11NioProtocol,Http11Nio2Protocol,Http11AprProtocol。
  4. Adapter:由于协议不同,客户端发过来的请求信息也不相同,Tomcat定义了自己的request类来封装这些信息。ProtocolHandler接口负责解析请求并生成Tomcat Request类。但是这个Request对象不是标准的ServletRequest,不能通过ServletRequest来作为参数调用容器。Tomcat设计者的解决方案是引入CoyoteAdapter,这是适配器模式的经典应用。

Tomcat容器Catalina

从另一角度说,Tomcat本质上就是一款Servlet容器,因为Catalina才是Tomcat的核心,其他模块都是为Catalina提供支持。

  • Catalina结构

    一个Catalina实例(容器)

    ​ 一个Server实例(容器)

    ​ 多个Service实例(容器)

    ​ 每个Service实例下可以有多个Connector实例和一个Container(实例)

    • Catalina

      负责解析Tomcat的配置文件(Server.xml),以此来创建服务器Server组件并进行管理

    • Server

      服务器表示整个Catalina Servlet容器以及其他组件,负责组装并启动Sevlet引擎,Tomcat连接器,Server通过实现Lifecycle接口,提供一种优雅的关闭和启动整个的方式。

    • Service

      服务是Server内部的组件,一个Server包含多个Service,它将若干个Conector组件绑定到一个Container

    • Container

      容器,负责处理用户的Servlet请求,并返回给web用户的模块。

  • Container组件的具体结构

    • Engine

      表示整个Catalina的Servlet引擎,用来管理多个虚拟站点,一个Service最多只能有一个Engine,但是一个引擎可以含有多个Host。

    • Host

      代表一个虚拟主机,或者说一个站点,可以给Tomcat配置多个虚拟主机地址,而一个虚拟主机下可以包含多个Context

    • Context

      表示一个Web应用程序,一个Web应用可包含多个Wrapper

    • Wrapper

      表示一个Servlet,Wrapper作为容器中的最底层,不能包含子容器。

Tomcat的初始化启动流程

  1. 先创建一个catalina对象
  2. 调用catalina.load读取server对象,创建和解析server对象
  3. 创建server中的多个service对象
  4. 初始化Engine(service引擎)和executor线程池对象
  5. 初始化connector组件,先初始化通信端点和http协议
  6. 默认初始化NIO模型和初始化8080端口
  7. 然后按照上方顺序执行启动流程

非常有意思的一个设定,Tomcat所有的组件启动和初始化都借助lifecycle这个接口来调用,通过这个接口可以统一的管理Tomcat中各个组件的生命周期。

  • tomcat的请求处理流程

当一个servlet请求到来的时候,tomcat怎么定位和执行对应servlet的

  1. 通过Connector连接器,交给engine引擎
  2. 在engine引擎下找到对应的host虚拟主机,
  3. 通过host虚拟主机来确认context(具体的哪个应用)
  4. 通过context来确认对应的wrapper
  5. 每个wrapper就相当于一个servlet,来执行对应的servlet

上方所有的映射关系的通过mapper组件来完成映射的

Tomcat类加载机制

打破了双亲委派机制

  • 引导类加载器和扩展类加载器的作用不变

  • 系统类加载器正常情况下加载的是CLASSPATH下的类,但是Tomcat的启动脚本并未使用该变量,而是加载tomcat启动的类,比如bootstrap.jar,通常在catalina.bat或者catalina.sh中指定。位于CATALINA_HOME/bin下

  • Common通用类加载器加载Tomcat使用以及应用通用的一些类,位于CATALINA_HOME/lib下,比如servlet-api.jar

  • Catalina ClassLoader用于加载服务器内部可见类,这些类应用程序不能访问

  • Shared ClassLoader用于加载应用程序共享类,这些类服务器不会依赖

  • Webapp cClassLoader,每个应用程序都会有一个独一无二的Webapp ClassLoader,它用来加载本应用程序 /WEB-INF/classes和/WEB-INF/lib下的类。

    tomcat默认改变了严格的双亲委派机制

    • 首先从BootStrap ClassLoader加载指定的类
    • 未加载到,从/WEB-INF/class加载
    • 未加载到,从/WEB-INF/lib/*.jar加载
    • 未加载到,则依次从System、Common、Shared加载(该步骤使用双亲委派机制)

Tomcat优化

Tomcat对HTTPS的支持

https用来加强数据传输安全的

HTTPS和HTTP的主要区别

  • HTTPS协议使用时需要对电子商务认证授权(CA)申请SSL证书
  • HTTP默认使用8080端口,HTTPS默认使用8443端口
  • HTTPS则是具有SSL加密的安全性传输协议,对数据的传输进行加密,效果上相当于HTTP的升级版
  • HTTP的连接是无状态的,不安全的;HTTPS协议是由SSL加HTTP协议构建的可进行加密传输,身份认证的网络协议,比HTTP协议安全

Tomcat性能优化

  • JVM虚拟优化

垃圾回收器

  • 串行回收(Serial Collector)

    单线程执行所有垃圾回收工作,适用于单核CPU服务器

    工作进程—STW开始–(单线程)垃圾回收线程进行垃圾回收—STW结束—工作进程继续

  • 并行回收器(Parallel Collector)

    工作进程—–STW开始–(多线程)垃圾回收线程进行垃圾回收—-STW结束—工作进程继续

    又称吞吐量回收器(关注吞吐量),以并行的方式进行年轻带的垃圾回收。该方式可以显著降低垃圾回收的开销(指多条垃圾回收线程并行工作,但此时用户仍处于等待状态)。适用于多处理器或多线程硬件上运行的数据量较大的应用

  • 并发收集器(Concurrent Collector)

    以并发的方式进行大部分垃圾回收工作,以缩短垃圾回收的暂停时间。适用于那些响应时间优先于吞吐量的应用,应为该收集器虽然最小化了暂停时间(指用户线程和垃圾收集线程同时执行,但不一定是并行的,可能会交替进行)。但是会降低应用的性能。

  • CMS收集器(Concurrent Mark Sweep Collector)

    并发标记清除收集器,适用于那些更愿意缩短垃圾回收暂停时间并且负担的起于垃圾回收共享处理器资源的应用

  • G1收集器(Garbage-First Garbage Collector)

    适用于大容量内存的多核服务器,可以在满足垃圾回收暂停目标的同时,以最大可能性实现高吞吐量(JDK1.7之后)

  • Tomcat自身相关的调优
  1. 调整Tomcat的线程池,让多个Connector共用同一个线程池

  1. 调整tomcat的连接器

  2. 禁用AJP连接器(没有Apache请求的需求,可以禁用此连接器)

  3. 调整IO模式

Tomcat8之前的版本默认使用BIO(阻塞式IO),对于每一个请求都创建一个线程来处理,不适合高并发,Tomcat8之后的版本默认使用NIO模式(非阻塞IO)

当Tomcat并发性能有较高要求或者出现瓶颈时,我们可以尝试使用APR模式,APR(Apache Portable Runtime)是从操作系统级别解决异步IO问题,使用是需要在操作系统上安装APR和Native(因为APR原理是使用JNI技术调整操作系统底层的IO接口)

  1. 动静分离

    可以使用Nginx+Tomcat相结合的部署方案,Nginx负责静态资源访问,Tomcat负责JSP等动态资源访问处理(因为Tomcat不擅长处理静态资源)

Nginx

NgInx是一个高性能的HTTP和反向代理web服务器,核心特点是占有内存少,并发能力强

  • HTTP服务器(Web服务器)

最大支持50000并发,性能消耗非常小

  • 正向代理

当浏览器想要访问某个网站,不能直接访问时,需要就用代理服务器来代替访问,

所有到服务器的请求和响应要先经过代理服务器再到浏览器。

  • 反向代理服务器

当服务器端只有一台服务器,客户端直接访问服务器。当服务器有多台时,请请求先发到Nginx服务器,在分发给后台服务器,后台服务器对于客户端来说是不可见的。

  • 负载均衡服务器

当一个请求到来的时候,Nginx将请求分发给功能相同的不同服务器

轮询,weight,ip_hash(每个请求安装ip的hash进行分配,每个客户端的请求会固定到同一个目标服务器上。

  • 动静分离

tomcat擅长jsp和Serlet的处理,不擅长静态资源的处理。利用Nginx把请求的静态资源放到特定服务器来处理,动态资源的请求再转发给tomcat服务器。

进程模型

由一个master进程来管理多个Worker进程,worker进程负责处理请求。

  • Reload热加载机制(./nginx -s reload)
  1. master进程对配置文件进行语法检测
  2. 尝试配置(比附修改监听端口,那就尝试分配新的监听端口)
  3. 尝试成功则使用新的配置,新建worker进程
  4. 新建成功,给旧的worker进程发送关闭消息
  5. 旧的worker进程收到信号会继续服务,知道把当前进程接收的请求处理完毕后关闭

所以reload之后worker进程pid是发生了变化的

  • 多进程的好处
  1. 每个worker进程都是独立的,不需要加锁、节省开销
  2. 每个worker进程都是独立的,互不影响,一个异常结束、其他照样能提供服务。

一致性hash

  • 请求的负载均衡(Nginx的ip_hash策略)

    Nginx的Ip_hash可以在客户端ip不变的情况下,将其发出的请求始终路由到同一个目标服务器上,实现会话粘滞,避免处理session共享问题

    如果没有Ip_hash算法,可以维护一张映射表,存储客户端的ip和sessionid与具体目标服务器的映射关系

    缺点:

    在客户端很多的情况下,映射表非常大,浪费内存空间

    客户端上下线,目标服务器上下线,都会导致重新维护映射表,映射表维护成本很大

  • 一致性hash算法的原理

当一致性hash算法的服务节点太少时,容易因为节点分布不均匀而造成数据倾斜问题。为了解决这个问题,引入了虚节点机制,对每个服务节点进行多个hash,每个计算结果的位置都放置这个节点,称为虚节点。

集群时钟同步

  • 每个服务器都是可以联网的

使用ntpdate来从时间服务器同步时间

1
ntpdate -u ntp.api.bz #网络时间同步命令
  • 只有部分服务器可以联网或者所有服务器都不能联网

修改服务器的/etc/ntp.conf文件

把集群中的其他节点都从一台服务器来同步时间

分布式ID

  • UUID

使用起来方便,没有什么规律,不能建立索引

  • 独立数据库的解决方案

建立一个独立的数据库表,利用主键自增的形式来当分布式id

1
select LAST_INSERT_ID();##查询某个表中的最后一条id

所有的id都是由者一台数据库来产生,如果服务器挂了,就无法产生id(不推荐)

  • 雪花算法

Twitter推出的分布式id的算法

符号位+时间戳+机器id+序列号

是连续的,不用借用什么其他的辅助工具。

  • 借助Redis的Incr命令

Redis的Incr命令,将key中存储的数字值增一,如果key不存在,那么key的值会被先初始化为0,然后再执行INCR操作

分布式调度

  • 什么是分布式调度

单体应用时,所有的定时任务都在一个服务器的一套程序中运行;

分布式拆分之后,不同的定时任务会拆分到不同的子系统中去,而不同的子系统又部署了多份。

  • 定时任务和消息队列的区别

共同点

异步处理:比如注册,下单事件

应用解耦:不管定时任务还是MQ都可以作为两个应用之间的齿轮实现应用解耦,这个齿轮可以中转数据,当然单体服务不需要考虑这些,服务拆分的时候往往都会考虑

流量削峰:任务作业和MQ都可以用来抗流量,后端系统根据服务能力定时处理订单或者从MQ抓取到一个订单时间来触发处理,对于前端用户来说看到的结果是已经下单成功了,下单是不受任何影响的。

不同

定时任务是时间驱动,而MQ是时间驱动

时间系统是不可代替的,比如金融系统每日的利息结算,不是说利息来一条就算一下,而往往是通过定时任务批量计算。

所以定时任务作业更倾向于批处理,MQ倾向于逐条处理。

Elastic-Job

当当网开源的一个分布式调度解决方案,基于Quartz二次开发的,由两个相互独立的子项目Elastic-Job-Lite和Elastic-Job-Cloud组成的。Elastic-Job-Lite轻量级无中心化的解决方案,使用jar包的形式提供分布任务的协调服务。

  • 分布式调度协调

    在分布式环境中,任务调度能够按指定的调度策略执行,并且能够避免同一任务多实例重复执行

  • 丰富的调度策略

    基于成熟的定时任务作业框架Quartz cron表达式执行定时任务

  • 弹性扩容缩容

    当集群中增加某一个实例,它应当也能够被选举并执行任务,当集群减少一个实例时,他所执行的任务也能够被转移到别的实例来执行

  • 失效转移

    某实例在任务执行失败后,会被转移到其他实例被执行

  • 错过执行作业重触发

    若因某种原因导致作业错过执行,自动记录错过执行的作业,并在上次作业完成后自动触发。

  • 支持并行调度

    支持任务分片,任务分片是将一个任务分成多个小任务项在多个实例同时执行。

  • 作业分片一致性

    当任务被分片后,保证同一分片在分布式环境中仅一个执行实例。

  • 去中心化

任务分片

Elastic-job可以配置成多个分片,每个机器上线时,自动把任务分给不同的机器处理不同的分片。

  1. 分片项也是一个job配置,修改配置,重新分片,在下次定时任务运行之前会重新调用分片算法,哪台机器运行哪个分片,这个结果存储载zk中,主节点会把分片给分好放到注册中心去,然后执行节点从任务中心获取信息,执行节点在任务开始的时候获取相应的分片
  2. 如果所有节点挂掉,只剩下一个节点,所有分片都会指向这一个节点,这就是elastic-job的高可用。

session一致性问题

  • session问题原因分析

因为Http协议是无状态的协议,客户端和服务端在某次会话中产生的数据不会被保留下来。

Http为什么要设计为无状态协议?早期都是静态页面,无所谓有无状态,后来有动态的内容更丰富,就需要有状态,出现了两种用于保持http状态的技术,那就是Cookie和Session。

解决Session一致性的方案

  • Nginx的IP_Hash策略(可以使用)

    同一个客户端IP的请求都会被路由到同一个目标服务器,也叫做回话粘滞

    优点:

    1. 配置简单,不入侵应用,不需要额外修改代码

    缺点:

    1. 服务器重启Session丢失
    2. 存在单点负载高的风险
    3. 单点故障问题
  • Sesion复制(不推荐)

    多个tomcat之间通过修改配置文件,达到Session之间的复制

    优点:

    1. 不入侵应用
    2. 便于服务器水平扩展
    3. 能适应各种负载均衡策略
    4. 服务器重启或者宕机不会造成Session丢失

    缺点:

    1. 性能低
    2. 内存消耗大
    3. 不能存储太多数据,否则数据越多越影响性能
    4. 有一定的延迟性
  • Session共享,Session集中存储(推荐)

    Session的本质就是缓存,那么就把Sesion数据交给专业的缓存中间件Redis

    优点:

    1. 能适应各种负载均衡策略
    2. 服务器重启或者宕机不会造成Session丢失
    3. 扩展能力强
    4. 适合大集群数量使用

    缺点:

    1. 对应用有入侵,引入了和Redis交互的代码

基于redis的Session共享的原理

相当于添加了一个过滤器,当接收到请求时,会先去redis中查询有没有此Sessionid的数据,如果有就直接使用,如果没有就创建一个Session提交到redis中去。全程不需要使用到tomcat本地的Session。

  • 传统的方式

如果没有上面的提到的Session共享的方式,默认请求来了之后,会去接收到请求的tomcat中去寻找是否有Session,如果没有就在本地创建一个。

HTTP

TCP

三次握手

TCP协议为了保证数据在两端准确连续的流动,两个建立起TCP通道的设备就如同接起了一根水管。TCP为了能让一个设备连接多根水管,它必须保证多个水管之间不会串联或者相互影响。

TCP为了保证数据能够正确的分发,TCP用了一种叫做TCB(传输控制块)的数据结构把发给不同设备的数据封装起来。一个TCB数据块包含了数据发送双方对应的socket信息以及拥有装载数据的缓冲区。

两个设备连接之前,双方都需要做一些准备工作,分配内存建立起TCB数据块就是连接建立前必须要做的准备工作。

  • 准备工作

    最开始客户端和服务端都是处于CLOSED状态。主动打开连接的是客户端,被动打开的服务端

    TCP服务器进程先创建传输控制块TCB,时刻准备接受客户端进程的连接请求,此时服务器就进入了LISTEN(监听)状态。

  • 一次握手

    TCP客户端进程也是先创建TCB传输控制块,然后向服务器发出连接请求报文,这是报文首部中的同部位SYN=1,同时选择一个初始序列号seq=x。此时,TCP客户端进入了SYN-SENT(同步已发送状态)。

    TCP规定,SYN=1报文段不能携带数据,但是需要消耗掉一个序号。

  • 二次握手

    TCP服务器收到请求报文之后,如果同意连接,会发出确认报文。确认报文中应该ACK=1,(确认应答),SYN=1(是同步连接),确认号是ack=x+1(通过确认号用来区分确认的是哪个序号的请求)。同时也要为自己初始化一个序列号seq=y,此时TCP服务器进入了SYN-RCVD(同步收到)状态。这个报文也不能携带数据,但是也要消耗一个序号。

    ACK为1表示确认号有效,为0表示报文中不包含确认信息。

  • 三次握手

    TCP客户端接收到确认后,还要向服务器发出确认,确认报文的ACK=1,ack=y+1,自己的序列号seq=x+1,此时TCP建立连接,客户端自己变成ESTABLISHED(已建立连接)状态。TCP规定,ACK报文段可以携带数据,如果不携带数据就不消耗序号。

    服务器接收到确认后,也进入已建立连接状态,此后双方就可以开始通讯了。

  • 为什么TCP客户端最后开药发送一次确认呢?

为了防止已经失效的连接请求报文突然有传送到服务器,从而产生错误。

假设不要发送第三次确认,如果客户端第一次建立连接请求网络出现波动,客户端又重试了一次,此时客户端和服务端已经建立了一个连接。但是由于延迟,突然第一次的连接请求又发送到了服务端,此时服务端就会和客户端创建了两个TCP连接。会导致错误和资源浪费。

如果有第三次握手,就算第一次建立连接报文又被接收到,服务端会回复第一条的确认报文,但客户端会根据序号不在发出第一条的过期确认报文给服务端。这样可以避免上面的情况。

  • 为什么要三次握手?

三次握手是为让客户端和服务端双方都确认自己和对方的收,发能力正常。

第一次握手:客户端给服务端发送请求。服务端确认到:客户端的发送能力,服务端的接收能力正常。

第二次握手:服务端给客户端发送请求。客户端确认到:客户端收发能力,服务端收发能力正常。

第三次握手:客户端给服务端发送确认报文,服务端确认到:客户端的接收能力正常,双方可以建立对应的正确连接。可以正常通讯。

  • TCP协议缺陷

DDOS又称分布式拒绝服务,利用合理的请求造成服务器资源过载,导致服务不可用。SYN flood是一种最为经典的DDOS攻击。他利用了TCP协议设计中的缺陷,而TCP/IP协议是整个互联网的基础,牵一发而动全身,如今修复这个缺陷几乎不可能。

SYN food攻击的原理

  1. 首先伪造大量的源ip地址,分别向服务端发送大量的SYN包。
  2. 服务端返回SYN/ACK包,因为源地址是伪造的,所以伪造的ip并不会应答
  3. 服务器端没有收到伪造ip的回应,会重试三到五次,并且等待一个SYN Time(一般是30秒到2分钟)如果超时才会丢弃这个连接
  4. 攻击者大量发送这种伪造源地址的SYN请求,服务器端会消耗非常多的资源来处理这种半连接,同时还要不断的对这些ip做SYN+ACK重试
  5. 导致服务器无暇理睬正常的连接请求,导致拒绝服务。

四次挥手

  1. TCP客户端发送一个FIN,用来关闭客户到服务器的数据传送。
  2. 服务器收到这个FIN,返回一个ACK,确认序号为收到序号加1,和SYN一样,一个FIN将占用一个序号。
  3. 服务器关闭客户端的连接,发送一个FIN给客户端。
  4. 客户端发回ACK报文确认,并将确认序号设置为收到序号加1。
  • 为什么客户端最后还要等待2MSL?

    1. 保证客户端发送的最后一个ACK报文能够到达服务器,因为这个报文可能会丢失,服务器已经发送了FIN+ACK报文请求断开了,客户端还没有回应,服务器认为它发送的请求客户端没有收到,于是服务器又重新发送一次,而客户端就可以在这2MSL时间内收到重新传的报文,接着给出回应报文,并且重新计算2MSL计时器。
    2. 等待2MSL时间,客户端可以放心的释放TCP占用的资源,端口号,如果不等,释放的端口可能会重连刚断开的服务器端口,这样依然存活在网络里的老TCP报文可能于新TCP连接报文冲突,造成数据冲突。等待2MSL可以让老的TCP连接报文全部失效。
  • 如果已经建立了连接,但客户端突然出现故障了怎么办?

TCP有一个保活计时器,如果服务器两小时没收到客户端的任何数据,服务器就会发送一个探测报文,以后每隔75秒发送一次,发送10个后,服务器关闭连接。

TCP数据传输

TCP传输是分段的,一个HTTP相应报文会被操作系统切分成多个MSS大小的端,知道接收端接收到完整的报文为止。在此过程中,报文分段按照顺序发送,没个报文段在发送时,会做顺序编号,以便能够完整正确地组装。

主机一般默认MSS为536字节

  • 端口号:

表示同一个算计上的不同端口

源端口号和目标端口号占用两个字节

TCP的源端口号和目标端口号以及IP报文中的源IP和目标IP就可以确认一条唯一的TCP连接

  • 序号:seq,4个字节。16位

确认序号:ack,确认回复的哪个序号的报文,4个字节,16位

  • 4位首部长度,6位保留位。
  • 控制位:6位

URG:1.紧急指针有效,0,无连接的指针

ACK:1.确认号有效,0,忽略确认号

PSH:1.接收方接到次报文 ,优先交给应用程序处理,0.优先回复

RST:用来重置连接,和拒绝非法的报文段

SYN:1.同步序列号,

FIN:结束标志,1为之后没有数据再发送了、

  • 窗口大小(滑动窗口大小)16位

告诉接收端,发送端的窗口大小是多少

  • 16位检验和

发送端生成,接收端来校验,类似现在下载的MD5校验

  • 16位紧急指针

和序号相加表示数据段中的最后一个数据

  • 选项

存放TCP数据的大小

  • 数据

存放数据。

滑动窗口协议

可靠性;保证数据确实到达目的地,如果未到达,能够发现并重传。

数据流控制:管理数据的发送速率,以使接收设备不至于过载

TCP协议的一种应用,御用网络传输的流量控制,避免发生阻塞。采用的滑动窗口算法

  • 丢包情况

如果一个已发送的数据包迟迟等不到ACK确认,就触发超时重发机制

每发送一个数据包,就维护一个计时器,如果计时器时间内没有收到ACK确认,就重新发送数据,如果重试找过一定次数,就会判断是网络出现了异常。(类似于TCP握手和挥手时客户端和服务器的超时重试机制)

TCP的性能

  • HTTP事务的时延主要原因
  1. 第一次连接时,通过DNS解析系统将URL中的主机域名转换成一个IP地址要花费对应的时间

  2. 在HTTP1.0和之前的版本,如果拥有数百个HTTP事务的话,建立连接的时间会非常的高。

  3. 网络传输请求报文和服务器处理请求报文都需要时间。

  4. web服务器会回送HTTP响应的花费时间

  • 延迟确认(ACK)

    在客户端给服务端发送了一条请求报文后,之前服务器会立刻给客户端发送一个收到了对应报文的ACK确认报文,这个报文数据量非常小。TCP发明了延迟确认算法,收到客户端报文后,不立刻返回ACK,而是等待100-200毫秒的窗口时间,再给客户端发送ACK确认报文。如果窗口时间内,服务器正好有数据要发送给客户端,就可以把数据和ACK确认报文一起发送过去。

    通常,延迟确认算法会引入相当大的时延。

  • TCP慢启动

    主机发送数据包时,如果一次发送大量的数据,可能会出现网络的阻塞。慢启动算法就是说第一次只发送一小段的数据,如果对方返回成功接收的报文,主机就发送两段数据,以此类推,主机发送的数据会越来越大。但这种算法也同样导致了发送数据的时间增加。

  • Nagle算法与TCP_NODELAY

    由于TCP的报文是分段传输的,而且每一段的大小没有限制,Nagle算法为了尽可能的时每一段数据的量最大,规定了在一个TCP通道里,只能有一个不完全满的数据包。这有就导致,一个请求,客户端如果发送了一个不是最大容量的包,就必须等服务端发送ACK确认此不满包后,才能发送下一次不满包。加上延迟确认机制,将大大的导致延迟。

    应用程序通常在自己的栈中设置参数TCP_NODELAY,禁用Nagle算法,Tomcat通过Server.xml进行设置,默认是true。

  • TCP事务的发展

串行:一个事务连接结束之后,才能和另一个事务连接。

并行:可以同时和多个事务连接,这样会消耗非常多的性能

持久连接:当事务间的连接结束后,不关闭通道,等后面又需要发送数据时,直接只用之前的通道。

管道化连接:在客户端想要发送多条请求时,先放入队列中,当第一条请求到达服务器后,不管服务器有没有响应,都会继续发送下一条请求。

  • 管道化连接的限制
  1. 必须按照请求相同的顺序返回HTTP响应,所以就算后面的请求先被处理完了,也要等先接收到的请求处理后被响应后才能返回。这样就会导致头部阻塞,如果一个先接收到的请求迟迟没有被处理完成,那么后面所有的响应都无法返回。
  2. HTTP客户端必须做好连接会在任意时刻关闭的准备,客户端发送了十个请求给服务器,服务器可能在只处理了五个请求后关闭连接,剩下的五个请求会处理失败,客户端必须能够重新发送这些失败的请求。
  3. 只有幂等性的请求才建议管道化,不应该用管道化发送会产生副作用的请求,(POST请求)由于无法安全的重发POST这样的非幂等请求,所以出错时,就存在某些方面永远不会被执行的风险。
  • SPDY

SPDY没有完全改写HTTP协议,而是在TCP/IP的应用层与传输层之间通过新加会话层的形式运作。同时考虑安全性问题,SPDY中使用了SSL。

HTTP2.0

二进制分帧(frame)

二进制分帧是HTTP2.0性能的核心。

在二进制分帧层上,HTTP2.0将传输的信息分割为更小的消息和帧,并将他们采用二进制格式的编码,其中HTTP1.*的首部信息会被封装到Header帧,request body则被封装到Data帧里,帧是数据传输的最小单位,以二进制传输代替原本的明文传输。

HTTP2.0所有的通信都在一个连接(TCP连接)上完成,这个连接可以承载任意数量的双向数据流。相应的,每个数据流以消息的形式发送,而消息由一个或多个帧组成,这些帧可以乱序发送,然后再根据每个流首部的流标识符重新组装。

HTTP性能的关键在于低延迟而不是高带宽! 大部分HTTP连接的时间都很短,而且是突发性的,但TCP只在长时间连接传输大块数据时效率才最高。HTTP2.0通过让所有数据流公用同一个连接,可以更有效的使用TCP连接,让高带宽也能真正服务于HTTP的性能提升。

  • 单连接多资源方式的好处:
  1. 可以减少服务连接压力,内存占用少了,连接吞吐量大了
  2. 由于TCP连接减少而使网络阻塞状态得以改观
  3. 慢启动时间减少,拥塞和丢包恢复更快。

头部压缩(HPACK)

头部下所需要双方都支持HTTP2.0:

  • 维护一份相同的静态表,包含常见的头部名称和值。
  • 维护一份相同的动态表,当一个header name或者header value在静态表里不存在,会被插入动态表中,可以动态的添加内容。索引从62开始。

动态表,第一次发送的时候需要明文发送(要经过Huffman编码),第二次和以后的发送表的索引号。

多路复用

http2.0连接都是持久化的,而且客户端和服务器之间只需要一个连接,http2连接可以承载数十个或数百个流的复用,多路复用意味着来自很多流的数据包能够混合在一起通过同样连接传输。当到达终点时,再根据不同帧首部的流标识重现还原进行组装。

  • http2.0的性能瓶颈

HTTP2启动后的性能获得了很大的提升,但TCP是下一个性能瓶颈。

单个TCP 丢失导致整个连接阻塞,因为流传输必须让每个请求都是有序的。此时所有的请求都会收到影响。

  • http的安全风险
  1. 窃听风险:通讯使用明文,明文报文不具备保密性,内容可能被窃听
  2. 冒充风险:不验证通信方的身份(不进行身份验证),有可能遇到伪装
  3. 篡改风险:无法证明报文的完整性,有可能已经篡改

HTTPS

HTTPS并非应用层新的协议,通常HTTP直接和TCP通信,HTTPS则先和安全层(TLS)通信,然后安全层再和TCP层通信。

  1. 所有的信息都是加密传输的,第三方无法窃听
  2. 配备身份验证(服务端程序),防止身份被冒充
  3. 具有校验机制,一旦被篡改,通信双方会立刻发现

HTTPS工作原理

HTTPS是身披TLS外壳的HTTP

  • 记录协议:

    TLS记录协议位于TLS握手协议的下层,是负责使用对称密码对消息进行加密通信的部分。

    加密使用的秘钥是通过握手协议在双方之间协商决定的。

  • 握手协议(有密码规则变更协议和警告协议组成)

    负责在客户端和服务器之间协商确定密码算法和共享秘钥

    密码规则变更协议负责向通信对象传达变更密码方式的信号,当协议中途发生错误,就会通过警告协议传达给对方。

    警告协议是负责在发生错误时,把错误传达给对方。

  • HTTPS和HTTP协议比较

  1. 数据完整性:内容传输经过完整性校验
  2. 数据隐私性:内容经过对称加密,每个连接生成一个唯一的加密秘钥
  3. 身份认证:第三方无法伪造服务端(客户端)身份

对称加密算法

同一个秘钥既可以用来加密,也可以用来解密,被称为对称加密算法,也叫单秘钥加密。

加密三要素:原文,秘钥,算法

一般秘钥越大,密码越安全,但是加解密的时间也越长

  • 算法

DES:数据加密标准(现在使用较少,因为加密强度不够,能够暴力破解)

3DES:原理和DES几乎一样,只是使用了3个密钥,对相同的数据执行三次加密,增强加密强度。(缺点:要维护三个密钥,大大增加了维护成本)

AES:高级加密标准,用来替代原先的DES,目前美国国家安全局使用,苹果就是采用的AES加密。是目前公认最安全的加密方式,是对称密钥加密中最流行的算法。

  • 优点:算法公开,计算量小,加密速度快。
  • 缺点:不算特别安全,只有一把密钥,密文如果被拦截,却密钥也被劫持,那么,信息很容易被破解。

非对称加密算法

非对称加密是计算机通信的基石,保证了加密数据不会被破解。

非对称加密需要两个密钥,公钥和私钥。

如果用公钥加密,只能用对应的私钥解密。

如果用私钥加密,只能用对应的公钥加密。

由于算法复杂,加密,和解密速度没有对称加密的速度快。由于有两个密钥,这样不需要像对称加密那样给对方传输密钥,这样就安全很多。

  • 在生产中,对称加密和非对称加密结合使用

目前已知:

非对称加密,加密的安全性要远高于对称加密,但性能远远低于对称加密

所以使用非对称加密协商出对称加密的秘钥进行通信。

具体执行步骤:

  1. 客户端先向服务器请求非对称加密的公钥
  2. 服务器返回非对称加密的公钥
  3. 客户端生成随机数,用非对称公钥来加密随机数给服务器
  4. 服务器使用非对称私钥来解密随机数,把随机数当成对称加密的公钥,加密后发给客户端
  5. 之后所有的数据都是用此随机数当对称加密的公钥来传输数据

存在的问题

如果有第三方伪装成服务器来和客户端交互,再转发给服务器,这样就可以得到客户端和真服务器之间对称加密的随机数。

解决上面的问题可以通过下面两个方案

报文被篡改—数字签名

通信方身份伪装—-数字证书

数字签名

主要功能:

确认消息的发送方没有问题,确认消息的完整性,证明数据没有被修改

  • 数字签名的过程
  1. 发送方用hash算法(也可以用MD5加盐的形式)把明文哈希
  2. 然后用自己的私钥把hash后的数据加密
  3. 把原文和加密后的数据一起发送给服务器
  4. 服务器用公钥解密数据
  5. 然后用相同的hash算法hash接收到的明文。和发送来的hash数据进行比较
  • 上面方式存在的缺陷

如果第一次发送方给服务器发送自己公钥时,发送到了伪装的服务上,伪装服务器还是可以得到发送方的数据,但是不能修改。

数字证书

有一个觉的权威几个可以颁发证书,在每次连接之前,客户端会先向服务器请求证书,检查证书是否正确,来校验接收方是否正确。

  • TSL完整的过程
  1. 浏览器给出TLS协议的版本号,一个客户端生成的随机数,以及客户端支持的加密方式。
  2. 服务器确认双方使用的加密方式,并给数字证书,以及一个服务器生成的随机数
  3. 浏览器确认数字证书有效,然后生成一个新的随机数,并使用数字证书作为公钥,加密这个随机数
  4. 服务器使用自己的私钥,获取客户端发来的随机数
  5. 客户端和服务器根据约定的加密方式,使用前面的三个随机数,生成“对话密钥”,用来加密加来整个过程
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计