当前位置: 首页 > 编程日记 > 正文

cinder存储服务

一、cinder 介绍:

理解 Block Storage

操作系统获得存储空间的方式一般有两种:

1、通过某种协议(SAS,SCSI,SAN,iSCSI 等)挂接裸硬盘,然后分区、格式化、创建文件系统;或者直接使用裸硬盘存储数据(数据库)

2、通过 NFS、CIFS 等 协议,mount 远程的文件系统 

第一种裸硬盘的方式叫做 Block Storage(块存储),每个裸硬盘通常也称作 Volume(卷) 第二种叫做文件系统存储。NAS 和 NFS 服务器,以及各种分布式文件系统提供的都是这种存储。 

理解 Block Storage Service

Block Storage Servicet 提供对 volume 从创建到删除整个生命周期的管理。从 instance 的角度看,挂载的每一个 Volume 都是一块硬盘。OpenStack 提供 Block Storage Service 的是 Cinder,其具体功能是:

1、提供 REST API 使用户能够查询和管理 volume、volume snapshot 以及 volume type

2、提供 scheduler 调度 volume 创建请求,合理优化存储资源的分配

3、通过 driver 架构支持多种 back-end(后端)存储方式,包括 LVM,NFS,Ceph 和其他诸如 EMC、IBM 等商业存储产品和方案 

Cinder 架构

下图是 cinder 的逻辑架构图

 

Cinder 包含如下几个组件:

cinder-api

接收 API 请求, 调用 cinder-volume 。是整个 Cinder 组件的门户,所有 cinder 的请求都首先由 cinder-api 处理。cinder-api 向外界暴露若干 HTTP REST API 接口。在 keystone 中我们可以查询 cinder-api 的 endponits。

客户端可以将请求发送到 endponits 指定的地址,向 cinder-api 请求操作。 当然,作为最终用户的我们不会直接发送 Rest API 请求。OpenStack CLI,Dashboard 和其他需要跟 Cinder 交换的组件会使用这些 API。

cinder-api 对接收到的 HTTP API 请求会做如下处理:

1、检查客户端传人的参数是否合法有效

2、调用 cinder 其他子服务的处理客户端请求

3、将 cinder 其他子服务返回的结果序列号并返回给客户端

cinder-api 接受哪些请求呢?简单的说,只要是 Volume 生命周期相关的操作,cinder-api 都可以响应。大部分操作都可以在 Dashboard 上看到。

cinder-volume

管理 volume 的服务,与 volume provider 协调工作,管理 volume 的生命周期。运行 cinder-volume 服务的节点被称作为存储节点。

cinder-volume 在存储节点上运行,OpenStack 对 Volume 的操作,最后都是交给 cinder-volume 来完成的。cinder-volume 自身并不管理真正的存储设备,存储设备是由 volume provider 管理的。cinder-volume 与 volume provider 一起实现 volume 生命周期的管理。 

通过 Driver 架构支持多种 Volume Provider

接着的问题是:现在市面上有这么多块存储产品和方案(volume provider),cinder-volume 如何与它们配合呢? 

通过的 Driver 架构。 cinder-volume 为这些 volume provider 定义了统一的接口,volume provider 只需要实现这些接口,就可以 Driver 的形式即插即用到 OpenStack 系统中。 

定期向 OpenStack 报告计算节点的状态

cinder-volume 会定期向 Cinder 报告存储节点的空闲容量来做筛选启动volume

实现 volume 生命周期管理

Cinder 对 volume 的生命周期的管理最终都是通过 cinder-volume 完成的,包括 volume 的 create、extend、attach、snapshot、delete 等。

cinder-scheduler

scheduler 通过调度算法选择最合适的存储节点创建 volume。 创建 Volume 时,cinder-scheduler 会基于容量、Volume Type 等条件选择出最合适的存储节点,然后让其创建 Volume

volume provider

数据的存储设备,为 volume 提供物理存储空间。 cinder-volume 支持多种 volume provider,每种 volume provider 通过自己的 driver 与cinder-volume 协调工作。

Message Queue

Cinder 各个子服务通过消息队列实现进程间通信和相互协作。因为有了消息队列,子服务之间实现了解耦,这种松散的结构也是分布式系统的重要特征。

Database Cinder 

有一些数据需要存放到数据库中,一般使用 MySQL。数据库是安装在控制节点上的,比如在我们的实验环境中,可以访问名称为“cinder”的数据库。

 

物理部署方案

Cinder 的服务会部署在两类节点上,控制节点和存储节点。我们来看看控制节点 controller 上都运行了哪些 cinder-* 子服务。

 

cinder-api 和 cinder-scheduler 部署在控制节点上,这个很合理。

至于 cinder-volume 也在控制节点上可能有些同学就会迷糊了:cinder-volume 不是应该部署在存储节点上吗?

要回答这个问题,首先要搞清楚一个事实: OpenStack 是分布式系统,其每个子服务都可以部署在任何地方,只要网络能够连通。无论是哪个节点,只要上面运行了 cinder-volume,它就是一个存储节点,当然,该节点上也可以运行其他 OpenStack服务。

cinder-volume 是一顶存储节点帽子,cinder-api 是一顶控制节点帽子。在我们的环境中,devstack-controller 同时戴上了这两顶帽子,所以它既是控制节点,又是存储节点。当然,我们也可以用一个专门的节点来运行 cinder-volume。

这再一次展示了 OpenStack 分布式架构部署上的灵活性: 可以将所有服务都放在一台物理机上,用作一个 All-in-One 的测试环境;而在生产环境中可以将服务部署在多台物理机上,获得更好的性能和高可用。

RabbitMQ 和 MySQL 通常放在控制节点上。另外,也可以用 cinder service list 查看 cinder-* 子服务都分布在哪些节点上

还有一个问题:volume provider 放在那里?

一般来讲,volume provider 是独立的。cinder-volume 使用 driver 与 volume provider 通信并协调工作。所以只需要将 driver 与 cinder-volume 放到一起就可以了。在 cinder-volume 的源代码目录下有很多 driver,支持不同的 volume provider。

后面我们会以 LVM 和 NFS 这两种 volume provider 为例讨论 cinder-volume 的使用,其他 volume provider 可以查看 OpenStack 的 configuration 文档。

二、 Cinder 的设计思想:

从 volume 创建流程看 cinder-* 子服务如何协同工作

对于 Cinder 学习来说,Volume 创建是一个非常好的场景,涉及各个 cinder-* 子服务,下面是流程图:

 

客户(可以是 OpenStack 最终用户,也可以是其他程序)向 API(cinder-api)发送请求:“帮我创建一个 volume”

API 对请求做一些必要处理后,向 Messaging(RabbitMQ)发送了一条消息:“让 Scheduler 创建一个 volume”

Scheduler(cinder-scheduler)从 Messaging 获取到 API 发给它的消息,然后执行调度算法,从若干计存储点中选出节点 A

Scheduler 向 Messaging 发送了一条消息:“让存储节点 A 创建这个 volume” 

存储节点 A 的 Volume(cinder-volume)从 Messaging 中获取到 Scheduler 发给它的消息,然后通过 driver 在 volume provider 上创建 volume

Cinder 的设计思想

Cinder 延续了 Nova 的以及其他组件的设计思想。

API 前端服务

cinder-api 作为 Cinder 组件对外的唯一窗口,向客户暴露 Cinder 能够提供的功能,当客户需要执行 volume 相关的操作,能且只能向 cinder-api 发送 REST 请求。这里的客户包括终端用户、命令行和 OpenStack 其他组件。

设计 API 前端服务的好处在于:

1、对外提供统一接口,隐藏实现细节

2、API 提供 REST 标准调用服务,便于与第三方系统集成

3、可以通过运行多个 API 服务实例轻松实现 API 的高可用,比如运行多个 cinder-api 进程

Scheduler 调度服务

Cinder 可以有多个存储节点,当需要创建 volume 时,cinder-scheduler 会根据存储节点的属性和资源使用情况选择一个最合适的节点来创建 volume。

调度服务就好比是一个开发团队中的项目经理,当接到新的开发任务时,项目经理会根据任务的难度,每个团队成员目前的工作负荷和技能水平,将任务分配给最合适的开发人员。

Worker 工作服务

调度服务只管分配任务,真正执行任务的是 Worker 工作服务。

在 Cinder 中,这个 Worker 就是 cinder-volume 了。这种 Scheduler 和 Worker 之间职能上的划分使得 OpenStack 非常容易扩展:当存储资源不够时可以增加存储节点(增加 Worker)。 当客户的请求量太大调度不过来时,可以增加 Scheduler。

Driver 框架

OpenStack 作为开放的 Infrastracture as a Service 云操作系统,支持业界各种优秀的技术,这些技术可能是开源免费的,也可能是商业收费的。

这种开放的架构使得 OpenStack 保持技术上的先进性,具有很强的竞争力,同时又不会造成厂商锁定(Lock-in)。 那 OpenStack 的这种开放性体现在哪里呢?一个重要的方面就是采用基于 Driver 的框架。

以 Cinder 为例,存储节点支持多种 volume provider,包括 LVM, NFS, Ceph, GlusterFS,以及 EMC, IBM 等商业存储系统。 cinder-volume 为这些 volume provider 定义了统一的 driver 接口,volume provider 只需要实现这些接口,就可以 driver 的形式即插即用到 OpenStack 中。下面是 cinder driver 的架构示意图:

 

在 cinder-volume 的配置文件 /etc/cinder/cinder.conf 中 volume_driver 配置项设置该存储节点使用哪种 volume provider 的 driver,下面的示例表示使用的是 LVM。

三、 cinder服务部署

三个节点首先各添加一块SATA类型硬盘,20G即可。控制节点#第一步 登陆数据库mysql -u root -p#创建存储服务的数据库CREATE DATABASE cinder;
#创建cinder的用户并允许本地和第三方登陆,并设置密码GRANT ALL PRIVILEGES ON cinder.* TO 'cinder'@'localhost' \IDENTIFIED BY 'CINDER_DBPASS';
GRANT ALL PRIVILEGES ON cinder.* TO 'cinder'@'%' \IDENTIFIED BY 'CINDER_DBPASS';
#退出exit
#第二步 宣告环境变量source openrc
#在openstack环境中创建cinder用户设置密码openstack user create --domain default --password=cinder cinder
#将cinder用户设置为管理员openstack role add --project service --user cinder admin
#创建cinder API服务v2和v3版本openstack service create --name cinderv2 \--description "OpenStack Block Storage" volumev2
openstack service create --name cinderv3 \--description "OpenStack Block Storage" volumev3
#给这个两个服务创建服务端点openstack endpoint create --region RegionOne \volumev2 public http://controller:8776/v2/%\(project_id\)s
openstack endpoint create --region RegionOne \volumev2 internal http://controller:8776/v2/%\(project_id\)s
openstack endpoint create --region RegionOne \volumev2 admin http://controller:8776/v2/%\(project_id\)s
openstack endpoint create --region RegionOne \volumev3 public http://controller:8776/v3/%\(project_id\)s
openstack endpoint create --region RegionOne \volumev3 internal http://controller:8776/v3/%\(project_id\)s
openstack endpoint create --region RegionOne \volumev3 admin http://controller:8776/v3/%\(project_id\)s
#第三步 安装cinderyum install openstack-cinder
#修改配置文件cd /etc/cinder/
cp cinder.conf cinder.conf.bak
vim cinder.conf
#清空原有内容,粘贴如下内容
[DEFAULT]my_ip = #本地第一块网卡IP#glance_api_servers = http://controller:9292

auth_strategy = keystone#enabled_backends = lvmtransport_url = rabbit://openstack:admin@controller
[backend][barbican][brcd_fabric_example][cisco_fabric_example][coordination][cors][cors.subdomain][database]connection = mysql+pymysql://cinder:CINDER_DBPASS@controller/cinder
[fc-zone-manager][healthcheck][key_manager][keystone_authtoken]auth_uri = http://controller:5000

auth_url = http://controller:35357

memcached_servers = controller:11211auth_type = passwordproject_domain_name = defaultuser_domain_name = defaultproject_name = serviceusername = cinderpassword = cinder[matchmaker_redis][oslo_concurrency]lock_path = /var/lib/cinder/tmp[oslo_messaging_amqp][oslo_messaging_kafka][oslo_messaging_notifications][oslo_messaging_rabbit][oslo_messaging_zmq][oslo_middleware][oslo_policy][oslo_reports][oslo_versionedobjects][profiler][ssl][lvm]#volume_driver = cinder.volume.drivers.lvm.LVMVolumeDriver#volume_group = cinder-vg#volumes_dir = $state_path/volumes#iscsi_protocol = iscsi#iscsi_helper = lioadm#iscsi_ip_address = 172.16.254.63#同步cinder数据库su -s /bin/sh -c "cinder-manage db sync" cinder
#第四步 配置计算服务使用后端存储(每个计算服务都要配置)vim /etc/nova/nova.conf
[cinder]
os_region_name = RegionOne
#重启nova-api#开启cinder服务systemctl enable openstack-cinder-api.service openstack-cinder-scheduler.service
systemctl start openstack-cinder-api.service openstack-cinder-scheduler.service
存储节点#第一步 安装cinder和lvm2、targetcli、python-keystoneyum install lvm2
yum install openstack-cinder targetcli python-keystone
#开启lvm2systemctl start lvm2-lvmetad.service
#创建物理卷pvcreate /dev/sdb
#查看是否创建成功pvdisplay 或者 pvscan
#添加卷组vgcreate cinder-volumes /dev/sdb
#第二步 编辑lvm配置文件vim /etc/lvm/lvm.conf
#把如下参数插入进devices配置段内
filter = [ "a/sdb/", "r/.*/"]
#编辑cinder配置文件cd /etc/cinder/
cp cinder.conf cinder.conf.bak
vim cinder.conf
#清空原有内容,粘贴如下内容
[DEFAULT]my_ip = #本地第一块网卡IPglance_api_servers = http://controller:9292

auth_strategy = keystoneenabled_backends = lvmtransport_url = rabbit://openstack:admin@controller
[backend][barbican][brcd_fabric_example][cisco_fabric_example][coordination][cors][cors.subdomain][database]connection = mysql+pymysql://cinder:CINDER_DBPASS@controller/cinder
[fc-zone-manager][healthcheck][key_manager][keystone_authtoken]auth_uri = http://controller:5000

auth_url = http://controller:35357

memcached_servers = controller:11211auth_type = passwordproject_domain_name = defaultuser_domain_name = defaultproject_name = serviceusername = cinderpassword = cinder[matchmaker_redis][oslo_concurrency]lock_path = /var/lib/cinder/tmp[oslo_messaging_amqp][oslo_messaging_kafka][oslo_messaging_notifications][oslo_messaging_rabbit][oslo_messaging_zmq][oslo_middleware][oslo_policy][oslo_reports][oslo_versionedobjects][profiler][ssl][lvm]volume_driver = cinder.volume.drivers.lvm.LVMVolumeDriver #卷服务的驱动volume_group = cinder-volumes   #我们刚才创建的卷组名volumes_dir = $state_path/volumes iscsi_protocol = iscsi  #使用的协议iscsi_helper = lioadmiscsi_ip_address = #本机IP  #iscsi服务器地址# 启动openstack-cinder-volume服务和target服务systemctl enable openstack-cinder-volume.service target.service
systemctl start openstack-cinder-volume.service target.service

转载于:https://www.cnblogs.com/shuaiyin/p/10995944.html

相关文章:

Ubuntu 14.04 64位机上配置Android Studio操作步骤

Android Studio是一个为Android平台开发程序的集成开发环境。2013年5月16日在Google I/O上发布,可供开发者免费使用。Android Studio基于JetBrains IntelliJ IDEA,为Android开发特殊定制,并在Windows、OS X和Linux平台上均可运行。1. 从 htt…

大规模1.4亿中文知识图谱数据,我把它开源了

作者 | Just出品 | AI科技大本营(ID:rgznai100)人工智能从感知阶段逐步进入认知智能的过程中,知识图谱技术将为机器提供认知思维能力和关联分析能力,可以应用于机器人问答系统、内容推荐等系统中。不过要降低知识图谱技术应用的门…

使用CSS 3创建不规则图形

2019独角兽企业重金招聘Python工程师标准>>> 前言 CSS 创建复杂图形的技术即将会被广泛支持,并且应用到实际项目中。本篇文章的目的是为大家开启它的冰山一角。我希望这篇文章能让你对不规则图形有一个初步的了解。 现在,我们已经可以使用CSS…

谷歌丰田联合成果ALBERT了解一下:新轻量版BERT,参数小18倍,性能依旧SOTA

作者 | Less Wright编译 | ronghuaiyang来源 | AI公园(ID:AI_Paradise)【导读】这是来自Google和Toyota的新NLP模型,超越Bert,参数小了18倍。你以前的NLP模型参数效率低下,而且有些过时。祝你有美好的一天。谷歌Resear…

C++中extern C的使用

C程序有时需要调用其它语言编写的函数,最常见的是调用C语言编写的函数。像所有其它名字一样,其它语言中的函数名字也必须在C中进行声明,并且该声明必须指定返回类型和形参列表。对于其它语言编写的函数来说,编译器检查…

Linux之tmpwatch命令

1、tmpwatch命令功能简介[rootvms002 /]# whatis tmpwatch tmpwatch (8) - removes files which havent been accessed for a period of... #删除一段时间内未被访问的文件tmpwatch删除最近一段时间内没有被访问的文件,时间以小时为单位,节省磁盘空间。…

你不得不知道的Visual Studio 2012(1)- 每日必用功能

2019独角兽企业重金招聘Python工程师标准>>> Visual Studio 2012已经正式发布,有很多花哨的新特性,也有很多方便使用者的新功能,当然也有负面声音。对于我们程序员,最关心的还是如何快速掌握VS2012,用于平时…

C++11中std::unique_lock的使用

std::unique_lock为锁管理模板类,是对通用mutex的封装。std::unique_lock对象以独占所有权的方式(unique owership)管理mutex对象的上锁和解锁操作,即在unique_lock对象的声明周期内,它所管理的锁对象会一直保持上锁状态;而unique…

为何Google将几十亿行源代码放在一个仓库?| CSDN博文精选

作者 | Rachel Potvin,Josh Levenberg译者 | 张建军编辑 | apddd【AI科技大本营导读】与大多数开发者的想象不同,Google只有一个代码仓库——全公司使用不同语言编写的超过10亿文件,近百TB源代码都存放在自行开发的版本管理系统Piper中&#…

小小hanoi

为什么80%的码农都做不了架构师?>>> View Code #include " iostream " using namespace std; int k 0 ; void hanoi( int m , char a , char b, char c){ if (m 1 ) { k ; printf( " %c->%c " ,a , c); return…

Unity3D心得分享

本篇文章的内容以各种tips为主,不间断更新 2019/05/10 最近更新: 使用Instantiate初始化参数去实例对象 Unity DEMO学习 Unity3D Adam Demo的学习与研究 Unity3D The Blacksmith Demo部分内容学习 Viking Village维京村落demo中的地面积水效果 Viking V…

django搭建示例-ubantu环境

python3安装--------------------------------------------------------------------------- 最新的django依赖python3,同时ubantu系统默认自带python2与python3,这里单独安装一套python3,并且不影响原来的python环境 django demo使用sqlite3&#xff0c…

C++11中std::lock_guard的使用

互斥类的最重要成员函数是lock()和unlock()。在进入临界区时,执行lock()加锁操作,如果这时已经被其它线程锁住,则当前线程在此排队等待。退出临界区时,执行unlock()解锁操作。更好的办法是采用”资源分配时初始化”(RAII)方法来加…

OpenAI机械手单手轻松解魔方,背靠强化学习+新技术ADR

编译 | 夕颜出品 | AI科技大本营(ID:rgznai100)【导读】10月15日,人工智能研究机构OpenAI发布了一条机械手单手解魔方的视频。这个自学式的类人机器人手臂名为 Dactyl,不仅可以单手解魔方,甚至能在外加各种干扰&#x…

AMD and CMD are dead之js模块化黑魔法

缘由 在2013-03-06 13:58的时候,曾甩下一片文章叫:《为什么不使用requirejs和seajs》,并放下豪言说发布一款完美的模块化库,再后来就把那篇文章删了,再然后就没有然后。该用seajs还用seajs,甚至我码的SCJ都…

一文了解Python常见的序列化操作

关于我 编程界的一名小小程序猿,目前在一个创业团队任team lead,技术栈涉及Android、Python、Java和Go,这个也是我们团队的主要技术栈。 联系:hylinux1024gmail.com 0x00 marshal marshal使用的是与Python语言相关但与机器无关的二…

TEE(Trusted Execution Environment)简介

TEE(Trusted Execution Environment),可信执行环境,该环境可以保证不被常规操作系统干扰的计算,因此称为”可信”。这是通过创建一个可以在TrustZone的”安全世界”中独立运行的小型操作系统实现的,该操作系统以系统调用(由TrustZ…

自动驾驶关键环节:行人的行为意图建模和预测(上)

作者 | 黄浴出品 | AI科技大本营(ID:rgznai100)【导读】介绍一下最近行人行为意图建模和预测的研究工作,还是分上下两部分,本文为上半部分。Social LSTM: Human Trajectory Prediction in Crowded Spaces比较早的是斯坦福大学 201…

自定义windows下自动清除文件夹或者文件的只读属性的脚本

脚本内容入下:其中脚本中 ”/d"作用 (可以用来改变当前驱动器目录)例如: 我现在是在D盘,现在我要切换到C:\windows目录 脚本参数中 ATTRIB -R /S /D 解释内容如下:(上述脚本参数中的 cd …

C++11容器中新增加的emplace相关函数的使用

C11中,针对顺序容器(如vector、deque、list),新标准引入了三个新成员:emplace_front、emplace和emplace_back,这些操作构造而不是拷贝元素。这些操作分别对应push_front、insert和push_back,允许我们将元素放置在容器头…

Silverlight+WCF 新手实例 象棋 主界面-棋谱-获取列表(三十八)

2019独角兽企业重金招聘Python工程师标准>>> 在线演示地址:SilverlightWCF 新手实例 象棋 在线演示 在SilverlightWCF 新手实例 象棋 主界面-棋谱-布局写谱(三十六)中,我们完成下棋双方的棋谱显示,这节,我们为观众增加…

确认!语音识别大牛Daniel Povey将入职小米,曾遭霍普金斯大学解雇,怒拒Facebook

整理 | 夕颜 出品 | AI科技大本营(ID:rgznai100) 【导读】10 月 17 日,语音界传奇 Daniel Povey 发布推特,宣布自己 2019 年末将要入职小米,目前正在签订合同阶段,入职后,他将带领一支团队研发…

软链接与硬链接

$ ln f1 f2 #创建f1的一个硬连接文件f2$ ln -s f1 f3 #创建f1的一个符号连接文件f3$ ls -li # -i参数显示文件的inode节点信息转载于:https://www.cnblogs.com/zhizouxiao/p/3794668.html

一文读懂Python复杂网络分析库networkx | CSDN博文精选

作者 | yyl424525来源 | CSDN博客文章目录1. 简介安装支持四种图绘制网络图基本流程2. Graph-无向图节点边属性有向图和无向图互转3. DiGraph-有向图一些精美的图例子环形树状图权重图Giant ComponentRandom Geometric Graph 随机几何图节点颜色渐变边的颜色渐变Atlas画个五角星…

C++11多线程中std::call_once的使用

C11中的std::call_once函数位于<mutex>头文件中。在多线程编程中&#xff0c;有时某个任务只需要执行一次&#xff0c;此时可以用C11中的std::call_once函数配合std::once_flag来实现。如果多个线程需要同时调用某个函数&#xff0c;std::call_once可以保证多个线程对该函…

Solaris 上网配置

2019独角兽企业重金招聘Python工程师标准>>> 早上装solaris10系统的时候&#xff0c;没选默认&#xff0c;选了desk-session模式安装。全英文无界面安装&#xff0c;中间还跑出几个乱码。 靠着随便选随便F2&#xff0c;终于安装完了。 就在那设完分辨率后&#xff0…

Configure,Makefile.am, Makefile.in, Makefile文件之间关系

为什么80%的码农都做不了架构师&#xff1f;>>> 1.autoscan (autoconf): 扫描源代码以搜寻普通的可移植性问题&#xff0c;比如检查编译器&#xff0c;库&#xff0c;头文件等&#xff0c;生成文件configure.scan,它是configure.ac的一个雏形。 your source files…

这款耳机一点不输千元级的AirPods

你如果问我&#xff1a;生活中你觉得必不可少的一件电子产品是什么&#xff1f;那么我会毫不犹豫的回答你&#xff1a;是耳机&#xff01;出门忘带耳机是绝对不能忍听不听没关系&#xff0c;但是有它比较安心我觉得生活中不仅是我很多人都对耳机有一种依赖因为很多人都喜欢音乐…

CUDA Samples: Image Process: BGR to Gray

在图像处理中&#xff0c;颜色变换BGR到Gray&#xff0c;常见的一般有两种计算方式&#xff0c;一种是基于浮点数计算&#xff0c;一种是基于性能优化的通过移位的整数计算。浮点数计算公式为&#xff1a; gray 0.1140 * B 0.5870 * G 0.2989 * R;整数计算公式为&#xff1…

CYQ.Data 数据框架系列索引

2019独角兽企业重金招聘Python工程师标准>>> 索引基础导航&#xff1a; 1&#xff1a;下载地址&#xff1a;http://www.cyqdata.com/download/article-detail-426 2&#xff1a;入门教程&#xff1a;http://www.cyqdata.com/cyqdata/article-cate-33 3&#xff1a;购…