RGW NFS/ganesha 源码分析

0×1 RGW NFS Open 流程

0x 2 Ganesha 核心模块:
– MemoryManager 负责Ganesha的内存管理
– RPC SES_GSS 负责使用RPCSEC_GSS的数据传输,通常使用krb5,SPKM3或LIPKEY来管理
– NFS NFS协议,主要是消息结构模块
– Metadata(Inode) Cache: 元数据缓存
– File Content Cache: 负责数据缓存,主要是小数据。
– FSAL (File system Abstraction Layer, 抽象的访问对象)
– Hash Tables rbtree group。

内存管理:
LibC malloc / free调用,内存是采用calloc分配的。

哈希表:
redblack tree
主要守护进程
– dispatcher thread: 用于监听和分发传入的NFS、MOUNT请求。它会选择处于最空闲的worker线程然后将请求添加到这个worker线程的待处理列表中。这个线程会保留最近10分钟内的请求答复,如果在10分钟内收到相同指令(存在哈希表并用RPC Xid4值寻址),则会返回以前的请求回复。
– worker thread: Ganesha中的核心线程,也是使用最多的线程。worker线程等待dispatcher的调度,收到请求后先对其进行解码,然后通过调用inode cache API和file content API来完成请求操作。
缓存:
Cache Inode Layer将元数据与对应FSAL对象handle放入哈希表中,用来关联条目。初版的Ganesha采用’write through’缓存策略来做元数据缓存。实例的属性会在一定的时间(可定义)后过期,过期后该实例将会在内存中删除。每个线程有一个LRU(Least Recently Used) 列表,每个缓存实例只能存在于1个线程的LRU中,如果某个线程获得了某个实例,将会要求原线程在LRU列表中释放对应条目。

每个线程需要自己负责垃圾回收,当垃圾回收开始时,线程将从LRU列表上最旧的条目开始执行。 然后使用特定的垃圾策略来决定是否保存或清除条目。由于元数据缓存应该非常大(高达数百万条目),因此占满分配内存的90%(高位)之前不会发生垃圾回收。Ganesha尽可能多得将FSAL对象放入缓存的‘树型拓扑’中,其中节点代表目录,叶子可代表文件和符号链接;叶子的垃圾回收要早于节点,当节点中没有叶子时才会做垃圾回收。

File Content Cache数据缓存并不是独立于与Inode Cache,一个对象的元数据缓存和数据缓存会一一对应(数据缓存是元数据缓存的‘子缓存’),从而避免了缓存不统一的情况。文件内容会被缓存至本地文件系统的专用目录中,一个数据缓存实例会对应2个文件:索引文件和数据文件。数据文件等同于被缓存的文件。索引文件中包含了元数据信息,其中包含了对重要的FSAL handle。索引文件主要用于重建数据缓存,当服务器端崩溃后没有干净地清掉缓存时,FSAL handle会读取索引文件中的信息来重建元数据缓存,并将其指向数据文件,用以重建数据缓存实例。

当缓存不足时,worker thread会查看LRU列表中很久未被打开的实例,然后开始做元数据缓存回收。当元数据缓存回收开始时,数据缓存的垃圾回收也会同时进行:在回收文件缓存实例时,元数据缓存会问询数据缓存是否认识该文件实例,如果不认识则代表该数据缓存已经无效,则元数据回收正常进行,并完成实例缓存回收;如果认识,对应的文件缓存以及数据缓存均会被回收,随后对应的元数据缓存也会被回收。这样保证了一个数据缓存有效的实例不会被回收。

这种方式很符合Ganesha的架构设计:worker线程可以同时管理元数据缓存和数据缓存,两者一直保持一致

0×3 RGW-NFS release notes:
New NFS-Ganesha FSALexporting RGW Namespace. Runs a full
Ceph RGW under an NFS-Ganesha process. Cache coherent peer
of all gateways in the cluster.
Goals:
Add RGW/S3 as an adjunct namespace on existing POSIX
clients
Support S3 Legacy “Prefix and Delimiter” Namespace
Convention
Only supports ‘/’ delimiter currently
Build foundation for more interesting workflows, e.g.
pNFS direct placement of sharded objects (future)
consistent caching (future)
0×4 参照:

http://blog.umcloud.com/nfs-ganesha/

解决X520 unsupported SFP+ or QSFP module 问题

解决X520无法识别的问题;
加载ixgbe模块发现问题:
[0x01 描述]

[0x02 安装驱动]
驱动为:ixgbe-5.3.3

[0x03 查看网卡信息]

[0x04 重新加载]

[0x05 再次查看]

systemtap 学习

SystemTap 提供了一个简单的命令行接口和强大的脚本语言,同时预定义了丰富的脚本库。基于内核中的 kprobes,SystemTap 允许用户自由地从运行中的内核收集调试信息和性能数据,来用于之后的分析和处理。用户可以随时开始或者停止这个收集过程,而无需漫长的修改代码、编译内核和重启系统这个循环
0×01 SystemTap Features

动态的性能分析能力,不打断分析目标的逻辑,不改写、侵入分析目标的代码。
多种多样的probe events
也可以调试分析功能性的问题
低开销,安全性高,适用于正式产品
持续长时间的性能分析
按需probe,可以用脚本编写,过滤信息的输出和采集
易用性较好

0×02 SystemTap 利用的技术Kprobes/Kretprobe/Uprobes/Relayfs
kernel层的一个接口,注册后可以非侵入的动态插入绝大多数(注1)函数并采集调试信息和性能数据。当插桩点被hit时,会指定一个自定义的处理函数(handler)来处理新的逻辑。
Kprobes 从 2.6.9 版本开始就添加到主流的 Linux 内核中,并且为探测内核提供一般性服务。它提供一些不同的服务,但最重要的两种服务是 Kprobe 和 Kretprobe。Kprobes插桩的技术很简单,同调试器和动态补丁技术的原理大致相同。首先会拷贝一份需要probe点的指令内容,并且把旧的代码段替换成一个断点指令(e.g., int3 on i386 and x86_64)。当断点指令被触发后,处理了新逻辑,然后会恢复原来的代码段内容,接着执行原始的指令(从断点开始)。
Kretprobes 有所不同,它操作调用函数的返回结果。注意,因为一个函数可能有多个返回点,所以听起来事情有些复杂。不过,它实际使用一种称为 trampoline 的简单技术。您将向函数条目添加一小段代码,而不是检查函数中的每个返回点。这段代码使用 trampoline 地址替换堆栈上的返回地址 —— Kretprobe 地址。当该函数存在时,它没有返回到调用方,而是调用 Kretprobe(执行它的功能),然后从 Kretprobe 返回到实际的调用方。
Relayfs 一种高速的数据转发文件系统。可以从kernel层高速,直接,可靠的把数据转发到用户空间读。
许多trace/debug工具都是利用了relayfs机制,eg. Systemtap/Lttng/Debugfs
0×03 SystemTap working
stap
语法分析阶段(parse)
主要是检查输入脚本是否存在语法错误,例如大括号是否匹配、变量定义是否规范等
细化(Elaborate)
细化是分析输入脚本并解析对内核的引用或用户符号与 tapsets 的处理阶段。Tapsets 是用来扩展脚本能力的脚本或 C 代码库。细化将脚本中的外部引用解析为符号信息并导入脚本子程序,为下一步转换为 C 程序做准备,这个过程就类似于将库文件链接到目标文件。对内核数据如函数参数、局部和全局变量、函数以及源地址都需要被解析为运行时实际的地址,这是通过对构建内核时编译器产生的 DWARF 调试信息进行处理来实现的。所有的调试数据都会在内核模块运行之前被处理。调试数据包含足够的信息来定位内联函数、局部变量、类型以及一些通常不被导出到内核模块的声明。
下面总结一下细化阶段所做的主要工作:

获取用户的探测脚本
预处理宏
包含所需要的脚本库
解析代码中对符号的引用
查找函数入口地址
查找行号信息
查找全局和局部变量的类型及地址

转换(Translate)
脚本被细化后它将会被转换为 C 语言代码,每个脚本子程序都被扩展成C语言代码块并进行安全检查,例如对循环结构进行递增检查了防止无限循环。由多个探测点共享的变量会被映射成适当的静态声明,并以块为单位进行访问保护。在内核中使用kprobes中的注册APIs对探测点处理器(probe handlers)进行注册。对于在内核中的探测点,会被插入到内核的内存空间中;对于用户级别探测点,它将被插入到可执行代码中,当处理器在内核中运行时将其载入到用户的内存空间。
构造(Build)
转换完成后,产生的 C 语言代码会被编译并与运行时进行链接成一个stand-alone 内核模块。该模块可被加密标记以用于安全归档或远程使用。
运行(Execution)
生成模块后 SystemTap 驱动程序会使用 insmod 将内核模块载入。该模块会进行初始化、插入探测点,然后等待探测点被触发。探测点被触发后会调用相关联的处理器程序并挂起执行线程,当该探测点所有的处理器都运行后,线程重新运行。当用户发送中断或脚本调用 exit 时,SystemTap 脚本将中止运行。然后卸载模块并移除探测点。
数据采集
SystemTap 需要将从内核中获取的数据传输到用户空间,并且需要很高的吞吐量、低延迟以及最小化对被监测系统性能的影响。缺省情况下,SystemTap 的输出会在脚本出口以批处理的方式写入 stdout,同时该输出会被自动保存到文件中。在用户空间,SystemTap 可以以简单的文本方式显示数据,或使用图形类的应用程序生成计算机可读的表格数据等。

0×04 语言基础
编写函数体和探测处理器的语法大部分借鉴于 awk 和 C 语言。SystemTap 还允许 C、C++和 awk 风格的注释。除了$也是合法的字符外,SystemTap 定义标识符的语法与 C 语言完全一样。标识符用来命名变量和函数,以$开头的标识符被认为是对目标程序(即被监测程序)中变量的引用而不是 SystemTap 脚本中的变量。SystemTap 的语言中包括少量的数据类型,但是没有类型声明:变量的类型是从它的使用中推断出来的。类似的,字符串和数字之间也没有隐式的类型转换。
语言中包含传统的if-then-else 语句以及 C语言和 awk 中的表达式,同时还支持结构化控制语句如 for和 while 循环,但不支持非结构化操作如标号和 goto 语句。为支持关联数组,SystemTap 语言包含了迭代器和 delete 语句。迭代器语句允许程序员指定执行数组中所有成员的操作,delete 操作可以移除数组中一个或全部成员。C 语言中典型的算术、位、赋值及一元操作在 SystemTap中都可以使用,但都是操作在 64 位数字上的,赋值和比较运算符可以重载为字符串使用。
Events
探测点指定了在内核的什么位置进行探测,探测点还可以定义在与目标程序上某个点没有联系的抽象事件上,但这时转换器就不能获得太多关于探测点的符号信息。

Handlers
探测点名称后紧跟的一组大括号内定义了每次内核运行到该探测点时需要进行的操作,比如可以指定输出数据过滤的条件,或者更为复杂的控制逻辑。这些操作完成后再返回探测点,继续下面的指令。
Helper functions

Tapset
当我们诊断系统级的问题时,通常需要跟踪操作系统和应用程序的不同子系统。为使我们更方便的进行诊断,SystemTap 包含了一个为多个子系统编写好的监测模块库,即 tapsets,用户可以在脚本中使用已经发布的tapsets。Tapset 的主要思想是:一个给定子系统的专家知道哪些方面对于深入理解该子系统是重要的;该专家会将重要的数据以 tapset 的形式,通过在探测点中调用一个或多个函数进行输出。这样,我们不需要成为内核所有领域中的专家,但仍然可以从系统中获得重要的数据。Tapsets已经覆盖包含的子系统: systemcalls, process, scheduler, filesystem, networking etc.

0×05 Systemtap安全特性
使用的toolchain经过了很好的测试,没有用新的compiler or interpreter
使用了经过完善测试的内核特性
另外systemtap语言本身的安全特性有:

No dynamic memory allocation
Types and type conversions limited
Limited pointer operations

内嵌的安全检查:

Infinite loops and recursion
Invalid variable access
Division by zero
Restricted access to kernel memory
Array bound checks
Version compatibility checks

Limitations

Off kernel. Generating kernel modules
Running kernel modules. Requires privilege to load, mistakes are fatal, mitigated by protected stap language
No early boot tracing
Review kernel codes detailedly, or have to understand tapsets clearly
Single step break

0×06 备注
1.实际上,systemtap也不是所有的kernel函数都可以插桩,有个blacklist屏蔽了systemstap插桩可能会引起问题的函数列表
2.尽管该语言允许开发复杂的脚本,但每个探针只能执行 1000 条语句(这个数量是可配置的)
3 systemtap tutorial
4 l-systemtap
5 systemtap-intro

ceph的pool的pg修改值的计算

pg的修改
当扩大pg num的时候,有时候会遇到报错:

限制pg spliting的参数来源于mon_osd_max_split_count value。
查看配置文件

计算脚本:

结果输出

block_size的计算

If the value of the above calculation is less than the value of ( OSD# ) / ( Size ), then the value is updated to the value of ( OSD# ) / ( Size ). This is to ensure even load / data distribution by allocating at least one Primary or Secondary PG to every OSD for every Pool.
The output value is then rounded to the nearest power of 2.
Tip: The nearest power of 2 provides a marginal improvement in efficiency of the CRUSH algorithm.
If the nearest power of 2 is more than 25% below the original value, the next higher power of 2 is used.

pg与osd的对应关系查找

利用pg在pool以及osd的分布关系可以更好的分析pg的分布是否均匀

首先获取pg的query数据。利用Ansible模块获取数据。数据如下:

利用python分析该数据: