Please enable Javascript to view the contents

存储老爷车上云 —— iSCSI简介

 ·  ☕ 5 分钟

缘由

我自认不是一个特别能鸡血自己去学习那些不直接应用到的知识的人。所以到现在还是没能深入 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,每个 InitiatorLogical 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 SANFibre 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 下维护一个指向设备文件的链接文件如:

1
2
3
4
5
# 对于 < 256 的 Logical Unit Number(LUN): 102
ip-10.0.xx.xx:3260-iscsi-iqn.2xx5-07.com.nexenta:02:xxx-a09e-xx-f91a-xx-lun-102  -> ../../sdgw

# 对于 > 255 的 Logical Unit Number(LUN) 用16进制。如 LUN 392 表示为
ip-10.0.xx.xx:3260-iscsi-iqn.2xx5-07.com.nexenta:02:xxx-a09e-xx-f91a-xx-lun-0x0188000000000000 -> ../../sdkz 

BTW:回应文章开头,我这次遇到的麻烦根源,就是上面的两种不同命名,一个开源的 CSI 没处理好。

之后,就可以 fdisk去格式化。之后,就可以 mount /dev/xxxx /mydisk 了。

iSCSI 与 Kubernetes

Kubernetes 官方有 iSCSI CSI:
https://github.com/kubernetes/examples/tree/master/volumes/iscsi

以后,我再深入写写 CSI 的一些控制面流程。

结语

只是个流水账的技术文章,没什么好总结的。唯一让我感触的是,学 Linux Kernel 基本原理,看似无聊,还是有用的。前提是你主动去找用得着的地方。

参考

iSCSI 参考

iSCSI 操作参考

分享

Mark Zhu
作者
Mark Zhu
An old developer