一、cinder介绍

1、Block Storage

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

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

  第一种裸硬盘的方式叫做 Block Storage(块存储),每个裸硬盘通常也称作 Volume(卷)

  第二种叫做文件系统存储。NAS 和 NFS 服务器,以及各种分布式文件系统提供的都是这种存储。

2、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 等商业存储产品和方案

3、Cinder 架构

下图是 cinder 的逻辑架构图

4、Cinder 包含如下几个组件:

(1)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 上看到。

(2)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 等。

(3)cinder-scheduler

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

(4)volume provider

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

(5)Message Queue

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

(6)Database Cinder

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

5、物理部署方案

  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。

二、cinder的设计思想

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

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

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

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

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

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

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

2、Cinder 的设计思想

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

3、API 前端服务

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

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

  1)对外提供统一接口,隐藏实现细节
  2)API 提供 REST 标准调用服务,便于与第三方系统集成
  3)可以通过运行多个 API 服务实例轻松实现 API 的高可用,比如运行多个 cinder-api 进程

4、Scheduler 调度服务

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

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

5、Worker 工作服务

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

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

6、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不用的服务:

(1) 禁用服务

openstack volume service set --disable HOST_NAME BINARY_NAME

(2) 从数据库中删除节点

cinder-manage service remove BINARY_NAME HOST_NAME

(3) 查看服务:

三、安装和配置cinder服务(Block Storage service

(一)在控制节点配置

1、创建cinder数据库及用户

[root@ren3 ~]# mysql -uroot -proot

MariaDB [(none)]> create database cinder;

MariaDB [(none)]> GRANT ALL PRIVILEGES ON cinder.* TO 'cinder'@'localhost' \
IDENTIFIED BY 'CINDER_DBPASS'; MariaDB [(none)]> GRANT ALL PRIVILEGES ON cinder.* TO 'cinder'@'%' \
IDENTIFIED BY 'CINDER_DBPASS';

2、创建cinder服务

(1)创建cinder用户

[root@ren3 ~]# source openrc
[root@ren3 ~]# openstack user create --domain default --password=cinder cinder
+---------------------+----------------------------------+
| Field | Value |
+---------------------+----------------------------------+
| domain_id | default |
| enabled | True |
| id | 4f001caf100b4a43a4e2ffd19b2be3cb |
| name | cinder |
| options | {} |
| password_expires_at | None |
+---------------------+----------------------------------+
[root@ren3 ~]# openstack role add --project service --user cinder admin

(2)创建cinderv2和cinderv3服务实体

[root@ren3 ~]# openstack service create --name cinderv2 \
--description "OpenStack Block Storage" volumev2
+-------------+----------------------------------+
| Field | Value |
+-------------+----------------------------------+
| description | OpenStack Block Storage |
| enabled | True |
| id | 6c80f053d1094573b070297b9e47eba6 |
| name | cinderv2 |
| type | volumev2 |
+-------------+----------------------------------+
[root@ren3 ~]# openstack service create --name cinderv3 \
--description "OpenStack Block Storage" volumev3
+-------------+----------------------------------+
| Field | Value |
+-------------+----------------------------------+
| description | OpenStack Block Storage |
| enabled | True |
| id | d9213d7647cc4c439acd9b853987b447 |
| name | cinderv3 |
| type | volumev3 |
+-------------+----------------------------------+
[root@ren3 ~]# openstack endpoint create --region RegionOne \
volumev2 public http://ren3:8776/v2/%\(project_id\)s
+--------------+------------------------------------+
| Field | Value |
+--------------+------------------------------------+
| enabled | True |
| id | 6975a94262df4fa59d2beb4f14c1b621 |
| interface | public |
| region | RegionOne |
| region_id | RegionOne |
| service_id | 6c80f053d1094573b070297b9e47eba6 |
| service_name | cinderv2 |
| service_type | volumev2 |
| url | http://ren3:8776/v2/%(project_id)s |
+--------------+------------------------------------+
[root@ren3 ~]# openstack endpoint create --region RegionOne \
volumev2 internal http://ren3:8776/v2/%\(project_id\)s
+--------------+------------------------------------+
| Field | Value |
+--------------+------------------------------------+
| enabled | True |
| id | 144a96b2909745439df20c8e9f946e0f |
| interface | internal |
| region | RegionOne |
| region_id | RegionOne |
| service_id | 6c80f053d1094573b070297b9e47eba6 |
| service_name | cinderv2 |
| service_type | volumev2 |
| url | http://ren3:8776/v2/%(project_id)s |
+--------------+------------------------------------+
[root@ren3 ~]# openstack endpoint create --region RegionOne \
volumev2 admin http://ren3:8776/v2/%\(project_id\)s
+--------------+------------------------------------+
| Field | Value |
+--------------+------------------------------------+
| enabled | True |
| id | 110131cbac834526ae3672df2304dbd3 |
| interface | admin |
| region | RegionOne |
| region_id | RegionOne |
| service_id | 6c80f053d1094573b070297b9e47eba6 |
| service_name | cinderv2 |
| service_type | volumev2 |
| url | http://ren3:8776/v2/%(project_id)s |
+--------------+------------------------------------+
[root@ren3 ~]# openstack endpoint create --region RegionOne \
volumev3 public http://ren3:8776/v3/%\(project_id\)s
+--------------+------------------------------------+
| Field | Value |
+--------------+------------------------------------+
| enabled | True |
| id | f387fd612aa044f3804f02671ccd74f0 |
| interface | public |
| region | RegionOne |
| region_id | RegionOne |
| service_id | d9213d7647cc4c439acd9b853987b447 |
| service_name | cinderv3 |
| service_type | volumev3 |
| url | http://ren3:8776/v3/%(project_id)s |
+--------------+------------------------------------+
[root@ren3 ~]# openstack endpoint create --region RegionOne volumev3 internal http://ren3:8776/v3/%\(project_id\)s
+--------------+------------------------------------+
| Field | Value |
+--------------+------------------------------------+
| enabled | True |
| id | 73706ddbf52d4694862b0a3412f0a7d7 |
| interface | internal |
| region | RegionOne |
| region_id | RegionOne |
| service_id | d9213d7647cc4c439acd9b853987b447 |
| service_name | cinderv3 |
| service_type | volumev3 |
| url | http://ren3:8776/v3/%(project_id)s |
+--------------+------------------------------------+
[root@ren3 ~]# openstack endpoint create --region RegionOne \
volumev3 admin http://ren3:8776/v3/%\(project_id\)s
opens+--------------+------------------------------------+
| Field | Value |
+--------------+------------------------------------+
| enabled | True |
| id | aff11bcd255f4f28b0778a6f3b8b0e93 |
| interface | admin |
| region | RegionOne |
| region_id | RegionOne |
| service_id | d9213d7647cc4c439acd9b853987b447 |
| service_name | cinderv3 |
| service_type | volumev3 |
| url | http://ren3:8776/v3/%(project_id)s |
+--------------+------------------------------------+
t[root@ren3 ~]# openstack endpoint list |grep volume
| 110131cbac834526ae3672df2304dbd3 | RegionOne | cinderv2 | volumev2 | True | admin | http://ren3:8776/v2/%(project_id)s |
| 144a96b2909745439df20c8e9f946e0f | RegionOne | cinderv2 | volumev2 | True | internal | http://ren3:8776/v2/%(project_id)s |
| 6975a94262df4fa59d2beb4f14c1b621 | RegionOne | cinderv2 | volumev2 | True | public | http://ren3:8776/v2/%(project_id)s |
| 73706ddbf52d4694862b0a3412f0a7d7 | RegionOne | cinderv3 | volumev3 | True | internal | http://ren3:8776/v3/%(project_id)s |
| aff11bcd255f4f28b0778a6f3b8b0e93 | RegionOne | cinderv3 | volumev3 | True | admin | http://ren3:8776/v3/%(project_id)s |
| f387fd612aa044f3804f02671ccd74f0 | RegionOne | cinderv3 | volumev3 | True | public | http://ren3:8776/v3/%(project_id)s |

3、安装软件包

[root@ren3 ~]# yum install openstack-cinder -y

4、修改cinder配置文件(/etc/cinder/cinder.conf)

[DEFAULT]
my_ip = 192.168.11.3
#glance_api_servers = http://ren3:9292
auth_strategy = keystone
#enabled_backends = lvm
transport_url = rabbit://openstack:admin@ren3 [backend] [barbican] [brcd_fabric_example] [cisco_fabric_example] [coordination] [cors] [cors.subdomain] [database]
connection = mysql+pymysql://cinder:CINDER_DBPASS@ren3/cinder [fc-zone-manager] [healthcheck] [key_manager] [keystone_authtoken]
auth_uri = http://ren3:5000
auth_url = http://ren3:35357
memcached_servers = ren3:11211
auth_type = password
project_domain_name = default
user_domain_name = default
project_name = service
username = cinder
password = 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 = 192.168.11.5

5、同步数据库

[root@ren3 cinder]# su -s /bin/sh -c "cinder-manage db sync" cinder

6、配置Compute以使用块存储(/etc/nova/nova.conf)

[cinder]
os_region_name = RegionOne

7、启动服务

[root@ren3 cinder]# systemctl restart openstack-nova-api.service
[root@ren3 cinder]# systemctl enable openstack-cinder-api.service openstack-cinder-scheduler.service
[root@ren3 cinder]# systemctl start openstack-cinder-api.service openstack-cinder-scheduler.service
[root@ren3 cinder]# openstack volume service list
+------------------+------+------+---------+-------+-------------------+
| Binary | Host | Zone | Status | State | Updated At |
+------------------+------+------+---------+-------+-------------------+
| cinder-scheduler | ren3 | nova | enabled | up | 2019-10-14T13:06: |
| | | | | | 44.000000 |
+------------------+------+------+---------+-------+-------------------+

8、开启计算节点cinder服务(/etc/nova/nova.conf)

[cinder]
os_region_name = RegionOne

(二)在存储节点配置

1、准备阶段,安装lvm,创建lvm卷

(1)添加一块磁盘

[root@ren5 ~]# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 20G 0 disk
├─sda1 8:1 0 1G 0 part /boot
└─sda2 8:2 0 19G 0 part
├─centos-root 253:0 0 17G 0 lvm /
└─centos-swap 253:1 0 2G 0 lvm [SWAP]
sdb 8:16 0 20G 0 disk
sr0 11:0 1 4.3G 0 rom

(2)安装lvm

[root@ren5 ~]# yum install lvm2 -y
[root@ren5 ~]# systemctl enable lvm2-lvmetad.service
[root@ren5 ~]# systemctl start lvm2-lvmetad.service

(3)创建lvm

[root@ren5 ~]# pvcreate /dev/sdb
Physical volume "/dev/sdb" successfully created.
[root@ren5 ~]# vgcreate cinder-volumes /dev/sdb
Volume group "cinder-volumes" successfully created

2、安装软件包

[root@ren5 ~]# yum install openstack-cinder targetcli python-keystone -y

3、修改cinder配置文件(/etc/cinder/cinder.conf)

[DEFAULT]
my_ip = 192.168.11.5
glance_api_servers = http://ren3:9292
auth_strategy = keystone
enabled_backends = lvm
transport_url = rabbit://openstack:admin@ren3 [backend] [barbican] [brcd_fabric_example] [cisco_fabric_example] [coordination] [cors] [cors.subdomain] [database]
connection = mysql+pymysql://cinder:CINDER_DBPASS@ren3/cinder [fc-zone-manager] [healthcheck] [key_manager] [keystone_authtoken]
auth_uri = http://ren3:5000
auth_url = http://ren3:35357
memcached_servers = ren3:11211
auth_type = password
project_domain_name = default
user_domain_name = default
project_name = service
username = cinder
password = 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 = lioadm
iscsi_ip_address = 192.168.11.5

4、启动服务

[root@ren5 cinder]# systemctl enable openstack-cinder-volume.service target.service
[root@ren5 cinder]# systemctl start openstack-cinder-volume.service target.service

5、验证(在控制节点)

[root@ren3 cinder]# openstack volume service list
+----------------+----------+------+---------+-------+-----------------+
| Binary | Host | Zone | Status | State | Updated At |
+----------------+----------+------+---------+-------+-----------------+
| cinder- | ren3 | nova | enabled | up | 2019-10-14T13:3 |
| scheduler | | | | | 7:55.000000 |
| cinder-volume | ren5@lvm | nova | enabled | up | 2019-10-14T13:3 |
| | | | | | 7:48.000000 |
+----------------+----------+------+---------+-------+-----------------+

云计算OpenStack核心组件---cinder存储服务(10)的更多相关文章

  1. 云计算openstack核心组件——cinder存储服务(11)

    一.cinder 介绍:   理解 Block Storage 操作系统获得存储空间的方式一般有两种: 通过某种协议(SAS,SCSI,SAN,iSCSI 等)挂接裸硬盘,然后分区.格式化.创建文件系 ...

  2. OpenStack核心组件-cinder存储服务

    1. cinder 介绍 Block Storage 操作系统获得存储空间的方式一般有两种: 1)     通过某种协议(SAS,SCSI,SAN,iSCSI 等)挂接裸硬盘,然后分区.格式化.创建文 ...

  3. openstack核心组件--cinder存储服务(6)

    一.cinder 介绍:   理解 Block Storage 操作系统获得存储空间的方式一般有两种: 通过某种协议(SAS,SCSI,SAN,iSCSI 等)挂接裸硬盘,然后分区.格式化.创建文件系 ...

  4. openstack核心组件——cinder存储服务(11)

    一.cinder 介绍:   理解 Block Storage 操作系统获得存储空间的方式一般有两种: 通过某种协议(SAS,SCSI,SAN,iSCSI 等)挂接裸硬盘,然后分区.格式化.创建文件系 ...

  5. 云计算openstack核心组件——nova计算服务(7)

    一.nova介绍:       Nova 是 OpenStack 最核心的服务,负责维护和管理云环境的计算资源.OpenStack 作为 IaaS 的云操作系统,虚拟机生命周期管理也就是通过 Nova ...

  6. 云计算OpenStack核心组件---nova计算服务(7)

    一.nova介绍 Nova 是 OpenStack 最核心的服务,负责维护和管理云环境的计算资源.OpenStack 作为 IaaS 的云操作系统,虚拟机生命周期管理也就是通过 Nova 来实现的. ...

  7. OpenStack组件——cinder存储服务

    1.cinder 介绍 1)理解 Block Storage 操作系统获得存储空间的方式一般有两种: (1)通过某种协议(SAS,SCSI,SAN,iSCSI 等)挂接裸硬盘,然后分区.格式化.创建文 ...

  8. 云计算OpenStack核心组件---neutron网络服务(8)*****

    一.neutron介绍 1.Neutron概述 传统的网络管理方式很大程度上依赖于管理员手工配置和维护各种网络硬件设备:而云环境下的网络已经变得非常复杂,特别是在多租户场景里,用户随时都可能需要创建. ...

  9. 云计算openstack核心组件——neutron网络服务(8)

    一.neutron 介绍:   Neutron 概述 传统的网络管理方式很大程度上依赖于管理员手工配置和维护各种网络硬件设备:而云环境下的网络已经变得非常复杂,特别是在多租户场景里,用户随时都可能需要 ...

随机推荐

  1. (十六)Struts2的标签库

    一.简介 Struts2的标签库使用OGNL为基础,大大简化了数据的输出,也提供了大量标签来生成页面效果,功能非常强大. 在早期的web应用开发中,jsp页面主要使用jsp脚本来控制输出.jsp页面嵌 ...

  2. Install Tensorflow object detection API in Anaconda (Windows)

    This blog is to explain how to install Tensorflow object detection API in Anaconda in Windows 10 as ...

  3. js--原型和原型链相关问题

    前言 阅读本文前先来思考一个问题,我们在 js 中创建一个变量,我们并没有给这个变量添加一些方法,比如 toString() 方法,为什么我们可以直接使用这个方法呢?如以下代码,带着这样的问题,我们来 ...

  4. JavaWeb 基础知识补充

    软件架构 1. C/S: Client/Server 客户端/服务器端         * 在用户本地有一个客户端程序,在远程有一个服务器端程序         * 如:QQ,迅雷...        ...

  5. (十七)VMware Harbor 垃圾清理

    1. 在线垃圾清理 注意:从Harbor中删除镜像时不释放空间,垃圾收集是通过从清单中不再引用文件系统中删除blob来释放空间的任务. 注意:在执行垃圾收集时,Harbor将进入只读模式,并且禁止对d ...

  6. 诸葛亮的锦囊妙计竟然是大名鼎鼎的Java设计模式:策略模式

    目录 应用场景 简单实现例子 改进代码 策略模式 定义 意图 主要解决问题 何时使用 优缺点 诸葛亮的锦囊妙计 应用场景 京东.天猫双十一,情人节商品大促销,各种商品有不同的促销活动 满减:满200减 ...

  7. Flowable中的Service

    前言 在学习博客[(https://blog.csdn.net/puhaiyang/article/details/79845248)]时,注意到Flowable中的各种Service(如下),进而在 ...

  8. Libraries

    Math.ceil() The Math.ceil() function returns the smallest integer greater than or equal to a given n ...

  9. [Web] 通用轮播图代码示例

    首先是准备好的几张图片, 它们的路径是: "img/1.jpg", "img/2.jpg", "img/3.jpg", "img/ ...

  10. hdu1247 字典树或者hash

    题意:      给你一些串,问你哪些串是由其他两个串连接成的. 思路:        我用了两种方法,一个是hash,hash的时候用map实现的,第二种方法是字典树,字典树我们枚举每个一字符串,查 ...