2024年1月

导航

说明

wing
是一个代码同步管理工具类似
repo
,具有以下特性:

  • 支持
    Winddows

    Linux

    MacOS
  • 支持代码同步和本地映射
  • 扩展了针对工作空间的
    git
    命令
  • 保留了原
    git
    命令
  • 增加了更多常用开发工具,覆盖开发环境、代码检查、模板创建、开发调试、应用发布


wing
更多的是一个让开发团队保持一致开发环境的工具,从团队协作和工程开发的角度构建产品或项目,围绕设计,开发,测试,编译,发布等环节的开发活动,提升团队的开发效率。

开发计划

设计

开发空间(dev-space)

结构设计

范例

项目代码

以下为本项目的代码目录简要说明,工程比较简单便于大家快速上手。

使用规范

manifest配置

manifest
是指定不同的开发人员获取不同的代码库,但整个代码结构保持一致。确保团队开发人员之间,服务端编译(如:
jenkins
)开发环境均一致。通过初始化命令来获取代码索引(如:
wing init iofomo master xxx.xml

manifest
中的
project
对应的是服务端库,其格式如下。

<!-- path:本地相对目录名称 -->
<!-- name:远程库相对地址 -->
<!-- revision:为指定的库分支或标签,未配置则使用默认 default 中的值,若已配置则在整体创建分支或标签时保持不变 -->
<project path="platform/doc" name="platform/doc.git" revision="master" >
    <!-- 将该库中src文件导出到本地目录下 -->
		<copyfile dest="build.py" src="build.py"/>
</project>

admin code group

通常
admin.xml
记录本项目或产品所有的库,不作为实际开发使用,项目或技术负责人使用此索引,可以看到整个团队开发每日详情,便于管理和代码审查。

<?xml version='1.0' encoding='UTF-8'?>
<manifest>
    <remote name="origin" fetch=".."/>

    <!-- branch -->
    <default revision="master" remote="origin" sync-j="4"/>

    <!-- doc -->
    <project path="doc" name="project/iofomo/doc.git" />

    <!-- platform: always with master -->
    <project path="platform/doc" name="platform/doc.git" revision="master" />

    <!-- Application -->
    <project path="application/client" name="project/iofomo/client.git" />

    <!-- Component -->
    <project path="compt/common" name="platform/compt/common.git" />
    <project path="compt/comm" name="platform/compt/comm.git" />
    <project path="compt/uikit" name="platform/compt/uikit.git" />
    <project path="compt/framework" name="platform/compt/framework.git" />

    <!-- PC: always with master -->
    <project path="pc/wing" name="platform/wing.git" />
    <project path="pc/tinyui" name="platform/tinyui.git" />

    <!-- Template: always with master -->
    <project path="template/as" name="platform/template_as.git" revision="master" />
    <project path="template/as_mts" name="platform/template_as_jni.git" revision="master" />
    <project path="template/as_jar" name="platform/template_as_jar.git" revision="master" />
    <project path="template/py" name="platform/template_py.git" revision="master" />

    <!-- server -->
    <project path="server/fomosite" name="project/iofomo/fomosite.git" />
    <project path="server/web" name="project/iofomo/web.git" />
    <project path="server/vue" name="project/iofomo/vue.git" />

    <!-- Test -->
    <project path="test/tools" name="platform/tools.git" revision="master" />
    <project path="test/testBot" name="project/iofomo/testBot.git" />

    <!-- build -->
    <project path="build" name="project/iofomo/build">
        <!--<copyfile dest="build.py" src="build.py"/>-->
    </project>

</manifest>

pc code group

这是
pc
组代码索引配置,里面仅包含公共库和
pc
相关的代码库。

<?xml version='1.0' encoding='UTF-8'?>
<manifest>
    <remote name="origin" fetch=".."/>

    <!-- branch -->
    <default revision="master" remote="origin" sync-j="4"/>

    <!-- doc -->
    <project path="doc" name="project/iofomo/doc.git" />

    <!-- platform: always with master -->
    <project path="platform/doc" name="platform/doc.git" revision="master" />

    <!-- PC: always with master -->
    <project path="pc/wing" name="platform/wing.git" />
    <project path="pc/tinyui" name="platform/tinyui.git" />

    <!-- Test -->
    <project path="test/tools" name="platform/tools.git" revision="master" />
    <project path="test/testBot" name="project/iofomo/testBot.git" />

    <!-- build -->
    <project path="build" name="project/iofomo/build">
        <!--<copyfile dest="build.py" src="build.py"/>-->
    </project>

</manifest>

test code group

这是自动化测试开发组代码索引配置,里面仅包含公共库和
test
相关的代码库。

<?xml version='1.0' encoding='UTF-8'?>
<manifest>
    <remote name="origin" fetch=".."/>

    <!-- branch -->
    <default revision="master" remote="origin" sync-j="4"/>

    <!-- doc -->
    <project path="doc" name="project/iofomo/doc.git" />

    <!-- platform: always with master -->
    <project path="platform/doc" name="platform/doc.git" revision="master" />

    <!-- Test -->
    <project path="test/tools" name="platform/tools.git" revision="master" />
    <project path="test/testBot" name="project/iofomo/testBot.git" />

    <!-- build -->
    <project path="build" name="project/iofomo/build">
        <!--<copyfile dest="build.py" src="build.py"/>-->
    </project>

</manifest>

创建分支或标签

如通过命令
wing -create b release_v1.0.0 master
即基于
master
分支创建新的
release_v1.0.0
分支(标签命令同理)。则:

  • manifest
    所在的
    Git
    库会自动创建一个
    release_v1.0.0
    的分支。

  • manifest
    中所有的
    xml
    索引文件中
    default
    默认分支的值为
    release_v1.0.0



test.xml
在新的分支内容变更如下,公共库(即指定
revision
分支)保持不变:

<?xml version='1.0' encoding='UTF-8'?>
<manifest>
    <remote name="origin" fetch=".."/>

    <!-- branch -->
    <default revision="release_v1.0.0" remote="origin" sync-j="4"/>

    <!-- doc -->
    <project path="doc" name="project/iofomo/doc.git" />

    <!-- platform: always with master -->
    <project path="platform/doc" name="platform/doc.git" revision="master" />

    <!-- Test -->
    <project path="test/tools" name="platform/tools.git" revision="master" />
    <project path="test/testBot" name="project/iofomo/testBot.git" />

    <!-- build -->
    <project path="build" name="project/iofomo/build">
        <!--<copyfile dest="build.py" src="build.py"/>-->
    </project>
</manifest>

快速开始

新手操作看
这里

安装

$ python setup.py install

配置环境变量

Windows:


C:\Users\${user name}\bin
添加至系统环境变量。

Linux/MacOS:


~/bin
配置为可执行全局目录。

创建工作空间

添加工作空间对应的代码
git
库服务地址,如:

# 本地索引模式
# wing -space add {space name} {git host} [manifest]
# such as:
$ wing -space add test git@github.com/iofomo

获取代码

$ mkdir test
$ cd test

# wing init {space name} {branch/tag} {manifest file}
# such as:
$ wing init test master admin.xml

在当前目录下自动创建一个空的模板索引文件(
.wing/manifests/admin.xml
),需要添加要同步的代码库映射关系。

许可协议

本项目基于
MIT
许可协议,详情查看
许可协议
文档。

本项目和所有的工具都是MIT许可证下的开源工具,这意味着你可以完全访问源代码,并可以根据自己的需求进行修改。

在 Part 1 中,我们一起了解了什么是 Prometheus 和 Grafana,以及使用这些工具的前提条件和优势。在本部分,将继续带您学习如何安装 Helm 以及如何使用 Prometheus Helm Charts。

开始使用 Helm 和 Helm Chart

ArtifactHub 为 Helm Chart 提供了公共和私有资源库。我们将使用这些 Helm Chart 来设置 Kubernetes 集群中的 pod 和服务。

Helm 社区为各种 Kubernetes 应用程序创建、管理和维护 Helm Chart,这些资源会时常更新。Helm Chart 可重复使用,安装简单。想要使用 Helm 在 Kubernetes 上集成 Prometheus 和 Grafana,让我们从安装 Helm 开始。

安装 Helm

安装 Helm 之前,必须使用以下命令启动 Minikube Kubernetes:

minikube start --driver=docker

下图显示 Minikube 正在运行。Kubectl 工具现已配置为使用 Minikube。

image

接下来,使用以下命令(根据你使用的操作系统使用对应的命令)安装 Helm:

在 Linux 上安装 Helm

sudo apt-get install helm

在 Windows 上安装 Helm

choco install Kubernetes-helm

在 macOS 系统上安装 Helm

brew install helm

提示:如果遇到问题,可以查看 Helm 官方文档指南
https://helm.sh/docs/intro/install/。

下图显示了 Helm 在 Windows 机器上的安装情况:

image

Helm 命令

要获取所有 Helm 命令,请运行此命令:

helm

命令输出结果:

The Kubernetes package manager

Common actions for Helm:

- helm search:    search for charts
- helm pull:      download a chart to your local directory to view
- helm install:   upload the chart to Kubernetes
- helm list:      list releases of charts

Usage:
  helm [command]

Available Commands:
  completion  generate autocompletion scripts for the specified shell
  create      create a new chart with the given name
  dependency  manage a chart's dependencies
  env         helm client environment information
  get         download extended information of a named release
  help        Help about any command
  history     fetch release history
  install     install a chart
  lint        examine a chart for possible issues
  list        list releases
  package     package a chart directory into a chart archive
  plugin      install, list, or uninstall Helm plugins
  pull        download a chart from a repository and (optionally) unpack it in local directory
  push        push a chart to remote
  registry    login to or logout from a registry
  repo        add, list, remove, update, and index chart repositories
  rollback    roll back a release to a previous revision
  search      search for a keyword in charts
  show        show information of a chart
  status      display the status of the named release
  template    locally render templates
  test        run tests for a release
  uninstall   uninstall a release
  upgrade     upgrade a release
  verify      verify that a chart at the given path has been signed and is valid
  version     print the client version information

Use "helm [command] --help" for more information about a command.

最常用的 Helm 命令有

  • helm search:在 ArtifactHub 资源库中搜索 Helm Chart。
  • helm pull:从 ArtifactHub 资源库中提取并下载 Helm Chart。
  • helm install:上传 Helm Chart 并将其部署到 Kubernetes 集群。
  • helm list:列出 Kubernetes 集群中部署的所有 Helm Chart。

Prometheus Helm Charts

首先,我们将搜索 Prometheus Helm Charts。要搜索 Prometheus Helm,请运行以下命令:

helm search hub prometheus

该命令列出以下 Prometheus Helm Chart:

URL                                                       CHART VERSION         APP VERSION                                           DESCRIPTION
https://artifacthub.io/packages/helm/prometheus...        25.1.0                v2.47.0                                               Prometheus is a monitoring system and time seri...
https://artifacthub.io/packages/helm/truecharts...        13.0.7                2.47.1                                                kube-prometheus-stack collects Kubernetes manif...
https://artifacthub.io/packages/helm/saurabh6-p...        0.2.0                 1.1                                                   This is a Helm Chart for Prometheus Setup.
https://artifacthub.io/packages/helm/prometheus...        13.0.0                2.22.1                                                Prometheus is a monitoring system and time seri...
https://artifacthub.io/packages/helm/wenerme/pr...        25.1.0                v2.47.0                                               Prometheus is a monitoring system and time seri...
https://artifacthub.io/packages/helm/wener/prom...        25.1.0                v2.47.0                                               Prometheus is a monitoring system and time seri...
https://artifacthub.io/packages/helm/romanow-he...        1.3.5                 2.40.0                                                Prometheus collects and stores its metrics as t...
https://artifacthub.io/packages/helm/mach1el-ch...        1.0.1                 v2.47.0                                               Prometheus Helm chart for Kubernetes
https://artifacthub.io/packages/helm/cloudposse...        0.2.1                                                                       Prometheus instance created by the CoreOS Prome...

您还可以前往 ArtifactHub 存储库(
https://artifacthub.io/)并搜索官方
Prometheus Helm Chart,如下图所示:

image

列表中的第一个是官方的 Prometheus Helm Chart。要获取此 Helm Chart,请运行以下命令:

helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update

输出结果:

"prometheus-community" has been added to your repositories
Hang tight while we grab the latest from your chart repositories...
...Successfully got an update from the "grafana" chart repository
...Successfully got an update from the "prometheus-community" chart repository
...Successfully got an update from the "bitnami" chart repository
Update Complete. ⎈Happy Helming!⎈

现在,我们已经下载好最新版本的 Prometheus 了。

在 K8s 集群上安装 Prometheus Helm Chart

要在 K8s 集群上安装 Prometheus Helm Chart,请运行以下
helm install
命令:

helm install prometheus prometheus-community/prometheus

输出结果:

NAME: my-prometheus
LAST DEPLOYED: Thu Oct 12 20:06:57 2023
NAMESPACE: monitoring
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
The Prometheus server can be accessed via port 80 on the following DNS name from within your cluster:
my-prometheus-server.monitoring.svc.cluster.local


Get the Prometheus server URL by running these commands in the same shell:
  export POD_NAME=$(kubectl get pods --namespace monitoring -l "app.kubernetes.io/name=prometheus,app.kubernetes.io/instance=my-prometheus" -o jsonpath="{.items[0].metadata.name}")
  kubectl --namespace monitoring port-forward $POD_NAME 9090


The Prometheus alertmanager can be accessed via port 9093 on the following DNS name from within your cluster:
my-prometheus-alertmanager.monitoring.svc.cluster.local


Get the Alertmanager URL by running these commands in the same shell:
  export POD_NAME=$(kubectl get pods --namespace monitoring -l "app.kubernetes.io/name=alertmanager,app.kubernetes.io/instance=my-prometheus" -o jsonpath="{.items[0].metadata.name}")
  kubectl --namespace monitoring port-forward $POD_NAME 9093
#################################################################################
######   WARNING: Pod Security Policy has been disabled by default since    #####
######            it deprecated after k8s 1.25+. use                        #####
######            (index .Values "prometheus-node-exporter" "rbac"          #####
###### .          "pspEnabled") with (index .Values                         #####
######            "prometheus-node-exporter" "rbac" "pspAnnotations")       #####
######            in case you still need it.                                #####
#################################################################################


The Prometheus PushGateway can be accessed via port 9091 on the following DNS name from within your cluster:
my-prometheus-prometheus-pushgateway.monitoring.svc.cluster.local


Get the PushGateway URL by running these commands in the same shell:
  export POD_NAME=$(kubectl get pods --namespace monitoring -l "app=prometheus-pushgateway,component=pushgateway" -o jsonpath="{.items[0].metadata.name}")
  kubectl --namespace monitoring port-forward $POD_NAME 9091

For more information on running Prometheus, visit:
https://prometheus.io/

现在我们已经在 Kubernetes 集群上安装了 Prometheus。我们可以通过80端口访问 Prometheus 服务器。下一步是查看部署的 Kubernetes 资源,也就是 Helm Chart 在 Kubernetes 集群中创建的 Pod 和服务。

要查看已部署的 Kubernetes 资源,请运行以下
kubectl
命令:

kubectl get all

输出结果:

NAME                                                        READY   STATUS    RESTARTS   AGE
pod/my-prometheus-prometheus-node-exporter-d5l8m            1/1     Running   0          27m
pod/my-prometheus-prometheus-node-exporter-kfbxb            1/1     Running   0          27m
pod/my-prometheus-prometheus-pushgateway-86d6f795cb-mlb7d   1/1     Running   0          27m
pod/my-prometheus-kube-state-metrics-6c4b65c7b9-wbh9r       1/1     Running   0          27m
pod/my-prometheus-prometheus-node-exporter-2z7rp            1/1     Running   0          27m
pod/my-prometheus-alertmanager-0                            1/1     Running   0          27m
pod/my-prometheus-server-795d8fc685-zcfct                   2/2     Running   0          27m

NAME                                             TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
service/my-prometheus-alertmanager-headless      ClusterIP   None            <none>        9093/TCP   27m
service/my-prometheus-server                     ClusterIP   10.43.186.10    <none>        80/TCP     27m
service/my-prometheus-prometheus-pushgateway     ClusterIP   10.43.154.83    <none>        9091/TCP   27m
service/my-prometheus-alertmanager               ClusterIP   10.43.217.41    <none>        9093/TCP   27m
service/my-prometheus-kube-state-metrics         ClusterIP   10.43.168.65    <none>        8080/TCP   27m
service/my-prometheus-prometheus-node-exporter   ClusterIP   10.43.195.241   <none>        9100/TCP   27m

NAME                                                    DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
daemonset.apps/my-prometheus-prometheus-node-exporter   3         3         3       3            3           kubernetes.io/os=linux   27m

NAME                                                   READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/my-prometheus-prometheus-pushgateway   1/1     1            1           27m
deployment.apps/my-prometheus-kube-state-metrics       1/1     1            1           27m
deployment.apps/my-prometheus-server                   1/1     1            1           27m

NAME                                                              DESIRED   CURRENT   READY   AGE
replicaset.apps/my-prometheus-prometheus-pushgateway-86d6f795cb   1         1         1       27m
replicaset.apps/my-prometheus-kube-state-metrics-6c4b65c7b9       1         1         1       27m
replicaset.apps/my-prometheus-server-795d8fc685                   1         1         1       27m

NAME                                          READY   AGE
statefulset.apps/my-prometheus-alertmanager   1/1     27m

安装 Helm Chart 会创建以下 Kubernetes 资源:

  • Pod
    :托管集群内已部署的 Prometheus Kubernetes 应用程序。
  • Replica Sets
    :Kubernetes 集群内同一应用程序实例的集合。它提高了应用程序的可靠性。
  • Deployments
    :这是创建应用程序 Pod 的蓝图。
  • Services
    :这是公开 Kubernetes 集群内运行的 Pod。我们用它来访问已部署的 Kubernetes 应用程序。

下一步是访问并启动 Prometheus Kubernetes 应用程序。这里将使用 Prometheus 的 Kubernetes 服务访问该应用程序。要获取 Prometheus 的所有 Kubernetes 服务,请运行以下命令:

kubectl get service

输出结果:


NAME                                     TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)    AGE
my-prometheus-alertmanager-headless      ClusterIP   None            <none>        9093/TCP   28m
my-prometheus-server                     ClusterIP   10.43.186.10    <none>        80/TCP     28m
my-prometheus-prometheus-pushgateway     ClusterIP   10.43.154.83    <none>        9091/TCP   28m
my-prometheus-alertmanager               ClusterIP   10.43.217.41    <none>        9093/TCP   28m
my-prometheus-kube-state-metrics         ClusterIP   10.43.168.65    <none>        8080/TCP   28m
my-prometheus-prometheus-node-exporter   ClusterIP   10.43.195.241   <none>        9100/TCP   28m

输出结果列出了 Prometheus 的下列 K8s service:

  • prometheus-alertmanager
  • prometheus-alertmanager-headless
  • prometheus-kube-state-metrics
  • prometheus-prometheus-node-exporter
  • prometheus-prometheus-pushgateway
  • prometheus-server

我们将使用
prometheus-server
Kubernetes service 来访问 Prometheus 应用程序。
prometheus-server
是 ClusterIP 类型。您只能在 Kubernetes 集群内访问它。因此我们需要公开这个 Kubernetes service,以便在 Kubernetes 集群外部访问它。公开
prometheus-server
Kubernetes service 将生成一个 URL。我们可以在浏览器上加载 URL 并访问正在运行的应用程序。

公开 prometheus-server Kubernetes service

要公开
prometheus-server
Kubernetes service,请运行以下命令:

kubectl expose service prometheus-server --type=NodePort --target-port=9090 --name=prometheus-server-ext

该命令会将
ClusterIP
类型转换为
NodePort
类型。这样,
prometheus-server
就能在 Kubernetes 集群之外通过 9090 端口访问。

现在,我们公开了
prometheus-server
Kubernetes service。接下来使用以下命令访问 Prometheus 应用程序:

minikube service prometheus-server-ext

该命令生成以下 URL:

image

URL 可能需要稍等一会儿才可用。您需要在浏览器上进行多次重试,直到使用此 URL 访问 Prometheus Kubernetes 应用程序。您还需要保持终端打开并运行命令,以便继续访问服务。

image

到这里,我们已经成功使用 Helm 在 Kubernetes 上安装了 Prometheus。Prometheus 已经在集群内部运行,我们可以使用浏览器或 URL 来进行访问。

本文分享自华为云社区《
当创建一个pvc后,kubernetes会发生什么?
》,作者:可以交个朋友。

一、背景

外部存储接入 Kubernetes 的方式主要有两种:In-Tree 和 Out-of-Tree:

  • In-Tree 是指存储驱动的源码都在 Kubernetes 代码库中,与 Kubernetes 一起发布、迭代、管理,这种方式灵活性较差,且门槛较高。
  • Out-of-Tree 是指存储插件由第三方编写、发布、管理,作为一种扩展与 Kubernetes 配合使用。Out-of-Tree 主要有 FlexVolume 和 CSI 两种实现方式,其中,FlexVolume 因为其命令式的特点,不易维护和管理,从 Kubernetes v1.23 版本开始已被弃用。因此 CSI 已经成为 Kubernetes 存储扩展( Out-of-Tree )的唯一方式。

外部存储最终的效果是将存储(磁盘、obs、nas盘等)挂载到容器中被业务使用,所以一般包括存在两个过程:

  • attach 是将存储介质在指定虚拟机上绑盘,部分存储介质才需要attach操作,比如容器中使用块存储,大致流程是1)需要先调用openstack接口,将某块evs绑到某个虚拟机上,成为虚拟机设备;2)在将存储设备挂载到容器目录上
  • mount 将某个存储挂载到对应文件系统上,是操作系统层面的行为,所有的存储介质挂载到容器中都需要mount阶段,比如容器中使用nas或者obs,本质上就是执行nfs命令将网络存储挂载到容器目录上

二、CSI 架构解读

kubernetes CSI存储插件的关键组件与推荐的容器化部署架构

三、动态创建 Volume 执行过程

以块类型存储为例,从声明pvc到pod挂载卷成功时序图:

1、涉及组件解读

  • PV Controller:负责处理集群中的pvc/pv对象,对pvc/pv对象进行状态转换,并根据需求进行数据卷的 Provision/Delete 操作(注:Static pv不会触发provisioner、Dynamic pv才会触发provisioner)

  • AD Controller:负责VolumeAttachement的生命周期管理,并通过external-attacher将设备挂载到目标节点或从目标节点卸载。VolumeAttachement是控制块存储设备的 Attach/Detach 操作的逻辑对象。(注:可通过kubelet配置文件开关控制节点是否由AD Controller管理)。

  • kubelet主要包含与存储相关的两个插件::1)Volume Manager:管理存储卷的 Mount/Unmount 操作、卷设备的格式化等操作(注:如果当前节点并没有交给AD Controller管理,那么就是volumeManager负责管理VolumeAttachement的生命周期);2)Volume Plugin:K8S平台为存储提供商提供存储接入的插件接口,其中包含in-tree的多种存储插件和out-tree的两种存储插件。通过该插件机制进而为容器应用提供各种类型的存储。社区推荐的是CSI架构的扩展插件

2、涉及资源解读

PV:PersistentVolume,集群级别的资源,由集群管理员 or External Provisioner创建。PV 的生命周期独立于使用 PV 的 Pod,PV 的 .Spec 中保存了存储设备的详细信息。

kind: PersistentVolume
apiVersion: v1
metadata:
name: pv
-test
labels:
failure
-domain.beta.kubernetes.io/region: cn-north-4failure-domain.beta.kubernetes.io/zone: cn-north-4a
annotations:
pv.kubernetes.io
/provisioned-by: xxxx-provisioner #存储提供者
spec:
capacity:
storage: 10Gi
csi:
driver: disk.csi.everest.io
volumeHandle: 698a99d8
-xxx-xxxx-xxxx-ab80b1ecbf #使用的存储设备信息
volumeAttributes:
everest.io
/disk-mode: SCSI
everest.io
/disk-volume-type: ESSD
storage.kubernetes.io
/csiProvisionerIdentity: xxxx-provisioner
accessModes:
-ReadWriteOnce
# 引用对象, 该pv由哪个pvc创建
claimRef:
kind: PersistentVolumeClaim
namespace: test
name: pvc
-test
uid: xxxx
-xxxx-xxxx-22bf9101f0ce
apiVersion: v1
persistentVolumeReclaimPolicy: Delete
storageClassName: csi
-disk
volumeMode: Filesystem
nodeAffinity:
required:
nodeSelectorTerms:
-matchExpressions:- key: failure-domain.beta.kubernetes.io/zoneoperator: In
values:
- cn-north-4a
status:
phase: Bound
# available : 表示当前的pv没有被绑定
# bound: 已经被pvc挂载
# released: pvc没有在使用pv, 需要管理员手工释放pv
# failed: 资源回收失败
  • PVC:PersistentVolumeClaim,命名空间(namespace)级别的资源,由用户 or StatefulSet 控制器(根据VolumeClaimTemplate)创建。PVC 类似于 Pod,Pod 消耗 Node 资源,PVC 消耗 PV 资源。Pod 可以请求特定级别的资源(CPU 和内存),而 PVC 可以请求特定存储卷的大小及访问模式(Access Mode)。

kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: pvc
-evs-testnamespace: test
uid: xxxx
-xxxx-xxxx-22bf9101f0ce
labels:
failure
-domain.beta.kubernetes.io/region: cn-north-4failure-domain.beta.kubernetes.io/zone: cn-north-4a
annotations:
volume.kubernetes.io
/selected-node: xxx.xxx.xxx.186everest.io/disk-volume-type: ESSD
volume.kubernetes.io
/storage-provisioner: xxxx-provisioner
spec:
# ReadWriteOnce:被单个节点mount为读写rw模式
# ReadOnlyMany 被多个节点mount为只读ro模式
# ReadWriteMany 被多个节点mount为读写rw模式
accessModes:
-ReadWriteOnce
resources:
requests:
storage: 10Gi
volumeName: pv
-test #绑定的pv name
# 使用的sc类型
storageClassName: csi
-disk
# 存储模式,包含Filesystem(文件系统)和Block(块设备)
volumeMode: Filesystem
status:
# Pending:pvc刚创建还未与pv绑定
# Bound: pvc与pv完成绑定
# Lost:对应的pv被删除
phase: Bound
accessModes:
- ReadWriteOnce
  • SC:StorageClass 是集群级别的资源,由集群管理员创建。SC 为管理员提供了一种动态提供存储卷的“类”模板,SC 中的 .Spec 中详细定义了存储卷 PV 的不同服务质量级别、备份策略等等。

apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: csi
-disk
parameters:
csi.storage.k8s.io
/csi-driver-name: disk.csi.everest.io
csi.storage.k8s.io
/fstype: ext4
everest.io
/disk-volume-type: SATA
everest.io
/passthrough: "true"provisioner: xxxx-provisioner
# 回收策略, pvc和pv解绑,删除了pvc, pv里面的数据是否还保留
# Retain: 保留数据, 需要手工删除
# delete: pv删除
reclaimPolicy: Delete
# Immediate: pv创建好之后立马将pvc和pv进行绑定
# WaitForFirstConsumer: 延迟绑定,直到使用pvc的pod被调度到节点上
volumeBindingMode: Immediate
allowVolumeExpansion:
true #是否允许扩容

3、涉及 CSI API 对象

CSINode

  • 判断外部 CSI 插件是否注册成功。在 Node Driver Registrar 组件向 Kubelet 注册完毕后,Kubelet 会创建该资源,故不需要显式创建 CSINode 资源
  • 将 Kubernetes 中 Node 资源名称与三方存储系统中节点名称(nodeID)一一对应。此处 Kubelet 会调用外部 CSI 插件 NodeServer 的 GetNodeInfo 函数获取 nodeID。
  • 显示卷拓扑信息。CSINode 中 topologyKeys 用来表示存储节点的拓扑信息,卷拓扑信息会使得 Scheduler 在 Pod 调度时选择合适的存储节点。
apiVersion: storage.k8s.io/v1
kind: CSINode
metadata:
annotations:
everest.io
/node.localvolume.capacity: "null"name: xxx.xxx.xxx.186ownerReferences:-apiVersion: v1
kind: Node
name: xxx.xxx.xxx.
186uid: 091cc415-b8bb-4173-8312-5f6318d4383f
uid: fea2c180
-99b8-4195-a966-3953b8bab16a
spec:
# 节点上有哪些driver
drivers:
-allocatable:
count:
58name: disk.csi.everest.io
nodeID: 7d279bf8
-c70f-4179-842e-5e501d591d17
topologyKeys:
- failure-domain.beta.kubernetes.io/zone-name: proxy.csi.everest.io
nodeID: 7d279bf8
-c70f-4179-842e-5e501d591d17
topologyKeys:
null -name: sfsturbo.csi.everest.io
nodeID: 7d279bf8
-c70f-4179-842e-5e501d591d17
topologyKeys:
null -name: nas.csi.everest.io
nodeID: 7d279bf8
-c70f-4179-842e-5e501d591d17
topologyKeys:
null...
apiVersion: storage.k8s.io
/v1
kind: CSINode
metadata:
annotations:
everest.io
/node.localvolume.capacity: "null"name: xxx.xxx.xxx.186ownerReferences:-apiVersion: v1
kind: Node
name: xxx.xxx.xxx.
186uid: 091cc415-b8bb-4173-8312-5f6318d4383f
uid: fea2c180
-99b8-4195-a966-3953b8bab16a
spec:
# 节点上有哪些driver
drivers:
-allocatable:
count:
58name: disk.csi.everest.io
nodeID: 7d279bf8
-c70f-4179-842e-5e501d591d17
topologyKeys:
- failure-domain.beta.kubernetes.io/zone-name: proxy.csi.everest.io
nodeID: 7d279bf8
-c70f-4179-842e-5e501d591d17
topologyKeys:
null -name: sfsturbo.csi.everest.io
nodeID: 7d279bf8
-c70f-4179-842e-5e501d591d17
topologyKeys:
null -name: nas.csi.everest.io
nodeID: 7d279bf8
-c70f-4179-842e-5e501d591d17
topologyKeys:
null...

CSIDriver

  • 简化外部 CSI 插件的发现。由集群管理员创建,通过 kubectl get csidriver 即可得知环境上有哪些 CSI 插件。
  • 自定义Kubernetes 行为,如一些外部 CSI 插件不需要执行卷挂接(VolumeAttach)操作,则可以设置 .spec.attachRequired 为 false。
apiVersion: storage.k8s.io/v1
kind: CSIDriver
metadata:
name: disk.csi.everest.io
uid: 5d33a29b
-4bf1-4ab8-815f-e97b207b991e
spec:
# 是否需要attache和mount,只有evs需要attach
attachRequired:
truepodInfoOnMount:truerequiresRepublish:falsestorageCapacity:falsevolumeLifecycleModes:- Persistent #volume生命周期,持久模式

VolumeAttachment

AD Controller 创建一个 VolumeAttachment,而 External-attacher 则通过观察该 VolumeAttachment,根据其状态属性来进行存储的挂载和卸载操作。

apiVersion: storage.k8s.io/v1
kind: VolumeAttachment
metadata:
annotations:
csi.alpha.kubernetes.io
/node-id: xxxx-xxxx-xxxx-5e501d591d17
finalizers:
- everest-csi-attacher/disk-csi-everest-io
name: csi
-d10b9f7e4dde469fa2b7f3461fcfef7862260883196647d6b7ae7bb17bc0e226
uid: 665b740f
-a544-4f3e-9953-00b8d186c548
spec:
attacher: disk.csi.everest.io
nodeName:xxx.xxx.xxx.
186source:
persistentVolumeName: pv
-test
status:
# 标记是否attached到节点上,attache后才能mount
attached:
trueattachmentMetadata: #attach的设备信息
bus: scsi
device:
/dev/sdg

四、存储拓展-延迟绑定

kubernetes里面有两个绑定:

  • kube-schedule将pod和node绑定
  • Pvc controller将pvc和pv绑定。正常情况下,kube-schedule绑定pod和node时候,如果pod有pvc,会等待pvc和pv绑定完成后根据pv所在的az选择node过滤一部分不满足节点,然后再完成绑定pod和node。延迟绑定场景,kube-schedule 先不等待PVC和PV绑定,先预调度node,然后把预调度结果写到PVC注解中,pvc控制接获取到预调度az信息后,再完成pv创建和pv绑定。所以,延迟绑定时延迟了pvc和pv绑定阶段。

stroageclass延迟绑定作用字段:VolumeBindingMode

  • Immediate :表示一旦创建了 PersistentVolumeClaim 也就完成了卷绑定和动态制备(不参与调度)。 对于由于拓扑限制而非集群所有节点可达的存储后端,PersistentVolume 会在不知道 Pod 调度要求的情况下绑定或者制备。
  • WaitForFirstConsumer :该模式将延迟 PersistentVolume 的绑定和制备,直到使用该 PersistentVolumeClaim 的 Pod 被创建。 PersistentVolume 会根据 Pod 调度约束指定的拓扑来选择或制备。 这些包括但不限于资源需求、 节点筛选器、 Pod 亲和性和互斥性、 以及污点和容忍度。

点击关注,第一时间了解华为云新鲜技术~

在uniapp中使用Recorder-UniCore插件可以实现跨平台录音功能,uniapp自带的recorderManager接口不支持H5、录音格式和实时回调onFrameRecorded兼容性不好,用Recorder插件可避免这些问题。

DCloud插件市场下载插件(有demo项目源码):
https://ext.dcloud.net.cn/plugin?name=Recorder-UniCore

Recorder-UniCore插件特性

  • 支持vue2、vue3、nvue
  • 支持编译成:H5、Android App、iOS App、微信小程序
  • 支持已有的大部分录音格式:mp3、wav、pcm、amr、ogg、g711a、g711u等
  • 支持实时处理,包括变速变调、实时上传、ASR语音转文字
  • 支持可视化波形显示

集成到项目中

1、通过npm安装
recorder-core

//在uniapp项目跟目录进行npm安装
npm install recorder-core

2、下载导入
Recorder-UniCore
插件

// 到插件市场 https://ext.dcloud.net.cn/plugin?name=Recorder-UniCore 下载插件
然后添加到你的项目中 /uni_modules/Recorder-UniCore

3、在vue页面文件内引入js

<script> /**这里是逻辑层**/
//必须引入的Recorder核心(文件路径是 /src/recorder-core.js 下同)
import Recorder from 'recorder-core' //使用import、require都行

//必须引入的RecordApp核心文件(文件路径是 /src/app-support/app.js)
import RecordApp from 'recorder-core/src/app-support/app'

//所有平台必须引入的uni-app支持文件(如果编译出现路径错误,请把@换成 ../../ 这种)
import '@/uni_modules/Recorder-UniCore/app-uni-support.js'

/** 需要编译成微信小程序时,引入微信小程序支持文件 **/
// #ifdef MP-WEIXIN
    import 'recorder-core/src/app-support/app-miniProgram-wx-support.js'
// #endif


/** H5、小程序环境中:引入需要的格式编码器、可视化插件,App环境中在renderjs中引入 **/
// #ifdef H5 || MP-WEIXIN
    //按需引入你需要的录音格式支持文件,如果需要多个格式支持,把这些格式的编码引擎js文件统统引入进来即可
    import 'recorder-core/src/engine/mp3'
    import 'recorder-core/src/engine/mp3-engine' //如果此格式有额外的编码引擎(*-engine.js)的话,必须要加上
    
    //可选的插件支持项
    import 'recorder-core/src/extensions/waveview'
// #endif
</script>
<!-- #ifdef APP -->
<script module="yourModuleName" lang="renderjs">
/**需要编译成App时,你需要添加一个renderjs模块,然后一模一样的import上面那些js(微信的js除外)
    ,因为App中默认是在renderjs(WebView)中进行录音和音频编码**/
import 'recorder-core'
import RecordApp from 'recorder-core/src/app-support/app'
import '../../uni_modules/Recorder-UniCore/app-uni-support.js' //renderjs中似乎不支持"@/"打头的路径,如果编译路径错误请改正路径即可

//按需引入你需要的录音格式支持文件,和插件
import 'recorder-core/src/engine/mp3'
import 'recorder-core/src/engine/mp3-engine' 

import 'recorder-core/src/extensions/waveview'

export default {
    mounted(){
        //App的renderjs必须调用的函数,传入当前模块this
        RecordApp.UniRenderjsRegister(this);
    },
    methods: {
        //这里定义的方法,在逻辑层中可通过 RecordApp.UniWebViewVueCall(this,'this.xxxFunc()') 直接调用
        //调用逻辑层的方法,请直接用 this.$ownerInstance.callMethod("xxxFunc",{args}) 调用,二进制数据需转成base64来传递
    }
}
</script>
<!-- #endif -->

调用录音

/**在逻辑层中编写**/
//import ... 上面那些import代码

export default {
data() { return {} }

,mounted() {
    this.isMounted=true;
    //页面onShow时【必须调用】的函数,传入当前组件this
    RecordApp.UniPageOnShow(this);
}
,onShow(){ //onShow可能比mounted先执行,页面可能还未准备好
    if(this.isMounted) RecordApp.UniPageOnShow(this);
}

,methods:{
    //请求录音权限
    recReq(){
        //编译成App时提供的授权许可(编译成H5、小程序为免费授权可不填写);如果未填写授权许可,将会在App打开后第一次调用请求录音权限时,弹出“未获得商用授权时,App上仅供测试”提示框
        //RecordApp.UniAppUseLicense='我已获得UniAppID=*****的商用授权';
        
        RecordApp.UniWebViewActivate(this); //App环境下必须先切换成当前页面WebView
        RecordApp.RequestPermission(()=>{
            console.log("已获得录音权限,可以开始录音了");
        },(msg,isUserNotAllow)=>{
            if(isUserNotAllow){//用户拒绝了录音权限
                //这里你应当编写代码进行引导用户给录音权限,不同平台分别进行编写
            }
            console.error("请求录音权限失败:"+msg);
        });
    }
    
    //开始录音
    ,recStart(){
        //录音配置信息
        var set={
            type:"mp3",sampleRate:16000,bitRate:16 //mp3格式,指定采样率hz、比特率kbps,其他参数使用默认配置;注意:是数字的参数必须提供数字,不要用字符串;需要使用的type类型,需提前把格式支持文件加载进来,比如使用wav格式需要提前加载wav.js编码引擎
            ,onProcess:(buffers,powerLevel,duration,sampleRate,newBufferIdx,asyncEnd)=>{
                //全平台通用:可实时上传(发送)数据,配合Recorder.SampleData方法,将buffers中的新数据连续的转换成pcm上传,或使用mock方法将新数据连续的转码成其他格式上传,可以参考Recorder文档里面的:Demo片段列表 -> 实时转码并上传-通用版;基于本功能可以做到:实时转发数据、实时保存数据、实时语音识别(ASR)等
                
                //注意:App里面是在renderjs中进行实际的音频格式编码操作,此处的buffers数据是renderjs实时转发过来的,修改此处的buffers数据不会改变renderjs中buffers,所以不会改变生成的音频文件,可在onProcess_renderjs中进行修改操作就没有此问题了;如需清理buffers内存,此处和onProcess_renderjs中均需要进行清理,H5、小程序中无此限制
                //注意:如果你要用只支持在浏览器中使用的Recorder扩展插件,App里面请在renderjs中引入此扩展插件,然后在onProcess_renderjs中调用这个插件;H5可直接在这里进行调用,小程序不支持这类插件;如果调用插件的逻辑比较复杂,建议封装成js文件,这样逻辑层、renderjs中直接import,不需要重复编写
                
                //H5、小程序等可视化图形绘制,直接运行在逻辑层;App里面需要在onProcess_renderjs中进行这些操作
                // #ifdef H5 || MP-WEIXIN
                if(this.waveView) this.waveView.input(buffers[buffers.length-1],powerLevel,sampleRate);
                // #endif
            }
            ,onProcess_renderjs:`function(buffers,powerLevel,duration,sampleRate,newBufferIdx,asyncEnd){
                //App中在这里修改buffers才会改变生成的音频文件
                //App中是在renderjs中进行的可视化图形绘制,因此需要写在这里,this是renderjs模块的this(也可以用This变量);如果代码比较复杂,请直接在renderjs的methods里面放个方法xxxFunc,这里直接使用this.xxxFunc(args)进行调用
                if(this.waveView) this.waveView.input(buffers[buffers.length-1],powerLevel,sampleRate);
            }`
            
            ,takeoffEncodeChunk:true?null:(chunkBytes)=>{
                //全平台通用:实时接收到编码器编码出来的音频片段数据,chunkBytes是Uint8Array二进制数据,可以实时上传(发送)出去
                //App中如果未配置RecordApp.UniWithoutAppRenderjs时,建议提供此回调,因为录音结束后会将整个录音文件从renderjs传回逻辑层,由于uni-app的逻辑层和renderjs层数据交互性能实在太拉跨了,大点的文件传输会比较慢,提供此回调后可避免Stop时产生超大数据回传
            }
            ,takeoffEncodeChunk_renderjs:true?null:`function(chunkBytes){
                //App中这里可以做一些仅在renderjs中才生效的事情,不提供也行,this是renderjs模块的this(也可以用This变量)
            }`
            
            ,start_renderjs:`function(){
                //App中可以放一个函数,在Start成功时renderjs中会先调用这里的代码,this是renderjs模块的this(也可以用This变量)
                //放一些仅在renderjs中才生效的事情,比如初始化,不提供也行
            }`
            ,stop_renderjs:`function(arrayBuffer,duration,mime){
                //App中可以放一个函数,在Stop成功时renderjs中会先调用这里的代码,this是renderjs模块的this(也可以用This变量)
                //放一些仅在renderjs中才生效的事情,不提供也行
            }`
        };
        
        RecordApp.UniWebViewActivate(this); //App环境下必须先切换成当前页面WebView
        RecordApp.Start(set,()=>{
            console.log("已开始录音");
            
            //创建音频可视化图形绘制,App环境下是在renderjs中绘制,H5、小程序等是在逻辑层中绘制,因此需要提供两段相同的代码
            //view里面放一个canvas,canvas需要指定宽高(下面style里指定了300*100)
            //<canvas type="2d" class="recwave-WaveView" style="width:300px;height:100px"></canvas>
            RecordApp.UniFindCanvas(this,[".recwave-WaveView"],`
                this.waveView=Recorder.WaveView({compatibleCanvas:canvas1, width:300, height:100});
            `,(canvas1)=>{
                this.waveView=Recorder.WaveView({compatibleCanvas:canvas1, width:300, height:100});
            });
        },(msg)=>{
            console.error("开始录音失败:"+msg);
        });
    }
    
    //暂停录音
    ,recPause(){
        if(RecordApp.GetCurrentRecOrNull()){
            RecordApp.Pause();
            console.log("已暂停");
        }
    }
    //继续录音
    ,recResume(){
        if(RecordApp.GetCurrentRecOrNull()){
            RecordApp.Resume();
            console.log("继续录音中...");
        }
    }
    
    //停止录音
    ,recStop(){
        RecordApp.Stop((arrayBuffer,duration,mime)=>{
            //全平台通用:arrayBuffer是音频文件二进制数据,可以保存成文件或者发送给服务器
            //App中如果在Start参数中提供了stop_renderjs,renderjs中的函数会比这个函数先执行
            
            //注意:当Start时提供了takeoffEncodeChunk后,你需要自行实时保存录音文件数据,因此Stop时返回的arrayBuffer的长度将为0字节
            
            //如果当前环境支持Blob,也可以直接构造成Blob文件对象,和Recorder使用一致
            if(typeof(Blob)!="undefined" && typeof(window)=="object"){
                var blob=new Blob([arrayBuffer],{type:mime});
                console.log(blob, (window.URL||webkitURL).createObjectURL(blob));
            }
        },(msg)=>{
            console.error("结束录音失败:"+msg);
        });
    }
    
}
}

上面代码中包含了开始录音、结束录音、暂停、继续的功能方法代码,在view中放几个按钮进行点击调用即可;在
onProcess
回调中可以做到录音数据实时处理,可视化图形的绘制操作也是在
onProcess
中进行的(Recorder提供了多中可视化波形显示),H5、App、小程序均可使用。

要编译成App时,记得先在
manifest.json
中配置好Android和iOS的录音权限声明:

//Android需要勾选的权限,第二个必须勾选,不然使用H5录音时将没法打开麦克风
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>

//iOS需要声明的权限
NSMicrophoneUsageDescription

上传录音

在上面录音recStop代码中,结束录音后会得到ArrayBuffer二进制数据,将ArrayBuffer上传到服务器即可;实时处理中也支持上传,实时得到音频数据的ArrayBuffer后按下面的上传方法上传即可。

上传方式一(简单):转成Base64文本上传

//由于是base64文本,因此直接使用普通的接口请求就可以了,代码简单,H5、App、小程序通用

uni.request({
	url: "上传接口地址"
	,method: "POST"
	,header: { "content-type":"application/x-www-form-urlencoded" }
	,data: {
		audio: uni.arrayBufferToBase64(arrayBuffer)
		,... 其他表单参数 ...
	}
	,success: (res) => { }
	,fail: (err)=>{ }
});

上传方式二(复杂):使用上传表单上传 multipart/form-data

//使用multipart/form-data表单上传文件,在uniapp中支持不是很好,每个平台单独处理

// #ifdef H5
	//H5中直接使用浏览器提供的File接口构造一个文件
	uni.uploadFile({
		url: "上传接口地址"
		,file: new File([arrayBuffer], "recorder.mp3")
		,name: "audio"
		,formData: {
			... 其他表单参数 ...
		}
		,success: (res) => { }
		,fail: (err)=>{ }
	});
// #endif

// #ifdef APP
	//App中直接将二进制数据保存到本地文件,然后再上传
	RecordApp.UniSaveLocalFile("recorder.mp3",arrayBuffer,(savePath)=>{
		uni.uploadFile({
			url: "上传接口地址"
			,filePath: savePath
			,name: "audio"
			,formData: {
				... 其他表单参数 ...
			}
			,success: (res) => { }
			,fail: (err)=>{ }
		});
	},(err)=>{});
// #endif

// #ifdef MP-WEIXIN
	//小程序中需要将二进制数据保存到本地文件,然后再上传
	var savePath=wx.env.USER_DATA_PATH+"/recorder.mp3";
	wx.getFileSystemManager().writeFile({
		filePath:savePath
		,data:arrayBuffer
		,encoding:"binary"
		,success:()=>{
			wx.uploadFile({
				url: "上传接口地址"
				,filePath: savePath
				,name: "audio"
				,formData: {
					... 其他表单参数 ...
				}
				,success: (res) => { }
				,fail: (err)=>{ }
			});
		}
		,fail:(e)=>{  }
	});
// #endif

ASR语音识别

假如你的服务器提供了识别接口,可以参考上面的文件上传,将文件上传给你的服务器后,服务器将识别结果返回给前端,此方式可以适配:腾讯云、阿里云、讯飞等的一句话语音识别,或自己搭建的语音识别,比较简单。

实时的语音识别可以参考Recorder-UniCore插件的demo项目,demo源码里面有个
page_asr.vue
示例页面,可以做到边录音边返回识别结果;此demo使用的是阿里云接口,其他语音识别接口同样的可以在
onProcess
中进行实时处理即可完成对接,可以参考Recorder H5录音开源库
https://github.com/xiangyuecn/Recorder
中的实时上传处理demo代码,不难做到边录音边上传到语音识别,H5、App、小程序中也是通用的。

【完】

随机森林分类
算法是一种基于集成学习(ensemble learning)的机器学习算法,
它的基本原理是通过对多个决策树的预测结果进行平均或投票,以产生最终的分类结果。

随机森林算法可用于
回归

分类
问题。
关于随机森林算法在
回归问题
上的应用可参考:
TODO

随机森林分类
算法可以应用于各种需要进行分类或预测的问题,如
垃圾邮件识别

信用卡欺诈检测

疾病预测
等,
它也可以与其他机器学习算法进行结合,以进一步提高预测准确率。

1. 算法概述

随机森林
的基本原理是构建多棵决策树,每棵树都是基于原始训练数据的一个随机子集进行训练。在构建每棵树时,算法会随机选择一部分特征进行考虑,而不是考虑所有的特征。

然后,对于一个新的输入样本,每棵树都会进行分类预测,并将预测结果提交给“森林”进行最终的分类决策。
一般来说,森林会选择出现次数最多的类别作为最终的分类结果。

理论上来看,
随机森林分类
应该比
决策树分类
有更加好的准确度,特别是在高维度的数据情况下。

2. 创建样本数据

为了后面比较随机森林分类算法和决策树算法的准确性,创建分类多一些(8个分类标签)的样本数据。

import matplotlib.pyplot as plt
from sklearn.datasets import make_classification

# 分类数据的样本生成器
X, y = make_classification(
    n_samples=1000, n_classes=8, n_clusters_per_class=2, n_informative=6
)
plt.scatter(X[:, 0], X[:, 1], marker="o", c=y, s=25)

plt.show()

image.png

3. 模型训练

首先,分割
训练集

测试集

from sklearn.model_selection import train_test_split

# 分割训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1)

这次按照
9:1的比例
来划分训练集和测试集。


决策树分类
模型来训练数据:

from sklearn.tree import DecisionTreeClassifier

reg_names = [
    "ID3算法",
    "C4.5算法",
    "CART算法",
]

# 定义
regs = [
    DecisionTreeClassifier(criterion="entropy"),
    DecisionTreeClassifier(criterion="log_loss"),
    DecisionTreeClassifier(criterion="gini"),
]

# 训练模型
for reg in regs:
    reg.fit(X_train, y_train)

# 在测试集上进行预测
y_preds = []
for reg in regs:
    y_pred = reg.predict(X_test)
    y_preds.append(y_pred)

for i in range(len(y_preds)):
    correct_pred = np.sum(y_preds[i] == y_test)
    print("决策树【{}】 预测正确率:{:.2f}%".format(reg_names[i], correct_pred / len(y_pred) * 100))

# 运行结果
决策树【ID3算法】 预测正确率:43.00%
决策树【C4.5算法】 预测正确率:42.00%
决策树【CART算法】 预测正确率:42.00%


随机森林分类
模型来训练数据:

from sklearn.ensemble import RandomForestClassifier

reg_names = [
    "ID3算法",
    "C4.5算法",
    "CART算法",
]

# 定义
regs = [
    RandomForestClassifier(criterion="entropy"),
    RandomForestClassifier(criterion="log_loss"),
    RandomForestClassifier(criterion="gini"),
]

# 训练模型
for reg in regs:
    reg.fit(X_train, y_train)

# 在测试集上进行预测
y_preds = []
for reg in regs:
    y_pred = reg.predict(X_test)
    y_preds.append(y_pred)

for i in range(len(y_preds)):
    correct_pred = np.sum(y_preds[i] == y_test)
    print("随机森林【{}】 预测正确率:{:.2f}%".format(reg_names[i], correct_pred / len(y_pred) * 100))

# 运行结果
随机森林【ID3算法】 预测正确率:64.00%
随机森林【C4.5算法】 预测正确率:63.00%
随机森林【CART算法】 预测正确率:69.00%

可以看出,
随机森林分类
的准确性确实比
决策树分类
提高了。
不过,运行过程中也可以发现,
随机森林
的训练时间会比
决策树
长一些。

4. 总结

随机森林分类
算法的优势在于:

  1. 抗过拟合能力强
    :由于采用随机选择特征的方式,可以有效地避免过拟合问题。
  2. 泛化能力强
    :通过对多个决策树的结果进行投票或平均,可以获得更好的泛化性能。
  3. 对数据特征的选取
    具有指导性
    :在构建决策树时会对特征进行选择,这可以为后续的特征选择提供指导。
  4. 适用于
    大规模数据集
    :可以有效地处理大规模数据集,并且训练速度相对较快。

当然,
随机森林分类
算法也存在一些劣势:

  1. 需要大量的内存和计算资源
    :由于需要构建多个决策树,因此需要更多的内存和计算资源。
  2. 需要调整参数
    :性能很大程度上取决于参数的设置,如树的数量、每个节点的最小样本数等,这些参数的设置需要一定的经验和实验。
  3. 对新样本的预测性能不稳定
    :由于是通过投票或平均多个决策树的结果来进行预测,因此对新样本的预测性能可能会受到影响。