diff --git a/deploy.sh b/deploy.sh index 23a8bf82..d6261261 100755 --- a/deploy.sh +++ b/deploy.sh @@ -10,8 +10,8 @@ dist_path=docs/.vuepress/dist # 打包生成的文件夹路径 push_branch=gh-pages # 推送的分支 # 生成静态文件 windows要加build:win -#npm run build:win -npm run build +npm run build:win +#npm run build # 进入生成的文件夹 cd $dist_path @@ -20,8 +20,8 @@ git init git add -A git commit -m "deploy, $commit_info" # mac中默认分支是main,win中默认是master -#git push -f $push_addr master:$push_branch -git push -f $push_addr main:$push_branch +git push -f $push_addr master:$push_branch +#git push -f $push_addr main:$push_branch cd - rm -rf $dist_path \ No newline at end of file diff --git a/docs/.vuepress/config.ts b/docs/.vuepress/config.ts index b362b8ce..566a40f7 100644 --- a/docs/.vuepress/config.ts +++ b/docs/.vuepress/config.ts @@ -53,6 +53,8 @@ export default defineConfig4CustomTheme({ { text: '《ReggieTakeOut》笔记', link: '/note/reggietakeout/'}, { text: '《MicroService》笔记', link: '/note/microservice/'}, { text: '《XueChengPlus》笔记', link: '/note/xuechengplus/'}, + { text: '《Flume》笔记', link: '/note/flume/'}, + { text: '《Python》笔记', link: '/note/python/'} ], }, ], diff --git "a/docs/01.\346\226\207\346\241\243\344\270\255\345\277\203/00.\345\255\246\344\271\240\347\254\224\350\256\260/20.\343\200\212Flume\343\200\213\347\254\224\350\256\260.md" "b/docs/01.\346\226\207\346\241\243\344\270\255\345\277\203/00.\345\255\246\344\271\240\347\254\224\350\256\260/20.\343\200\212Flume\343\200\213\347\254\224\350\256\260.md" new file mode 100644 index 00000000..fdae302d --- /dev/null +++ "b/docs/01.\346\226\207\346\241\243\344\270\255\345\277\203/00.\345\255\246\344\271\240\347\254\224\350\256\260/20.\343\200\212Flume\343\200\213\347\254\224\350\256\260.md" @@ -0,0 +1,17 @@ +--- +pageComponent: + name: Catalogue + data: + path: 《Flume》笔记 + imgUrl: https://jsd.cdn.zzko.cn/gh/xugaoyi/image_store/blog/20200112160453.png + description: 本章内容为博主在原教程基础上添加学习笔记,教程版权归原作者所有。来源:ES6教程 +title: 《Flume》笔记 +date: 2025-1-17 15:39:16 +permalink: /note/flume/ +article: false +comment: false +editLink: false +author: + name: xugaoyi + link: https://github.com/xugaoyi +--- diff --git "a/docs/01.\346\226\207\346\241\243\344\270\255\345\277\203/00.\345\255\246\344\271\240\347\254\224\350\256\260/26.\343\200\212Python\343\200\213\347\254\224\350\256\260.md" "b/docs/01.\346\226\207\346\241\243\344\270\255\345\277\203/00.\345\255\246\344\271\240\347\254\224\350\256\260/26.\343\200\212Python\343\200\213\347\254\224\350\256\260.md" new file mode 100644 index 00000000..f8c7b983 --- /dev/null +++ "b/docs/01.\346\226\207\346\241\243\344\270\255\345\277\203/00.\345\255\246\344\271\240\347\254\224\350\256\260/26.\343\200\212Python\343\200\213\347\254\224\350\256\260.md" @@ -0,0 +1,17 @@ +--- +pageComponent: + name: Catalogue + data: + path: 《Python》笔记 + imgUrl: https://jsd.cdn.zzko.cn/gh/xugaoyi/image_store/blog/20200112160453.png + description: 本章内容为博主在原教程基础上添加学习笔记,教程版权归原作者所有。来源:ES6教程 +title: 《Python》笔记 +date: 2025-1-17 15:39:26 +permalink: /note/python/ +article: false +comment: false +editLink: false +author: + name: xugaoyi + link: https://github.com/xugaoyi +--- diff --git "a/docs/\343\200\212Flume\343\200\213\347\254\224\350\256\260/01.Flume.md" "b/docs/\343\200\212Flume\343\200\213\347\254\224\350\256\260/01.Flume.md" new file mode 100644 index 00000000..a0726d7c --- /dev/null +++ "b/docs/\343\200\212Flume\343\200\213\347\254\224\350\256\260/01.Flume.md" @@ -0,0 +1,2302 @@ +--- +title: Flume +date: 2025-01-17 15:28:08 +permalink: /pages/ceb8cc/ +categories: + - 《Flume》笔记 +tags: + - +author: + name: onetion + link: https://github.com/onetioner +--- +# Flume概述 + +Flume是的一个分布式、高可用、高可靠的海量日志采集、聚合和传输的系统,支持在日志系统中定制各类数据发送方,用于收集数据,同时提供了对数据进行简单处理并写到各种数据接收方的能力。 + +> 分布式:部署多个Agent来做分布式 +> +> 高可用:通过Sink的负载均衡(或者说是副本机制)来保证高可用 +> +> 高可靠:是通过Channel事务来保证高可靠 +> +> 定制各类数据:指定各种Source +> +> 简单处理:通过拦截器实现修改、丢弃 +> +> 各种接收方:指定各种Sink + +Flume的设计原理是基于数据流的,能够将不同数据源的海量日志数据进行高效收集、聚合、移动,最后存储到一个中心化数据存储系统中。 Flume能够做到近似实时的推送,并且可以满足数据量是持续且量级很大的情况。比如它可以收集社交网站日志,并将这些数量庞大的日志数据从网站服务器上汇集起来,存储到HDFS或 HBase分布式数据库中。 + +Flume的应用场景:比如一个电商网站,想从网站访问者中访问一些特定的节点区域来分析消费者的购物意图和行为。为了实现这一点,需要收集到消费者访问的页面以及点击的产品等日志信息,并移交到大数据 Hadoop平台上去分析,可以利用 Flume做到这一点。现在流行的内容推送,比如广告定点投放以及新闻私人定制也是基于这个道理。 + +# Flume架构 + +![image-20200327112206283](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/202501071706044.png) + +## Event + +事件是Flume内部数据传输的最基本单元,将传输的数据进行封装。事件本身是由一个载有数据的字节数组和可选的headers头部信息构成,如下图所示。Flume以事件的形式将数据从源头传输到最终的目的地。 + +![image-20200323103129436](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/202501071706046.png) + +## Agent + +Flume Agent 是一个JVM进程,通过三个组件(source、channel、sink)将事件流从一个外部数据源收集并发送给下一个目的地。 + +### Source + +从数据发生器接收数据,并将数据以Flume的Event格式传递给一个或多个通道(Channel) + +支持Source: + +* [Avro Source](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#avro-source) +* [Thrift Source](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#thrift-source) +* [Exec Source](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#exec-source) +* [JMS Source](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#jms-source) +* [Spooling Directory Source](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#spooling-directory-source) +* [Taildir Source](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#taildir-source) +* [Twitter 1% firehose Source (experimental)](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#twitter-1-firehose-source-experimental) +* [Kafka Source](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#kafka-source) +* [NetCat TCP Source](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#netcat-tcp-source) +* [NetCat UDP Source](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#netcat-udp-source) +* [Sequence Generator Source](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#sequence-generator-source) +* [Syslog Sources](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#syslog-sources) +* [HTTP Source](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#http-source) +* [Stress Source](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#stress-source) +* [Legacy Sources](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#legacy-sources) +* [Custom Source](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#custom-source) + +### Channel + +一种短暂的存储容器,位于 Source和Sink之间,起着桥梁的作用。 Channel将从Source处接收到的 Event格式的数据缓存起来,当Sink成功地将 Events发送到下一跳的Channel或最终目的地后, Events从 Channel移除。Channel是一个完整的事务,这一点保证了数据在收发的时候的一致性。可以把 Channel看成一个FIFO(先进先出)队列,当数据的获取速率超过流出速率时,将Event保存到队列中,再从队中一个个出来。 + +有以下几种Channel: + +* **Memory Channel** 事件存储在可配置容量的内存队列中,队列容量即为可存储最大事件数量,适用于高吞吐量场景,在agent出现错误时有可能会丢失部分数据 +* **File Channel** 基于文件系统的持久化存储 +* Spillable Memory Channel 内存和文件混合Channel,当内存队列满了之后,新的事件会存储在文件系统,目前处于实验阶段,不建议在生产环境中使用 +* JDBC Channe 事件存储在持久化的数据库中,目前只支持Derby +* Kafka Channel 事件存储在Kafka集群中 +* Pseudo Transaction Channel 伪事务Channel,仅用于测试,不能在生产环境使用 +* Custom Channel 自定义Channel + +### Sink + +获取Channel暂时保存的数据并进行处理。sink从channel中移除事件,并将其发送到下一个agent(简称下一跳)或者事件的最终目的地,比如HDFS。 + +Sink分类: + +* [HDFS Sink](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#hdfs-sink) +* [Hive Sink](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#hive-sink) +* [Logger Sink](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#logger-sink) +* [Avro Sink](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#avro-sink) +* [Thrift Sink](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#thrift-sink) +* [IRC Sink](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#irc-sink) +* [File Roll Sink](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#file-roll-sink) 将Events保存在本地文件系统 +* [Null Sink](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#null-sink) 抛弃从Channel接收的所有事件 +* [HBaseSinks](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#hbasesinks) +* [MorphlineSolrSink](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#morphlinesolrsink) +* [ElasticSearchSink](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#elasticsearchsink) +* [Kite Dataset Sink](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#kite-dataset-sink) +* [Kafka Sink](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#kafka-sink) +* [HTTP Sink](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#http-sink) +* [Custom Sink](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#custom-sink) + +## 数据流模型 + +![Agent component diagram](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/202501071706047.png) + +过程简要说明如下: +(1)外部数据源(Web Server)将Flume可识别的 Event发送到 Source +(2) Source收到 Event事件后存储到一个或多个Channel通道中。 +(3)Channel保留 Event直到Sink将其处理完毕。 +(4)Sink从 Channel中取出数据,并将其传输至外部存储(HDFS)。 + + + +### 可靠性 + +事件在每个agent的channel中短暂存储,然后事件被发送到下一个agent或者最终目的地。事件只有在存储在下一个channel或者最终存储后才从当前的channel中删除。 + +Flume使用事务的办法来保证Events的可靠传递。Source和Sink分别被封装在事务中,事务由保存Event的存储或者Channel提供。这就保证了Event在数据流的点对点传输中是可靠的。在多跳的数据流中,上一跳的sink和下一跳的source均运行事务来保证数据被安全地存储到下一跳的channel中。 + +# Flume安装 + +Flume下载页面:http://flume.apache.org/download.html + +![image-20200323142300139](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/202501071706048.png) + +将[ apache-flume-1.9.0-bin.tar.gz](http://www.apache.org/dyn/closer.lua/flume/1.9.0/apache-flume-1.9.0-bin.tar.gz)下载到CentOS系统中,对其解压 + +```shell +# 解压命令 +tar xzf apache-flume-1.9.0-bin.tar.gz +# 进入到apache-flume-1.9.0-bin 目录 +cd apache-flume-1.9.0-bin +# Flume使用需要依赖JDK1.8以上环境,确保已安装 +# 将Flume安装目录配置到PATH中,方便在任意目录使用 +vi /etc/profile +# 添加以下内容 +export JAVA_HOME=/opt/soft/jdk1.8.0_231 +export JRE_HOME=/opt/soft/jdk1.8.0_231/jre +export FLUME_HOME=/opt/soft/apache-flume-1.9.0-bin +export PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin:$FLUME_HOME/bin: +# 保存成功后刷新 +source /etc/profile +# 查看是否设置成功 +echo $FLUME_HOME +``` + +# 入门使用示例 + +## 案例说明 + +使用Flume监听某个端口,使用Netcat向这个端口发送数据,Flume将接收到的数据打印到控制台。 + +Netcat是一款TCP/UDP测试工具,可以通过以下命令安装 + +```shell +yum install -y nc + +# 开启一个服务端 +nc -lk localhost 44444 + +# 新建一个会话,开启一个客户端,连接端口44444 +nc localhost 44444 + +# 客户端发送数据,服务端就能接收数据 +hello +``` + +## 使用组件 + +- [NetCat TCP Source](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#netcat-tcp-source) + + 必须属性 + + | 属性名 | 默认值 | 说明 | + | :----------- | :----- | :--------------------- | + | **channels** | – | | + | **type** | – | `netcat` | + | **bind** | – | 绑定的主机名或者IP地址 | + | **port** | – | 绑定端口 | + +- [Memory Channel](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#memory-channel) + + 必须属性 + + | 属性名 | 默认值 | 说明 | + | :------- | :----- | :------- | + | **type** | – | `memory` | + +- [Logger Sink](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#logger-sink) + + 必须属性 + + | 属性名 | 默认值 | 说明 | + | :---------- | :----- | :------- | + | **channel** | – | | + | **type** | – | `logger` | + +## 添加配置文件 + +在apache-flume-1.9.0-bin/conf目录下添加配置文件example.conf + +```properties +# example.conf: 单节点Flume配置 +# 定义agent名称为a1 +# 设置3个组件的名称 +a1.sources = r1 +a1.sinks = k1 +a1.channels = c1 + +# 配置source类型为NetCat,监听地址为本机,端口为44444 +a1.sources.r1.type = netcat +a1.sources.r1.bind = localhost +a1.sources.r1.port = 44444 + +# 配置sink类型为Logger +a1.sinks.k1.type = logger + +# 配置channel类型为内存,内存队列最大容量为1000,一个事务中从source接收的Events数量或者发送给sink的Events数量最大为100 +a1.channels.c1.type = memory +a1.channels.c1.capacity = 1000 +a1.channels.c1.transactionCapacity = 100 + +# 将source和sink绑定到channel上 +a1.sources.r1.channels = c1 +a1.sinks.k1.channel = c1 +``` + +## 启动flume + +查看Flume使用命令 + +```shell +flume-ng help +``` + +```shell +Usage: /opt/soft/apache-flume-1.9.0-bin/bin/flume-ng [options]... + +commands: + help display this help text + agent run a Flume agent + avro-client run an avro Flume client + version show Flume version info + +global options: + --conf,-c use configs in directory + --classpath,-C append to the classpath + --dryrun,-d do not actually start Flume, just print the command + --plugins-path colon-separated list of plugins.d directories. See the + plugins.d section in the user guide for more details. + Default: $FLUME_HOME/plugins.d + -Dproperty=value sets a Java system property value + -Xproperty=value sets a Java -X option + +agent options: + --name,-n the name of this agent (required) + --conf-file,-f specify a config file (required if -z missing) + --zkConnString,-z specify the ZooKeeper connection to use (required if -f missing) + --zkBasePath,-p specify the base path in ZooKeeper for agent configs + --no-reload-conf do not reload config file if changed + --help,-h display help text + +avro-client options: + --rpcProps,-P RPC client properties file with server connection params + --host,-H hostname to which events will be sent + --port,-p port of the avro source + --dirname directory to stream to avro source + --filename,-F text file to stream to avro source (default: std input) + --headerFile,-R File containing event headers as key/value pairs on each new line + --help,-h display help text + + Either --rpcProps or both --host and --port must be specified. + +Note that if directory is specified, then it is always included first +in the classpath. +``` + +启动agent + +```shell +flume-ng agent --conf conf --conf-file conf/example.conf --name a1 -Dflume.root.logger=INFO,console +``` + +或者 + +```shell +flume-ng agent -n a1 -c conf -f example.conf -Dflume.root.logger=INFO,console +``` + + + +![image-20200110174336210](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/202501071706049.png) + +## 使用Netcat测试 + +从另一个终端启动Netcat连接到44444端口,发送一些字符串 + +```shell +nc localhost 44444 +``` + +![image-20200323153910638](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/202501071706050.png) + +观察agent控制台 + +![image-20200323154036797](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/202501071706051.png) + +从这里可以看到事件由头部和字节数组组成。 + + + +在另外一台虚拟机通过Netcat连接,需要更改配置文件 + +```shell +# 将绑定端口配置为IP地址,绑定为localhost或者127.0.0.1在另外一台机器上无法连接 +# 绑定指定ip不行,绑定0.0.0.0可以 +a1.sources.r1.type = netcat +a1.sources.r1.bind = 192.168.85.132 +a1.sources.r1.port = 44444 +``` + +如果开启了防火墙,需要添加防火墙规则 + +```shell +firewall-cmd --zone=public --add-port=44444/tcp --permanent +firewall-cmd --reload +``` + + + +## 使用telnet测试 + +如果没有安装telnet,检查源 + +```shell +yum list | grep telnet +``` + +![image-20200110173530605](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/202501071706052.png) + +安装telnet + +```shell +yum install -y telnet.x86_64 +yum install -y telnet-server.x86_64 +``` + +启动telnet + +```shell +telnet 127.0.0.1 44444 +``` + +在控制台输入内容 + +![image-20200110174126132](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/202501071706053.png) + + + +可以在flume窗口查看到消息 + +![image-20200110174514218](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/202501071706054.png) + +# 数据持久化 + +使用组件 + +- [File Channel](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#file-channel) + +属性设置 + +| 属性名 | 默认值 | 说明 | +| :------------ | :------------------------------- | :----------------------------------------------------------- | +| **type** | – | `file` | +| checkpointDir | ~/.flume/file-channel/checkpoint | 检查点文件存放路径 | +| dataDirs | ~/.flume/file-channel/data | 日志存储路径,多个路径使用逗号分隔. 使用不同的磁盘上的多个路径能提高file channel的性能 | + +添加配置文件file-channel.conf,添加一个FileChannel + +```shell +# 定义agent名称为a1 +# 设置3个组件的名称 +a1.sources = r1 +a1.sinks = k1 +# 多个channel使用空格分隔 +a1.channels = c1 c2 + +# 配置source类型为NetCat,监听地址为本机,端口为44444 +a1.sources.r1.type = netcat +a1.sources.r1.bind = localhost +a1.sources.r1.port = 44444 + +# 配置sink类型为Logger +a1.sinks.k1.type = logger + +# 配置channel类型为内存,内存队列最大容量为1000,一个事务中从source接收的Events数量或者发送给sink的Events数量最大为100 +a1.channels.c1.type = memory +a1.channels.c1.capacity = 1000 +a1.channels.c1.transactionCapacity = 100 + +# 配置FileChannel,checkpointDir为检查点文件存储目录,dataDirs为日志数据存储目录, +a1.channels.c2.type = file +a1.channels.c2.checkpointDir = /opt/soft/flume/checkpoint +a1.channels.c2.dataDirs = /opt/soft/flume/data + +# 将source和sink绑定到channel上 +# source同时绑定到c1和c2上 +a1.sources.r1.channels = c1 c2 +a1.sinks.k1.channel = c1 +``` + +为了方便日志打印,可以将`-Dflume.root.logger=INFO,console`添加在conf的环境配置中,从模板复制一份配置 + +```shell +cp flume-env.sh.template flume-env.sh +vi flume-env.sh +# 添加JAVA_OPTS +export JAVA_OPTS="-Dflume.root.logger=INFO,console" +``` + +启动Flume + +```shell +flume-ng agent -n a1 -c ./ -f file-channnel.conf +``` + + + +通过Netcat发送数据,,此时发送到c2的数据没有被消费,关闭Flume,修改配置文件 + +```shell +# 将sink绑定到c2上 +a1.sinks.k1.channel = c2 +``` + +重启Flume,可以看到会**重新消费c2的数据** + +![image-20200323164045854](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/202501071706055.png) + +# 日志文件监控 + +## 案例说明 + +企业中应用程序部署后会将日志写入到文件中,可以使用Flume从各个**日志文件**将日志收集到日志中心以便于查找和分析。 + +## 使用Exec Soucre + +- [Exec Source](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#exec-source) + +Exec Source通过指定命令监控文件的变化,加粗属性为必须设置的。 + +| 属性名 | 默认值 | 说明 | +| :------------- | :---------- | :----------------------------------------- | +| **channels** | – | | +| **type** | – | `exec` | +| **command** | – | 要执行的命令 | +| restart | false | 如果执行命令挂了是否要重启 | +| batchSize | 20 | 同时往channel发送的最大行数 | +| batchTimeout | 3000 | 批量发送超时时间 | +| selector.type | replicating | channel选择器replicating 或者 multiplexing | +| selector.* | | 通道选择器匹配属性 | +| interceptors | – | 拦截器 | +| interceptors.* | | | + +添加配置文件exec-log.conf + +```shell +# 定义agent名称为a1 +# 设置3个组件的名称 +a1.sources = r1 +a1.sinks = k1 +a1.channels = c1 + +# 配置source类型为exec,命令为 tail -F app.log +a1.sources.r1.type = exec +a1.sources.r1.command = tail -F app.log # 目前放在同路径下 + +# 配置sink类型为Logger +a1.sinks.k1.type = logger + +# 配置channel类型为内存,内存队列最大容量为1000,一个事务中从source接收的Events数量或者发送给sink的Events数量最大为100 +a1.channels.c1.type = memory +a1.channels.c1.capacity = 1000 +a1.channels.c1.transactionCapacity = 100 + +# 将source和sink绑定到channel上 +a1.sources.r1.channels = c1 +a1.sinks.k1.channel = c1 +``` + +启动Flume + +```shell +flume-ng agent -n a1 -c ./ -f exec-log.conf -Dflume.root.logger=INFO,console +``` + +通过命令更新app.log文件 + +```shell +echo "abcdef">> app.log +``` + +可以查看agent控制台接收到了最新的日志 + +![image-20200323184443240](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/202501071706056.png) + + + +存在问题:重启Flume,会重复消费 + +## **解决重复消费问题** + +- [Taildir Source](http://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#taildir-source)(Apache Flume 1.7.0之后才有的) + +| 属性名 | 默认值 | 说明 | +| :----------------------------- | :----------------------------- | :--------------------------------------------- | +| **channels** | – | | +| **type** | – | `TAILDIR`. | +| **filegroups** | – | 可以定义多个组. 每个组里包含一序列被监控的文件 | +| `**filegroups.**` | – | 被监控文件的**绝对路径**,文件名支持正则表达式 | +| positionFile | ~/.flume/taildir_position.json | 记录监控文件的绝对路径、上次读取位置的json文件 | + +新增dir-log.conf + +```shell +# 定义agent名称为a1 +# 设置3个组件的名称 +a1.sources = r1 +a1.sinks = k1 +a1.channels = c1 + +# 配置source类型为TAILDIR +a1.sources.r1.type = TAILDIR +a1.sources.r1.positionFile = /opt/soft/flume/position.json +a1.sources.r1.filegroups = f1 f2 +a1.sources.r1.filegroups.f1 = /opt/soft/apache-flume-1.9.0-bin/conf/app.log +a1.sources.r1.filegroups.f2 = /opt/soft/apache-flume-1.9.0-bin/conf/applogs/.*log + +# 配置sink类型为Logger +a1.sinks.k1.type = logger + +# 配置channel类型为内存,内存队列最大容量为1000,一个事务中从source接收的Events数量或者发送给sink的Events数量最大为100 +a1.channels.c1.type = memory +a1.channels.c1.capacity = 1000 +a1.channels.c1.transactionCapacity = 100 + +# 将source和sink绑定到channel上 +a1.sources.r1.channels = c1 +a1.sinks.k1.channel = c1 +``` + +启动Flume(消费了`app.log`中的数据) + +```shell +flume-ng agent -n a1 -c ./ -f dir-log.conf +``` + +查看`position.json`文件,`"pos":28` + +![image-20250107170236134](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/202501071706057.png) + +通过命令更新app.log文件 + +```shell +echo "123">> app.log +``` + +此时查看`position.json`文件,`"pos":32` + +![image-20250107171105143](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/202501071711222.png) + +停掉重启Flume,发现没有出现重复消费问题,可再次通过命令更新app.log文件验证 + +重复消费问题解决是因为这个position.json文件记录了被监控文件最后读取的位置 + + + +**同时Taildir Source还支持目录的监控** + +在applogs目录中新建一个文件 + +![image-20250107171933366](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/202501071719449.png) + +Flume会话已经监控到这个文件的创建了 + +![image-20250107172241980](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/202501071722017.png) + +通过命令更新1.log文件 + +```shell +echo "12345" >> 1.log +``` + +查看position.json文件 + +![image-20250107172732288](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/202501071727368.png) + +新建2.log文件 + +![image-20250108134554126](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250108134554126.png) + +此时Flume会监控到2.log文件的创建 + +![image-20250108135432383](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250108135432383.png) + +通过命令更新2.log文件 + +```shell +echo "123" >> 2.log +``` + +此时Flume + +![image-20250108135121342](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250108135121342.png) + +此时position.json文件 + +![image-20250108135815260](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250108135815260.png) + +# 多个agent模型 + +可以将多个Flume agent 程序连接在一起,其中一个agent的sink将数据发送到另一个agent的source。Avro文件格式是使用Flume通过网络发送数据的标准方法。 + +![image-20200324142535996](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/202501071706058.png) + +从多个Web服务器收集日志,发送到一个或多个集中处理的agent,之后再发往日志存储中心: + +![image-20200324151344310](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/202501071706059.png) + + + +同样的日志发送到不同的目的地: + +![image-20200324151408108](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/202501071706060.png) + +将前面两个示例组合应用 + +第一个agent从Netcat接收数据,增加一个channel和sink,将这个sink发送到第二个agent + +第二个agent在监控文件变化的同时监控从sink发送来的事件,最终输出到控制台 + +使用Avro Sink,必须设置以下属性 + +| 属性名 | 默认值 | Description | +| :----------- | :----- | :--------------------- | +| **channel** | – | | +| **type** | – | `avro` | +| **hostname** | – | 绑定的主机名或者IP地址 | +| **port** | – | 监听端口 | + +使用Avro Source,必须设置以下属性 + +| 属性名 | 默认值 | 说明 | +| :----------- | :----- | :--------------------- | +| **channels** | – | | +| **type** | – | `avro` | +| **bind** | – | 绑定的主机名或者IP地址 | +| **port** | – | 监听端口 | + +添加agent1.conf配置文件(拷贝example.conf并修改)(agent1发送agent2) + +```shell +# agent.conf1:多个agent使用 +# 定义agent名称为a1 +# 设置3个组件的名称,配置两个sink,两个channel +a1.sources = r1 +a1.sinks = k1 k2 +a1.channels = c1 c2 + +# 配置source类型为NetCat,监听地址为本机,端口为44444 +a1.sources.r1.type = netcat +a1.sources.r1.bind = localhost +a1.sources.r1.port = 44444 + +# 配置sink类型为Logger +a1.sinks.k1.type = logger +# 配置sink类型为Avro +a1.sinks.k2.type = avro +a1.sinks.k2.hostname = localhost +a1.sinks.k2.port = 55555 + +# 配置channel类型为内存,内存队列最大容量为1000,一个事务中从source接收的Events数量或者发送>给sink的Events数量最大为100 +a1.channels.c1.type = memory +a1.channels.c1.capacity = 1000 +a1.channels.c1.transactionCapacity = 100 +# 配置第二个channel +a1.channels.c2.type = memory +a1.channels.c2.capacity = 1000 +a1.channels.c2.transactionCapacity = 100 + +# 将source和sink绑定到channel上,c1和c2通道 +a1.sources.r1.channels = c1 c2 +a1.sinks.k1.channel = c1 +# sink绑定到c2 +a1.sinks.k2.channel = c2 +``` + +添加agent2.conf配置文件(拷贝dir-log.conf并修改) + +```shell +# 定义agent名称为a1 +# 设置3个组件的名称,添加r2,r1用来监控日志文件,r2用来读取agent1中的sink +a1.sources = r1 r2 +a1.sinks = k1 +a1.channels = c1 + +# 配置source类型为TAILDIR +a1.sources.r1.type = TAILDIR +a1.sources.r1.positionFile = /opt/soft/flume/position.json +a1.sources.r1.filegroups = f1 f2 +a1.sources.r1.filegroups.f1 = /opt/soft/apache-flume-1.9.0-bin/conf/app.log +a1.sources.r1.filegroups.f2 = /opt/soft/apache-flume-1.9.0-bin/conf/applogs/.*log +# 配置source为agent1的sink +a1.sources.r2.type = avro +a1.sources.r2.bind = localhost +a1.sources.r2.port = 55555 + +# 配置sink类型为Logger +a1.sinks.k1.type = logger + +# 配置channel类型为内存,内存队列最大容量为1000,一个事务中从source接收的Events数量或者发送给sink的Events数量最大为100 +a1.channels.c1.type = memory +a1.channels.c1.capacity = 1000 +a1.channels.c1.transactionCapacity = 100 + +# 将source和sink绑定到channel上 +a1.sources.r1.channels = c1 +a1.sinks.k1.channel = c1 +# 将source r2 也绑定到 channel c1 上 +a1.sources.r2.channels = c1 +``` + +先启动agent2再启动agent1(可以先读) + +```shell +flume-ng agent -n a1 -c ./ -f agent2.conf +flume-ng agent -n a1 -c ./ -f agent1.conf +``` + + + +启动agent2 + +![image-20250108140448412](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250108140448412.png) + +再启动agent1 + +![image-20250108140549152](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250108140549152.png) + +此时agent2,显示已连接指定ip和端口 + +![image-20250108140635411](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250108140635411.png) + + + +先往app.log中写入日志,可以在agent2看到最新数据 + +![image-20250108140902196](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250108140902196.png) + + + +打开Netcat连接到44444,发送数据,可以同时在agent1和agent2看到最新数据。 + +![image-20250108141055489](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250108141055489.png) + +agent1 + +![image-20250108141227550](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250108141227550.png) + +agent2 + +![image-20250108141138110](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250108141138110.png) + + + +# 拦截器 + +拦截器可以**修改或者丢弃**事件,Flume支持链式调用拦截器,拦截器定义在source中 + +## Host Interceptor + +[Host Interceptor](https://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#host-interceptor) + +这个拦截器将运行agent的hostname 或者 IP地址写入到事件的headers中 + +| 属性名 | 默认值 | 说明 | +| :--------------- | :----- | :----------------------------------------------------------- | +| **type** | – | `host` | +| preserveExisting | false | 如果header已经存在host, 是否要保留 - true保留原始的,false写入当前机器 | +| useIP | true | true为IP地址, false为 hostname. | +| hostHeader | host | header中key的名称 | + + + +添加agent3.conf(拷贝agent1.conf并修改),拦截器是添加在sources上面的(示范拦截器的配置)agent3发送到agent2 + +```shell +# 定义agent名称为a1 +# 设置3个组件的名称,配置两个sink,两个channel +a1.sources = r1 +a1.sinks = k1 k2 +a1.channels = c1 c2 + +# 配置source类型为NetCat,监听地址为本机,端口为44444 +a1.sources.r1.type = netcat +a1.sources.r1.bind = localhost +a1.sources.r1.port = 44444 +# 添加拦截器 +a1.sources.r1.interceptors = i1 +al.sources.r1.interceptors.i1.type = host + +# 配置sink类型为Logger +a1.sinks.k1.type = logger +# 配置sink类型为Avro +a1.sinks.k2.type = avro +a1.sinks.k2.hostname = localhost +a1.sinks.k2.port = 55555 + +# 配置channel类型为内存,内存队列最大容量为1000,一个事务中从source接收的Events数量或者发送给sink的Events数量最大为100 +a1.channels.c1.type = memory +a1.channels.c1.capacity = 1000 +a1.channels.c1.transactionCapacity = 100 +# 配置第二个channel +a1.channels.c2.type = memory +a1.channels.c2.capacity = 1000 +a1.channels.c2.transactionCapacity = 100 + +# 将source和sink绑定到channel上,c1和c2通道 +a1.sources.r1.channels = c1 c2 +a1.sinks.k1.channel = c1 +# sink绑定到c2 +a1.sinks.k2.channel = c2 +``` + + + +启动agent3(启动之前先启动agent2,因为要发送到agent2) + +```shell +flume-ng agent -n a1 -c ./ -f agent2.conf +flume-ng agent -n a1 -c ./ -f agent3.conf +``` + +可以在agent2控制台看到agent3已经连接成功 + +![image-20250108143000294](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250108143000294.png) + +打开Netcat连接到44444,发送数据 + +![image-20250108143655837](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250108143655837.png) + +agent3和agent2都能看到如下: + +![image-20250108143616742](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250108143616742.png) + + + +**同时可以使用另一台虚拟机来测试** + +打开另外一台虚拟机,安装好Flume(虚拟机192.168.88.131)(131连130) + +添加agent_example.conf,将数据发送到虚拟机130(agent2)上(拷贝agent3.conf并修改,相当于上述agent3连agent2) + +```shell +# 定义agent名称为a1 +# 设置3个组件的名称,配置两个sink,两个channel +a1.sources = r1 +a1.sinks = k1 k2 +a1.channels = c1 c2 + +# 配置source类型为NetCat,监听地址为本机(132),端口为44444 +a1.sources.r1.type = netcat +a1.sources.r1.bind = localhost +a1.sources.r1.port = 44444 +# 添加拦截器 +a1.sources.r1.interceptors = i1 +al.sources.r1.interceptors.i1.type = host + +# 配置sink类型为Logger +a1.sinks.k1.type = logger +# 配置sink类型为Avro +a1.sinks.k2.type = avro +a1.sinks.k2.hostname = 192.168.88.130 +a1.sinks.k2.port = 55555 + +# 配置channel类型为内存,内存队列最大容量为1000,一个事务中从source接收的Events数量或者发送给sink的Events数量最大为100 +a1.channels.c1.type = memory +a1.channels.c1.capacity = 1000 +a1.channels.c1.transactionCapacity = 100 +# 配置第二个channel +a1.channels.c2.type = memory +a1.channels.c2.capacity = 1000 +a1.channels.c2.transactionCapacity = 100 + +# 将source和sink绑定到channel上,c1和c2通道 +a1.sources.r1.channels = c1 c2 +a1.sinks.k1.channel = c1 +# sink绑定到c2 +a1.sinks.k2.channel = c2 +``` + +上述配置就是从131中的Netcat收到数据,通过两个chanel,一个直接打印,一个发送给130虚拟机中(暂时不行) + +这里注意需要在130上开启防火墙端口 + +```shell +firewall-cmd --zone=public --add-port=55555/tcp --permanent +firewall-cmd --reload +``` + +启动example(131上的Flume)(发送给130) + +```shell +flume-ng agent -n a1 -c ./ -f agent4.conf +``` + +可以在130的agent2控制台看到example已经连接成功 + +![image-20200324153714003](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20200324153714003.png) + +在132上通过Netcat发送数据,发送的是132上的example + +```shell +nc localhost 44444 +``` + +而example会发送到135上的agent2,可以在135上agent2上看到添加了headers + + + +因此,使用Host Inteceptor可以把当前主机地址发送过来,从而区分这个日志或者事件从哪个主机发送过来的 + + + +## Timestamp Interceptor + +这个拦截器将**当前时间**写入到事件的headers中 + +| 属性名 | 默认值 | 说明 | +| :--------------- | :-------- | :----------------------------------------------------------- | +| **type** | – | `timestamp` | +| headerName | timestamp | header中key的名称 | +| preserveExisting | false | If the timestamp already exists, should it be preserved - true or false | + +再次回到agent3中的配置,修改如下, + +再添加一个拦截器(直接拷贝来一个agent4.conf) + + +```shell +a1.sources.r1.interceptors = i1 i2 +a1.sources.r1.interceptors.i1.type = host +a1.sources.r1.interceptors.i2.type = timestamp +``` + +```shell +启动agent4 +flume-ng agent -n a1 -c ./ -f agent4.conf +``` + +此时agent2控制台显示已连接 + +![image-20250108152342166](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250108152342166.png) + +打开Netcat连接到44444,发送数据 + +```shell +nc localhost 44444 +``` + +![image-20250108152527595](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250108152527595.png) + +agent4控制台输出**timestamp**日期 + +![image-20250108152904610](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250108152904610.png) + + + +## Static Interceptor + +运行用户对所有的事件添加**固定的header** + +| 属性名 | 默认值 | 说明 | +| :--------------- | :----- | :----------------------------------------------------------- | +| **type** | – | `static` | +| preserveExisting | true | If configured header already exists, should it be preserved - true or false | +| key | key | header 中key名称 | +| value | value | header 中value值 | + +在agent4.conf中修改即可,**自定义key value** + +```shell +a1.sources.r1.interceptors = i1 i2 i3 +a1.sources.r1.interceptors.i1.type = host +a1.sources.r1.interceptors.i2.type = timestamp +a1.sources.r1.interceptors.i3.type = static +a1.sources.r1.interceptors.i3.key = datacenter +a1.sources.r1.interceptors.i3.value = NEW_YORK +``` + +打开Netcat连接到44444,发送数据 + +![image-20250108154253711](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250108154253711.png) + +agent4控制台输出 + +![image-20250108154633688](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250108154633688.png) + + + +## UUID Interceptor + +[UUID Interceptor](https://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#uuid-interceptor) + +生成唯一ID + +![image-20250108160309260](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250108160309260.png) + +在agent4.conf中修改 + +```shell +a1.sources.r1.interceptors = i1 i2 i3 i4 +a1.sources.r1.interceptors.i1.type = host +a1.sources.r1.interceptors.i2.type = timestamp +a1.sources.r1.interceptors.i3.type = static +a1.sources.r1.interceptors.i3.key = datacenter +a1.sources.r1.interceptors.i3.value = NEW_YORK +a1.sources.r1.interceptors.i4.type = org.apache.flume.sink.solr.morphline.UUIDInterceptor$Builder +``` + +打开Netcat连接到44444,发送数据 + +![image-20250108160000856](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250108160000856.png) + +agent4控制台输出 + +![image-20250108160104769](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250108160104769.png) + + + +## Search and Replace Interceptor + +[Search and Replace Interceptor](https://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#search-and-replace-interceptor) + +查找并替换 + +![image-20250108160243230](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250108160243230.png) + +```shell +a1.sources.r1.interceptors = i1 i2 i3 i4 i5 +a1.sources.r1.interceptors.i1.type = host +a1.sources.r1.interceptors.i2.type = timestamp +a1.sources.r1.interceptors.i3.type = static +a1.sources.r1.interceptors.i3.key = datacenter +a1.sources.r1.interceptors.i3.value = NEW_YORK +a1.sources.r1.interceptors.i4.type = org.apache.flume.sink.solr.morphline.UUIDInterceptor$Builder +a1.sources.r1.interceptors.i5.type = search_replace +# 支持正则表达式,查找并替换,例如手机号脱敏操作(中间几位隐藏) +a1.sources.r1.interceptors.i5.searchPattern = \\d{6} +a1.sources.r1.interceptors.i5.replaceString = ****** +``` + +打开Netcat连接到44444,发送数据 + +![image-20250108160958778](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250108160958778.png) + +agent4控制台输出(并还是headers中,而是消息体里面做了替换) + +![image-20250108161153572](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250108161153572.png) + + + +## 自定义拦截器 + +新建工程,添加pom引用 + +```xml + + org.apache.flume + flume-ng-core + 1.9.0 + +``` + +添加自定义拦截器 + +```java +import org.apache.flume.Context; +import org.apache.flume.Event; +import org.apache.flume.interceptor.Interceptor; + +import java.util.List; + +public class MyInterceptor implements Interceptor { + private static final Logger logger = LoggerFactory + .getLogger(MyInterceptor.class); + public void initialize() { + + } + + /** + * 拦截单个事件 + * @param event + * @return + */ + public Event intercept(Event event) { + String host = event.getHeaders().get("host"); + logger.info("接收到host为:"+host); + if (host.equals("192.168.85.131")) { + logger.info("丢弃事件"); + return null; + } + return event; + } + + public List intercept(List list) { + List newList = new ArrayList(); + for (Event event : list) { + event = intercept(event); + if(event!=null){ + newList.add(event); + } + } + return newList; + } + + public void close() { + + } + + public static class Builder implements Interceptor.Builder{ + + public Interceptor build() { + return new MyInterceptor(); + } + + public void configure(Context context) { + + } + } +} +``` + +将项目打成jar包后复制到Flume安装目录的lib目录中 + +修改agent2.conf(因为agent2接收从网络发送过来的数据) + +```shell +# 配置拦截器 +a1.sources.r2.interceptors = i1 +a1.sources.r2.interceptors.i1.type = com.itheima.flume.interceptor.MyInterceptor$Builder +``` + +先开启131机器上的agent4 + +```shell +flume-ng agent -n a1 -c ./ -f agent4.conf +``` + +再开启130机器上的agent2 + +```shell +flume-ng agent -n a1 -c ./ -f agent2.conf +``` + +此时再从131发送数据过来,可以看到数据被拦截了,拦截后的数据不会进入channel,即不会被sink消费 + +![image-20200324182058523](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/202501071706068.png) + +# Channel选择器 + +## Replicating Channel Selector + +[复制选择器](https://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#replicating-channel-selector-default),如果没有指定,这个为默认选择器 + +可选属性如下 + +| 属性名 | 默认值 | 说明 | +| :---------------- | :---------- | :------------ | +| selector.type | replicating | `replicating` | +| selector.optional | – | `optional` | + +使用案例: + +```shell +a1.sources = r1 +a1.channels = c1 c2 c3 +a1.sources.r1.selector.type = replicating +a1.sources.r1.channels = c1 c2 c3 +a1.sources.r1.selector.optional = c3 +``` + +上面的配置中,c3是一个可选的channel,写入c3失败的话会被忽略, + +而c1和c2没有标记为可选,如果写入c1和c2失败会导致事务的失败。 + +## Multiplexing Channel Selector + +[多路channel选择器](https://flume.apache.org/releases/content/1.9.0/FlumeUserGuide.html#multiplexing-channel-selector),可选属性如下 + +| 属性名 | 默认值 | 说明 | +| :----------------- | :-------------------- | :------------- | +| selector.type | replicating | `multiplexing` | +| selector.header | flume.selector.header | 键值Key | +| selector.default | – | | +| selector.mapping.* | – | 路由 | + +使用案例: + +```shell +a1.sources = r1 +a1.channels = c1 c2 c3 c4 +a1.sources.r1.selector.type = multiplexing +a1.sources.r1.selector.header = state +a1.sources.r1.selector.mapping.CZ = c1 c2 +a1.sources.r1.selector.mapping.US = c1 c3 +a1.sources.r1.selector.default = c1 c4 +``` + +这里通过事件的header值来判断将事件发送到哪个channel,可以配合拦截器一起使用。 + +```shell +# 创建multichannel目录 +mkdir multichannel +cd multichannel +``` + +创建agent5.conf + +```shell +# 定义agent名称为a1 +# 设置3个组件的名称 +a1.sources = r1 +a1.sinks = k1 k2 k3 k4 +a1.channels = c1 c2 c3 c4 + +# 配置source类型为NetCat,监听地址为本机,端口为44444 +a1.sources.r1.type = netcat +a1.sources.r1.bind = localhost +a1.sources.r1.port = 44444 + +# 配置sink1类型为Logger +a1.sinks.k1.type = logger + +# 配置sink2,3,4类型为Avro +a1.sinks.k2.type = avro +a1.sinks.k2.hostname = 192.168.88.130 +a1.sinks.k2.port = 4040 + +a1.sinks.k3.type = avro +a1.sinks.k3.hostname = 192.168.88.130 +a1.sinks.k3.port = 4041 + +a1.sinks.k4.type = avro +a1.sinks.k4.hostname = 192.168.88.130 +a1.sinks.k4.port = 4042 + +# 配置channel类型为内存,内存队列最大容量为1000,一个事务中从source接收的Events数量或者发送给sink的Events数量最大为100 +a1.channels.c1.type = memory +a1.channels.c1.capacity = 1000 +a1.channels.c1.transactionCapacity = 100 + +a1.channels.c2.type = memory +a1.channels.c2.capacity = 1000 +a1.channels.c2.transactionCapacity = 100 + +a1.channels.c3.type = memory +a1.channels.c3.capacity = 1000 +a1.channels.c3.transactionCapacity = 100 + +a1.channels.c4.type = memory +a1.channels.c4.capacity = 1000 +a1.channels.c4.transactionCapacity = 100 + + +# 将source和sink绑定到channel上 +a1.sources.r1.channels = c1 c2 c3 c4 +a1.sinks.k1.channel = c1 +a1.sinks.k2.channel = c2 +a1.sinks.k3.channel = c3 +a1.sinks.k4.channel = c4 +``` + +添加agent6.conf + +```shell +# 定义agent名称为a2 +# 设置3个组件的名称 +a2.sources = r1 +a2.sinks = k1 +a2.channels = c1 + +# 配置source类型为avro +a2.sources.r1.type = avro +a2.sources.r1.bind = 192.168.88.130 +a2.sources.r1.port = 4040 + + +# 配置sink类型为logger +a2.sinks.k1.type = logger + +# 配置channel类型为内存,内存队列最大容量为1000,一个事务中从source接收的Events数量或者发送给sink的Events数量最大为100 +a2.channels.c1.type = memory +a2.channels.c1.capacity = 1000 +a2.channels.c1.transactionCapacity = 100 + +# 将source和sink绑定到channel上 +a2.sources.r1.channels = c1 +a2.sinks.k1.channel = c1 +``` + +添加agent7.conf + +```shell +# 定义agent名称为a3 +# 设置3个组件的名称 +a3.sources = r1 +a3.sinks = k1 +a3.channels = c1 + +# 配置source类型为avro +a3.sources.r1.type = avro +a3.sources.r1.bind = 192.168.88.130 +a3.sources.r1.port = 4041 + + +# 配置sink类型为logger +a3.sinks.k1.type = logger + +# 配置channel类型为内存,内存队列最大容量为1000,一个事务中从source接收的Events数量或者发送给sink的Events数量最大为100 +a3.channels.c1.type = memory +a3.channels.c1.capacity = 1000 +a3.channels.c1.transactionCapacity = 100 + +# 将source和sink绑定到channel上 +a3.sources.r1.channels = c1 +a3.sinks.k1.channel = c1 +``` + +添加agent8.conf + +```shell +# 定义agent名称为a4 +# 设置3个组件的名称 +a4.sources = r1 +a4.sinks = k1 +a4.channels = c1 + +# 配置source类型为avro +a4.sources.r1.type = avro +a4.sources.r1.bind = 192.168.88.130 +a4.sources.r1.port = 4042 + + +# 配置sink类型为logger +a4.sinks.k1.type = logger + +# 配置channel类型为内存,内存队列最大容量为1000,一个事务中从source接收的Events数量或者发送给sink的Events数量最大为100 +a4.channels.c1.type = memory +a4.channels.c1.capacity = 1000 +a4.channels.c1.transactionCapacity = 100 + +# 将source和sink绑定到channel上 +a4.sources.r1.channels = c1 +a4.sinks.k1.channel = c1 +``` + +启动agent6、agent7、agent8和agent5 + +```shell +flume-ng agent -n a2 -c ./ -f agent6.conf +flume-ng agent -n a3 -c ./ -f agent7.conf +flume-ng agent -n a4 -c ./ -f agent8.conf +flume-ng agent -n a1 -c ./ -f agent5.conf +``` + +使用Netcat往agent1发送消息,可以在agent2\3\4上看到消息 + + + +修改agent5.conf,配置通道选择器 + +```shell +# 配置拦截器 +a1.sources.r1.interceptors = i1 +a1.sources.r1.interceptors.i1.type = static +a1.sources.r1.interceptors.i1.key = state +a1.sources.r1.interceptors.i1.value = CZ +# 配置通道选择器,如果匹配不上就走default +a1.sources.r1.selector.type = multiplexing +a1.sources.r1.selector.header = state +a1.sources.r1.selector.mapping.CZ = c1 c2 +a1.sources.r1.selector.mapping.US = c1 c3 +a1.sources.r1.selector.default = c1 c4 +``` + +运行所有agent,发送数据到agent1,可以看到只有agent2收到了数据, + +修改拦截器的值为US,结果是agent3收到数据。 + +![image-20250109194557859](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250109194557859.png) + +# Sink处理器 + +通过sink来消费,如果消费端出现宕机,就会造成消息的积压,可能内存就不够了或者文件很大,那如何出现消息积压问题呢?Sink处理器 + +可以将多个sink放入到一个组中,Sink处理器能够对一个组中所有的sink进行负载均衡,在一个sink出现临时错误时进行故障转移。 + +必须设置属性: + +| 属性名 | 默认值 | 说明 | +| :----------------- | :-------- | :------------------------------------- | +| **sinks** | – | 组中多个sink使用空格分隔 | +| **processor.type** | `default` | `default`, `failover` 或`load_balance` | + +举例: + +```shell +a1.sinkgroups = g1 +a1.sinkgroups.g1.sinks = k1 k2 +a1.sinkgroups.g1.processor.type = failover +``` + +## Default Sink Processor + +默认的Sink处理器只支持单个Sink + +## Failover Sink Processor + +**故障转移处理器**维护了一个带有优先级的sink列表,故障转移机制将失败的sink放入到一个冷却池中,如果sink成功发送了事件,将其放入到活跃池中,sink可以设置优先级,数字越高,优先级越高,如果一个sink发送事件失败,下一个有更高优先级的sink将被用来发送事件,比如,优先级100的比优先级80的先被使用,如果没有设置优先级,按配置文件中配置的顺序决定。设置属性如下: + +| 属性名 | 默认值 | 说明 | +| :---------------------- | :-------- | :--------------------- | +| **sinks** | – | 组内多个sinks空格分隔 | +| **processor.type** | `default` | `failover` | +| **processor.priority.** | – | 优先级 | +| processor.maxpenalty | 30000 | 失败sink的最大冷却时间 | + +示例如下: + +```shell +a1.sinkgroups = g1 +a1.sinkgroups.g1.sinks = k1 k2 +a1.sinkgroups.g1.processor.type = failover +a1.sinkgroups.g1.processor.priority.k1 = 5 +a1.sinkgroups.g1.processor.priority.k2 = 10 +a1.sinkgroups.g1.processor.maxpenalty = 10000 +``` + + + +修改以上agent5.conf,直接agent9.conf + +```shell +# 定义agent名称为a1 +# 设置3个组件的名称 +a1.sources = r1 +a1.sinks = k1 k2 k3 k4 +a1.channels = c1 + +# 配置source类型为NetCat,监听地址为本机,端口为44444 +a1.sources.r1.type = netcat +a1.sources.r1.bind = localhost +a1.sources.r1.port = 44444 + +# 配置sink组 +a1.sinkgroups = g1 +a1.sinkgroups.g1.sinks = k1 k2 k3 k4 +a1.sinkgroups.g1.processor.type = failover +a1.sinkgroups.g1.processor.priority.k1 = 5 +a1.sinkgroups.g1.processor.priority.k2 = 10 +a1.sinkgroups.g1.processor.priority.k3 = 15 +a1.sinkgroups.g1.processor.priority.k4 = 20 +a1.sinkgroups.g1.processor.maxpenalty = 10000 + +# 配置sink1类型为Logger +a1.sinks.k1.type = logger + +# 配置sink2,3,4类型为Avro +a1.sinks.k2.type = avro +a1.sinks.k2.hostname = 192.168.88.130 +a1.sinks.k2.port = 4040 + +a1.sinks.k3.type = avro +a1.sinks.k3.hostname = 192.168.88.130 +a1.sinks.k3.port = 4041 + +a1.sinks.k4.type = avro +a1.sinks.k4.hostname = 192.168.88.130 +a1.sinks.k4.port = 4042 + +# 配置channel类型为内存,内存队列最大容量为1000,一个事务中从source接收的Events数量或者发送给sink的Events数量最大为100 +a1.channels.c1.type = memory +a1.channels.c1.capacity = 1000 +a1.channels.c1.transactionCapacity = 100 + +# 将source和sink绑定到channel上 +a1.sources.r1.channels = c1 +a1.sinks.k1.channel = c1 +a1.sinks.k2.channel = c1 +a1.sinks.k3.channel = c1 +a1.sinks.k4.channel = c1 +``` + +启动agent6\7\8和agent9,通过Netcat发送消息到agent9,可以看到消息一直发送给其中一个agent(agent8优先级最高),将这个agent关闭后,消息会发送到其他agent(优先级次高)。 + +## Load balancing Sink Processor + +**负载均衡处理器**,可以通过**轮询或者随机**的方式进行负载均衡,也可以通过继承AbstractSinkSelector 自定义负载均衡,设置属性如下: + +| 属性名 | 默认值 | 说明 | +| :---------------------------- | :------------ | :------------------------------------------ | +| **processor.sinks** | – | 组内多个sinks空格分隔 | +| **processor.type** | `default` | `load_balance` | +| processor.backoff | false | 是否将失败的sink加入黑名单 | +| processor.selector | `round_robin` | 轮询机制:`round_robin`, `random` 或者自定义 | +| processor.selector.maxTimeOut | 30000 | 黑名单有效时间(单位毫秒) | + +示例如下: + +```shell +a1.sinkgroups = g1 +a1.sinkgroups.g1.sinks = k1 k2 +a1.sinkgroups.g1.processor.type = load_balance +a1.sinkgroups.g1.processor.backoff = true +a1.sinkgroups.g1.processor.selector = round_robin +``` + +修改上面的agent9.conf,直接agent10.conf,将所有的sink都绑定到c1上 + +```shell +# 定义agent名称为a1 +# 设置3个组件的名称 +a1.sources = r1 +a1.sinks = k1 k2 k3 k4 +a1.channels = c1 + +# 配置source类型为NetCat,监听地址为本机,端口为44444 +a1.sources.r1.type = netcat +a1.sources.r1.bind = localhost +a1.sources.r1.port = 44444 + +# 配置sink组 +a1.sinkgroups = g1 +a1.sinkgroups.g1.sinks = k1 k2 k3 k4 +a1.sinkgroups.g1.processor.type = load_balance +a1.sinkgroups.g1.processor.backoff = true +a1.sinkgroups.g1.processor.selector = round_robin + +# 配置sink1类型为Logger +a1.sinks.k1.type = logger + +# 配置sink2,3,4类型为Avro +a1.sinks.k2.type = avro +a1.sinks.k2.hostname = 192.168.88.130 +a1.sinks.k2.port = 4040 + +a1.sinks.k3.type = avro +a1.sinks.k3.hostname = 192.168.88.130 +a1.sinks.k3.port = 4041 + +a1.sinks.k4.type = avro +a1.sinks.k4.hostname = 192.168.88.130 +a1.sinks.k4.port = 4042 + +# 配置channel类型为内存,内存队列最大容量为1000,一个事务中从source接收的Events数量或者发送给sink的Events数量最大为100 +a1.channels.c1.type = memory +a1.channels.c1.capacity = 1000 +a1.channels.c1.transactionCapacity = 100 + +# 将source和sink绑定到channel上 +a1.sources.r1.channels = c1 +a1.sinks.k1.channel = c1 +a1.sinks.k2.channel = c1 +a1.sinks.k3.channel = c1 +a1.sinks.k4.channel = c1 +``` + +也可以修改成随机·`random`,试下效果 + +# 使用Flume导入数据到HDFS + +在这里安装了hadoop集群,用户名为hadoop + +数据导出到HDFS需要使用HDFS Sink,需要配置属性如下: + +| 属性名 | 默认值 | 说明 | +| :------------ | :----------- | :----------------------------------------------------------- | +| **channel** | – | | +| **type** | – | `hdfs` | +| **hdfs.path** | – | HDFS 文件路径 (例如 hdfs://namenode/flume/webdata/) | +| hdfs.fileType | SequenceFile | 文件格式: `SequenceFile`, `DataStream` or `CompressedStream` (1)DataStream 不会压缩输出文件且不用设置 codeC (2)CompressedStream 需要设置 hdfs.codeC | +| hdfs.codeC | | 压缩格式 : gzip, bzip2, lzo, lzop, snappy | + +注:使用HDFS Sink需要用到Hadoop的多个包,可以在装有Hadoop的主机上运行Flume, + +如果是单独部署的Flume,可以通过多个Agent的形式将单独部署的Flume Agent 日志数据发送到装有Hadoop的Flume Agent上。 + +创建hdfs.conf + +```properties +# agent名称为a1 +# 设置3个组件的名称 +a1.sources = r1 +a1.sinks = k1 +a1.channels = c1 + +# 配置source类型为NetCat,监听地址为本机,端口为44444 +a1.sources.r1.type = netcat +a1.sources.r1.bind = localhost +a1.sources.r1.port = 44444 + +# 配置sink类型为hdfs +a1.sinks.k1.type = hdfs +a1.sinks.k1.hdfs.path = hdfs://node:8020/user/flume/logs +a1.sinks.k1.hdfs.fileType = DataStream + +# 配置channel类型为内存,内存队列最大容量为1000,一个事务中从source接收的Events数量或者发送给sink的Events数量最大为100 +a1.channels.c1.type = memory +a1.channels.c1.capacity = 1000 +a1.channels.c1.transactionCapacity = 100 + +# 将source和sink绑定到channel上 +a1.sources.r1.channels = c1 +a1.sinks.k1.channel = c1 +``` + +启动flume + +```shell +flume-ng agent -n a1 -c ./ -f hdfs.conf + +bin/flume-ng agent --conf conf/ --conf-file conf/hdfs.conf -Dfile.root.logger=debug,info,console --name hdfs +``` + +注:如果出现`com.google.common.base.Preconditions.checkArgument` 查看下`flume/lib`目录下 + +的`guava.jar`版本是否与`hadoop/share/hadoop/common/lib`中的版本是否一致,不一致拷贝新版 + +重新运行 + +![image-20250110105658916](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250110105658916.png) + +从另一个终端启动Netcat连接到44444端口,发送一些字符串 + +![image-20250110105949785](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250110105949785.png) + +![image-20200112212041558](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/202501071706069.png) + +在后台查看 + +```shell +hadoop fs -cat /user/flume/messages/flume-.1578835130630 +``` + +![image-20200112212150353](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/202501071706070.png) + +# 使用多个Agent导出数据到HDFS + +130->131 + +agent11.conf(130机器上) + +```shell +# 定义agent名称为a1 +# 设置3个组件的名称 +a1.sources = r1 +a1.sinks = k1 +a1.channels = c1 + +# 配置source类型为NetCat,监听地址为本机,端口为44444 +a1.sources.r1.type = netcat +a1.sources.r1.bind = localhost +a1.sources.r1.port = 44444 + +# 配置sink类型为Avro +a1.sinks.k1.type = avro +a1.sinks.k1.hostname = 192.168.88.131 +a1.sinks.k1.port = 4040 + +# 配置channel类型为内存,内存队列最大容量为1000,一个事务中从source接收的Events数量或者发送给sink的Events数量最大为100 +a1.channels.c1.type = memory +a1.channels.c1.capacity = 1000 +a1.channels.c1.transactionCapacity = 100 + +# 将source和sink绑定到channel上 +a1.sources.r1.channels = c1 +a1.sinks.k1.channel = c1 +``` + +multi-agent.conf(131机器上) + +```shell +# agent名称为a1 +# 设置3个组件的名称 +a1.sources = r1 +a1.sinks = k1 +a1.channels = c1 + +# 配置source类型为avro +a1.sources.r1.type = avro +a1.sources.r1.bind = 192.168.88.131 +a1.sources.r1.port = 4040 + +# 配置sink类型为hdfs +a1.sinks.k1.type = hdfs +a1.sinks.k1.hdfs.path = hdfs://node:8020/user/flume/logs +a1.sinks.k1.hdfs.fileType = DataStream + +# 配置channel类型为内存,内存队列最大容量为1000,一个事务中从source接收的Events数量或者发送 +给sink的Events数量最大为100 +a1.channels.c1.type = memory +a1.channels.c1.capacity = 1000 +a1.channels.c1.transactionCapacity = 100 + +# 将source和sink绑定到channel上 +a1.sources.r1.channels = c1 +a1.sinks.k1.channel = c1 +``` + +启动agent + +```shell +flume-ng agent -n a1 -c ./ -f multi-agent.conf + +flume-ng agent -n a1 -c ./ -f agent11.conf +``` + +从130机器另一个终端启动Netcat连接到44444端口,发送一些字符串 + +![image-20250113114845680](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250113114845680.png) + +在131机器上可以看到 + +![image-20250113114959939](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250113114959939.png) + +浏览器访问http://node:9870/,点击Utilities中的Browse the file system + +![image-20250113115334039](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250113115334039.png) + +`hadoop`中查看 + +![image-20250113130802139](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250113130802139.png) + +# Flume SDK + + + +## 自定义Source + +> 想去哪里获取数据就可以自定义 + +[自定义Source示例](https://flume.apache.org/releases/content/1.11.0/FlumeDeveloperGuide.html#source) + +```java +public class MySource extends AbstractSource implements Configurable, PollableSource { + private String myProp; + + @Override + public void configure(Context context) { + String myProp = context.getString("myProp", "defaultValue"); + + // Process the myProp value (e.g. validation, convert to another type, ...) + + // Store myProp for later retrieval by process() method + this.myProp = myProp; + } + + @Override + public void start() { + // Initialize the connection to the external client + } + + @Override + public void stop () { + // Disconnect from external client and do any additional cleanup + // (e.g. releasing resources or nulling-out field values) .. + } + + @Override + public Status process() throws EventDeliveryException { + Status status = null; + + try { + // This try clause includes whatever Channel/Event operations you want to do + + // Receive new data + Event e = getSomeData(); + + // Store the Event into this Source's associated Channel(s) + getChannelProcessor().processEvent(e); + + status = Status.READY; + } catch (Throwable t) { + // Log exception, handle individual exceptions as needed + + status = Status.BACKOFF; + + // re-throw all Errors + if (t instanceof Error) { + throw (Error)t; + } + } finally { + txn.close(); + } + return status; + } +} +``` + +添加MySource + +```java +package org.example.flumedemo.source; + +import org.apache.flume.Context; +import org.apache.flume.Event; +import org.apache.flume.EventDeliveryException; +import org.apache.flume.PollableSource; +import org.apache.flume.conf.Configurable; +import org.apache.flume.event.SimpleEvent; +import org.apache.flume.source.AbstractSource; + +/** + * 自定义Source + */ +public class MySource extends AbstractSource implements Configurable, PollableSource { + + // 处理数据 + @Override + public Status process() throws EventDeliveryException { + + Status status = null; + try { + // 自己模拟数据来发送 + for (int i = 0; i < 10; i++) { + Event event = new SimpleEvent(); + event.setBody(("data:" + i).getBytes()); + // 将数据存储到与Source关联的Channel中 + getChannelProcessor().processEvent(event); + // 数据准备消费 + status = Status.READY; + } + // 休眠5秒 + Thread.sleep(5000); + } catch (Exception e) { + // 打印日志 + e.printStackTrace(); + status = Status.BACKOFF; + } + + return status; + } + + @Override + public long getBackOffSleepIncrement() { + return 0; + } + + @Override + public long getMaxBackOffSleepInterval() { + return 0; + } + + @Override + public void configure(Context context) { + + } +} + +``` + +添加完自定义Source后,然后package打包一下,复制上传到/opt/soft/flume/lib/下 + + + +添加mySourceAgent.conf + +```shell +# 定义agent名称为a1 +# 设置3个组件的名称 +a1.sources = r1 +a1.sinks = k1 +a1.channels = c1 + +# 配置source类型为mysource +a1.sources.r1.type = org.example.flumedemo.source.MySource + +# 配置sink类型为Logger +a1.sinks.k1.type = logger + +# 配置channel类型为内存,内存队列最大容量为1000,一个事务中从source接收的Events数量或者发送给sink的Events数量最大为100 +a1.channels.c1.type = memory +a1.channels.c1.capacity = 1000 +a1.channels.c1.transactionCapacity = 100 + +# 将source和sink绑定到channel上 +a1.sources.r1.channels = c1 +a1.sinks.k1.channel = c1 +``` + +启动Flume + +```shell +flume-ng agent -n a1 -c ./ -f mySourceAgent.conf +``` + +输出结果 + +![image-20250113140244503](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250113140244503.png) + +## 自定义Sink + +[自定义Sinkf示例](https://flume.apache.org/releases/content/1.11.0/FlumeDeveloperGuide.html#sink) + +```java +public class MySink extends AbstractSink implements Configurable { + private String myProp; + + @Override + public void configure(Context context) { + String myProp = context.getString("myProp", "defaultValue"); + + // Process the myProp value (e.g. validation) + + // Store myProp for later retrieval by process() method + this.myProp = myProp; + } + + @Override + public void start() { + // Initialize the connection to the external repository (e.g. HDFS) that + // this Sink will forward Events to .. + } + + @Override + public void stop () { + // Disconnect from the external respository and do any + // additional cleanup (e.g. releasing resources or nulling-out + // field values) .. + } + + @Override + public Status process() throws EventDeliveryException { + Status status = null; + + // Start transaction + Channel ch = getChannel(); + Transaction txn = ch.getTransaction(); + txn.begin(); + try { + // This try clause includes whatever Channel operations you want to do + + Event event = ch.take(); + + // Send the Event to the external repository. + // storeSomeData(e); + + txn.commit(); + status = Status.READY; + } catch (Throwable t) { + txn.rollback(); + + // Log exception, handle individual exceptions as needed + + status = Status.BACKOFF; + + // re-throw all Errors + if (t instanceof Error) { + throw (Error)t; + } + } + return status; + } +} +``` + +添加MySink,可以参考LoggerSink + +```java +package org.example.flumedemo.sink; + +import org.apache.flume.*; +import org.apache.flume.conf.Configurable; +import org.apache.flume.sink.AbstractSink; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class MySink extends AbstractSink implements Configurable { + private static final Logger LOGGER = LoggerFactory.getLogger(MySink.class); + + // 处理数据 + @Override + public Status process() throws EventDeliveryException { + Status status = null; + // 获取跟Sink绑定的Channel + Channel ch = getChannel(); + // 获取事务 + Transaction transaction = ch.getTransaction(); + try { + // 开启事务 + transaction.begin(); + // 从channel中接收数据 + Event event = ch.take(); + if (event == null) { + status = Status.BACKOFF; + } else { + // 可以将数据发送到外部存储 + // storeSomeData(e); + // 模拟实现LoggerSink的功能 + LOGGER.info(new String(event.getBody())); + status = Status.READY; + } + //提交事务 + transaction.commit(); + + } catch (Exception e) { + // 事务回滚 + transaction.rollback(); + // 打印异常 + LOGGER.error(e.getMessage()); + // 返回失败状态 + status = Status.BACKOFF; + } finally { + // 关闭事务 + transaction.close(); + } + return status; + } + + @Override + public void configure(Context context) { + + } +} +``` + +重新package打包,上传到opt/soft/flume/lib/ + + + +修改上面的mySourceAgent.conf + +```shell +# 定义agent名称为a1 +# 设置3个组件的名称 +a1.sources = r1 +a1.sinks = k1 +a1.channels = c1 + +# 配置source类型为mysource +a1.sources.r1.type = com.itheima.flume.source.MySource + +# 配置sink类型为MySink +a1.sinks.k1.type = com.itheima.flume.sink.MySink + +# 配置channel类型为内存,内存队列最大容量为1000,一个事务中从source接收的Events数量或者发送给sink的Events数量最大为100 +a1.channels.c1.type = memory +a1.channels.c1.capacity = 1000 +a1.channels.c1.transactionCapacity = 100 + +# 将source和sink绑定到channel上 +a1.sources.r1.channels = c1 +a1.sinks.k1.channel = c1 +``` + +启动Flume + +```shell +flume-ng agent -n a1 -c ./ -f mySourceAgent.conf +``` + +输出结果(相当于自己实现logger) + +![image-20250113143840898](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/image-20250113143840898.png) + +# Flume监控 + +Ganglia是UC Berkeley发起的一个开源集群监视项目,设计用于测量数以千计的节点。 + +Ganglia的核心包含**gmond(监控守护进程)、gmetad(元数据守护进程)以及一个Web前端。** + +主要是用来**监控系统性能**,如:cpu 、mem、硬盘利用率, I/O负载、网络流量情况等,通过曲线很容易见到每个节点的工作状态,对合理调整、分配系统资源,提高系统整体性能起到重要作用。 + +## Ganglia安装 + +**中心节点的安装 ** + +- epel包的安装:yum install -y epel-release(解决不能yum安装某些安装包的问题) +- gmetad的安装:yum install -y ganglia-gmetad +- gmond的安装:yum install -y ganglia-gmond(监控守护进程会使用到下面的工具rrdtool) +- rrdtool的安装:yum install -y rrdtool +- httpd服务器的安装:yum install -y httpd(Web前端需要部署在httpd上) +- ganglia-web及php安装:yum install -y ganglia-web php(ganglia前端是php写的) + +**被监测节点的安装** + +- epel包的安装:yum install -y epel-release(解决不能yum安装某些安装包的问题) +- gmond的安装:yum install -y gmond(提示找不到,感觉应该换成上面那个yum install -y ganglia-gmond) + +## Ganglia配置 + +**中心节点的配置** +安装目录说明 + +- ganglia配置文件目录:/etc/ganglia +- rrd数据库存放目录:/var/lib/ganglia/rrds +- ganglia-web安装目录:/usr/share/ganglia +- ganglia-web配置目录:/etc/httpd/conf.d/ganglia.conf + +相关配置文件修改 +将ganglia-web的站点目录连接到httpd主站点目录 + +```shell +# 把 /usr/share/ganglia 链接到 /var/www/html/ 下,默认以ganglia命令 +$ ln -s /usr/share/ganglia /var/www/html +``` + +修改httpd主站点目录下ganglia站点目录的访问权限 +将ganglia站点目录访问权限改为apache:apache,否则会报错 + +```shell +$ chown -R apache:apache /var/www/html/ganglia +$ chmod -R 755 /var/www/html/ganglia +``` + +修改rrd数据库存放目录访问权限 +将rrd数据库存放目录访问权限改为nobody:nobody,否则会报错 + +```shell +$ chown -R nobody:nobody /var/lib/ganglia/rrds +``` + +修改ganglia-web的访问权限: +修改/etc/httpd/conf.d/ganglia.conf + +```shell +Alias /ganglia /usr/share/ganglia + + Require all granted + #Require ip 10.1.2.3 + #Require host example.org + +``` + +修改dwoo下面的权限 + +```shell +chmod 777 /var/lib/ganglia/dwoo/compiled +chmod 777 /var/lib/ganglia/dwoo/cache +``` + +配置/etc/ganglia/gmetad.conf + +```shell +data_source "my cluster" 192.168.88.130:8649(注意是所有节点都加上,如master:8649 slave0x:8649) + +setuid_username nobody +``` + +配置/etc/ganglia/gmond.conf + +```shell +cluster { + name = "my cluster" + ... +} +udp_send_channel { + # the host who gather this cluster's monitoring data and send these data to gmetad node + #注释掉多播模式的,以下出现这个都要注释掉 + #mcast_join = 239.2.11.71 + #添加单播模式的 + host = 192.168.88.130 + port = 8649 +} +udp_recv_channel { + # 0.0.0.0 + bind = 0.0.0.0 + port = 8649 +} +tcp_accept_channel { + port = 8649 +} +``` + +**被监测节点的配置** +配置/etc/ganglia/gmond.conf + +```shell +cluster { + name = "hadoop cluster" + ... +} +udp_send_channel { + # the host who gather this cluster's monitoring data and send these data to gmetad node + host = 192.168.26.139 + port = 8649 +} +udp_recv_channel { + port = 8649 +} +tcp_accept_channel { + port = 8649 +} +``` + +## Ganglia启动 + +**中心节点的启动** +start httpd, gmetad, gmond + +```shell +$ systemctl start httpd.service +$ systemctl start gmetad.service +$ systemctl start gmond.service +$ systemctl enable httpd.service +$ systemctl enable gmetad.service +$ systemctl enable gmond.service + + +# 也可以使用 +sevice httpd start +servie httpd status + +sevice gmetad start +servie gmetad status + +sevice gmond start +servie gmond status +``` + +**被监测节点的启动** +start gmond + +```shell +$ systemctl start gmond.service +$ systemctl enable gmond.service +``` + +**关闭selinux** + +vi /etc/selinux/config,把SELINUX=enforcing改成SELINUX=disable;该方法需要重启机器。 +可以使用命令setenforce 0来关闭selinux而不需要重启,刷新页面,即可访问;不过此法只是权宜之计,如果想永久修改selinux设置,还是要使用第一种方法 + +**开启防火墙**(外网访问需要开启端口,默认80。目前机器防火墙是关闭的) + +```shell +firewall-cmd --zone=public --add-port=80/tcp --permanent +firewall-cmd --reload +``` + +**访问网页** +浏览器访问 {namenode的ip}/ganglia即可 + +![image-20200326103901392](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/202501071706071.png) + +## 添加Flume监控 + +修改flume-env.sh配置,添加虚拟机选项 + +```shell +JAVA_OPTS="-Dflume.monitoring.type=ganglia -Dflume.monitoring.hosts=192.168.88.130:8649 -Xms100m -Xmx200m" +``` + +![image-20250117151019808](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/202501171510906.png) + +启动flume + +```shell +flume-ng agent -n a1 -c ./ -f mySourceAgent.conf -Dflume.monitoring.type=ganglia -Dflume.monitoring.hosts=192.168.88.130:8649 +``` + +查看ganglia页面 + +![image-20250117150708576](https://raw.githubusercontent.com/onetioner/img/main/PicGo1/202501171507683.png) + + + +| 字段(图表名称) | 字段含义 | +| --------------------- | ------------------------------------------------------------ | +| EventPutAttemptCount | source尝试写入channel的事件总数量 | +| EventPutSuccessCount | 成功写入channel且提交的事件总数量 | +| EventTakeAttemptCount | sink尝试从channel拉取事件的总数量。这不意味着每次事件都被返回,因为sink拉取的时候channel可能没有任何数据。 | +| EventTakeSuccessCount | sink成功读取的事件的总数量 | +| StartTime | channel启动的时间(毫秒) | +| StopTime | channel停止的时间(毫秒) | +| ChannelSize | 目前channel中事件的总数量 | +| ChannelFillPercentage | channel占用百分比 | +| ChannelCapacity | channel的容量 | + +目前mySourceAgent.conf配置文件中 + +```shell +# channel的容量为1000 +a1.channels.c1.capacity = 1000 +``` + +每张图片可点击查看具体情况 \ No newline at end of file diff --git "a/docs/\343\200\212Python\343\200\213\347\254\224\350\256\260/01.\347\254\254\344\270\200\347\253\240\350\212\202-\344\275\240\345\245\275Python.md" "b/docs/\343\200\212Python\343\200\213\347\254\224\350\256\260/01.\347\254\254\344\270\200\347\253\240\350\212\202-\344\275\240\345\245\275Python.md" new file mode 100644 index 00000000..55f4b6f8 --- /dev/null +++ "b/docs/\343\200\212Python\343\200\213\347\254\224\350\256\260/01.\347\254\254\344\270\200\347\253\240\350\212\202-\344\275\240\345\245\275Python.md" @@ -0,0 +1,801 @@ +--- +title: 第一章节-你好Python +date: 2025-01-17 15:34:21 +permalink: /pages/da94c8/ +categories: + - 《Python》笔记 +tags: + - +author: + name: onetion + link: https://github.com/onetioner +--- +# 第一章节:你好Python + +> 妙不可言的Python之旅 +> +> 从今天开始成为一名优雅的Pythoneer + +# 目录 + +- 初识Python + +- 什么是编程语言 + +- Python安装 + +- 第一个Python程序 + +- Python解释器 + +- Python开发工具 + +# 1. 初始Python + +## 1.1 Python的起源 + +1989年,为了**打发**圣诞节假期,Gudio van Rossum吉多· 范罗苏姆(龟叔)决心开发一个新的解释程序(Python雏形) + +1991年,第一个Python解释器诞生 + +Python这个名字,来自龟叔所挚爱的电视剧Monty Python's Flying Circus + +> 闲着没事的程序员是有多虎? + +image-20250115234031412 + +image-20250115234141585 + +image-20250115234159260 + +## 1.2 为什么选择Python + +- 优雅 + +简单、易学、开发效率高 + +![image-20250115234413110](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501152344145.png) + +- 适用面广泛 + +| **人群/岗位** | **用Python做什么** | +| --------------------- | ------------------------------------------------ | +| IT从业者 | 自动化脚本(运维开发、测试开发等) | +| 普通白领 | 自动化办公 | +| 后端开发 | WEB应用程序 | +| 科学家 | 基于Python完成数据计算(生物、化学、物理) | +| **人工智能/机器学习** | **基于**Python开发AI程序** | +| **大数据开发** | **基于Python完成大数据任务开发(Spark、Flink)** | +| **学生** | **计算机二级考试** **小学六年级Python课程** | + +![image-20250115234708893](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501152347927.png) + +![image-20250115234714400](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501152347432.png) + +![image-20250115234740324](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501152347349.png) + +## 1.3 总结 + +1.Python的诞生? + + 1991年吉多·范·罗苏姆(龟叔)创建 + +2. 为什么使用Python? + + 简单易学、全球第一、优雅、应用场景丰富(就业方向多) + +3. Python的应用场景? + +![image-20250115234943181](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501152349225.png) + +# 2. 什么是编程语言 + +## 2.1 什么是编程语言 + +首先,不管Python,我们先明白,什么是编程语言 + +> What is programming language? + + + +语言:进行沟通交流的表达方式 + +情况1: + +![image-20250115235451137](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501152354167.png) + +![image-20250115235334926](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501152353960.png) + +情况2: + +![image-20250115235621624](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501152356650.png) + +![image-20250115235713695](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501152357733.png) + +情况3: + +![image-20250115235809949](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501152358979.png) + +![image-20250115235906379](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501152359415.png) + +> 计算机只认识二进制0和1 + + + +人类翻译官无法沟通,那要怎么做才能和计算机交流呢? + +> 编程语言 + + + +以Python为例 + +![image-20250116000109386](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160001415.png) + + + +**思考** + +为什么不直接把中文翻译成二进制呢? + +中文: + +- 在屏幕上显示你好帅 + +- 把你好帅显示在屏幕上 + +- 快夸我帅 + +Python: + +- print(“你好帅”) + +> 自然语言远比编程语言复杂,编程语言语法”死板”,“翻译官”更容易翻译 + + + +## 2.2 总结 + +1. 什么是编程语言? + +- 人类和计算机交流的一种专有领域语言 + +2. 编程语言的工作原理? + +- 想法转换为编程语言代码 + +- 通过翻译官(解释器)翻译成二进制提交计算机执行 + + + +**彩蛋** + +0和1的二进制,真的能保存数据吗?大家何不亲自动手尝试一下? + +``` +111010011001101110110110 111001011001111110111010 111001111010000110000000 111001011010110110100110 01001001 01010100 111011111011110010001100 111001101001110010001000 111010001001011010101010 111010001011111110000111 111001001011100010000111 111011111011110010001100 111001011011000010110001 111001101001110110100101 111010011011101110010001 111010011010100110101100 111001111010100010001011 111001011011101010001111 111001011001000110011000 +``` + +百度搜索:二进制转中文 + +大家试一试,这个二进制保存了什么信息? + +![image-20250116000636139](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160006179.png) + +# 3. Python安装 + +**目标** + +完成Python环境的安装 + + + +## 3.1 Python安装(Windows) + +- 下载 + +想要使用Python语言编写程序,我们必须下载Python安装包并配置Python环境, + +Python目前最新版本是:3.10.4(发布于2022年3月24日) + +本次课程就基于当前最新版本进行学习 + +![image-20250116000918706](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160009753.png) + +下载最新版Python + +https://www.python.org/downloads + +![image-20250116000953148](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160009197.png) + +点击即可下载 + +- 安装 + +双击打开下载的安装包(以Windows系统为例) + +![image-20250116001127735](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160011776.png) + +![image-20250116001132783](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160011813.png) + +![image-20250116001155208](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160011254.png) + +![image-20250116001212265](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160012297.png) + +![](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160012703.png) + +- 验证安装 + +点击左下角windows键 + +![image-20250116001253705](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160012750.png) + +输入: cmd + +打开“命令提示符”程序 + +![image-20250116001316622](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160013667.png) + +在命令提示符程序内,输入:python 并回车 + +![image-20250116001342355](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160013404.png) + + + +## 3.2 Python安装(MacOS) + +**目标** + +完成Python环境的安装(MacOS操作系统) 基于MacOS 12.4 + +- 下载 + +下载最新版Python + +https://www.python.org/downloads + +![image-20250116001611982](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160016018.png) + +找到macOS系统按钮,并点击 + +点击后在弹出的网页内 + +点击最新的python3.10.4的按钮 + +![image-20250116001702847](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160017899.png) + +下载完成后,应该可以看到如下文件: + +![image-20250116001723989](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160017040.png) + +- 安装 + +双击打开下载好的:python-3.10.4-macos11.pkg 文件,开始安装 + +![image-20250116001806294](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160018339.png) + +![image-20250116001918393](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160019448.png) + +![image-20250116001931483](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160019537.png) + +![image-20250116002141928](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160021976.png) + +![image-20250116001815817](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160018856.png) + +![image-20250116001829510](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160018553.png) + +![image-20250116001839316](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160018362.png) + +![image-20250116001856413](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160018459.png) + +- 验证安装 + +找到mac中的“终端”程序并打开: + +![image-20250116002504117](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160025153.png) + +直接在终端中输入: + +![image-20250116002539982](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160025056.png) + +![image-20250116002549290](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160025359.png) + +如图,最新版3.10.4已经安装成功。 + +- 扩展 + +如果想要使用python命令,而非python3命令执行python + +那么可以设置环境变量来解决,在终端中执行如下代码: + +```shell +echo 'alias python=python3' >> .bash_profile +``` + +退出且重新打开终端,然后执行: + +``` +python +``` + +![image-20250116002735507](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160027557.png) + +## 3.3 Python(Linux) + +完成Python环境的安装(Linux操作系统)基于CentOS 7 + + + +提示:在Linux上安装Python需要如下前置技能: + +•有过Linux系统的使用经验,熟悉Linux操作系统的常见命令,如: + +•yum、cd、wget、vi编辑器、软链接等 + + + +- 下载 + +在Linux上安装Python需要先安装前置依赖程序。 + +登陆到Linux中,使用yum程序进行依赖程序安装,执行如下命令: + +```shell +yum install wget zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gcc make zlib zlib-devel libffi-devel -y +``` + +下载最新版Python + +https://www.python.org/downloads + +![image-20250116002926752](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160029798.png) + +找到Linux系统按钮,并点击 + +点击后在弹出的网页内 + +点击最新的python3.10.4的按钮 + +![image-20250116003019453](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160030498.png) + +拖动网页到最下方,如下图 + +![image-20250116003034356](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160030405.png) + +找到Gzipped source tarball按钮,点击右键,选择复制链接 + +![image-20250116003043916](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160030981.png) + +进入到Linux系统内,使用wget命令,粘贴复制的下载链接,进行下载: + +执行下载: + +```shell +cd ~ +wget https://www.python.org/ftp/python/3.10.4/Python-3.10.4.tgz +``` + +![image-20250116003114950](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160031993.png) + + + +- 安装 + +下载完成后,即可看到已下载好的安装包文件: + +![image-20250116003138885](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160031939.png) + +解压安装包,执行: + +```shell +tar -xvf Python-3.10.4.tgz +``` + +![image-20250116003201233](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160032298.png) + +切换目录到解压后的Python安装文件夹: + +```shell +# 切换目录 +cd Python-3.10.4 +``` + +1. 配置 + +```shell +./configure --prefix=/usr/local/python3.10.4 +``` + +大约耗时30秒 + +2. 编译 + +```shell +make && make install +``` + +大约耗时10分钟,请耐心等待 + +编译完成后,可以配置软链接,方便快速使用python: + +执行: + +```shell +# 删除系统自带的老版本(python2)的软链接 +rm -f /usr/bin/python + +# 创建软链接 +ln -s /usr/local/python3.10.4/bin/python3.10 /usr/bin/python +``` + +创建软链接后,会破坏yum程序的正常使用(只能使用系统自带的python2) + +修改如下2个文件: + +```shell +/usr/bin/yum +/usr/libexec/urlgrabber-ext-down +``` + +使用vi编辑器,将这2个文件的第一行,从 + +```shell +#!/usr/bin/python +``` + +修改为: + +```shell +#!/usr/bin/python2 +``` + +- 验证安装 + +在Linux系统命令行窗口内,直接执行:python 并回车: + +![image-20250116003547202](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160035255.png) + +如图,看到Python 3.10.4字样,即表明安装成功。 + +# 4. 第一个Python程序 + +**目标** + +开发出第一个Python程序 + +## 4.1 第一个Python程序 + +向世界说你好,应该是全世界,所有程序员入门编程语言时,都会选择的第一个程序。 + +让我们也延续这一份来自程序员之间的浪漫,学习如何使用Python,向世界说你好。 + + + +我们的Python代码非常简单,如下: + +```python +print(“Hello World!!!”) +``` + +含义:向屏幕上输出(显示),Hello World!!! + +> **注意**:输入的双引号和括号,请使用**英文符号**哦 + + + +打开CMD(命令提示符)程序,输入Python并回车 + +然后,在里面输入代码回车即可立即执行 + +![image-20250116003738262](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160037338.png) + + + +**扩展**:第一个Python程序 - 常见问题 + +- 问题1; + +![image-20250116003936828](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160039900.png) + +- 问题2: + +![image-20250116004030971](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160040039.png) + +- 问题3: + +![image-20250116004141776](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160041818.png) + +![image-20250116004206795](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160042854.png) + + + +- 问题4: + +![image-20250116004235413](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160042464.png) + +# 5. Python解释器 + +**目标** + +理解并认识Python解释器程序 + + + +## 5.1 Python解释器 + +首先,一个基本原理是: + +**计算机只认识二进制,即:0和1** + +![image-20250116004444007](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160044062.png) + +> print(“Hello World!!!”) +> +> 为什么计算机会认识? + + + +其实很简单,计算机是不会认识Python代码的。但是Python有解释器程序,如下图 + +![image-20250116004558895](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160045949.png) + +安装Python环境,本质上,就是在电脑中,安装: + +Python解释器程序 + +代码,随时可以写,但能不能运行,就要看电脑里面有没有解释器程序了。 + + + +Python解释器,是一个计算机程序,用来翻译Python代码,并提交给计算机执行。 + +所以,它的功能很简单,就2点: + +1. 翻译代码 + +2. 提交给计算机运行 + +> 解释器我明白了,可是解释器在哪呢? + + + +解释器存放在:``/**python.exe** + +![image-20250116004659412](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160046456.png) + +**我们在CMD(命令提示符)程序内,执行的python,就是上图的python.exe程序哦** + +![image-20250116004713435](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160048448.png) + +不使用解释器,计算机不认识Python代码哦 + +![image-20250116004817012](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160048076.png) + +**Python解释器程序,就能执行Python代码了** + +![image-20250116004833747](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160048821.png) + + + +**思考一下:** + +**在python解释器程序内,我们发现,写完一行代码并回车后,会直接运行他。** + +**问题来了:** + +**我们能否写好多行代码,一次性的运行呢?** + +**那,肯定是:可以的** + + + +我们可以将代码,写入一个以”.py”结尾的文件中,使用python命令去运行它。 + + + +如,在Windows系统的D盘,我们新建一个名为:test.py的文件,并通过记事本程序打开它,输入如下内容: + +![image-20250116004959623](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160049679.png) + +在“命令提示符”程序内,使用python命令,运行它,如图: + +![image-20250116005014790](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160050870.png) + +## 5.2 总结 + +1. 计算机只认识什么? + +- 0和1 + +2. Python解释器的作用是 + +- 将Python代码翻译成计算机认识的0和1并提交计算机执行 + +- 在解释器环境内可以一行行的执行我们输入的代码 + + -也可以使用解释器程序,去执行”.py”代码文件 + +3. “.py”文件是什么? + +- python语言的代码文件,里面记录了python的代码 + +4. Python解释器程序在 + +- ``/python.exe + +# 6. Python开发环境 + +**目标** + +- 安装和配置PyCharm工具 + +## 6.1 Python开发环境 + +Python程序的开发有许多种方式,一般我们常见的有: + +- Python解释器环境内,执行单行代码 + +- 使用Python解释器程序,执行Python代码文件 + +- **使用第三方IDE(集成开发工具),如PyCharm软件,开发Python程序** +- **最常用的就是使用PyCharm软件进行开发** + + + +PyCharm集成开发工具(IDE),是当下全球Python开发者,使用**最频繁的工具软件**。 + +绝大多数的Python程序,都是在PyCharm工具内完成的开发。 + +本次课程全程基于PyCharm软件工具,来讲解Python。 + + + +首先,我们先下载并安装它: + +\- 打开网站:https://www.jetbrains.com/pycharm/download/#section=windows + +![image-20250116005357302](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160053381.png) + +步骤1: + +![image-20250116005436330](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160056706.png) + +步骤2: + +![image-20250116005451896](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160054970.png) + +步骤3: + +![image-20250116005506211](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160055285.png) + +步骤4: + +![image-20250116005528300](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160055364.png) + +步骤5: + +![image-20250116005701894](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160057983.png) + +步骤6:,安装完成。 + +![image-20250116005716367](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160057444.png) + +找到安装好的Python,打开: + +![image-20250116005729874](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160057956.png) + +即可看到软件正常可用: + +![image-20250116005744899](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160057975.png) + +创建一个工程,我们来尝试写一写代码 + +![image-20250116005805517](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160058583.png) + +指定工程路径以及选择Python解释器 + +![image-20250116005829355](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160058425.png) + +![image-20250116005918355](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160059424.png) + +配置Python解释器: + +![image-20250116010007548](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160100614.png) + +确认工程路径和解释器 + +![image-20250116010026518](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160100605.png) + +工程创建完成: + +![image-20250116010048712](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160100791.png) + +创建一个Python代码文件 ,名称test.py + +![image-20250116010101672](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160101754.png) + +![image-20250116010113246](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160101331.png) + +填写如下内容 + +![image-20250116010153034](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160101133.png) + +在空白处右键,然后选择运行: + +![image-20250116010206502](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160102591.png) + +运行成功啦 + +![image-20250116010218717](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160102813.png) + +```python +print("Hello World!!!") +print("王大锤yyds!!!") +``` + +## 6.2 总结 + +1.Python最常见的开发环境是: + +- PyCharm软件,这是一个专用于Python的开发工具 + +2.PyCharm需要以“工程”为单元,供我们使用。想要写代码需要先创建一个工程 + +# 7. 扩展 - PyCharm的基础使用 + +## 7.1 修改主题 + +默认是黑色主题,我们可以在PyCharm的右上角,点击“齿轮”![image-20250116010436651](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160104719.png) + + + +然后点击:”theme”,选择主题:![image-20250116010442349](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160104429.png) + + + +选择想要的主题即可:![image-20250116010507289](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160105394.png) + +## 7.2 修改默认字体和大小 + +打开设置:![image-20250116010549575](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160105682.png) + +![image-20250116010618478](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160106556.png) + +## 7.3 通过快捷键快速设置字体大小 + +打开设置:![image-20250116010653914](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160106020.png) + +![image-20250116010704612](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160107701.png) + +添加鼠标快捷键: + +![image-20250116010731949](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160107038.png) + +按ctrl + 鼠标滚轮上 + +![image-20250116010751437](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160107536.png) + +## 7.4 汉化软件 + +打开插件功能:![image-20250116010849824](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160108917.png) + +![image-20250116010856375](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160108466.png) + +## 7.5 其它插件: + +翻译软件: + +![image-20250116010933117](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501160109199.png) + +## 7.6 常用快捷健 + +- ctrl + alt + s : 打开软件设置 + +- ctrl + d :复制当前行代码 + +- shift + alt + 上\下 : 将当前行代码上移或下移 +- •crtl + shift + f10 : 运行当前代码文件 +- shift + f6 :重命名文件 +- ctrl + a : 全选 +- ctrl + c\v\x : 复制、粘贴、剪切 +- ctrl + f : 搜索 \ No newline at end of file diff --git "a/docs/\343\200\212Python\343\200\213\347\254\224\350\256\260/02.\347\254\254\344\272\214\347\253\240-Python\345\237\272\347\241\200\350\257\255\346\263\225.md" "b/docs/\343\200\212Python\343\200\213\347\254\224\350\256\260/02.\347\254\254\344\272\214\347\253\240-Python\345\237\272\347\241\200\350\257\255\346\263\225.md" new file mode 100644 index 00000000..0d2f2f77 --- /dev/null +++ "b/docs/\343\200\212Python\343\200\213\347\254\224\350\256\260/02.\347\254\254\344\272\214\347\253\240-Python\345\237\272\347\241\200\350\257\255\346\263\225.md" @@ -0,0 +1,1524 @@ +--- +title: 第二章-Python基础语法 +date: 2025-01-17 15:34:37 +permalink: /pages/d15384/ +categories: + - 《Python》笔记 +tags: + - +author: + name: onetion + link: https://github.com/onetioner +--- +# 第二章:Python基础语法 + +# 目录 + +- 字面量 +- 注释 +- 变量 +- 数据类型 +- 数据类型转换 +- 标识符 +- 运算符 +- 字符串扩展 +- 数据输入 + + + +# 1. 字面量 + +## 1.1 学习目标 + +1.掌握字面量的含义 + +2.了解常见的字面量类型 + +3.基于print语句完成各类字面量的输出 + +## 1.2 什么是字面量 + +字面量:在代码中,被**写下来**的的固定的**值**,称之为字面量 + +> Python中有哪些值可以被写下来? +> +> 如何在代码中写它们呢? + +## 1.3 常用的值类型 + +Python中常用的有**6**种值(数据)的类型 + +- 数字(Number) + - 整数(int) + - 如:10、-10 + - 浮点数(float) + - 如:13.14、-13.14 + - 复数(complex) + - 如:4+3j,以j结尾表示复数 + - 布尔(bool) + - 表达现实生活中的逻辑,即真和假,True表示真,False表示假。True本质上是一个数字记作1,False记作0 +- 字符串(String) + - 描述文本的一种数据类型 + - 由任意数量的字符组成 +- 列表(List) + - 有序的可变序列 + - Python中使用最频繁的数据类型,可有序记录一堆数据 +- 元组(Tuple) + - 有序的不可变序列 + - 可有序记录一堆不可变的Python数据集合 +- 集合(Set) + - 无序不重复集合 + - 可无序记录一堆不重复的Python数据集合 +- 字典(Dictionary) + - 无序Key-Value集合 + - 可无序记录一堆Key-Value型的Python数据集合 + +## 1.4 字符串 + +字符串(string),又称文本,是由任意数量的字符如中文、英文、各类符号、数字等组成。所以叫做字符的串 + +如: + +- "黑马程序员" + +- "学Python来黑马" + +- "!@#$%^&" + +- "传智教育的股票代码是:003032" + +> **Python**中,字符串需要用双引号(")包围起来 +> +> 被引号包围起来的,都是字符串 + +## 1.5 如何在代码中写它们 + +我们目前要学习的这些类型,如何在代码中表达呢? + +| **类型** | **程序中的写法** | **说明** | +| -------------- | ---------------- | -------------------------------- | +| 整数 | 666,-88 | 和现实中的写法一致 | +| 浮点数(小数) | 13.14,-5.21 | 和现实中的写法一致 | +| 字符串(文本) | "黑马程序员" | 程序中需要加上双引号来表示字符串 | + +## 1.6 总结 + +1. 掌握字面量的含义 + +- 代码中,被写在代码中的固定的值,称之为字面量 + +2. 常见的字面量类型 + +- 我们目前了解:整数、浮点数、字符串这三类即可 + +3. 如何基于print语句完成各类字面量的输出 + +- print(字面量),如: + + - print(10),输出整数10 + + - print(13.14),输出浮点数13.14 + + - print("黑马程序员"),输出字符串:黑马程序员 + +# 2. 注释 + +## 2.1 学习目标 + +1.了解注释的作用 + +2.能够使用单行注释和多行注释 + +## 2.2 注释的作用 + +- 未使用注释代码 + + ```python + 666 + 13.14 + "黑马程序员" + + print(666) + print(13.14) + print("黑马程序员") + ``` + +- 使用注释的代码 + + ```python + """ + 演示: + - 各类字面量的写法 + - 通过print语句输出各类字面量 + """ + # 写一个整数字面量 + 666 + # 写一个浮点数字面量 + 13.14 + # 写一个字符串字面量 + “黑马程序员” + + # 通过print语句输出各类字面量 + print(666) + print(13.14) + print("黑马程序员") + ``` + +- 注释:在程序代码中对程序代码进行解释说明的文字。 + +- 作用:注释不是程序,**不能被执行**,只是对程序代码进行解释说明,让别人可以看懂程序代码的作用,能够大大增强程序的可读性。 + +## 2.3 注释的分类 + +- 单行注释:以 #开头,#右边的所有文字当作说明,而不是真正要执行的程序,起辅助说明作用 + + > **注意**,#号和注释内容一般建议以一个空格隔开 + +![image-20250116214105858](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162141941.png) + +- 多行注释: 以 一对三个双引号引起来 ("""注释内容""")来解释说明一段代码的作用使用方法 + +![image-20250116214406019](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162144058.png) + + ## 2.4 注释实战 + +image-20250116214456970 + +按照如图所示,对代码添加 + +- 单行注释以及 + +- 多行注释 + +添加完成注释后,执行程序 + +验证注释是否对程序产生影响 + +## 2.5 总结 + +1. 注释的作用是? + +- 注释是代码中的解释型语句,用来对代码内容进行注解 + +- 注释不是代码,不会被程序执行 + +2. 单行注释如何定义? + +- 通过 # 号定义,在#号右侧的所有内容均作为注释 + +- 建议在#号和注释内容之间,间隔一个空格 + +- 单行注释一般用于对一行或一小部分代码进行解释 + +3. 多行注释如何定义? + +- 通过一对三个引号来定义("""注释内容"""),引号内部均是注释,可以换行 + +- 多行注释一般对:Python文件、类或方法进行解释 + + + +**思考** + +1. 思考第二个print语句会执行吗? + +- 会执行的弹幕扣1,不会执行的弹幕扣2 + +![image-20250116214726610](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162147658.png) + +- 这是注释不会执行 + +## 2.6 扩展 + +关于注释的面试题 + +1. 单行注释中能否使用多行注释? +2. 多行注释中能否使用单行注释? +3. 多行注释中能否使用多行注释? + +# 3. 变量 + +## 3.1 学习目标 + +1. 理解变量的作用及特征 + +2. 掌握变量的定义方式 + +## 3.2 什么是变量 + +变量:**在程序运行时**,能储存计算结果或能表示值的抽象概念。 + +简单的说,变量就是在程序运行时,记录数据用的 + + + +变量的定义格式 + +``` +变量名称 = 变量的值 + || || || + || || || + || || vv + || || 每一个变量都有自己存储的值(内容),称之为:变量值 + || vv + || 赋值,表示将等号右侧的值,赋予左侧的变量 + vv + 每一个变量都有自己的名称,称之为:变量名,也就是变量本身 +``` + +image-20250116215811274 + +## 3.2 案例-模拟钱包 + +![image-20250116220411087](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162204123.png) + +```python +""" +演示Python中变量的相关操作 +""" + +# 定义一个变量,用来记录钱包余额 +money = 50 +# 通过print语句,输出变量记录的内容 +print("钱包还有:", money) + +# 买了一个冰淇淋,花费10元 +money = money - 10 +print("买了冰淇淋花费了10元,还剩余:", money, "元") + +# 假设,,每隔一小时,输出一下钱包的余额 +print("现在是下午1点,钱包余额剩余:", money) +print("现在是下午2点,钱包余额剩余:", money) +print("现在是下午3点,钱包余额剩余:", money) +print("现在是下午4点,钱包余额剩余:", money) +``` + +## 3.3 变量的特征 + +变量,从名字中可以看出,表示“量”是可变的。 + +所以,变量的特征就是,**变量存储的数据,是可以发生改变的。** + +![image-20250116220659979](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162207013.png) + +> 如上图,盒子刚开始是“足球”,然后把“篮球”放进去 + + + +**思考** + +为什么必须要使用变量? + +都是输出内容,直接输出不行吗? + + + +**变量的目的是存储运行过程的数据** + +**存储的目的是为了:重复使用** + + + +## 3.4 总结 + +1. 变量是什么,有什么作用? + +- 变量就是在程序运行时,记录数据用的 + +2. 变量的定义格式是? + +- 变量名 = 变量值 + +3. 变量的特征是? + +- 变量的值可以改变 + +4. print语句如何输出多份内容? + +- print(内容1, 内容2, ......, 内容N) + +5. Python中如何做减法? + +- 使用符号 - 即可完成减法运算 + +- 拓展:加(+)、减(-)、乘(*)、除(/) + +## 3.5 练习-求钱包余额 + +请在程序中,定义如下变量: + +- 钱包余额(变量名:money),初始余额50 + +- 请通过程序计算,在购买了: + - 冰淇淋10元 + - 可乐5元 + +- 后,钱包余额还剩余多少元。请通过print语句按照下图所示,进行输出: + +![image-20250116221049569](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162210615.png) + +```python +# 定义一个变量,用来记录钱包的余额 +qian = 50 +print("当前钱包余额:", qian, "元") + +# 买了一个冰淇淋,花费10元 +qian = qian - 10 +print("购买了冰淇淋,花费:", 10, "元") + +# 买了一瓶可乐,花费了5元 +qian = qian - 5 +print("购买了可乐,花费:", 5, "元") + +# 最终,钱包剩余多少钱 +print("最终,钱包剩余:", qian, "元") +``` + +# 4. 数据类型 + +## 4.1 学习目标 + +1. 掌握使用type()语句查看数据的类型 + +2. 理解变量无类型而数据有类型的概念 + +## 4.2 数据类型 + +在学习字面量的时候,我们了解到:数据是有类型的。 + +目前在入门阶段,我们主要接触如下三类数据类型: + +| 类型 | 描述 | 说明 | +| ---------- | ---------------- | --------------------------------- | +| **string** | 字符串类型 | 用引号引起来的数据都是字符串 | +| **int** | 整型(有符号) | 数字类型,存放整数 如 -1,10, 0 等 | +| **float** | 浮点型(有符号) | 数字类型,存放小数 如 -3.14, 6.66 | + +string、int、float这三个英文单词,就是类型的标准名称。 + +## 4.3 type()语句 + +那么,问题来了,如何验证数据的类型呢? + + + +我们可以通过type()语句来得到数据的类型: + +语法: + +- type(被查看类型的数据) + +## 4.4 type()语句的使用方式 + +1. 在print语句中,直接输出类型信息: + +image-20250116221928434 + +> str是string的缩写 + +2. 用变量存储type()的结果(返回值): + +image-20250116222058067 + +3. 查看的都是<字面量>的类型,能查看变量中存储的数据类型吗? + + 那当然:可以 + +image-20250116222222046 + +## 4.5 变量有类型吗? + +我们通过type(变量)可以输出类型,这是查看变量的类型还是数据的类型? + +查看的是:变量存储的数据的类型。因为,变量无类型,但是它存储的数据有。 + +![image-20250116222402534](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162224569.png) + +> 我们可能会说:字符串变量 +> +> 但要知道,不是变量是字符串,而是它存储了:字符串 + +## 4.6 总结 + +1. 使用什么语句可以查看数据的类型? + +- type() + +2. 如下代码,name_type变量可以存储变量name的类型信息,是因为? + +- 因为type()语句会给出结果(返回值) + +![image-20250116222520685](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162225733.png) + +3. 变量有没有类型? + +- 没有,字符串变量表示变量存储了字符串而不是表示变量就是字符串 + +## 4.7 字符串类型的不同定义方式 + +字符串有3种不同的定义方式: + +- 双引号定义法 :"字符串" +- 单引号定义法: '字符串' + +- 三引号定义法:"""字符串""" + +![image-20250116222758541](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162227574.png) + +三引号定义法,表示在一堆三个双引号的范围内,均是字符串,如下: + +![image-20250116222847075](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162228138.png) + +要注意的是,包含范围是:**从三个引号开始,到下一个三个引号结束** + +![image-20250116222928064](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162229114.png) + +# 5. 数据类型转换 + +## 5.1 学习目标 + +1. 掌握如何在字符串、整数、浮点数之间进行相互转换 + +2. 了解转换的注意事项 + +## 5.2 为什么要转换类型 + +数据类型之间,在特定的场景下,是可以相互转换的,如字符串转数字、数字转字符串等 + +那么,我们为什么要转换它们呢? + + + +数据类型转换,将会是我们以后经常使用的功能。 + +如: + +- 从文件中读取的数字,默认是字符串,我们需要转换成数字类型 + +- 后续学习的input()语句,默认结果是字符串,若需要数字也需要转换 + +- 将数字转换成字符串用以写出到外部系统 +- 等等 +- 用途很多,那么让我们来学习一下如何转换吧。 + +## 5.3 常见的转换语句 + +| **语句(函数)** | **说明** | +| :------------: | :--------------------: | +| int(x) | 将x转换为一个整数 | +| float(x) | 将x转换为一个浮点数 | +| str(x) | 将对象 x 转换为字符串 | + +> 同前面学习的type()语句一样,这三个语句,都是带有结果的(返回值) +> +> 我们可以用print直接输出 +> +> 或用变量存储结果值 + +## 5.4 类型转换注意事项 + +```python +# 将数字类型转换成字符串 +num_str = str(11) +print(type(num_str), num_str) + +float_str = str(11.3) +print(type(float_str), float_str) + +# 将字符串转成数字 +num = int("11") +print(type(num), num) + +num2 = float("11.34") +print(type(num2), num2) + +# num3 = int("黑马程序员") # 字符串内不是数字,是无法完成数字的转换的,所以这里报错 +# print(type(num3), num3) + +# 整数转浮点数 +float_num = float(11) +print(type(float_num), float_num) + +# 浮点数转整数 +int_num = int(11.545) +print(type(int_num), int_num) +``` + +类型转换不是万能的,毕竟强扭的瓜不会甜,我们需要注意: + + + +1. 任何类型,都可以通过str(),转换成字符串 + +2. 字符串内必须真的是数字,才可以将字符串转换为数字 + +![image-20250116225306555](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162253601.png) + +## 5.5 总结 + +1. 字符串、整数、浮点数类型转换的语句是? + +| **语句(函数)** | **说明** | +| :------------: | :--------------------: | +| int(x) | 将x转换为一个整数 | +| float(x) | 将x转换为一个浮点数 | +| str(x) | 将对象 x 转换为字符串 | + +2. 任何类型都可以转换成字符串,对不对? + +- 正确 + +3. 字符串可以随意转换成数字,对不对? + +- 错误,字符串内必须只有数字才可以 + +4. 浮点数转整数会丢失什么? + +- 丢失精度,也就是小数部分 + +## 5.6 今日作业 + +1. 描述什么是变量以及变量命名规范。 + +2. 熟悉Python中的7种数据类型以及定义方式。 + +3. 定义4个变量,需求:姓名:孙悟空,年龄:600岁,技能:筋斗云、72变,主要战绩:大闹天宫 + +4. 定义变量,c1 = '可乐',c2 = '牛奶',通过Python代码把c1内容调整为牛奶,c2调整为可乐。(提示:两个数的交换) + +# 6. 标识符 + +## 6.1 学习目标 + +1. 理解什么是标识符 +2. 掌握标识符的命名规则 +3. 掌握变量的命名规范 + +## 6.2 什么是标识符 + +在Python程序中,我们可以给很多东西起名字,比如: + +- 变量的名字 + +- 方法的名字 + +- 类的名字,等等 + +这些名字,我们把它统一的称之为标识符,用来做内容的标识。 + +所以,标识符: + +是用户在编程的时候所使用的一系列名字,用于给变量、类、方法等命名。 + +> 既然要起名字,就会有对应的限制 + +## 6.3 标识符命名规则 + +Python中,标识符命名的规则主要有3类: + +- **内容限定** + +- **大小写敏感** + +- **不可使用关键字** + +## 6.4 标识符命名规则 - 内容限定 + +标识符命名中,只允许出现: + +- 英文 + +- 中文 + +- 数字 + +- 下划线(_) + +这四类元素。 + +其余任何内容都不被允许。 + +> **1.** 不推荐使用中文 +> +> **2.** 数字不可以开头 + +![image-20250116230622720](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162306780.png) + +## 6.5 标识符命名规则 - 大小写敏感 + +以定义变量为例: + +Andy = “安迪1” + +andy = “安迪2” + +字母a的大写和小写,是完全能够区分的。 + +image-20250116230710346 + +## 6.6 标识符命名规则 - 不可使用关键字 + +image-20250116230840019 + +**Python中有一系列单词,称之为关键字** + +**关键字在Python中都有特定用途** + +**我们不可以使用它们作为标识符** + +![image-20250116230926022](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162309071.png) + + + +```python +# 规则1:内容限定,限定只能使用中文、英文、数字、下划线,注意:不能以 数字 开头 + +# 错误的代码示范 +# 1_name = "张三" +# name_! = "张三" + +name_ = "张三" +_name = "张三" +name_1 = "张三" + +# 规则2:大小写敏感 +Itheima = "黑马程序员" +itheima = 666 + +print(Itheima) +print(itheima) + +# 规则3:不可使用关键字 + +# class = 1 错误示例:使用了关键字 +# def = 1 + +Class = 1 +``` + +## 6.7 变量命名规范 + +学完了标识符(变量、类、方法)的命名**规则**后,我们在来学习标识符的命名**规范**。 + +- 变量名 + +- 类名 + +- 方法名 + +不同的标识符,有不同的规范。 + + + +我们目前只接触到了:变量。所以,目前学习:变量的命名规范。 + +- 见名知意 + +- 下划线命名法 + +- 英文字母全小写 + +## 6.8 变量命名规范 - 见名知意 + +变量的命名要做到: + +- 明了:尽量做到,看到名字,就知道是什么意思 + +![image-20250116231204416](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162312453.png) + +- 简洁:尽量在确保“明了”的前提下,减少名字的长度 + +![image-20250116231222642](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162312701.png) + +## 6.9 变量命名规范 - 下划线命名法 + +多个单词组合变量名,要使用下划线做分隔。 + +![image-20250116231313036](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162313066.png) + +## 6.10 变量命名规范 - 英文字母全小写 + +命名变量中的英文字母,应全部小写: + +![image-20250116231400540](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162314575.png) + +## 6.11 总结 + +1. 什么是标识符? + +- 用户编写代码时,对变量、类、方法等编写的名字,叫做标识符。 + +2. 标识符的命名规则? + +- 内容限定 + + - (中文、英文、数字、下划线) + +- 大小写敏感 + +- 不可使用关键字 + + ![image-20250116231508888](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162315946.png) + +3. 变量的命名规范? + +- 见名知意 +- 下划线命名法 +- 英文字母全小写 + + + +> 不遵守规则:会出现问题 +> +> 不遵守规范:不太高级 + +# 7. 运算符 + +## 7.1 学习目标 + +了解Python中常见 + +- 算术(数学)运算符 + +- 赋值运算符 + +## 7.2 算术(数学)运算符 + +| 运算符 | 描述 | 实例 | +| :----: | :----: | ------------------------------------------------------------ | +| **+ ** | 加 | 两个对象相加 a + b 输出结果 30 | +| **-** | 减 | 得到负数或是一个数减去另一个数 a - b 输出结果 -10 | +| ***** | 乘 | 两个数相乘或是返回一个被重复若干次的字符串 a * b 输出结果 200 | +| **/** | 除 | b / a 输出结果 2 | +| // | 取整除 | 返回商的整数部分 9//2 输出结果 4 , 9.0//2.0 输出结果 4.0 | +| % | 取余 | 返回除法的余数 b % a 输出结果 0 | +| ** | 指数 | a**b 为10的20次方, 输出结果 100000000000000000000 | + +## 7.3 算术运算符的演示 + +加减乘除和求平方,我们在前面已经使用过啦。 + +现在再带上:整除以及求余数,一起试一试吧。 + +![image-20250116232054324](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162320359.png) + +```python +# 算术(数学)运算符 +print("1 + 1 = ", 1 + 1) +print("2 - 1 = ", 2 - 1) +print("3 * 3 = ", 3 * 3) +print("4 / 2 = ", 4 / 2) +print("11 // 2 = ", 11 // 2) +print("9 % 2 = ", 9 % 2) +print("2 ** 2 = ", 2 ** 2) +``` + +## 7.4 赋值运算符 + +| **运算符** | **描述** | **实例** | +| :--------: | :--------: | ------------------------------------------------------------ | +| = | 赋值运算符 | 把 = 号右边的结果 赋给 左边的变量,如 num = 1 + 2 * 3,结果num的值为7 | + +```python +# 赋值运算符 +num = 1 + 2 * 3 +``` + +## 7.5 复合赋值运算符 + +| **运算符** | **描述** | **实例** | +| :--------: | :--------------: | ----------------------------- | +| += | 加法赋值运算符 | c += a 等效于 c = c + a | +| -= | 减法赋值运算符 | c -= a 等效于 c = c - a | +| *= | 乘法赋值运算符 | c *= a 等效于 c = c * a | +| /= | 除法赋值运算符 | c /= a 等效于 c = c / a | +| %= | 取模赋值运算符 | c %= a 等效于 c = c % a | +| **= | 幂赋值运算符 | `c **= a 等效于 c = c ** a` | +| //= | 取整除赋值运算符 | c //= a 等效于 c = c // a | + +```python +# 复合赋值运算符 +num = 1 + +num += 1 # num = num + 1 +print("num += 1: ", num) + +num -= 1 # num = num - 1 +print("num -= 1: ", num) + +num *= 4 +print("num *= 4: ", num) + +num /= 2 +print("num /= 2: ", num) + +num = 3 +num %= 2 +print("num %= 2: ", num) + +num **= 2 +print("num **= 2: ", num) + +num = 9 +num //= 2 +print("num //= 2: ", num) +``` + +## 7.6 总结 + +1. 常见的算术(数学)运算符有: + +加(+)、减(-)、乘(*)、除(/)、整除(//)、取余(%)、求平方(**) + +2. 赋值运算符有: + +- 标准赋值: = +- 复合赋值:+=、-=、*=、/=、//=、%=、**= + +# 8. 字符串扩展 + +## 8.1 目录 + +- 字符串扩展 + + - 字符串的三种定义方式 + - 字符串拼接 + - 字符串格式化 + + - 格式化的精度控制 + + - 字符串格式化方式2 + + - 对表达式进行格式化 + +## 8.2 字符串的三种定义方式 + +### 8.2.1 字符串的三种定义方 + +字符串在Python中有多种定义形式: + +1. 单引号定义法:![image-20250116232844884](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162328336.png) + +2. 双引号定义法:![image-20250116232925125](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162329681.png) + +3. 三引号定义法:![image-20250116232930691](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162329287.png) + + + +三引号定义法,和多行注释的写法一样,同样支持换行操作。 + +使用变量接收它,它就是字符串 + +不使用变量接收它,就可以作为多行注释使用。 + +```python +""" +演示字符串的三种定义方式: +- 单引号定义法 +- 双引号定义法 +- 三引号定义法 +""" + +# 单引号定义法,使用单引号进行包围 +name = '黑马程序员' +print(type(name)) + +# 双引号定义法 +name = "黑马程序员" +print(type(name)) + +# 三引号定义法 +name = """ +我是 +黑马 +程序员 +""" +print(type(name)) +``` + +### 8.2.2 字符串的引号嵌套 + +思考:如果我想要定义的字符串本身,是包含:单引号、双引号自身呢?如何写? + +- 单引号定义法,可以内含双引号 + +- 双引号定义法,可以内含单引号 + +- 可以使用转移字符(\)来将引号解除效用,变成普通字符串 + +```python +# 在字符串内 包含双引号 +name = '"黑马程序员"' +print(name) + +# 在字符串内 包含单引号 +name = "'黑马程序员'" +print(name) + +# 使用转义字符 \ 解除引号的效用 +name = "\"黑马程序员\"" +print(name) + +name = '\'黑马程序员\'' +print(name) +``` + +### 8.2.3 总结 + +1. 字符串的三种定义方式: + +- **单引号方式** +- *双引号方式 +- 三引号方式** + +2. 引号的嵌套 + +- 可以使用:\来进行转义 +- 单引号内可以写双引号或双引号内可以写单引号 + +## 8.3 字符串拼接 + +### 8.3.1 学习目标 + +1. 掌握如何拼接字符串 + +### 8.3.2 字符串拼接 + +如果我们有两个字符串(文本)字面量,可以将其拼接成一个字符串,通过+号即可完成,如: + +```python +# 字符串字面量之间的拼接 +print("学IT来黑马" + "月薪过万") +``` + +输出结果:![image-20250116233747058](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162337153.png) + +不过一般,单纯的2个字符串字面量进行拼接显得很呆,一般,字面量和变量或变量和变量之间会使用拼接,如: + +![image-20250116233813521](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162338598.png) + +![image-20250116233825701](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162338756.png) + + + +既然,字符串和变量进行拼接,我们来完成一个小需求: + +定义2个变量: + +- name,内容是“黑马程序员” + +- address,内容是“建材城东路9号” + +要求写程序通过print语句以及字符串拼接的方式输出: + +“我是:黑马程序员,我的地址是:建材城东路9号院“ + +```python +# 字符串字面量和字符串变量的拼接 +name = "黑马程序员" +address = "建材城东路9号院" +print("我是:" + name + ",我的地址是:" + address) +``` + +![image-20250116233917425](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162339493.png) + + + +既然可以和字符串变量完成拼接,那么,是否可以和其它变量类型如数字类型完成拼接呢? + +让我们试一试。![image-20250116234059815](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162340902.png) + +![image-20250116234126654](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162341710.png) + +> 字符串无法和非字符串变量进行拼接,因为类型不一致,无法接上,就像接力赛一样,不是队友,不能接力的哦 + +### 8.3.3 总结 + +1. 如何完成字符串拼接? + +- 使用“+”号连接字符串变量或字符串字面量即可 + +2. 有哪些注意事项? + +- 无法和非字符串类型进行拼接 + +## 8.4 字符串格式化 + +### 8.4.1 学习目标 + +1. 掌握通过占位的形式拼接字符串(字符串格式化) + +### 8.4.2 字符串格式化 + +我们会发现,这个拼接字符串也不好用啊 + +1. 变量过多,拼接起来实在是太麻烦了 + +![image-20250116234528896](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162345950.png) + +2. 字符串无法和数字或其它类型完成拼接。 + + + +所以,有没有其它方式,即方便又支持拼接其它类型呢? + +这个方式,就是字符串的格式化 + + + +我们可以通过如下语法,完成字符串和变量的快速拼接。 + +```python +# 通过点位的形式,完成拼接 +name = "黑马程序员" +message = "学IT来:%s" % name +print(message) +``` + +![image-20250116234608872](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162346838.png) + +其中的,%s + +- % 表示:我要占位 + +- s 表示:将变量变成字符串放入占位的地方 + +- 所以,综合起来的意思就是:我先占个位置,等一会有个变量过来,我把它变成字符串放到占位的位置 + + + +那,数字类型呢?可以不可以占位? + +那必须可以,我们来尝试如下代码: + +```python +# 通过占位的形式,完成数字和字符串的拼接 +class_num = 57 +avg_salary = 16781 +message = "Python大数据学科,北京%s期,毕业平均工资:%s元" % (class_num, avg_salary) +print(message) +``` + +![image-20250116234717713](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162347795.png) + +> 多个变量占位,变量要用括号括起来,并按照占位的顺序填入 + +数字也能用%s占位吗? + +可以的哦,这里是将数字 转换成了 字符串哦 + +也就是数字57,变成了字符串"57"被放入占位的地方 + +![image-20250116234912864](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162349931.png) + + + +数字类型,也太没有地位了吧,竟然要被转成字符串拼接。 + +有没有体面一点的方式,让数字以其原本的面貌拼接进去呢? + +安排。 + +Python中,其实支持非常多的数据类型占位 + +最常用的是如下三类 + +| 格式符号 | 转化 | +| :------: | :------------------------------: | +| %s | 将内容转换成字符串,放入占位位置 | +| %d | 将内容转换成整数,放入占位位置 | +| %f | 将内容转换成浮点型,放入占位位置 | + +如下代码,完成字符串、整数、浮点数,三种不同类型变量的占位 + +```python +name = "传智播客" +setup_year = 2006 +stock_price = 19.99 +message = "%s, 成立于%d年,我今天的股份是%f元" % (name, setup_year, stock_price) +print(message) +``` + +![image-20250116235032480](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162350542.png) + +### 8.4.3 总结 + +1. 字符串格式化的语法? + +- "%占位符" % 变量 + +2. 常用占位符有哪3个? + +- 字符串:%s + +- 整数:%d + +- 浮点数:%f + + + +## 8.5 格式化的精度控制 + +### 8.5.1 学习目标 + +1. 掌握格式化字符串的过程中做数字的精度控制 + +### 8.5.2 字符串格式化 + +如下代码,完成字符串、整数、浮点数,三种不同类型变量的占位 + +![image-20250116235635493](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162356561.png) + +细心的同学可能会发现: + +浮点数19.99,变成了19.990000输出 + +这里我们就要讲解一下,字符串格式化之“数字精度控制” + +### 8.5.3 字符串格式化 - 数字精度控制 + +我们可以使用辅助符号"m.n"来控制数据的宽度和精度 + +- m,控制宽度,要求是数字(很少使用),设置的宽度小于数字自身,不生效 + +- .n,控制小数点精度,要求是数字,会进行小数的四舍五入 + +示例: + +- %5d:表示将整数的宽度控制在5位,如数字11,被设置为5d,就会变成:`[空格][空格][空格]11`,用三个空格补足宽度。 + +- %5.2f:表示将宽度控制为5,将小数点精度设置为2 + - 小数点和小数部分也算入宽度计算。如,对11.345设置了%7.2f 后,结果是`[空格][空格]11.35`。2个空格补足宽度,小数部分限制2位精度后,四舍五入为 .35 + +- %.2f:表示不限制宽度,只设置小数点精度为2,如11.345设置%.2f后,结果是11.35 + + + +体验一下如下代码的快乐吧 + +```python +num1 = 11 +num2 = 11.345 +print("数字11宽度限制5,结果是:%5d" % num1) +print("数字11宽度限制1,结果是:%1d" % num1) +print("数字11.345宽度限制7,小数精度2,结果是:%7.2f" % num2) +print("数字11.345宽度不限制,小数精度2,结果是:%.2f" % num2) +``` + +![image-20250116235949805](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501162359886.png) + +### 8.5.4 总结 + +1. 精度控制的语法是: + +- m.n的形式控制,如%5d、%5.2f、%.2f + +- m和.n均可省略 + +2. 如果m比数字本身宽度还小,会发生什么事? + +- m不生效 + +3. .n会对小数部分做精度限制,同时:? + +- 会对小数部分做四舍五入 + +## 8.6 字符串格式化方式2 + +### 8.6.1 学习目标 + +1. 掌握快速字符串格式化的方式 + +### 8.6.2 字符串格式化 - 快速写法 + +目前通过%符号占位已经很方便了,还能进行精度控制。 + +可是追求效率和优雅的Python,是否有更加优雅的方式解决问题呢? + +那当然:有 + +通过语法:f"内容{变量}"的格式来快速格式化 + + + +看如下代码 + +```python +""" +演示第二种字符串格式化的方式:f"{占位}" +""" + +name = "传智播客" +set_up_year = 2006 +stock_price = 19.99 +# f:format +print(f"我是{name}, 我成立于{set_up_year}年,我的股份是{stock_price}元") +``` + +![image-20250117000410753](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501170004841.png) + +> 这种写法不做精度控制 +> +> 也不理会类型 +> +> 适用于快速格式化字符串 + +### 8.6.3 总结 + +1. 可以通过 + +- f”{变量} {变量}”的方式进行快速格式化 + +2. 这种方式: + +- 不理会类型 + +- 不做精度控制 + +- 适合对精度没有要求的时候快速使用 + +## 8.7 对表达式进行格式化 + +### 8.7.1 学习目标 + +1. 了解什么是表达式 + +2. 掌握对表达式进行字符串格式化 + +### 8.7.2 字符串格式化 - 表达式的格式化 + +刚刚的演示,都是基于变量的。 + +可是,我想更加优雅些,少写点代码,直接对“表达式”进行格式化是否可行呢? + +那么,我们先了解一下什么是表达式。 + + + +表达式:一条具有明确执行结果的代码语句 + +如: + +1 + 1、5 * 2,就是表达式,因为有具体的结果,结果是一个数字 + +又或者,常见的变量定义: + +```python +name = “张三” age = 11 + 11 +``` + +等号右侧的都是表达式呢,因为它们有具体的结果,结果赋值给了等号左侧的变量。 + + + +那么,对于字符串格式化,能否直接格式化一个表达式呢? + +可以,上代码: + +```python +""" +演示对表达式进行字符串格式化 +""" + +print("1 * 1 的结果是:%d" % (1 * 1)) +print(f"1 * 2 的结果是:{1 * 2}") +print("字符串在Python中的类型名是:%s" % type("字符串")) +``` + +![image-20250117000922016](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501170009075.png) + +在无需使用变量进行数据存储的时候,可以直接格式化表达式,简化代码哦 + +### 8.7.3 总结 + +1. 表达式是什么? + +- 表达式就是一个具有明确结果的代码语句,如 1 + 1、type(“字符串”)、3 * 5等 + +- 在变量定义的时候,如 age = 11 + 11,等号右侧的就是表达式,也就是有具体的结果,将结果赋值给了等号左侧的变量 + +2. 如何格式化表达式? + +- f"{表达式}" + +- "%s\%d\%f" % (表达式、表达式、表达式) + +## 8.8 练习 - 股价计算小程序 + +定义如下变量: + +- name,公司名 + +- stock_price,当前股价 + +- stock_code,股票代码 + +- stock_price_daily_growth_factor,股票每日增长系数,浮点数类型,比如1.2 + +- growth_days,增长天数 + +计算,经过growth_days天的增长后,股价达到了多少钱 + +使用字符串格式化进行输出,如果是浮点数,要求小数点精度2位数。 + +示例输出: + +![image-20250117001111707](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501170011760.png) + +红色框框都是变量,要使用格式化的方式拼接进去 + +> 提示,可以使用: 当前股价 ***** 增长系数 ***\*** 增长天数, 用来计算最终股价哦 +> +> 如,股价19.99 * 系数1.2 ** 7天 = 71.62778419199998,小数点现在精度2位后结果:71.63 + +```python +""" +讲解字符串格式化的课后练习题 +""" +# 定义需要的变量 +name = "大锤" +stock_price = 19.99 +stock_code = "003032" +# 股票价格每日增长系数 +stock_price_daily_growth_factor = 1.2 +growth_days = 7 + +# 打印 +print(f"公司:{name}, 股票代码{stock_code}, 当前股份:{stock_price}") + +# 计算股价 +finally_stock_price = stock_price * stock_price_daily_growth_factor ** growth_days + +# 打印 +print("每日增长系数是:%.1f,经过%d天的增长后,股价达到了:%.2f" % (stock_price_daily_growth_factor, growth_days, finally_stock_price)) +``` + +# 9. 数据输入 + +## 9.1 学习目标 + +- 掌握input语句(函数)的使用 + +## 9.2 获取键盘输入 + +试想一下,我们经常遇到过程序需要我们输入信息的场景。 + +比如:银行取钱 + +![image-20250117001604624](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501170016705.png) + +如何在Python中做到读取键盘输入的内容呢? + +这里就要请出input语句了 + +## 9.3 input语句(函数) + +我们前面学习过print语句(函数),可以完成将内容(字面量、变量等)输出到屏幕上。 + +在Python中,与之对应的还有一个input语句,用来获取键盘输入。 + +- 数据输出:print + +- 数据输入:input + +使用上也非常简单: + +- 使用input()语句可以从键盘获取输入 + +- 使用一个变量接收(存储)input语句获取的键盘输入数据即可 + +```python +""" +演示Python的input语句 +获取键盘的输入信息 +""" + +print("请告诉我你是谁?") +name = input() +print("Get!!!,你是:%s" % name) +``` + +![image-20250117001659013](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501170016110.png) + + + +在前面的代码中,输出”请告诉我你是谁?“的print语句其实是多余的 + +![image-20250117001941282](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501170019405.png) + +input()语句其实是可以在要求使用者输入内容前,输出提示内容的哦,方式如下: + +![image-20250117002000259](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501170020378.png) + +如图,在input的括号内直接填入提示内容即可。 + +```python +name = input("请告诉我你是谁?") +print("我知道了,你是:%s" % name) +``` + +## 9.4 input语句获取的数据类型 + +我们刚刚试验的都是输入了字符串类型的数据。 + +那么如果我们输入数字类型或其它类型,结果会如何? + + + +那么,让我们通过前面学习过的??? + +**type()**语句 + +来验证一下输入内容的数据类型吧。 + +![image-20250117002156205](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501170021305.png) + +可以看到,无论键盘输入何种类型的数据 + +**最终的结果都是:字符串类型的数据** + +## 9.5 总结 + +1. input()语句的功能是,获取键盘输入的数据 + +2. 可以使用:input(提示信息),用以在使用者输入内容之前显示提示信息。 + +3. 要注意,无论键盘输入什么类型的数据,获取到的数据**永远都是字符串类型** + +## 9.6 练习-欢迎登陆小程序 + +定义两个变量,用以获取从键盘输入的内容,并给出提示信息: + +- 变量1,变量名:user_name,记录用户名称 + +- 变量2,变量名:user_type,记录用户类型 + +并通过格式化字符串的形式,通过print语句输出欢迎信息,如下: + +![image-20250117002444554](https://raw.githubusercontent.com/onetioner/img/main/PicGo2/202501170024644.png) + +```python +user_name = input("请输入你的用户名?") +user_type = input("请输入你的VIP类型?") +print(f"您好:{user_name},您是尊贵的:{user_type} 用户,欢迎您的光临。") +``` + +# 10. 拓展-以专业视角看待变量 + +## 10.1 前言 + +本套Python视频教程,力求以最通俗易懂的方式来讲解知识点。 + + + +但是,对于一些知识点,我们以简单的方式学习过后呢,我们仍希望给同学们补充一下 + +从专业视角去看待它们的讲解。 + + + +这些高阶的拓展知识点,在刚开始大家可能听不太懂,所以我们对这些知识点不做强制要求。 + +同学们可以跳过这些知识点,等待以后学习更加深入后,再来回看即可。 + +这些高阶拓展都是独立的,跳过也不影响后面的学习。 \ No newline at end of file