负载均衡

1. 负载均衡的作用 负载均衡(Load Balance LB),是通过单一的入口,使用某些算法,对用户流量进行分发,使用户请求合理的分配到多个服务器节点中的一种技术。 现代应用通常需要同时对大量用户提供服务,此时单台机器已经难以承担这些需求,因此需要使用多个节点同时为用户提供服务,但显然不能让用户记住多个域名甚至IP。LB位于用户与服务器集群之间,充当不可见的协调者,确保均等使用所有资源服务器。 2. DNS负载均衡 基于DNS的负载均衡比较简单,其原理是为一个域名配置多个A记录,这样当对域名进行请求时,就可以通过返回不同的域名进行流量的分配。 一种最常见的 DNS 负载平衡技术是循环 DNS。即在请求到来时,IP地址以循环方式轮换返回,请请求分散到关联的服务器上。 当然,也可以采用其他负载均衡策略,例如根据IP地址的地域等分配较劲的服务器。 3. 四层LB与七层LB 从形式上来说LB都可以分为两种:四层负载均衡和七层负载均衡。其中四层负载均衡的优势是性能高,七层负载均衡的优势是功能强。这里的四层、七层指的是OSI网络分层标准中的第四层传输层和第七层应用层。 3.1 四层LB 这里存在一个误解: **四层负载均衡并不是只工作在第四层传输层,事实上它们主要工作在二层(数据链路层)和三层(网络层)上。**根据OSI模型,当数据包到达第四层,其实已经到达了目标主机上,所以此时显然不存在什么流量转发了。四层负载均衡的真正含义是:这些工作模式的共同特点是都维持着同一个TCP连接。 数据链路层LB 数据链路层数据帧中包括有目的MAC地址和源MAC地址,数据链路层负载均衡所做的工作,是修改请求的数据帧中的 MAC 目标地址,让用户原本是发送给负载均衡器的请求的数据帧,被二层交换机根据新的 MAC 目标地址,转发到服务器集群中,对应的服务器的网卡上,这样真实服务器就获得了一个原本目标并不是发送给它的数据帧。 数据链路层的负载均衡只对目标MAC地址进行了修改,不涉及其他层次,因此对于更上层的网络层来说,数据是无变化的,这样网络层才能正常工作。 这是因为第三层的数据包,也就是 IP 数据包中,包含了源(客户端)和目标(均衡器)的 IP 地址,只有真实服务器保证自己的 IP 地址与数据包中的目标 IP 地址一致,这个数据包才能被正确处理。 所以,我们在使用这种负载均衡模式的时候,需要把真实物理服务器集群所有机器的虚拟 IP 地址(Virtual IP Address,VIP),配置成跟负载均衡器的虚拟 IP 一样,这样经均衡器转发后的数据包,就能在真实服务器中顺利地使用。 另外,也正是因为实际处理请求的真实物理服务器 IP 和数据请求中的目的 IP 是一致的,所以响应结果就不再需要通过负载均衡服务器进行地址交换,我们可以把响应结果的数据包直接从真实服务器返回给用户的客户端,避免负载均衡器网卡带宽成为瓶颈,所以数据链路层的负载均衡效率是相当高的。 这种传输方式被称为三角传输,返回的流量不经过LB,避免负载均衡器网卡带宽成为瓶颈,效率较高. 数据链路层的劣势也很明显,因为其需要通过修改MAC地址的方式进行工作,因此真实目标服务器必须和LB服务器在同一子网下。 网络层LB 与数据链路层类似的,网络层是通过修改三层数据包的目标IP地址进行工作: 其修改方式主要有两种: 第一种是保持原来的数据包不变,新创建一个数据包,把原来数据包的 Headers 和 Payload 整体作为另一个新的数据包的 Payload,在这个新数据包的 Headers 中,写入真实服务器的 IP 作为目标地址,然后把它发送出去。 这种方式需要在接收时重新进行拆包,取出原来要发送的数据包,这样,IP数据包的源IP和目的IP无变化,真实服务器仍然可以直接将数据发送给客户端,不需要经过LB,也即仍具有三角传输的特性。 这种方式被称为IP隧道,因为其工作在网络层,可以跨VLAN进行传输,但要求目标服务器支持IP隧道协议。 第二种方式直接把数据包 Headers 中的目标地址改掉,修改后原本由用户发给均衡器的数据包,也会被三层交换机转发送到真实服务器的网卡上,而且因为没有经过 IP 隧道的额外包装,也就无需再拆包了。 但这样的话,真实服务器在将数据返回给客户端时,就会使用自己的IP作为源IP,客户端一看:“我想要的是A服务器响应,你给我来了个B服务器响应,滚犊子”,不能正常处理这个应答,因此必须让响应返回LB再发给客户端。...

March 24, 2023 · 1 min · 李昌

Install Docker on Arch

官方给出的教程是使用docker desktop, 但内存占用太大。 1. 安装docker二进制文件 从这里下载平台对应的二进制文件:https://download.docker.com/linux/static/stable/ 然后解压安装: $ tar xzvf /path/to/<FILE>.tar.gz $ sudo cp docker/* /usr/bin/ 这时可以手动执行sudo dockerd &以启动守护进程,但我们不这样做 配置守护进程 从https://github.com/moby/moby/tree/master/contrib/init/systemd拷贝docker.service, docker.socket两个文件到/etc/systemd/system/docker.service, /etc/systemd/system/docker.socket 然后运行: $ sudo systemctl daemon-reload # 重新加载配置 $ sudo systemctl start docker #启动dockerd $ sudo systemctl enable docker # 设置开机启动 其实也可以直接yay -S docker :-) docker-compose $ yay -S docker-compose References https://docs.docker.com/desktop/install/archlinux/ https://docs.docker.com/engine/install/binaries/#install-daemon-and-client-binaries-on-linux https://docs.docker.com/config/daemon/systemd/ https://wiki.archlinux.org/title/docker https://wiki.archlinux.org/title/Systemd#Drop-in_files

February 21, 2023 · 1 min · 李昌

Manjaro恢复grub

https://wiki.manjaro.org/index.php/GRUB/Restore_the_GRUB_Bootloader#EFI_System 启动笔记本时,突然发现gurb引导项故障了,记录一下修复过程: 首先用U盘制备一个manjaro引导盘。然后有两种方式 timeshift 进入系统BIOS设置U盘启动,然后直接从U盘启动一个manjaro。 如果你有timeshift备份,可以先尝试使用timeshift进行恢复,不行的话,就尝试方法二 grub恢复 进入系统BIOS设置U盘启动,在manjaro提示你选择如何启动系统时,选择Select a bootloader,然后选择grub,不出意外,你的原系统就启动了,但这时如果重启,还是找不到grub引导项。可做如下操作: 首先更新grub sudo pacman -Syu grub 然后: grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=manjaro --recheck grub-mkconfig -o /boot/grub/grub.cfg 如果第二个命令提示:/usr/bin/grub-probe:警告: 未知的设备类型 nvme0n1. 那么直接删除/etc/grub.d/60_memtest86+这个文件即可(无风险) 然后重试: grub-mkconfig -o /boot/grub/grub.cfg 提示完成后,拔掉U盘重启,应该就可以了。

February 13, 2023 · 1 min · 李昌

在AUR上发布包

如何在AUR上发布包 1. 准备PKGBUILD 文件 https://wiki.archlinux.org/title/PKGBUILD https://wiki.archlinux.org/title/Creating_packages 想要打包一个可以在AUR上发布的package, 需要使用makepkg工具,makepkg在运行时会寻找当前工作目录下的PKGBUILD文件。 找到之后,会从PKGBUILD配置的source去获取源码并根据PKGBUILD的配置去进行编译,最终产生二进制文件以及一些元信息文件。 如果你使用的是arch系的系统,可以在/usr/share/pacman/目录下找到一些PKGBUILD示例文件。例如: $ cat /usr/share/pacman/PKGBUILD.proto # This is an example PKGBUILD file. Use this as a start to creating your own, # and remove these comments. For more information, see 'man PKGBUILD'. # NOTE: Please fill out the license field for your package! If it is unknown, # then please put 'unknown'. # Maintainer: Your Name <youremail@domain.com> pkgname=NAME pkgver=VERSION pkgrel=1 epoch= pkgdesc="" arch=() url="" license=('GPL') groups=() depends=() makedepends=() checkdepends=() optdepends=() provides=() conflicts=() replaces=() backup=() options=() install= changelog= source=("$pkgname-$pkgver....

February 10, 2023 · 3 min · 李昌

python生成器函数和go通道

python生成器函数 def gen_char(): """ 定义了一个生成器函数,将会生成a~z """ for i in range(0, 26): yield chr(ord('a') +i) for char in gen_char(): print(char, end=' ') # 输出 # a b c d e f g h i j k l m n o p q r s t u v w x y z golang通道 func main() { ch := make(chan string) // 一个通道 wg := &sync.WaitGroup{} // 用于goroutine同步 wg.Add(1) go func() { // 定义了一个“生成器函数“ defer wg....

October 28, 2022 · 2 min · 李昌

python高阶函数

如果一个函数能接收一个函数为参数或返回一个函数,那这个函数就被称为高阶函数。 1. sorted sorted可以说是最常用的高阶函数,其用法如下: m = {"three": 3, "tow": 2, "one": 1 sorted(m.items(), key=lambda x: x[1]) # [('one', 1), ('tow', 2), ('three', 3)] sorted可根据其参数key返回的值来进行排序。 2. map map()函数接收两个参数,一个是函数,一个是Iterable,map将传入的函数依次作用到序列的每个元素,并把结果作为新的Iterator返回。 如: def add10(x): return x+10 print(map(add10, [1, 2, 3])) # <map object at 0x7f5824cd01c0> list(map(add10, [1, 2, 3])) # [11, 12, 13] list(map(str, [1, 2, 3, 4, 5, 6, 7, 8, 9])) # ['1', '2', '3', '4', '5', '6', '7', '8', '9'] functools....

October 19, 2022 · 2 min · 李昌

stat系列性能分析工具

1. sysstat简介 sysstat是一个软件包,包含监测系统性能及效率的一组工具,这些工具对于我们收集系统性能数据,比如:CPU 使用率、硬盘和网络吞吐数据,这些数据的收集和分析,有利于我们判断系统是否正常运行,是提高系统运行效率、安全运行服务器的得力助手。 sysstat包含多个工具套件: 首先是stat系列 iostat 输出CPU的统计信息和所有I/O设备的输入输出(I/O)统计信息 mpstat 关于CPU的详细信息(单独输出或者分组输出) pidstat 关于运行中的进程/任务、CPU、内存等的统计信息 sysstat sysstat 工具包的 man 帮助页面。 nfsiostat NFS(Network File System)的I/O统计信息 cifsiostat CIFS(Common Internet File System)的统计信息 还有sa系列 7. sar 保存并输出不同系统资源(CPU、内存、IO、网络、内核等)的详细信息 8. sadc 系统活动数据收集器,用于收集sar工具的后端数据 9. sa1 系统收集并存储sadc数据文件的二进制数据,与sadc工具配合使用 10. sa2 配合sar工具使用,产生每日的摘要报告 11. sadf 用于以不同的数据格式(CVS或者XML)来格式化sar工具的输出 2. 简单使用 iostat iostat: 显示从系统启动至今的io历史数据 iostat -d 2: 每隔两秒显示一个连续的设备报告。 iostat -d 2 6: 为所有设备显示6个报告,每隔两秒显示一个 iostat -x sda sdb 2 6: 为sda和sdb两个设备显示6个报告,每隔2秒显示一个...

September 17, 2022 · 1 min · 李昌

多版本语言环境

npm: nvm python: pyenv go: asdf asdf可用于多个语言的多版本环境管理

September 5, 2022 · 1 min · 李昌

runtime篇五:slice

本系列代码基于golang1.19 runtime篇一:接口 runtime篇二:通道 runtime篇三:defer runtime篇四:panic runtime篇五:slice 推荐阅读:slice和数组的区别 切片append规则 1. 切片的结构 切片的底层表示是runtime.slice: type slice struct { array unsafe.Pointer len int cap int } 非常简单,只有一个array指针指向底层数组结构,len标记切片长度,cap标记数组容量。 2. 新建一个切片 当我们使用如make([]int, 0)语法来新建一个切片的时候,调用的是runtime.makeslice函数: func makeslice(et *_type, len, cap int) unsafe.Pointer { mem, overflow := math.MulUintptr(et.size, uintptr(cap)) if overflow || mem > maxAlloc || len < 0 || len > cap { // NOTE: Produce a 'len out of range' error instead of a // 'cap out of range' error when someone does make([]T, bignumber)....

August 14, 2022 · 3 min · 李昌

runtime篇三:defer

本系列代码基于golang1.19 runtime篇一:接口 runtime篇二:通道 runtime篇三:defer runtime篇四:panic runtime篇五:slice 1. defer是什么 defer,是一种特殊的机制,在调用普通函数或方法前加上关键字defer,就完成了defer所需要的语法。当defer语句被执行时,跟在defer后面的函数会被延迟执行。直到包含该defer语句的函数执行完毕时,defer后的函数才会被执行,多个defer的执行顺序与声明顺序相反。 对于defer的使用及需要注意的地方,可参考defer用法。这里不再讨论。 在golang runtime中,defer被描述为一个结构体: type _defer struct { started bool // 是否开始执行defer函数 heap bool // 是否分配在堆上 openDefer bool // 是否经过开放编码(open-coded)的优化 sp uintptr // 调用defer时的栈指针 stack pointer pc uintptr // 调用defer函数时的pc值 fn func() // defer关键字传入的函数, 当使用open-coded defer时可为空 _panic *_panic // defer函数中的_panic链表 link *_defer // 在goroutine中的下一个defer,可指向堆或栈 // 如果openDefer为true,则下面的字段将记录具有open-code defer的栈帧和相关的函数。 // 上面的sp将为帧的sp,pc将为defer调用的地址。 fd unsafe....

August 12, 2022 · 5 min · 李昌