简介
存储虚拟化技术 是一种 在 物理 存储 介质 上 , 二次进行 存储 分配的 技术.
比如 lvm 以及 常见的 分区 也是 一种 简单 的 存储 虚拟化.
一块 物理磁盘 分成了 两块 进行使用, 或者 10 块 磁盘 聚合成 1 块 存储磁盘.
用来 满足 不同用户的 不同需求.
特点
区别于 cpu 以及 内存 , 由于 当前(2021年) 网卡 速度 在 100m-1000g/s 之间, 所以 cpu 与 内存 是 无法 进行 跨节点的 虚拟化的, 即便 强行实现 ,性能 也 十分低下,
但是 普通 磁盘 速度 远小于 网卡 速度, 以 较新的 nvme 为例, 2-4g/s. 并且 同一个 主机 可能 插有 数十块 存储磁盘. 所以 存储 介质的 虚拟化 , 可以 通过 网络 进行 聚合. 结合上 元数据的 查找 优化, 以及 利用 内存 缓存 热点数据. 都 十分 具有前景.
cinder 是什么
openstack 的 存储 插件, cinder 并没有 自己实现 所有的 存储 能力, 而是 借用 不同的 接口 实现了 自身的 存储 能力.
比如 调用 lvm 进行 本地的 虚拟机 磁盘存储,直接 利用 本地的 磁盘 存储能力.
或者 调用 rbd 依托于 ceph 进行 存储。
cinder 服务 构成
api, scheduler, volume, backup,服务 构成。
可以通过 systemctl status 查看 相应 服务 状态,
配置 文件 /etc/cinder
数据 目录 /var/lib/cinder
日志 目录 /var/log/cinder
可以 通过 8776 请求 方式 调用,
也可以 通过 cinderclient 项目 提供的 cinder 命令行 cli 工具 调用。
以创建 volume 为例 分析 cinder 代码
命令行 -> api -> api-server
可以直接 命令行 也可以 api
创建 大概 过程
- v2/volume/api create
- cinder/volume/api create
- scheduler_rpcapi
函数调用顺序
- web 或者 cinderclint 提交 volume_create 请求
- 请求 会被 url 到 api 映射到以下函数
/root/cinder/cinder/volume/api.py:218 def create
def create(self, context, size, name, description, snapshot=None,
image_id=None, volume_type=None, metadata=None,
availability_zone=None, source_volume=None,
scheduler_hints=None,
source_replica=None, consistencygroup=None,
cgsnapshot=None, multiattach=False, source_cg=None):
3.参数检查
其中检查参数的 格式合法性, 也会检查 资源存量 是否足够。
# 参数检查内容很多,列举一个 if size and (not strutils.is_int_like(size) or int(size) <= 0): msg = _('Invalid volume size provided for create request: %s ' '(size argument must be an integer (or string ' 'representation of an integer) and greater ' 'than zero).') % size raise exception.InvalidInput(reason=msg)
- 通过之后,创建 sched_rpcapi volume_rpcapi flow_engine
其中 /root/cinder/cinder/volume/rpcapi.py:35 volume_rpcapi 中有更加详细的创建过程
sched_rpcapi = (self.scheduler_rpcapi if (not cgsnapshot and not source_cg) else None) volume_rpcapi = (self.volume_rpcapi if (not cgsnapshot and not source_cg) else None) flow_engine = create_volume.get_flow(self.db, self.image_service, availability_zones, create_what, sched_rpcapi, volume_rpcapi)
- 执行 flow_engine 创建 volume
# Attaching this listener will capture all of the notifications that # taskflow sends out and redirect them to a more useful log for # cinders debugging (or error reporting) usage. with flow_utils.DynamicLogListener(flow_engine, logger=LOG): flow_engine.run() vref = flow_engine.storage.fetch('volume') LOG.info(_LI("Volume created successfully."), resource=vref) return vref
- 返回 vref ,volume 对象的ref(引用对象)
volume_rpc_api 创建 volume 过程
def create_volume(self, ctxt, volume, host, request_spec, filter_properties, allow_reschedule=True): request_spec_p = jsonutils.to_primitive(request_spec) msg_args = {'volume_id': volume.id, 'request_spec': request_spec_p, 'filter_properties': filter_properties, 'allow_reschedule': allow_reschedule} if self.client.can_send_version('2.0'): version = '2.0' msg_args['volume'] = volume elif self.client.can_send_version('1.32'): version = '1.32' msg_args['volume'] = volume else: version = '1.24' cctxt = self._get_cctxt(host, version) request_spec_p = jsonutils.to_primitive(request_spec) """Invoke a method and return immediately. See RPCClient.cast().""" cctxt.cast(ctxt, 'create_volume', **msg_args) # 实际上 到此为止 创建服务就是 cctxt 向消息队列提供了一个任务 --> self.transport._send(self.target, ctxt, msg, retry=self.retry)
判断 list 或者 map 中是否 有哪些键名
# Check that the required keys are present, return an error if they # are not. required_keys = set(['ref', 'host']) missing_keys = list(required_keys - set(volume.keys())) if missing_keys: # 代表 这些 键名 不全部存在 msg = _("The following elements are required: %s") % \ ', '.join(missing_keys) raise exc.HTTPBadRequest(explanation=msg)