这是我参与「第三届青训营 -后端场」笔记创作活动的的第6篇笔记
本文主要介绍了网络接入核心组件及基本原理,其中包括了DNS解析,HTTPS接入,全站加速接入,四层负载均衡及七层负载均衡等
课程实验参考:网络与部署
网络访问域名主要经过哪些过程
主要访问过程包括了DNS解析-TCP连接-TLS握手-HTTP请求等,这个过程中包括了网络OSI各个层级的协议沟通,下图显示了网络接入过程中涉及的一些关键技术和组件
域名系统和DNS
域名空间
- 域名空被组织成树形结果,通过划分zone的方式进行分层授权管理
- 全球公共域名空间仅对应一棵树
- 根域名服务器的主要作用便是作为查询起点
- 域名组成格式:[a-zA-Z0-9_-],以点划分label
DNS解析过程
DNS即Domain Name System,是域名解析服务的意思。它在互联网的作用是:把域名转换成为网络可以识别的ip地址。人们习惯记忆域名,但机器间互相只认IP地址,域名与IP地址之间是一一对应的,它们之间的转换工作称为域名解析,域名解析需要由专门的域名解析服务器来完成,整个过程是自动进行的。
如下图所示,DNS的解析过程包括(来自:一张图看懂DNS域名解析全过程 - ximu-xin - 博客园 (cnblogs.com)):
- 输入www.163.com时,电脑会发出一个DNS请求到本地DNS服务器。
- 本地DNS服务器收到查询请求时,本地DNS服务器会首先查询它的缓存记录,如果缓存中有此条记录,就可以直接返回结果。如果没有,本地DNS服务器还要向DNS根服务器进行查询。
- 根DNS服务器没有记录具体的域名和IP地址的对应关系,而是告诉本地DNS服务器,你可以到域服务器上去继续查询,并给出域服务器的地址。
- 本地DNS服务器继续向域服务器发出请求,在这个例子中,请求的对象是.com域服务器。.com域服务器收到请求之后,也不会直接返回域名和IP地址的对应关系,而是告诉本地DNS服务器,你的域名的权威DNS服务器的地址。
- 本地DNS服务器向权威DNS服务器发出请求,这时就能收到一个域名和IP地址对应关系,本地DNS服务器不仅要把IP地址返回给用户电脑,还要把这个对应关系保存在缓存中,以备下次别的用户查询时,可以直接返回结果,加快网络访问。
DNS记录类型
- A/AAAA:IP指向记录,用于指向IP,前者为IPv4记录,后者为IPv6记录
- CNAME:别名记录,配置值为别名或主机名,客户端根据别名继续解析以提取IP地址
- TXT:文本记录,购买证书时需要
- MX:邮件交换记录,用于指向邮件交换服务器
- NS:解析服务器记录,用于指定哪台服务器对于该域名解析
- SOA 记录:起始授权机构记录,每个zone有且仅有唯一的一条SOA记录,SOA是描述zone属性以及主要权威服务器的记录
权威DNS架构
常见开源DNS:bind、nsd、knot、coredns
涉及过程:
- DNS Query
- DNS Response
- DNS Update
- DNS Notify
- DNS XFR
常用名词解释
- 权威DNS:保存了相应域名的权威信息。权威DNS即通俗上“这个域名我说了算”的服务器
- LocalDNS:缓存+递归查询,运营商(集团网)部署的本地DNS服务器,直接接受网内客户端请求
- 根DNS服务器:全球有13台,LocalDNS未命中缓存查询的起点服务器
- DNS Update:DNS主服务器master接受外部的变更指令
- DNS Notify:DNS主服务器master接受变更命令后,会自增自身的serial号,同时将变更的serial号告知从服务器slave
- DNS IXFR:DNS从服务器slave以增量的形式向master要求获取本次变更的内容
- DNS AXFR:DNS从服务器slave以全量的形式向master要求获取当前的全量数据
接入DNS服务
HTTPS协议
相关知识可以参考学习:
HTTPS涉及SSL的通信,这是建立在TCP三次握手之前的操作,主要用于协商通信双方的对称加密密钥,在此强调一下过程
- client hello: 客户端通过发送"client hello"消息向服务器发起握手请求,该消息包含了客户端所支持的 TLS 版本和密码组合以供服务器进行选择,还有一个"client random"随机字符串。
- server hello消息: 服务器发送"server hello"消息对客户端进行回应,该消息包含了数字证书,服务器选择的密码组合和"server random"随机字符串。
- 验证: 客户端对服务器发来的证书进行验证,确保对方的合法身份,验证过程可以细化为以下几个步骤(更多验证的详情详见上述链接):
- 是否是可信机构颁布
- 域名是否跟实际访问的一致
- 检查数字签名
- 验证证书链
- 检查证书的有效期
- 检查证书的撤回状态
- premaster secret字符串: 客户端向服务器发送另一个随机字符串"premaster secret (预主密钥)",这个字符串是经过服务器的公钥加密过的,只有对应的私钥才能解密。
- 使用私钥: 服务器使用私钥解密"premaster secret"。
- 生成共享密钥:客户端和服务器均使用 client random,server random 和 premaster secret,并通过相同的算法生成相同的共享密钥 KEY。
- 客户端就绪: 客户端发送经过共享密钥 KEY加密过的"finished"信号。
- 服务器就绪: 服务器发送经过共享密钥 KEY加密过的"finished"信号。
- 达成安全通信: 握手完成,双方使用对称加密进行安全通信。
验证过程中涉及的重要概念
- 对称加密:使用相同的秘钥来加密传输内容,一端加密后,对端收到数据会用相同的秘钥来解密
- 非对称加密:如果用公钥对数据进行加密,只有用对应的私钥才能解密;如果用私钥对数据进行加密,那么只有用对应的公钥才能解密。
- 数字证书:由证书认证机构 (Certificate Authority, 简称 CA)签发给服务器的认证证书,其中包括了证书所有者的公钥、证书所有者的专有名称、证书颁发机构的专有名称、证书的有效起始日期等信息,在进行https通信时,服务器会把公钥连同证书一起发送给客户端,私钥则由服务器自己保存以确保安全。
- 数字签名:主要是为了确保数据发送者的合法身份,也可以确保数据内容未遭到篡改,保证数据完整性,在数字证书的应用场景中,数字签名的生成和验证流程如下:
- 服务器对证书内容进行信息摘要计算 (常用算法有 SHA-256等),得到摘要信息,再用CA私钥把摘要信息加密,就得到了数字签名
- 服务器把数字证书连同数字签名一起发送给客户端
- 客户端用CA公钥解密数字签名,得到摘要信息
- 客户端用相同的信息摘要算法重新计算证书摘要信息,然后对这两个摘要信息进行比对,如果相同,则说明证书未被篡改,否则证书验证失败https
基于nginx配置https
- 增加443端口转发四层配置
upstream hello_proxy_ssl {
server 10.227.89.58:8443;
}
server {
listen 443;
proxy_connect_timeout 1s;
proxy_timeout 300s;
proxy_pass hello_proxy_ssl;
}
- server块增加ssl配置
server {
listen 880;
listen 8443 ssl;
server_name www.example.com;
# 引用中间CA证书
ssl_certificate /etc/nginx/ssl/TestIntermediateCA.pem;
ssl_certificate_key /etc/nginx/ssl/TestIntermediateCA.key;
# 引用域名证书
ssl_certificate /etc/nginx/ssl/_.example.com.pem;
ssl_certificate_key /etc/nginx/ssl/_.example.com.key;
# 自动跳转到HTTPS
if ($server_port = 880) {
rewrite ^(.*)$ https://$host$1 permanent;
}
...
}
接入全站加速
外网用户访问站点时,可能出现诸多问题,从而出现“响应慢,卡顿”的错觉,比如:
- 源站容量低,可承载的并发请求数低,容易被打垮
- 报文经过的网络设备多,出现丢包、劫持、mtu等问题
- 自主选路网络链路长,时延高 对于源站容量问题,可以增加后端机器扩容;静态内容使用静态加速缓存;对于网络传输问题,是哦那个动态加速DCDN;全站加速则是静态加速+动态加速,什么是全站加速 (aliyun.com)
概念介绍
静态加速:针对视频、图片等不变的内容,将其缓存在靠近用户的边缘节点,缓存预热后用户直接从边缘获取,从而加速访问速度;
动态加速DCDN:针对API类返回值不同的请求,通过特殊的网络优化方式(路由优化、传输优化)等技术加速其达到源站的速度
CDN:CDN的全称是(Content Delivery Network),即内容分发网络。其目的是通过在现有的Internet中增加一层新的CACHE(缓存)层,将网站的内容发布到最接近用户的网络”边缘“的节点,使用户可以就近取得所需的内容,提高用户访问网站的响应速度。从技术上全面解决由于网络带宽小、用户访问量大、网点分布不均等原因,提高用户访问网站的响应速度。
静态加速
个人认为就是对静态资源的缓存处理,参考:CDN加速原理
基于传统方式:
基于DNS方式:
动态加速
针对POST请求等不能在边缘缓存的业务,基于智能选路技术,从众多回源线路中择优选择一条线路进行传输
架构上可以划分为边缘节点,汇聚节点和核心机房
在上图示例中,
如果直接访问核心机房,需要耗时:35(TCP)+35*2(TLS)+35(routine) = 140ms 如果通过DCDN,需要耗时:20(TCP)+20*2(TLS)+ 20 + 10+ 10(routine) = 100ms(边缘节点到汇聚及汇聚到核心的tls握手耗时已经在最开始的服务启动中已经预热连上了)
场景应用
- 用户登录,注册等操作:动态加速DCDN
- 抖音用户点击某个特定的短视频加载后观看:静态加速CDN
- 用户打开新闻官网进行网页浏览:静态+动态加速
使用接入全站加速
四层负载均衡
基于IP+端口,利用某种算法将报文转发给某个后端服务器,实现负载均衡地落到后端服务器上,主要具有解耦vip和rs;NAT;防攻击:syn proxy等功能.
- VIP:虚拟IP,一般作为四层反向代理的入口,client看起来一直在与VIP交互
- RS:Real Server,VIP后实际承受client请求的服务,可能是物理机/虚拟机/容器POD
常用调度算法
- RR轮询:Round Robin,将所有的请求平均分配给每个真实服务器RS
- 加权RR轮询:给每个后端服务器一个权值比例,将请求按照比例分配
- 最小连接:把新的连接请求分配到当前连接数最小的服务器
- 五元组hash:根据sip、sport、proto、dip、dport对静态分配的服务器做散列取模(缺点:当后端某个服务器故障后,所有连接都重新计算,影响整个 hash 环)
- 一致性hash:只影响故障服务器上的连接session,其余服务器上的连接不受影响
常见的实现方式 FULLNAT
特点
- 大部分都是通过 dpdk 技术实现,技术成熟,大厂都在用
- 纯用户态协议栈,kernel bypass,消除协议栈瓶颈
- 无缓存,零拷贝,大页内存(减少 cache miss)
- 仅针对4层数据包转发,小包转发可达到限速,可承受高 cps
开源的解决方案
基于LVS+keepalived实现 wsgzao.github.io
基于nginx的四层负载均衡实现
- 将到达本机的53端口的udp报文转发到DNS服务器
- 将到达本机的1234端口的tcp报文转发到自己准备的backend后端服务上
- 还可以转发到unix socket
编辑/etc/nginx/nginx.conf,新增stream模块,若nginx未安装stream模块,则自行添加stream模块或者重新编译nginx即可。
#四层转发,tcp/udp协议转发
stream {
log_format proxy '$remote_addr [$time_local] '
'$protocol $status $bytes_sent $bytes_received '
'$session_time "$upstream_addr" '
'"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"';
access_log /var/log/nginx/access.log proxy;
open_log_file_cache off;
upstream dns_proxy {
server 10.227.89.58:8053;
}
upstream backend {
server 10.227.89.58:8080;
}
server {
listen 53 udp reuseport;
proxy_pass dns_proxy;
}
server {
listen 1234;
proxy_connect_timeout 1s;
proxy_timeout 300s;
proxy_pass backend;
}
server {
listen [::1]5678;
proxy_pass uinx:/tmp/stream.socket;
}
}
使用4层负载均衡
七层负载均衡(开发过程中经常提到的负载均衡即七层负载均衡)
七层负载均衡在业务方面现主要基于网关或nginx来实现,nginx相关见:
- nginx news
- Alphabetical index of directives (nginx.org) 也可以通过API网关等方式来实现负载均衡处理:比如 eolinker/apinto
nginx内部架构
基于nginx进行七层负载均衡
设置upstream
upstream backend {
server 127.0.0.1:8888;
}
http模块配置如下:
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
keepalive_timeout 65;
upstream backend {
server 10.227.89.58:8080;
}
server {
listen 80;
server_name www.example.com;
location / {
proxy_pass http://backend;
# 重置host字段等操作
proxy_set_header HOST $host;
proxy_connect_timeout 60;
proxy_send_timeout 60;
proxy_read_timeout 60;
}
}
}
使用7层负载均衡
如何将本地服务开放到外网访问
项目地址:ngrok - Online in One Line
命令:./ngrok http 8080(将本地8080端口开放到公网)
服务状态:
访问: