06-HTTP探索

124 阅读10分钟

HTTP探索

Nginx

进程池

Nginx是一个轻量级的Web服务器,因为其CPU、内存占用都非常少同样的资源配置下就能够为更多的用户提供服务

之前的服务器都是是多线程的,这样会存在创建进程或线程的成本,还会有进程线程上下文切换的额外开销

Nginx则没有使用多线程,而是使用进程池和单线程的工作模式

Nginx在启动的时候会先创建好固定数量的worker数量,在之后的运行过程中不会再fork出新进程,这就是线程池

可以自动把进程绑定到独立的CPU上,这样就完全消除了进行创建和切换的成本,能够充分利用多核CPU的计算能力

进程池之上还有一个master进程,专门用来管理进程池,监控进程,自动恢复发生异常的worker,保持进程池的稳定和服务能力

I/O多路复用

由于Nginx采用单线程的方式,开发简单,没有互斥锁的成本,但是其处理能力能够超越其他多线程服务器

这是因为Nginx使用了I/O多路复用接口epoll

把多个HTTP请求处理打散成碎片,都复用到一个单线程中,不按照先来后到的顺序处理,而是只当连接上真正可读可写的时候才处理,可能发生阻塞就立马切换出去,处理其他请求

又因为网络收发并不会消耗太多的CPU计算能力,也不需要却换进程、线程,所以整体的CPU负载是很低的

epoll还有一个特点,大量的连接管理工作都是在操作系统内核中做的,这就减轻了应用程序的负担,所以Nginx可以为每个连接分配很小的内存维护状态

多阶段处理

Nginx处理HTTP请求的方式是通过化整为零的方式处理的

把整个Web服务器分解成多个功能模块,实现高度的灵活性和扩展性

Nginx的HTTP处理有四大类模块:

  • handler模块:直接处理HTTP请求
  • filter模块:不直接处理请求,而是加工过滤响应报文
  • upstream:实现反向代理,转发请求到其他服务器
  • balance:实现反向代理的负载均衡算法

职责链:像工厂中的流水线,原料从一头流入,工程会进行各种加工,另一头流出完整产品

Nginx中的handler和filter就是这种模式,HTTP报文是原材料,各个模块就是工厂里的工人,走完模块构成的流水线,出来的就是处理完成的响应报文

OpenResty

Nginx也存在一些缺点,比如Nginx的配置每次修改后都需要重启才能生效

这对于频繁变动业务是非常麻烦的,仅仅增加一行或者删除一行就要分发,重启所有机器,这样成本很高

所以现在又出现了一个Web服务器OpenResty没有Nginx的缺点,又轻量、高性能、灵活、可动态配置

OpenResty是什么

OpenResty基于Nginx,利用了其模块化,可扩展性的特性,开发了一系列增强模块

OpenResty的核心虽然是Nginx,但是又超过了Nginx,关键在于其**ngx_lua模块**,他把小巧灵活的Lua语言嵌入了Nginx,可以用脚本的方法操作Nginx内部的进程、多路复用、阶段式处理等各种构件

脚本语言的好处:不需要编译,随写随执行

动态的Lua

Lua的设计目标是嵌入到其他应用程序中运行的,为其他编程语言提供脚本化的能力

作为脚本语言,Lua还有一个重要的代码热加载特性,不需要重启进程,就能够从磁盘、Redis或者其他地方加载数据,随时替换内存中的代码片段

使用OpenResty就能实现永不停机在微秒毫秒级别实现配置和业务逻辑的实时更新

高效率的Lua

同步非阻塞的编程方式是OpenResty高效运行的基础

但是同步非阻塞本质上还是一种多路复用,但是还是有区别的

  • epoll是操作系统级别的多路复用,运行在内核空间;而OpenResty则是基于Lua内建的协程,是应用程序级别的多路复用,运行在用户空间,所以消耗资源更少
  • OpenResty每一段Lua程序都由携程来调度运行,发生阻塞则马上切换出去,执行其他程序

阶段式处理

OpenResty也使用流水线来处理HTTP请求,底层运行基础是Nginx的阶段式处理

Nginx的流水线是由一个个C模块组成的,只能在静态文件中配置,开发麻烦,配置麻烦

OpenResty流水线则是由一个个Lua脚本组成的,可以从磁盘上加载,也可以从Redis、MySQL加载,编写调试方便快捷

WAF

HTTPS只是保证了通信链路的安全,但是对于通信链路的两端,也就是客户端和服务器,就不能提供保护了

Web服务遇到的威胁

这有几种常见的攻击Web服务的方式:

  • DDos(洪水攻击):黑客控制许多僵尸计算机,向目标服务器发起大量的无效请求,服务器由于不能区别正常用户和黑客,所以会全收,这样就会挤占了正常用户应有的资源,如果攻击强度很大,那么就会对网站的服务能力造成冲击,耗尽带宽、CPU和内存,导致网站无法正常提供服务

    这种方式技术含量比较低,不涉及HTTP协议内部细节

  • SQL注入利用了服务器字符串拼接形成SQL语句的漏洞,构造出非正常的SQL语句,获取数据库内部的敏感信息

  • HTTP头注入在Host、User-Agent等字段加上了恶意数据或代码,服务器如果解析不当,则会执行预设的恶意代码

  • XSS攻击跨站脚本攻击,属于JS代码注入,利用JS脚本获取未设防的Cookie

网络应用防火墙

传统的防火墙只工作在三层或四层,隔离了外网和内网,使用预设的规则,只允许某些IP地址和端口号的数据包通过,拒绝不符合调教的数据流入或流出内网,实际上是一种网络数据过滤设备

网络应用防火墙也就是WAF工作在七层看到的不仅是IP地址和端口号,还能看到整个HTTP报文,所以就能够对报文做更深入细致的审核,使用更复杂的规则来过滤数据,实际上是一种HTTP入侵检测和防御系统

一款产品称为WAF需要具备的功能:

  • IP黑名单和白名单,拒绝黑名单访问,或者只允许白名单访问
  • URI黑名单和白名单,类似于上一代你,允许或禁止对某些URI进行访问
  • 防护DDos攻击对特定的IP地址限连限速
  • 过滤请求报文,防御代码注入攻击
  • 过滤响应报文,防御敏感信息外泄
  • 审计日志,记录所有检测到的入侵操作

Nginx实现IP地址黑名单:

 map $remote_addr $blocked {
     default     0;
     "1.2.3.4"   1;
     "5.6.7.8"   1;
 }
 if($blocked){
     return 403 "you are blocked"
 }

CDN

现在我们可以使用HTTPS强化通信链路安全,使用HTTP/2优化传输效率;使用Nginx/OpenResty提升网站服务能力,WAF抵御网站入侵攻击

现在我们来了解一个外部加速HTTP协议的服务,就是CDN,即内容分发网络

为什么要有网络加速

虽然说现在的HTTP传输并不算差,但是在现实中,可能由于各种因素的影响,还是会存在传输慢的情况

在实际中,电缆的传输速度会比光速慢三分之一(20万公里/秒),虽然说这个速度还很快,但是如果距离足够长,那么就会产生一定的时延

并且,互联网是一张大网,由许多小网络组成,小网络内沟通很顺畅,但是网络之间只有很少的联通点,而宽带有限,所以还是会带来延迟的

网络中还存在许多路由器和网关,数据每经过一个节点都会停顿一下,这也会消耗时间带来时延

什么是CDN

CDN就是专门解决长距离访问速度慢而诞生的一种网络应用服务

CDN有三个关键词:内容、分发、网络

  • 网络

    CDN的核心原则是就近访问,所以如果用户能在本地几十公里的距离内获取到数据,那么时延就近似于0了

    所以CDN在全国乃至全球各大枢纽城市建立了机房,部署了大量拥有高存储高带宽的节点,构建了一个专用网络

    这个专用网络是跨运营商的、跨地域的,基本上可以认为不存在网络拥堵

  • 分发

    把源站的内容逐级缓存到网络上的每一个节点上

    所以用户在上网的时候就不需要直接访问源站了,而是访问离他最近的一个CDN节点,也叫做边缘节点,这样就可以省去长途跋涉的时间成本了,实现网络加速

  • 内容

    内容其实是HTTP协议中的资源,如超文本、图片、视频等

    资源又分为静态资源和动态资源,静态资源可以被缓存加速、就近访问,但是动态资源只能由源站实时生成,缓存了也没有意义,不过也可以做短暂的缓存(使用Cache-Control),可以被CDN缓存加速

CDN负载均衡

CDN两个关键组成部分:全局负载均衡和缓存系统

全局负载均衡一般简称GSLB,主要用于用户接入网络的时候在CDN专网挑选出一个最佳节点提供服务,解决的是用户如何找到最近的边缘节点,对整个CDN网络进行负载均衡

GSLB最常见的实现方式是DNS负载均衡

权威DNS返回的不是IP地址,而是一个CNAME别名记录,指向的就是CDN的GSLB,因为没拿到IP地址,所以本地DNS就会向GSLB再发起请求,这样就进入了CDN的全局负载均衡系统,开始智能调度:

  • 看用户的IP地址,查表得知地理位置,选择最近的边缘节点
  • 看用户的运营商网络,找相同网络的边缘节点
  • 检查边缘节点的负载情况,选择负载轻的边缘节点

把上面这些因素综合,找出最合适的边缘节点返回给用户

CDN缓存代理

如果缓存系统的服务能力不够,那么即便GSLB算法再优秀也没用

由于资源无穷无尽,所以缓存系统只能缓存最常用的那些资源

这里有两个关键概念:命中和回源

  • 命中:用户访问的资源刚好在缓存系统中,可以直接返回给用户
  • 回源:缓存中没有用户访问的资源,所以需要用代理的方式回源站取
  • 命中率:命中次数与访问次数之比
  • 回源率:回源次数与访问次数之比

提高命中率,降低回源率的方法:

  • 从存储系统下手,采用高速CPU、大内存等硬件
  • 划分一级缓存节点和二级缓存节点
  • 使用高性能的缓存服务

\