Background 自很久以前就开始使用静态博客,并且在GitHub Pages上部署后同时在服务器上进行同步,每次push新的修改后都需要在服务器上手动pull,因此决定探究使用Github Workflow自动化部署静态博客的解决方案。
Intro Github Workflows 在仓库的目录下,创建.github/workflows目录,目录内存放需要使用的工作流配置文件。
例如:
1 2 3 .github └── workflows └── rsync-action.yml Rsync Action Github提供了很全面的Actions操作,包括Hooks功能,支持在对仓库进行push、merge等操作后触发对应的脚本。对于本需求,我们需要使用GitHub的Rsync Action插件。
插件主页 Rsync Deployments Action
包含如下参数:
switches* - The first is for any initial/required rsync flags, eg: -avzr --delete rsh - Remote shell commands path - The source path. Defaults to GITHUB_WORKSPACE and is relative to it remote_path* - The deployment target path remote_host* - The remote host remote_port - The remote port.
Intro 优化I/O的方法
用户层面直接调用外部存储设备,需要应用包含文件系统的调用,臃肿,同时不同应用和用户间的冲突问题。 优化操作系统内核的I/O 栈 使用轮询来减少上下文切换的开销 在底层减少一半的中断处理 分散I/O指令 I/O block调度机制 Related Work 减少内核的开销
减少中断处理的后半部分 是用轮询技术而非中断,减少上下文切换 混合轮询 基于SSD的闪存随机读写简化调度策略 在NVMe固件中进行调度 对高优先级的任务,提供不同的IO path支持,最小化IO path的开销 修改存储接口
分散/分散 IO合并多个IO到一个指令,减少往返次数 移除doorbell机制和完成信号 改善fsync
冲fsync请求发出到收到response,延长数据持久化的时间 在日志提交记录中使用校验和,有效的重叠日志写入和块写入 提出写守序系统调用,重叠的fsync效果相同,当应用需要使用fsync时,关于IO的操作将同步进行 用户层直接访问外设,存在隔离、保护等安全问题
Motivation 背景 现状:
I/O 请求过程中太多的步骤 页面缓存分配和索引 DMA,一系列数据结构的创建 目前的 ULL SDD实现了低于10微妙的IO延迟,然而操作系统内核产生的延迟没有明显变化
本文专注于:
Linux内核中的read()和write()+fsync() 基于NVMe SSD的Ext4文件系统 For Read Path 研究发现许多剩余的操作不必在设备I/O之前或之后执行
此类操作可以在设备I/O操作进行时执行
因为此类操作大多独立于设备I/O操作,因此考虑让这些操作与IO重叠
For Write Path 缓冲写write(),并不发起IO请求,不能异步处理
由于fsync的回写机制和文件系统崩溃一致性(日志系统),包含部分IO请求
由于文件系统带来的三次IO操作
数据块写 jbd2发起写入日志Block I/O 提交Block I/O 这些IO的创建,涉及众多过程(block分配,请求缓冲页,创建和提交bio,设置DMA地址),因此可以让CPU将这些前置操作在IO请求发起前预执行。
For Lightweight Block Layer 传统Block Layer涉及过多过程,推迟了IO指令提交给设备的时间
因为ULL SSD的高速随机IO性能和低速的顺序IO,请求重排的效果很低
超低延迟固态硬盘从内核到固件的服务器存储堆栈
个别名词解释 the 99^th percentile 超过统计数据99%的数是多少
blk-mq Linux Multiqueue block layer 内核对ssd随机I/O的优化
message signaled interrupt (MSI)
1.摘要 flash share
在内核中,扩展了系统堆栈的数据结构,传递应用程序的属性(?),包括内核层到SSD固件。
对于给定的属性,FlashShare的块层管理IO调度并处理NVMe中断。
评估结果表明,FLASHSHARE可以将共同运行应用程序的平均周转响应时间分别缩短22%和31%。
1.0 Intro 1.1 现状 网络服务提供商,满足服务级别协议SLA,延迟敏感
某个段时间短可能有大量请求涌入,供应商会超额配置机器以满足SLA
现状:该场景并不常见,因此大部分情况下服务器的资源占用率非常低,能耗比低。
为了解决利用率低,服务器会运行离线的数据分析应用,延迟不敏感,以吞吐量为导向。
因此,在运行了多个进程的服务器上,I/O延迟增高,满足SLA非常困难。
现有的ULL SSD相较于NVMe SSD可以减少10倍的延迟
但是这些ULL SSD在同时运行多个进程下高强度压榨服务器的时候,不能充分利用ULL SSD的优势/表现一般。
the 99th percentile 是0.8ms(apache)
但是当服务器同时运行pagerank的时候,延迟会增加228.5%。
原因:略
从固件到内核优化堆栈的存储。
内核级别的增强:
两个挑战
Linux的blk-mq导致I/O请求队列化,引入延迟 NVMe的队列机制没有对I/O优先级的策略,因此,来自离线应用的IO请求容易阻塞在线应用的紧急请求,造成延迟。 对于latency critical的请求,绕过NVMe的请求队列。同时令NVMe的驱动通过知晓每个应用的延迟临界匹配NVMe的提交和请求队列。
固件层设计:
即使内核级的优化保证了延迟敏感的请求可以获得高优先级,但如果基础固件不了解延迟临界值,ULL特性(类似内存的性能)无法完全暴露给用户。本文中重新设计了I/O调度和缓存的固件,以直接向用户暴露ULL特性。将ULL SSD的集成缓存进行分区,并根据工作负载的属性对每个I/O服务独立的分配缓存。固件动态的更新分区大小并以精细粒度调整预取I/O粒度。
ULL SSD的新中断处理服务: 当前的NVMe中断机制没有对ULL I/O服务优化。轮询方法(Linux 4.9.30)消耗了大量的CPU资源去检查I/O服务的完成情况。当轮询在线交互服务的IO请求完成状态时,flashShare使用一个仅对离线应用程序使用消息信号中断的选择性中断服务程序Select-ISR。
通过将NVMe队列和ISR卸载到硬件加速器中来进一步优化NVMe completion routine。
各种仿真实验后效果不错,效率提高了22%和31%。
2.0 Background 2.1 存储内核栈 Linux文件系统IO
DNS 使用UDP 53端口
多路复用和多路分解 无连接运输UDP UDP无需建立连接,速度快
无连接状态,不需要维护序列号,可以支持更多用户活跃(游戏服务器)
首部只有8个字节,源端口号和目的端口号,长度和check sum
为什么需要checksum校验和:
在路由器内存中可能有bit差错 链路传输不可靠 checksum最终为1111111…则可能无差错
端到端原则:某种功能应该在较高级别提供,在较低级别上设置该功能可能会冗余
UDP只能检查错误,不能纠错
DNS服务采用UDP
何时UDP,何时TCP?
不希望延迟报文的发送,TCP有拥塞控制机制,并容忍数据的丢失 可靠数据传输 差错检测
接收方反馈:
ACK肯定确认 NAK否定确认 ACK 0接收成功,ACK 1接收失败
重传,收方发现差错,发送方重传
序号,检测哪个数据包出错进行重传
数据包可靠传输:
在没有ack的情况下,等待一定的时间后进行重传 序号可以保证传输不冗余(接收方检测是否冗余) 发送方需要实现:
没发送或者重传一个分组,启动定时器countdown timer 定时器过期后响应 终止定时器 流水线可靠传输协议:
采用极小的数据包,接收方收到最后一bit立即ack GBN协议(回退N步),滑动窗口协议 限制数据包的序号,直到相应序号ack之后再发送后续的序号,用长度为N的窗口控制。
GBN发送方:
发送数据包时,检查发送窗口,未满则返回未发送的分组 收到ack后,对分组中的序号累积确认,表明接收方,正确接收到序号为n的分组以及以前的所有分组,[0, N] 超时,发送方重传所有未被确认的分组 接收方收到的分组都是有序的,如果出现无序,会丢弃后面的数据包,等待重传
选择重传 避免不必要的重传
发送方接收方都维护一个窗口
发送方:
收到send base后窗口右移到第一个没确认的分组处 接收ack将窗口内分组标记为ack 定时器防止分组丢失 接收方:
接收的分组落在窗口内,返回ack 如果序号不连续,直接缓存 如果分组序号等于rcv_base将从rcv base开始的已缓存分组交付给上层,窗口移动 序号落在窗口之外,[rcv_base-N, rcv_base-1]上一个窗口中,返回ack 窗口长度不能太大
TCP 运行与端系统中,路由器等视角下看到的是数据报
全双工
socket是对tcp协议的封装
流量控制 每一方都设置接收缓存,数据先放在缓存中,应用程序从缓存中读取数据。
目的是消除发送方使接收方缓存溢出的可能。匹配发送方和接收方的读写速率。
收发各自维护接收窗口。保存接收方还有多少缓存空间rwnd。
基础知识 单进程多线程,线程之间共享内存
OLTP Online Transaction Processing 在线事务处理
InnoDB overview 特点:
行级锁 支持外键 支持事务 MVCC并发控制,插入缓冲,二次写,自适应哈希索引,预读
四种隔离级别:
REPEATABLE 默认 聚集方式保存数据,按主键顺序存放,没有主键则生成6字节的ROWID
后台线程 Master Thread 缓冲区数据异步更新到磁盘 IO Thread innodb使用异步IO,提高数据库性能,负责接受回调 Purge Thread 事务提交后回收undolog页 Page Cleaner Thread 脏页刷新 主要都是为了减轻Master的负担,提高性能,减少对用户查询线程的阻塞
内存 用页管理记录
缓冲池:通过内存来弥补低速硬盘的影响,数据库读取页,从磁盘获取页放入缓冲池fix,读取时先判断缓冲区,命中后直接读取;修改时先修改缓冲池的页,然后通过checkpoint机制刷新到磁盘上。基本上和虚拟内存一样。
配置参数innodb_buffer_pool_size
数据页分类:索引页,数据页,undo页,插入缓冲,自适应哈希索引,innodb锁信息,数据字典信息等
允许有多个缓冲池
内存管理 LRU List 频繁使用的在列表前,不频繁的在列表后,先释放尾部的页
页默认大小16KB
innodb会把新读取的页放入midpoint位置,为列表长度的$$\frac{5}{8}$$,midpoint之后为old,之前为new,如果放在首部会导致某些sql导致缓冲池页被刷新,如全表扫描遍历全表。防止一条指令拖慢其他指令效率。
Free列表保存空闲页
MyISAM 表锁 全文索引 不支持事务 缓冲区只缓存索引文件,不缓冲数据
MYD保存数据,MYI保存索引文件
myisampack使用Huffman编码压缩MYD,压缩后只读