1. 负载均衡
1.1 SLB
SLB: Server Load Balance
通过设置虚拟服务地址(IP),将位于同一区域(Region)的多台云服务器(Elastic Compute Service,ECS)的资源虚拟成一个高性能、高可用的应用服务池;再根据应用指定的方式,将来自客户端的网络请求分发到云服务器池中
SLB服务会检查云服务器池中ECS的健康状态,自动隔离异常状态的ECS,从而解决了单台ECS的单点问题,同时提高了应用的整体服务能力
负载均衡算法:
轮询 (Round Robin)
最小连接 (Leaster Connections): 优先选择连接数最小的服务器
Source: 根据请求源IP的hash值来选择要转发的服务器,保证特定用户连接到相同服务器
1.2 LVS
LVS:Linux Virtual Server
当用户向负载均衡调度器(Director Server)发起请求,调度器将请求发送至内核空间
PREROUTING链首先会接收到用户请求,判断目标IP是否本机IP,将数据包发往INPUT链
IPVS工作在INPUT上,当用户请求到达INPUT时,IPVS会将用户请求和定义好的集群服务进行比对,如果请求时集群服务,那么IPVS将强行修改数据包里的目标IP和端口,并将新数据包发往POSTROUTING链
POSTROUTING链接收数据包后发现目标IP地址刚好时自己的后端服务器,通过选路,将数据包最终发送给后端服务器
LVS 程序组成:
- ipvs: ip virtual server, 工作在内核空间的一段代码,实现负载均衡调度
- ipvsadm: 工作在用户空间,负责ipvs内核框架的编写规则
iptables 内置的4个表:
filter: 包过滤
nat: 网络地址转换
mangle: 包重构(修改)
raw: 数据跟踪处理
链(chains): 数据包传播的路径,每一条链其实就是众多规则中的一个检查清单,每一条链中可以有一 条或数条规则
默认包括5种规则链
INPUT:处理入站数据包
OUTPUT:处理出站数据包
FORWARD:处理转发数据包
POSTROUTING链:在进行路由选择后处理数据包(对数据链进行源地址修改转换)
PREROUTING链:在进行路由选择前处理数据包(做目标地址转换)
2. 高可用软件
- Heartbeat:可实现对服务器资源(IP即程序服务等资源)的监控和管理,并在出现故障的情况下,将资源集合从一台已经故障的计算机快速转移到另一台机器上继续提供服务
- Keepalived:
- 通过IP漂移,实现服务的高可用:服务器集群共享一个虚拟IP,同一时间只有一个服务器占有虚拟IP并对外提供服务,若该服务器不可用,则虚拟IP漂移到另一台服务器并对外提供服务
- 对LVS应用服务器集群状态进行监控:若应用不可用,则keepalived将其从集群中摘除,若服务器恢复,将其加入集群中
3. 弹性伸缩
弹性伸缩(Auto Scaling): 根据业务需求和伸缩策略,自动调整计算机资源。请求高峰时,自动增加业务实例数量,以保证性能不受影响;请求低谷时,自动释放业务实例数量以减低成本
4. 孤儿进程 & 僵尸进程
孤儿进程:父进程退出,但它的子进程还在运行,那么这些进程即为孤儿进程。孤儿进程会被init进程(PID=1)接收,并由init进程堆它们完成状态收集工作
僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程未调用wait或waitpid获取子进程状态,那么子进程描述符仍然保存在系统中,这种进程称之为僵尸进程。
5. epoll & select
epoll 和 select 都是I/O多路复用技术,都实现同时监听多个I/O事件的状态
epoll 比 select 高效,主要基于其操作系统支持的 I/O 事件通知机制,而select是基于轮询机制
epoll 支持水平触发和边缘触发两种模式
6. ping IP
根据目地IP和路由表决定走哪个网卡
根据网卡子网掩码判断目的IP是否在子网内
如果不在子网内,则通过arp缓存查询IP的网卡地址,不存在的话先通过广播询问目的IP的mac地址,该地址会缓存下来
根据获取的mac地址,然后发包
7. 解决hash冲突的办法
7.1 开放地址法
即 再散列法,基本思想:当关键字key的哈希地址p=H(key) 出现冲突时,以p为基础,产生另一个哈希地址p1,如果p1仍然冲突,再以p为基础,产生另一个哈希地址p2,…,直到找出一个不冲突的哈希地址pi ,将相应元素存入其中。
- 线性探测再散列:冲突发生时,顺序查看表中下一单元,直到找出一个空单元或查遍全表。
- 二次探测再散列:冲突发生时,在表的左右进行跳跃式探测,比较灵活 (1^2,-1^2, …)
- 伪随机探测再散列: 建立一个伪随机数发生器,并给定一个随机数做起点
7.2 再哈希法
使用不同的哈希函数,直到冲突解决
缺点:耗时较长
7.3 链地址法
将哈希值相同的元素构成一个同义词的单链表,并将单链表的头指针存放在哈希表的第i个单元中,查找、插入和删除主要在同义词链表中进行。链表法适用于经常进行插入和删除的情况。
7.4 建立一个公共溢出区
将哈希表分为公共表和溢出表,当溢出发生时,将所有溢出数据统一放到溢出区。
8. Git
git rebase
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 # 1. 合并多次提交记录
git rebase -i HEAD~4 # 最近四次
git rebase --edit-todo # 异常退出vi时执行
git rebase --continue # 返回继续编辑
# 2. 合并分支
git checkout master
git pull
git checkout dev
git rebase master # 将master最新分支同步到当前分支
git rebase --continue # 有冲突,并解决冲突后执行
git rebase --abort # 有冲突,放弃,回到rebase前的状态
git checkout master
git merge dev
git push
git rebase master 做了哪些操作?
- 先取消当前dev分支的提交记录
- 将在当前dev中新开发的代码保存成patch文件,存入.git/rebase目录下
- 当前dev分支合并最新的master分支
- 将patch文件应用到当前dev分支
在 dev 分支,使用 git rebase master,然后就会把 dev 接到 master 分支之上。Git 是这么做的:
- 首先,找到这两条分支的最近公共祖先 LCA
- 然后,从 master 节点开始,重演 LCA 到 dev 几个 commit 的修改,如果这些修改和 LCA 到 master 的 commit 有冲突,就会提示你手动解决冲突
- 最后,把 dev 的分支完全接到 master 上面。
9. 进程、线程、协程
9.1 进程
进程:程序的执行过程,包括了动态创建、调度和消亡的整个过程,是程序资源管理的最小单位
多进程模型:启动多个服务进程。由于多进程地址空间不同,数据不能共享,需要搭建各个进程间的通信桥梁,即IPC (InterProcess Communication)
常见IPC类型
管道 Pipe:一个内核缓冲区,以先进先出FIFO的方式从缓冲区存取数据;以半双工方式通信,数据只能单向流动,且只能在父子进程间通信
命名管道FIFO:以文件形式存于文件系统中
/tmp/fifo
, 只要可以访问该文件的进程,均可通信信号 Signal:用户空间进程和内核直接交互,内核可利用信号来通知用户空间进程发生哪些系统事件
消息队列 Message Queue:存放在内核中的消息链表,每个消息队列由消息队列标识符表示,只在内核重启或主动删除时,消息队列才会被删除
共享内存 Shared memory:多个进程可以直接读写同一块内存空间,是最快的IPC
套接字 Socket:通过网络接口将数据发送到本机的不同进程或远程计算机的进程
9.2 线程
线程:进程中,资源调度的最小单位
多线程模型:
线程同步:线程之间的一种直接制约关系,一个线程的执行依赖另一个线程的通知,当它没有得到另一个线程的通知时必须等待,直到消息到达时才被唤醒。
线程互斥:多线程对资源访问的排他性,即多个线程要使用某个共享资源时,任何时刻最多只允许一个线程获得该共享资源的使用权
多线程同步和互斥方法:
互斥锁
条件变量
读写锁
自旋锁:线程反复去获取锁,但这个锁被其他线程占用,此线程将会等待,间隔一段时间后再次尝试获取。这种循环加锁的等待机制被称为自旋锁(spinlock)
信号量
9.3 协程
协程:一种比线程更轻量化的微线程
协程优势:
协程在线程内实现,因此始终在一个线程中共享资源,不存在多线程抢占资源和资源同步问题
生产者协程和消费者协程,相互配合协作完成工作,而不是相互抢占
协程的创建和切换开销比线程小的多
9.4 总结
进程、线程、协程的关系和区别:
- 进程拥有独立的堆和栈,既不共享堆,也不共享栈,由操作系统负责调度。
- 线程拥有独立的栈和共享的堆,由操作系统负责调度(内核线程)。
- 协程拥有独立的栈和共享的堆,有 golang 的调度器负责调度。
9.5 实现自旋锁
1 | type SpinLock uint32 |
10. 函数递归问题
为什么递归“效率低”?
函数调用开销问题:函数调用前,需要做许多工作,比如准备函数内局部变量使用的空间、保存函数的参数,记录函数调用位置等,这些操作较为耗资源。
某些递归算法,本身存在低效问题。斐波那契中求某一项,子问题会大量重复出现,产生大量重复计算,效率低下
不断入栈出栈操作
栈容量的限制,可能导致stack overflow
11. 压测工具
- vegeta: 高性能http(s)负载测试工具。它是一个负载测试工具而不是基准测试工具。基准测试试图找到系统在峰值容量下所能承受的极限,而负载测试则倾向于讲述系统在不同的负载点和配置下的表现。
1 | echo "GET http://10.137.8.40" | vegeta attack -rate=20000 -duration=60s | tee test.dat | vegeta report -ouput test-result.dat |
QPS: query per second
- goconvey: 集成go test, 支持Web-GUI
关于goconvey,下面说法正确的是(ABC)
A. goconvey是一个支持golang的单元测试框架
B. goconvey能够自动监控文件修改并启动测试,并可以将测试结果实时输出到web界面
C. goconvey提供了丰富的断言简化测试用例的编写
D. goconvey无法与go test集成
1 | func TestStringSliceEqual(t *testing.T) { |
- GoStub
GoStub框架的使用场景如下:
A、为一个全局变量打桩
B、为一个函数打桩
C、为一个过程打桩
D、由任意相同或不同的基本场景组合而成
12. 字符编码
大端 (LitteEndian):高位写左边,从左向右读
小端 (LitteEndian):高位写右边,从右向左读