消息中间件Kafka(PHP版本)

        小编最近需要用到消息中间件,有需要要复习一下以前的东西,有需要的自取,强调一点,如果真的想了解透彻,一定要动手脑袋会了不代表就会写了

        Kafka是由Scala和Java编写。Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者在网站中的所有动作流数据。 这种动作(网页浏览,搜索和其他用户的行动)是在现代网络上的许多社会功能的一个关键因素。 这些数据通常是由于吞吐量的要求而通过处理日志和日志聚合来解决。 对于像Hadoop一样的日志数据和离线分析系统,但又要求实时处理的限制,这是一个可行的解决方案。Kafka的目的是通过Hadoop的并行加载机制来统一线上和离线的消息处理,也是为了通过集群来提供实时的消息

Kafka 的特性

高吞吐、低延迟:kakfa 最大的特点就是收发消息非常快,kafka 每秒可以处理几十万条消息,它的最低延迟只有几毫秒。
高伸缩性: 每个主题(topic) 包含多个分区(partition),主题中的分区可以分布在不同的主机(broker)中。
持久性、可靠性: Kafka 能够允许数据的持久化存储,消息被持久化到磁盘,并支持数据备份防止数据丢失,Kafka 底层的数据存储是基于 Zookeeper 存储的,Zookeeper 我们知道它的数据能够持久存储。
容错性: 允许集群中的节点失败,某个节点宕机,Kafka 集群能够正常工作
高并发: 支持数千个客户端同时读写

Kafka 的使用场景

活动跟踪:Kafka 可以用来跟踪用户行为,比如我们经常回去淘宝购物,你打开淘宝的那一刻,你的登陆信息,登陆次数都会作为消息传输到 Kafka ,当你浏览购物的时候,你的浏览信息,你的搜索指数,你的购物爱好都会作为一个个消息传递给 Kafka ,这样就可以生成报告,可以做智能推荐,购买喜好等。
传递消息:Kafka 另外一个基本用途是传递消息,应用程序向用户发送通知就是通过传递消息来实现的,这些应用组件可以生成消息,而不需要关心消息的格式,也不需要关心消息是如何发送的。
度量指标:Kafka也经常用来记录运营监控数据。包括收集各种分布式应用的数据,生产各种操作的集中反馈,比如报警和报告。
日志记录:Kafka 的基本概念来源于提交日志,比如我们可以把数据库的更新发送到 Kafka 上,用来记录数据库的更新时间,通过kafka以统一接口服务的方式开放给各种consumer,例如hadoop、Hbase、Solr等。
流式处理:流式处理是有一个能够提供多种应用程序的领域。
限流削峰:Kafka 多用于互联网领域某一时刻请求特别多的情况下,可以把请求写入Kafka 中,避免直接请求后端程序导致服务崩溃。

消息:
Kafka中的数据单元被称为消息,也被称为记录,可以把它看作数据库表中某一行的记录。
批次:为了提高效率,消息会分批次写入Kafka,批次就代指的是一组消息。

主题:
消息的种类称为主题(Topic),可以说一个主题代表了一类消息。相当于是对消息进行分类。主题就像是数据库中的表。

分区:
主题可以被分为若干个分区(partition),同一个主题中的分区可以不在一个机器上,有可能会部署在多个机器上,
由此来实现 kafka 的伸缩性,单一主题中的分区有序,但是无法保证主题中所有的分区有序

生产者:
向主题发布消息的客户端应用程序称为生产者(Producer),生产者用于持续不断的向某个主题发送消息。

消费者:
订阅主题消息的客户端程序称为消费者(Consumer),消费者用于处理生产者产生的消息。

消费者群组:
生产者与消费者的关系就如同餐厅中的厨师和顾客之间的关系一样,一个厨师对应多个顾客,也就是一个生产者对应多个消费者,
消费者群组(Consumer Group)指的就是由一个或多个消费者组成的群体。

偏移量:
偏移量(Consumer Offset)是一种元数据,它是一个不断递增的整数值,用来记录消费者发生重平衡时的位置,以便用来恢复数据。

broker:
一个独立的 Kafka 服务器就被称为 broker,broker 接收来自生产者的消息,为消息设置偏移量,并提交消息到磁盘保存。

broker 集群:
broker 是集群 的组成部分,broker 集群由一个或多个 broker 组成,每个集群都有一个 broker 同时充当了集群控制器的角色(自动从集群的活跃成员中选举出来)。
副本:Kafka 中消息的备份又叫做 副本(Replica),副本的数量是可以配置的,Kafka 定义了两类副本:领导者副本(Leader Replica) 和 追随者副本(Follower Replica),前者对外提供服务,后者只是被动跟随。
重平衡:Rebalance。消费者组内某个消费者实例挂掉后,其他消费者实例自动重新分配订阅主题分区的过程。Rebalance 是 Kafka 消费者端实现高可用的重要手段。

安装

下载地址

librdkafka获取地址:https://github.com/edenhill/librdkafka
kafka获取地址:https://github.com/arnaud-lb/php-rdkafka

安转java环境

下载地址:https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html
下载解压完成之后,设置系统变量:path(路径为:安装目录/bin)
设置环境变量:JAVA_HOME(路径为:安装目录\bin)

查看是否安装成功:java -version

Zookeeper安装

下载地址:https://www.apache.org/dyn/closer.lua/zookeeper/zookeeper-3.6.4/apache-zookeeper-3.6.4-bin.tar.gz
设置环境变量:path(路径为:安装目录\bin)
新建data文件夹,新建logs文件夹
config文件夹:zoo_sample.cfg  新复制一个:zoo.cfg
编辑zoo.cfg文件:
新增(配置路径【一定要配置\\,要不然不识别】:安装路径\\zookeeper\\apache-zookeeper-3.6.4-bin\\):
dataDir= 安装路径\zookeeper\apache-zookeeper-3.6.4-bin\data
dataLogDir=安装路径\zookeeper\apache-zookeeper-3.6.4-bin\log
audit.enable=truezookeeper/conf/zoo.cfg 参数详解

tickTime=2000:
        这个时间是作为 Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个 tickTime 时间就会发送一个心跳,单位是毫秒
        
initLimit=10:
        这个配置项是用来配置 Zookeeper 接受客户端(这里所说的客户端不是用户连接 Zookeeper 服务器的客户端,而是 Zookeeper 服务器集群中连接到 Leader 的 Follower 服务器)初始化连接时最长能忍受多少个心跳时间间隔数。当已经超过 5个心跳的时间(也就是 tickTime)长度后 Zookeeper 服务器还没有收到客户端的返回信息,那么表明这个客户端连接失败。总的时间长度就是 5*2000=10 秒,10秒内要启动集群并出现leader和floower。
syncLimit=5:
        这个配置项标识 Leader 与Follower 之间发送消息,请求和应答时间长度,最长不能超过多少个 tickTime 的时间长度,总的时间长度就是5*2000=10秒,超出时间认为是死机。
dataDir:
        快照日志的存储路径
dataLogDir:
        事物日志的存储路径,如果不配置这个那么事物日志会默认存储到dataDir制定的目录,这样会严重影响zk的性能,当zk吞吐量较大的时候,产生的事物日志、快照日志太多
clientPort=12181:
        这个端口就是客户端连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求。修改他的端口改大点

启动zkServer

启动目录:\bin\zkServer.sh

启动命令:zkServer.sh start

查找看到:binding to port .0.0.0.0/0.0.0.2181能表示成功

安装Scala

下载地址:https://downloads.lightbend.com/scala/2.11.12/scala-2.11.12.msi
安装:一键安装(一直next,直到完成)
配置环境变量(这个需要配置):安装目录/bin
判断是否安装完成:scala -version

Kafka安装

下载地址:https://kafka.apache.org/downloads
Kafka安装目录下新建目录logs
编辑config\server.properties文件
log.dirs=安装目录\\logs(注意双斜线,如果是cmd命令出现命令行太长,那就把Kafka安装安装在磁盘的最外面,D盘的最外层)
新增参数:listeners=PLAINTEXT://localhost:9092

启动

一定要先启动zookeeper(命令:zkServer)
然后启动kafka(命令(cmd进入Kafka安装目录):.\bin\windows\kafka-server-start.bat .\config\server.properties)
查找看到:from now on will use node localhost:9092
能表示成功(如果启动不了,删除logs文件夹下的文件)

操作:

创建topics(主题):

kafka-topics.bat --create --bootstrap-server localhost:9092 --replication-factor 1 --partitions 1 --topic test


查看主题:

kafka-topics.bat --bootstrap-server localhost:9092 --list

生产者:

cmd进入:安装目录\bin\windows
打开生产者:kafka-console-producer.bat --broker-list localhost:9092 --topic test

消费者:

cmd进入:安装目录\bin\windows
打开消费者:kafka-console-consumer.bat --bootstrap-server localhost:9092 --topic test --from-beginning

测试:

生产者发送消息,消费者订阅收到消息

注意:
1.一共打开四个窗口,1.zookeeper 2.kafka  3.生产者  4.消费者  (注意,这四个窗口不能关闭,要一直开着)
2.一定是生产者生产消息,消费者才会收到消息(注意,生产者和消费者的topics一定要是一样的,要不然收不到消息)

方法

getOutQlen方法

使用方法:$producer->getOutQLen();
作用:
1.用于获取生产者(Producer)内部队列中等待发送到Kafka broker的消息数量。
2.getOutQLen() 方法允许你查询这个内部队列中当前待发送的消息数量。通常用于监控和调试目的,帮助了解生产者的发送速率和队列积压情况
3.getOutQLen() 返回的是近似值,它可能在调用之间发生变化
输出数据:
int(0)


poll方法

使用方法:
while ($producer->getOutQLen() > 0) {
    $producer->poll(1);
}
作用:
用于从Kafka集群中拉取消息,当消费者调用poll()方法时,如果在规定的时间内没有收到任何消息,它会立即返回,并且没有任何消息被拉取到(轮询一次就相当于拉取一定时间段broker中可消费的数据)


 
flush方法

使用方法:$producer->flush(10000);
作用:将生产者内部缓冲区中的消息强制发送到Kafka broker的过程。


consumerstart方法

使用方法:$topic->consumeStart(0, RD_KAFKA_OFFSET_STORED);
作用:在Kafka中,consumerstart方法是用于启动消费者线程并开始从Kafka集群中拉取消息的方法。


Consume方法

使用方法:$topic->consume(0, 120*10000);
作用:是指Kafka消费者从Kafka集群中读取消息的过程。首先需要从集群中先拉取数据


Purge方法

使用方法:$producer->purge(RD_KAFKA_PURGE_F_QUEUE);
作用:是指清除已完成或已过期的请求,以释放缓存资源。


initTransactions方法

作用:用于初始化一个事务。Kafka从0.11.0.0版本开始支持事务性生产者API,允许生产者将多个消息组合成一个事务,确保这些消息被原子性地写入Kafka。这意味着要么所有消息都成功写入,要么都不写入,保证了消息的一致性


beginTransaction方法

作用:用于开始一个新的生产者事务。Kafka从0.11.0.0版本开始支持事务性生产者API,它允许你将多个消息组合成一个事务,确保这些消息被原子性地写入Kafka。这意味着要么所有消息都成功写入,要么都不写入,这保证了消息的一致性


commitTransaction方法

作用:它用于提交一个事务。当你使用 Kafka 的事务性生产者 API 时,你可以将一系列的消息发送操作组合成一个原子性的事务。这意味着这些操作要么全部成功,要么全部失败,从而确保数据的一致性和顺序性


abortTransaction方法

作用:中止事务,当发送消息或提交事务过程中发生错误时使用

getMetadata方法

使用方法:$producer->getMetadata(false, $topic, 10*1000);

作用:
用于获取Kafka集群的元数据
获取数据包括:1.主题(topics)2.分区(partitions)3.副本(replicas)4.ISR(In-Sync Replicas)等信息。
通常,客户端库(如PHP的php-kafka)会在初始化时或需要时自动执行此操作,以便了解集群的状态和可用主题。


代码:

class Kafka extends CI_Controller {

    //定义变量(分区)
    private $borker_list = "";
    //定义变量(配置)
    private $conf = "";
    //定义变量(主题)
    private $topics = "";
    //定义变量(分组)
    private $topics_group = "";

    //构造
    public function __construct(){
        parent::__construct();
        //初始化数据
        $this->borker_list = "localhost:9092";
        $this->topics = "test";
        $this->topics_group = "test-group";
    }

    //消息生产者
    public function producter(){
        //初始化
        $conf=  new RdKafka\Conf();
        //设置分区
        $conf->set('metadata.broker.list', $this->borker_list);
        //初始化生产者
        $producer = new RdKafka\Producer($conf);
        //设置主题
        $topic = $producer->newTopic($this->topics);
        //产生信息
        for ($i = 0; $i < 10; $i++) {
            $topic->produce(RD_KAFKA_PARTITION_UA, 0, "Message $i");
            $producer->poll(0);
        }
        //消息刷新
        for ($flushRetries = 0; $flushRetries < 10; $flushRetries++) {
            $result = $producer->flush(10000);
            if (RD_KAFKA_RESP_ERR_NO_ERROR === $result) {
                break;
            }
        }
        //刷新结果
        if (RD_KAFKA_RESP_ERR_NO_ERROR !== $result) {
            throw new \RuntimeException('Was unable to flush, messages might be lost!');
        }
    }

    //消息订阅者
    public function consumer(){
        set_time_limit(0);
        //初始化
        $conf = new RdKafka\Conf();
        //设置分区
        $conf->set('metadata.broker.list', $this->borker_list);
        $conf->set('group.id',$this->topics_group);
        //初始化消费者
        $rk = new RdKafka\Consumer($conf);

        //主题配置
        $topicConf = new RdKafka\TopicConf();
        $topicConf->set('auto.commit.interval.ms', 100);
        $topicConf->set('offset.store.method', 'file');
        $topicConf->set('offset.store.path', sys_get_temp_dir());
        $topicConf->set('auto.offset.reset', 'smallest');

        $topic = $rk->newTopic($this->topics, $topicConf);
        $topic->consumeStart(0, RD_KAFKA_OFFSET_STORED);

        while (true) {
            $message = $topic->consume(0, 120*10000);
            switch ($message->err) {
                case RD_KAFKA_RESP_ERR_NO_ERROR:
                    //没有错误打印信息
                    var_dump($message);
                    break;
                case RD_KAFKA_RESP_ERR__PARTITION_EOF:
                    echo "等待接收信息\n";
                    break;
                case RD_KAFKA_RESP_ERR__TIMED_OUT:
                    echo "超时\n";
                    break;
                default:
                    throw new \Exception($message->errstr(), $message->err);
                    break;
            }
        }
    }

    //获取元数据(包括主题(topics)、分区(partitions)、副本(replicas)和ISR(In-Sync Replicas)等信息)
    public function gettest(){
        //初始化
        $conf=  new RdKafka\Conf();
        //设置分区
        $conf->set('metadata.broker.list', $this->borker_list);
        //初始化生产者
        $producer = new RdKafka\Producer($conf);
        $topic = $producer->newTopic($this->topics);
//        $result = $producer->getMetadata(false, $topic, 10*1000);
        $result = $producer->getOutQLen();
        var_dump($result);die;
    }


    //获取元数据
    public function metadata(){
        $conf = new RdKafka\Conf();
        $conf->setDrMsgCb(function ($kafka, $message) {
            file_put_contents("./xx.log", var_export($message, true), FILE_APPEND);
        });
        $conf->setErrorCb(function ($kafka, $err, $reason) {
            printf("Kafka error: %s (reason: %s)\n", rd_kafka_err2str($err), $reason);
        });

        $conf->set('group.id', 'myConsumerGroup');

        $rk = new RdKafka\Consumer($conf);
        $rk->addBrokers("127.0.0.1");

        $allInfo = $rk->getMetadata(true, NULL, 60e3);
        $topics = $allInfo->getTopics();

        //循环输出
        foreach ($topics as $topic) {
            $topicName = $topic->getTopic();
            if ($topicName == "__consumer_offsets") {
                continue ;
            }
            $partitions = $topic->getPartitions();
            foreach ($partitions as $partition) {
                $topPartition = new RdKafka\TopicPartition($topicName, $partition->getId());
                echo  "当前的话题:" . ($topPartition->getTopic()) . " - " . $partition->getId() . " - ";
                echo  "offset:" . ($topPartition->getOffset()) . PHP_EOL;
            }
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/619395.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Debian Linux 下给Nginx 1.26.0 编译增加Brotli算法支持

明月发现参考【给Nginx添加谷歌Brotli压缩算法支持】一文给出的方法&#xff0c;在Debian Linux 12.5下就一直编译失败&#xff0c;主要的错误是因为文件缺失&#xff0c;在专门又安装了apt-get install libbrotli-dev的依赖库后依然会因为文件缺失无法编译完成&#xff0c;就这…

用 Python 从头开始​​编写线性回归

找到最佳拟合线的方法是使用梯度下降&#xff0c;我们将随机绘制一条线&#xff0c;计算该线的误差 计算误差 给定m和b&#xff0c;我们将计算直线的误差。Eeeor用sigma表示法表示 def compute_error_for_line_given_points(b, m, points):totalError 0for i in range(0, len…

安装conda并搭建python环境(入门教程)

文章目录 1. 什么是 conda&#xff1f;1.1 Conda 与 Anaconda 的区别1.2 Conda 与 pip 的区别 2. 下载安装3. 配置并使用 conda3.1 配置下载源3.2 环境管理3.2.1 创建&#xff08;删除&#xff09;环境3.2.2 激活&#xff08;切换&#xff09;环境3.2.2 下载&#xff08;卸载&a…

机器学习——2.损失函数loss

基本概念 损失函数也叫代价函数。损失函数就是计算预测结果和实际结果差距的函数&#xff0c;机器学习的过程就是试图将损失函数的值降到最小。 图左&#xff1a;&#xff5c;t_p - t_c&#xff5c; 图右&#xff1a;&#xff08;t_p - t_c&#xff09;**2 代码实…

[OpenGL高级光照] 阴影改善

目录 一 阴影失真 二 阴影改善 2.1 减小片段深度值 2.2 降低纹理 2.3 注意事项 三 消除Repeat的问题 3.1 让裁剪矩阵的立方体变大 ​3.2 利用采样范围重置 四 精度问题 本章节源码 点击此处 一 阴影失真 在上一篇中,实现了阴影效果之后,但是我们会发现阴影效果中地面…

47-Qt控件详解:Buttons Containers1

一 QPushButton (命令按钮) #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow> #include <QPushButton>//引入QPushButton类对应的头文件class MainWindow : public QMainWindow {Q_OBJECTpublic:MainWindow(QWidget *parent nullptr);~MainWind…

【IMX6ULL项目】IMX6ULL下Linux实现产测工具框架

电子产品量产测试与烧写工具。这是一套软件&#xff0c;用在我们的实际生产中&#xff0c; 有如下特点&#xff1a; 1.简单易用&#xff1a; 把这套软件烧写在 SD 卡上&#xff0c;插到 IMX6ULL 板子里并启动&#xff0c;它就会自动测试各个模块、烧写 EMMC 系统。 工人只要按…

40 -1 入侵检测系统(IDS)- IDS的使用及规则

xampp 官网:XAMPP Installers and Downloads for Apache Friends 一、安装 XAMPP XAMPP 简介 XAMPP是完全免费且易于安装的Apache发行版,其中包含MariaDB、PHP和Perl。XAMPP开放源码包的设置让安装和使用出奇容易。 开始安装 如果命令行下载太慢,就在浏览器中下载完再拉…

【2024新版】龙年新版ui周易测算网站H5源码/在线起名网站源码/运势测算网站系统源码

>>>功能说明&#xff1a; 1、系统配置&#xff1a;系统基本配置、测算价格配置、在线预约配置、系统信息配置、代理分成配置、推广积分配置、VIP价格配置、账号管理 2、推广管理&#xff1a;我的信息、推广链接、订单管理、体现管理 3、付费应用&#xff0c;订单管…

高校课程评价|基于SSM+vue的高校课程评价系统的设计与实现(源码+数据库+文档)

高校课程评价系统 目录 基于SSM&#xff0b;vue的高校课程评价系统的设计与实现 一、前言 二、系统设计 三、系统功能设计 1管理员功能模块 2学生功能 3教师功能 4专家功能 四、数据库设计 五、核心代码 六、论文参考 七、最新计算机毕设选题推荐 八、源码获取&…

Windows Docker 使用 httpd 部署静态 Web 站点

一、简介 httpd 是 Apache超文本传输协议&#xff08;HTTP&#xff09;服务器的主程序&#xff0c;是一个独立运行的后台进程&#xff0c;专门负责处理 HTTP 请求。它通过建立子进程或线程的池来高效管理请求&#xff0c;确保服务器能够迅速响应客户端的需求。httpd 因其高效率…

【Delphi】OpenCV 实战(一):OpenCV简介及开发环境配置

目录 一、OpenCV 功能模块 二、Delphi 中使用OpenCV 三、OpenCV 4.7 Delphi开发环境配置 1. 环境配置 2. OpenCV 中Demo程序的编译配置 3. 运行 Demo (OpenCV for Delphi) OpenCV 是世界上最大的计算机视觉库。 它是开源的,包含 2500 多种算法,由非营利…

信息系统项目管理师0105:项目评估与决策(7项目立项管理—7.3项目评估与决策)

点击查看专栏目录 文章目录 7.3项目评估与决策1.评估依据2.评估的程序3.项目评估的内容4.项目评估报告内容大纲记忆要点总结7.3项目评估与决策 项目评估指在项目可行性研究的基础上,由第三方(国家、银行或有关机构)根据国家颁布的政策、法规、方法、参数和条例等,从国民经济…

算法题② —— 链表专栏

1. 链表数据结构 struct ListNode {int val;ListNode *next;ListNode() : val(0), next(nullptr) {}ListNode(int x) : val(x), next(nullptr) {}ListNode(int x, ListNode *next) : val(x), next(next) {}};2. 链表的删除 2.1 移除链表元素 力扣&#xff1a;https://leetco…

大规模 RGB LED灯控系统 Lumos:创新与智能化的融合

灯控系统&#xff1a;创新与智能化的融合 在现代照明技术不断进步的背景下&#xff0c;灯控系统的应用已经从简单的开关控制&#xff0c;发展到能够进行复杂程控操作的智能化管理。我们推出的新一代灯控解决方案&#xff0c;凭借其高度的可配置性和跨平台兼容性&#xff0c;已…

Python | Leetcode Python题解之第86题分隔链表

题目&#xff1a; 题解&#xff1a; class Solution:def partition(self, head: Optional[ListNode], x: int) -> Optional[ListNode]:sml_dummy, big_dummy ListNode(0), ListNode(0)sml, big sml_dummy, big_dummywhile head:if head.val < x:sml.next headsml sm…

Android 10.0 Launcher3定制folder文件夹2x2布局之二foldericon的2x2的显示布局

1.前言 在10.0的系统rom产品定制化开发中,在对Launcher3的folder文件夹功能定制中,要求folder文件夹跨行显示,就是 2x2布局显示,默认的都是占1格的,现在要求占4格显示,系统默认是不支持显示4格的,所以接下来需要分析相关的 功能,然后来实现这个功能 2.Launcher3定制fo…

项目管理-计算题公式-补充【复习】

1.EMV决策树 定义&#xff1a;用决策树在若干备选行动方案中选择一个最佳方案。在决策树 中&#xff0c;用不同的分支代表不同的决策或事件&#xff0c;即项目的备选路径。每个决策或事件 都有相关的成本和单个项目风险(包括威胁和机会)。决策树分支的终点表示沿特 定路径发展的…

[C/C++] -- 搜索迷宫路径

DFS&#xff08;深度优先搜索&#xff09;和BFS&#xff08;广度优先搜索&#xff09;是两种常用的图遍历算法&#xff0c;它们在搜索图或树中的节点时有着不同的策略和特点。 深度优先搜索 (DFS): 在DFS中&#xff0c;从起始节点开始&#xff0c;沿着一条路径尽可能深地搜索&a…

基于数据挖掘与机器学习揭秘脱发主因

&#x1f31f;欢迎来到 我的博客 —— 探索技术的无限可能&#xff01; &#x1f31f;博客的简介&#xff08;文章目录&#xff09; 基于数据挖掘与机器学习揭秘脱发主因 目录 一、绪论背景描述数据说明内容大概 二、导入包以及数据读取三、数据预览四、探究导致脱发的因素4.1…