缘由
我自认不是一个特别能鸡血自己去学习那些不直接应用到的知识的人。所以到现在还是没能深入 JVM 和红黑树,更不用说 Paxos/Raft 了。不过,如果有解决切实问题需要时,还算能快速入门吧。
最近项目在 Kubernetes 中使用到基于 iSCSI 的 CSI(存储插件)。遇到了一些麻烦,需要定位和解决。于是,开始了这期的 iSCSI 学习,并最后也似乎解决了问题。于是把学习结果记录下来,希望能对其它同学有用。对于自己,也好有个记录和总结吧。是的,还是老样子,没有什么大格局。
SCSI 是什么鬼
可能这个词对于90后非运维同学来说,和 ZMODEM、BBS 一样陌生。没关系,我来 wiki 一下。
Small Computer System Interface (SCSI, /ˈskʌzi/ SKUZ-ee) is a set of standards for physically connecting and transferring data between computers and peripheral devices.
大白话是:SCSI
是用于电脑与外部设备间连接与传输数据的一堆标准。
一张 1985 年的 ISA
接口的 SCSI 适配卡:
一开始,SCSI 适配到外设间用是的并口(parallel Interface)
后来发现并口在高速传输中有很大的问题(时钟偏差),串口(Serial interfaces)成为主流。
时钟偏差:
clock skew
。这里不打算展开说,我第一次看到这个词是在做微服务全链路跟踪(Open Tracing/Jaeger)时。
通讯协议
说到IO,不过是通讯,说到通讯,逃不过协议,说到协议,得先搞清楚协议的参与方:
下面是一个连接示例:
下面是规范定义的概念模型:
可见,SCSI 协议以 client-server 模式运行。但有其专用术语:
- Initiator: 即 Client
- Target: 即 Server
一般,上图 SCSI 适配器既充当Initiator
同时也是Target
(注:这两个概念在 iscsi 中有明显的分离)。但有时候,一个Target
可以同时服务多个Initiator
。
Logical Unit
:
一个 Target
可以连接多个逻辑存储卷。Initiator
在读写时,需要指定逻辑存储卷。一个 Logical Unit
一般对应电脑外部的存储设备,如简单硬盘或CD-ROM。但也有一个 RAID 硬盘阵列拆分为多个 Logical Unit
的情况。
Logical Unit Number(LUN)
:
有两个版本的解说:
解说一:
每个Logical Unit
均使用一个数字标识,这个数字就叫Logical Unit Number
。根据相关规范,这个数字在小于1字节时,每个bit有其意义和取值规范。其中一些bit和物理接口编址相关。
解说二:
Logical Unit Number
只是一个相对于具体Initiator
的专用编号。即Initiator
用这个编号来寻址到Logical Unit
。于对相同的Logical Unit
,每个Initiator
的Logical Unit Number
可以不同。(见: https://en.wikipedia.org/wiki/Logical_unit_number)
具体什么情况下是一还是二,我未深入研究。但有一点一致的是:
Initiator
要访问Logical Unit
,需要用Logical Unit Number
寻址。
好了,说在一大堆的 SCSI,还是回到主题 iSCSI
上吧
iSCSI 是什么
SCSI 在制订之时,用于主机对外设的连接。但后来有了大型网络储存设备方案,就出现了基于 IP/TCP 的 SCSI
,即 iSCSI(https://datatracker.ietf.org/doc/html/rfc3720)
。
在说 iSCSI 之前,不得不说它的竞争者 Fibre Channel SAN
。Fibre Channel SAN
顾名思义,就是用光纤做媒介的网络存储了。性能当然好,从主机出来,到中间交换机,全光纤。但最大问题是:贵! 在以太网统一天下的今天,再搞一套光纤基础设施显得成本太高。
iSCSI
保留了大部分的 SCSI 术语、协议和规范。只是在下面加了一层 TCP。
规范:https://datatracker.ietf.org/doc/html/rfc3720
为何要 iSCSI
在 VM 和 Cloud Native 时代,应用的分布式自动部署是默认的要求。而有状态应用、存储成为了难点。于是把存储移出应用主机,让应用可以独立于存储去移动,成为了一个可选方案。网络存储
,可以应用在这个场景。而 网络存储
按操作层面的不同,可分为:
- Block(块存储)
- File(文件存储)
- Object (对象存储)
NFS 属于 File
。而 iSCSI 属于 Block
。即以块设备作为操作接口。它是需要使用方自己的格式化、文件系统管理的能力。一般数据库类型的应用,更喜欢使用 Block
,因为可以直接管控IO同步时机与缓存(PageCache,O-Direct) 等,以优化性能和保证落盘事务一致性。
注:本文先不说 ceph 和 Rook。
iSCSI 与 Linux
Linux 有自己的 SCSI 与 iSCSI 相关实现。有兴趣的可以研究,不过,这不是本文的重点。
iSCSI 服务端(Target)
实现:
http://stgt.sourceforge.net/
安装教程:
https://www.tecmint.com/setup-iscsi-target-and-initiator-on-debian-9/
iSCSI 客户端(Initiator)
实现:
https://github.com/open-iscsi/open-iscsi
它包括两部分:
- 内核部分:scsi_transport_iscsi.ko, libiscsi.ko and iscsi_tcp.ko
- 用户空间部分:iscsid、iscsiadm
内核态负责数据面TCP通讯、块设备驱动。用户空间部分负责是控制面,如配置、管理 Target 会话与元信息收集。
安装教程:
https://www.tecmint.com/setup-iscsi-target-and-initiator-on-debian-9/
成功与 Target
建立会话,并获取对方元信息后,Linux iSCSI Initiator 会在 /dev
目录下维护Target
授权的设备文件。同时在 /dev/disk/by-path
下维护一个指向设备文件的链接文件如:
|
|
BTW:回应文章开头,我这次遇到的麻烦根源,就是上面的两种不同命名,一个开源的 CSI 没处理好。
之后,就可以 fdisk
去格式化。之后,就可以 mount /dev/xxxx /mydisk
了。
iSCSI 与 Kubernetes
Kubernetes 官方有 iSCSI CSI:
https://github.com/kubernetes/examples/tree/master/volumes/iscsi
以后,我再深入写写 CSI 的一些控制面流程。
结语
只是个流水账的技术文章,没什么好总结的。唯一让我感触的是,学 Linux Kernel 基本原理,看似无聊,还是有用的。前提是你主动去找用得着的地方。
参考
- https://en.wikipedia.org/wiki/SCSI
- https://en.wikipedia.org/wiki/SCSI_architectural_model
- https://en.wikipedia.org/wiki/Logical_unit_number
- https://en.wikipedia.org/wiki/SCSI_host_adapter
- https://www.t10.org/ftp/t10/document.02/02-119r0.pdf
- http://www.csit-sun.pub.ro/~cpop/Documentatie_SMP/Standarde_magistrale/SCSI/T10%20Technical%20Committee_files/scsi-3.htm
- https://en.wikipedia.org/wiki/Clock_skew
iSCSI 参考
- https://datatracker.ietf.org/doc/html/rfc3720
- https://docs.oracle.com/en/operating-systems/oracle-linux/6/admin/about-iscsi-storage.html