网络接入
路由发包原理:
- 同网段:配置网段即可默认添加静态路由。获取对端MAC直接发包
Note: 同网段并不一定都是通过物理设备连接的,也可能是通过上层的虚拟网络定义的同网段。
-
跨网段:配置网关路由。获取网关MAC地址发包
路由一定是对称的吗?
路由是网状的,不一定是对称的
ARP协议
-
逻辑同网段才能发送ARP
-
ARP请求广播,ARP应答单播
-
代理ARP
-
免费ARP
免费 ARP 报文与普通 ARP 请求报文的区别在于报文中的目标 IP 地址。普通 ARP 报文中的目标 IP 地址是其他主机的 IP 地址;而免费 ARP 的请求报文中,目标 IP 地址是自己的 IP 地址。
免费ARP有以下 3 个作用:
- 该类型报文起到一个宣告作用。它以广播的形式将数据包发送出去,不需要得到回应,只为了告诉其他计算机自己的 IP 地址和 MAC 地址。
- 可用于检测 IP 地址冲突。当一台主机发送了免费 ARP 请求报文后,如果收到了 ARP 响应报文,则说明网络内已经存在使用该 IP 地址的主机。
- 可用于更新其他主机的 ARP 缓存表。如果该主机更换了网卡,而其他主机的 ARP 缓存表仍然保留着原来的 MAC 地址。这时,可以发送免费的 ARP 数据包。其他主机收到该数据包后,将更新 ARP 缓存表,将原来的 MAC 地址替换为新的 MAC 地址。
IP协议
-
MAC地址能够代替IP地址吗?
MAC地址是数据链路层使用的地址,它也能唯一地确定一台主机在网络中的位置。但是它没有一种办法很好地区分不同的网络。
MAC地址一共有48bit,分为两部分,前24bit是厂商代码,后24bit是厂家自己分配的。假如我们认为MAC地址可以区分不同的网络的话,那只能是使用厂商代码来区分不同的网络,也就是说使用同一个厂商生产的网卡的主机或者网络设备,就是属于同一个网络。举个例子,比如说企业A使用了思科的网络设备,企业B也使用了思科的网络设备,那这两家企业就属于同一个网络了。现实中这种情况是不可能的。
NAT
-
多个内网客户端访问同一个目标地址+端口,源端口恰好一样,会冲突吗?
NAPT同时映射IP地址和端口号:来自不同内部地址的数据报的源地址可以映射到同一外部地址,但它们的端口号被转换为该地址的不同端口号,因而仍然能够共享同一地址,也就是“私有地址+端口号”与“公网IP地址+端口号”之间的转换。
网络传输
以kernel为例
1、 DNS请求 - 域名映射ip
客户端发送递归请求,递归DNS服务器进行迭代请求。
DNS协议通过UDP进行传输。
UDP协议结构:
UDP怎么保证协议可靠?
2、TCP连接
拔了网线,TCP连接会断开吗?
针对这个问题,要分场景来讨论:
- 拔掉网线后,有数据传输;
在客户端拔掉网线后,服务端向客户端发送的数据报文会得不到任何的响应,在等待一定时长后,服务端就会触发超时重传机制,重传未得到响应的数据报文。
如果在服务端重传报文的过程中,客户端刚好把网线插回去了,由于拔掉网线并不会改变客户端的 TCP 连接状态,并且还是处于 ESTABLISHED 状态,所以这时客户端是可以正常接收服务端发来的数据报文的,然后客户端就会回 ACK 响应报文。
此时,客户端和服务端的 TCP 连接依然存在的,就感觉什么事情都没有发生。
但是,如果如果在服务端重传报文的过程中,客户端一直没有将网线插回去,服务端超时重传报文的次数达到一定阈值后,内核就会判定出该 TCP 有问题,然后通过 Socket 接口告诉应用程序该 TCP 连接出问题了,于是服务端的 TCP 连接就会断开。
而等客户端插回网线后,如果客户端向服务端发送了数据,由于服务端已经没有与客户端相同四元祖的 TCP 连接了,因此服务端内核就会回复 RST 报文,客户端收到后就会释放该 TCP 连接。
此时,客户端和服务端的 TCP 连接都已经断开了。
- 拔掉网线后,没有数据传输;
针对拔掉网线后,没有数据传输的场景,还得看是否开启了 TCP keepalive 机制 (TCP 保活机制)。
如果没有开启 TCP keepalive 机制,在客户端拔掉网线后,并且双方都没有进行数据传输,那么客户端和服务端的 TCP 连接将会一直保持存在。
而如果开启了 TCP keepalive 机制,在客户端拔掉网线后,即使双方都没有进行数据传输,在持续一段时间后,TCP 就会发送探测报文:
- 如果对端是正常工作的。当 TCP 保活的探测报文发送给对端, 对端会正常响应,这样 TCP 保活时间会被重置,等待下一个 TCP 保活时间的到来。
- 如果对端主机崩溃,或对端由于其他原因导致报文不可达。当 TCP 保活的探测报文发送给对端后,石沉大海,没有响应,连续几次,达到保活探测次数后,TCP 会报告该 TCP 连接已经死亡。
所以,TCP 保活机制可以在双方没有数据交互的情况,通过探测报文,来确定对方的 TCP 连接是否存活。
TCP keepalive 是 TCP 层(内核态) 实现的,它是给所有基于 TCP 传输协议的程序一个兜底的方案。
实际上,我们应用层可以自己实现一套探测机制,可以在较短的时间内,探测到对方是否存活。
比如,web 服务软件一般都会提供 keepalive_timeout 参数,用来指定 HTTP 长连接的超时时间。如果设置了 HTTP 长连接的超时时间是 60 秒,web 服务软件就会启动一个定时器,如果客户端在完后一个 HTTP 请求后,在 60 秒内都没有再发起新的请求,定时器的时间一到,就会触发回调函数来释放该连接。
三次握手?
seq number、ack number
Time wait?
TCP丢包怎么办?
滑动窗口、流量控制?
3、HTTP/HTTP 1.1
为什么不直接使用TCP通信?
HTTP依然是TCP,只是多了这个分层能够让用户更清晰/简洁。
HTTP1.1有哪些优化?
- 长连接
- 部分传输
- HOST
- 缓存
4、HTTPS
HTTP + SSL/TLS
网络提速 - 协议优化
HTTP 2.0
多路复用/stream
如果TCP丢包怎么办?
发生队头阻塞,全部重传。
QUIC/HTTP 3.0
网络提速 - 网络路径协议优化
数据中心分布
同运营商访问
静态资源(图片视频)优化(CDN)
动态API(播放/评论接口)优化(DSA)
网络稳定 - 容灾
故障发生 -> 故障感知 -> 自动切换 -> 服务恢复
- 案例一
通过外网容灾应对专线挂掉情况。
- 案例二
- 案例三
云到端 -> 主动降级/容灾
场景局限性:
- 云控本身宕机
- 用户不让执行某些命令
- web界面无法嵌入SDK
- 案例四
Bug导致全crash -> 前置兜底逻辑/cache文件
网络稳定 - 故障
故障明确 -> 故障止损 -> 分段排查
故障排查常用命令
`dig 查询 dns 问题
`ping/telnet/nmap 查询三/四层连通性
`Traceroute 排查中间链路
`iptables
`tcpdump
- 案例一
客户端异常 -> 服务端自测正常 -> 网关转发异常 -> 健康检查异常
- 案例二
个别用户报故障,生产环境大多数是客户端的问题
- 案例三
某电信报障某APP无法使用 -> 服务端正常,电信流量突降 -> 电信客户端ping不通目标服务 -> 电缆被挖断
- 案例四
某APP故障 -> 后端服务器反馈服务正常 -> 网络转发设备异常 -> 抓包 -> 路由不对称
如何将我的服务开放给用户
企业接入
host管理 -> 域名系统
域名购买与配置迁移
域名解析绑定公网ip
自建DNS服务器
问题背景
-
内网域名的解析也得从公网去获取,效率低下
-
外部用户能看到内网ip地址,容易被hacker攻击
-
云厂商权威DNS容易出故障,影响用户体验
-
扩大品牌公司技术影响力
**从公有云托管 -> 构建自己的DNS系统 **
站在企业的角度思考,我们需要哪种DNS服务器?
权威DNS、LocalDNS(可选)
常见的开源DNS:bind、nsd、knot、coredns
接入 HTTPS 协议
问题背景
- 页面出现某些奇怪的东西
- 返回403
- 页面弹窗广告
对称加密喝非对称加密
SSl握手过程(RSA)
公钥是可信的吗?会不会被劫持?
Server 端发送的是带签名的证书链
Client收到后会进行验证:
证书链
接入全站加速
源站容量问题 增加后端及其扩容;静态加速缓存
网络传输问题 动态加速DCDN
全站加速 静态加速 + 动态加速
静态加速
缓存
-
解决服务端的“第一公里”问题 // 第一公里:要将请求尽可能的优化在靠近用户的节点上进行响应,从而缩短网络链路
-
缓解甚至消除了不同运营商之间互联的瓶颈造成的影响
-
减轻各省的出口带宽压力
-
优化网上热点内容的分布
动态加速 DCDN
DCDN原理
使用全站加速
4层负载均衡
思考:怎么充分利用有限的公司ip资源?
四层负载均衡:基于IP + 端口,利用某种算法将报文转发给某个后端服务器,实现负载均衡后落地到后端服务器上。
主要功能
-
解耦vip 和 rs
-
NAT
-
防止攻击: syn proxy
常见的调度算法原理
常见的实现方式 FULLNAT
rs怎么知道真实的CIP?
通过TCP option字段传递,然后通过特殊的内核模块反解
4层负载均衡特点
使用4层负载均衡
7层负载均衡
四层负载对100.1.2.3 只能 bind 一个80 端口,而有多个外部站点需要使用,如何解决?
有一些7层相关的配置需求,该怎么做?
Nginx简介
Nginx内部结构
事件驱动模型
传统服务器:一个进程/线程处理一个连接/请求模型,依赖OS实现并发
Nginx:一个进程/线程处理多个连接/请求异步非阻塞模型、减少OS进程切换
Nginx 调优
使用7层负载均衡
服务开发前期,如何低成本的让别人访问自己的服务?
Ngork, Expose your localhost to the web.
使用github账号授权登陆,即可使用。详见https://dashboard.ngrok.com/get-started/setup
命令:./ngrok http 8080(将本地8080端口开放到公网)
相关实验
权威DNS及LocalDNS搭建实验
1、权威侧zone文件准备
这里拟采用著名的开源软件bind9作为DNS服务的server
新建zone文件/etc/bind/example.com.zone,并编辑为以下内容
@ IN SOA ns1.example.com admin.example.com. (
0 ; serial
1D ; refresh
1H ; retry
1W ; expire
3H ) ; minimum
@ IN NS ns1.example.com.
; 这里ns1主机的ip地址可以换成本机地址
ns1 A 10.227.89.58
; 这里www主机的ip地址可以换成本机地址
www A 10.227.89.58
2、#### bind9配置准备
直接编辑/etc/bind/named.conf即可,配置参考如下:
logging {
channel default_log {
#这里注意提前创建log目录
file "/var/log/named/named.log" versions 10 size 200m;
severity dynamic;
print-category yes;
print-severity yes;
print-time yes;
};
channel query_log {
file "/var/log/named/query.log" versions 10 size 200m;
severity dynamic;
print-category yes;
print-severity yes;
print-time yes;
};
channel resolver_log {
file "/var/log/named/resolver.log" versions 10 size 200m;
severity dynamic;
print-category yes;
print-severity yes;
print-time yes;
};
category default {default_log;};
category queries {query_log;};
category query-errors {query_log;};
category resolver {resolver_log;};
};
options {
#这里的ip地址可以换成本机地址
listen-on port 53 { 10.227.89.58; };
directory "/etc/bind";
dnssec-validation no;
#支持递归查询
recursion yes;
#转发到公共DNS优先,而不是自己去迭代查询,节省网络IO资源消耗
forward first;
forwarders {
223.5.5.5;
223.6.6.6;
};
allow-query { any; };
};
zone "example.com" {
type master;
file "example.com.zone";
};
3、使用dig命令验证
- 验证权威DNS服务命令:dig @10.227.89.58 www.example.com (10.227.89.58可以换成上面监听的本机地址),命中本地托管的zone example.com,直接吐数据
- 验证LocalDNS服务
dig @10.227.89.58 www.toutiao.com (10.227.89.58可以换成上面监听的本机地址),未命中本地托管的zone数据,直接向任一forwarders(公共DNS)请求,获取结果后缓存到本地
git
git 配置
Git 自带一个 git config 的工具来帮助设置控制 Git 外观和行为的配置变量。 这些变量存储在三个不同的位置:
/etc/gitconfig文件: 包含系统上每一个用户及他们仓库的通用配置。 如果在执行git config时带上--system选项,那么它就会读写该文件中的配置变量。 (由于它是系统配置文件,因此你需要管理员或超级用户权限来修改它。)~/.gitconfig或~/.config/git/config文件:只针对当前用户。 你可以传递--global选项让 Git 读写此文件,这会对你系统上 所有 的仓库生效。- 当前使用仓库的 Git 目录中的
config文件(即.git/config):针对该仓库。 你可以传递--local选项让 Git 强制读写此文件,虽然默认情况下用的就是它。。 (当然,你需要进入某个 Git 仓库中才能让该选项生效。)
每一个级别会覆盖上一级别的配置,所以 .git/config 的配置变量会覆盖 /etc/gitconfig 中的配置变量。
可以通过以下命令查看所有的配置以及它们所在的文件:
$ git config --list --show-origin
用户信息
安装完 Git 之后,要做的第一件事就是设置你的用户名和邮件地址。 这一点很重要,因为每一个 Git 提交都会使用这些信息,它们会写入到你的每一次提交中,不可更改:
$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com
再次强调,如果使用了 --global 选项,那么该命令只需要运行一次,因为之后无论你在该系统上做任何事情, Git 都会使用那些信息。 当你想针对特定项目使用不同的用户名称与邮件地址时,可以在那个项目目录下运行没有 --global 选项的命令来配置。
很多 GUI 工具都会在第一次运行时帮助你配置这些信息。
文本编辑器
既然用户信息已经设置完毕,你可以配置默认文本编辑器了,当 Git 需要你输入信息时会调用它。 如果未配置,Git 会使用操作系统默认的文本编辑器。
如果你想使用不同的文本编辑器,例如 Emacs,可以这样做:
$ git config --global core.editor emacs
在 Windows 系统上,如果你想要使用别的文本编辑器,那么必须指定可执行文件的完整路径。 它可能随你的编辑器的打包方式而不同。
检查配置信息
如果想要检查你的配置,可以使用 git config --list 命令来列出所有 Git 当时能找到的配置。
$ git config --list
user.name=John Doe
user.email=johndoe@example.com
color.status=auto
color.branch=auto
color.interactive=auto
color.diff=auto
...
你可能会看到重复的变量名,因为 Git 会从不同的文件中读取同一个配置(例如:/etc/gitconfig 与 ~/.gitconfig)。 这种情况下,Git 会使用它找到的每一个变量的最后一个配置。
你可以通过输入 git config <key>: 来检查 Git 的某一项配置
$ git config user.name
John Doe