XiSun的博客

Learning is endless

0%

Gitlab 代码开发的一般流程

  • PM(项目主管/项目经理) 在 Gitlab 创建任务,分配给开发人员;
  • 开发人员领取任务后,在本地使用 git clone 命令拉取代码库;
  • 开发人员创建开发分支,并进行开发;
  • 开发人员完成代码之后,提交到本地仓库;
  • 开发人员在 Gitlab 界面上申请分支合并请求;
  • PM 在 Gitlab 上查看代码提交和修改情况,确认无误后,将开发人员的分支合并到主分支(master)。
  • 开发人员在 Gitlab 上 Mark done 确认开发完成,并关闭 issue。这一步在提交合并请求时,可以通过描述中填写 “close #1” 等字样,直接关闭 issue。

Gitlab 常用命令

  • 拉取远程仓库的代码到本地:git pull <REMOTENAME> <BRANCHNAME>。例如:

    1
    $ git pull origin master				# 远程仓库:origin,分支:master
    • 不建议使用 git pull 这种模糊的命令。
  • 推送本地代码到远程仓库:git push <REMOTENAME> <BRANCHNAME>。例如:

    1
    2
    3
    4
    5
    $ git add .								# 添加待提交的代码到本地库,.可以替换为指定的代码文件或文件夹

    $ git commit -m 'definition message' # 提交本地库代码,并附加提交的信息

    $ git push origin master # 推送代码到远程仓库:origin,分支:master
    • 不建议使用 git push 这种模糊的命令。
  • s

Gitlab 创建分支

  • 创建新分支:

    1

  • 切换分支:

  • 查看分支:

本文参考

CentOS 安装 Ceph

节点规划

  • 各节点规划:

    主机名 ip 磁盘 角色
    hadoop102 192.168.10.102 系统盘:sda
    osd盘:sdb
    cephadm,monitor,mgr,rgw,mds,osd,nfs
    hadoop103 192.168.10.103 系统盘:sda
    osd盘:sdb
    monitor,mgr,rgw,mds,osd,nfs
    hadoop104 192.168.10.104 系统盘:sda
    osd盘:sdb
    monitor,mgr,rgw,mds,osd,nfs
  • 各节点内核版本:

    1
    2
    [root@hadoop102 opt]# uname -r
    3.10.0-1160.49.1.el7.x86_64
  • 各节点操作系统版本:

    1
    2
    [root@hadoop102 opt]# cat /etc/redhat-release
    CentOS Linux release 7.9.2009 (Core)
  • 各节点配置 CentOS 7 yum 阿里云镜像源:

    1
    2
    3
    4
    5
    [root@hadoop102 opt]# curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo
    # 清空缓存
    [root@hadoop102 opt]# yum clean cache
    # 生成缓存
    [root@hadoop102 opt]# yum makecache
    • 执行命令 curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo,会把 Centos-7.repo 下载到 /etc/yum.repos.d/ 目录下,如果该目录下有 CentOS-Base.repo,则会自动覆盖。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      [root@hadoop102 opt]# ll /etc/yum.repos.d/
      总用量 56
      -rw-r--r--. 1 root root 2523 12月 21 14:16 CentOS-Base.repo # yum源
      -rw-r--r--. 1 root root 1309 11月 23 2020 CentOS-CR.repo
      -rw-r--r--. 1 root root 649 11月 23 2020 CentOS-Debuginfo.repo
      -rw-r--r--. 1 root root 314 11月 23 2020 CentOS-fasttrack.repo
      -rw-r--r--. 1 root root 630 11月 23 2020 CentOS-Media.repo
      -rw-r--r--. 1 root root 1331 11月 23 2020 CentOS-Sources.repo
      -rw-r--r--. 1 root root 8515 11月 23 2020 CentOS-Vault.repo
      -rw-r--r--. 1 root root 616 11月 23 2020 CentOS-x86_64-kernel.repo
      -rw-r--r--. 1 root root 477 12月 21 15:38 ceph.repo # ceph源
      -rw-r--r--. 1 root root 2081 12月 20 12:37 docker-ce.repo # docker源
      -rw-r--r--. 1 root root 1358 9月 5 01:37 epel.repo
      -rw-r--r--. 1 root root 1457 9月 5 01:37 epel-testing.repo
  • 各节点更新 yum 包(生产环境中此步操作需慎重,看自己情况,学习的话随便搞,这个命令不是必须执行的):

    1
    2
    [root@hadoop102 opt]# yum -y update
    [root@hadoop102 opt]# yum -y upgrade
    • yum -y update:升级所有包,也升级软件和系统内核。
    • yum -y upgrade:升级所有包,但不升级软件和系统内核。
  • 各节点配置主机名:

    1
    2
    3
    [root@hadoop102 opt]# vim /etc/hostname
    [root@hadoop102 opt]# cat /etc/hostname
    hadoop102
  • 各节点配置 host 解析:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    [root@hadoop102 opt]# vim /etc/hosts
    [root@hadoop102 opt]# cat /etc/hosts
    127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
    ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6

    192.168.10.99 centos7
    192.168.10.100 hadoop100
    192.168.10.101 hadoop101
    192.168.10.102 hadoop102
    192.168.10.103 hadoop103
    192.168.10.104 hadoop104
    192.168.10.105 hadoop105
    192.168.10.106 hadoop106
    192.168.10.107 hadoop107
    192.168.10.108 hadoop108

关闭防火墙

  • 关闭防火墙:

    1
    2
    3
    [root@hadoop102 xisun]# systemctl stop firewalld.service
    [root@hadoop102 xisun]# firewall-cmd --state
    not running
  • 关闭防火墙开机自启:

    1
    2
    3
    4
    5
    6
    [root@hadoop102 xisun]# systemctl disable firewalld.service 
    Removed symlink /etc/systemd/system/multi-user.target.wants/firewalld.service.
    Removed symlink /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.
    # 查看防火墙是否开机自启
    [root@hadoop102 opt]# systemctl list-unit-files | grep firewalld.service
    firewalld.service disabled

SSH 免密登录

服务器时间同步

  • 在 Linux 系统中,可以通过 ntpdate 和 ntpd 两种方式实现 NTP 时间同步,ntpdate 为断点更新,ntpd 为步进式地逐渐调整时间。对于新服务器,可以使用 ntpdate 同步时间,对于已经承载有运行中业务的服务器,建议使用 ntpd 同步时间。
  • 直接同步:使用 ntpdate 命令进行同步,直接进行时间变更。如果服务器上存在一个 12 点运行的任务,当前服务器时间是 13 点,但标准时间时 11 点,使用此命令可能会造成任务重复执行。因此使用 ntpdate 同步可能会引发风险,该命令也多用于配置时钟同步服务时第一次同步时间时使用。
  • 平滑同步:使用 ntpd 进行时钟同步,可以保证一个时间不经历两次,它每次同步时间的偏移量不会太陡,是慢慢来的,这正因为这样,ntpd 平滑同步可能耗费的时间比较长。

NTP 服务器配置

  • 寻找 NTP Server,https://www.ntppool.org/ 是 NTP 的官方网站,在这上面我们可以找到离我们城市最近的 NTP Server。NTP 建议我们为了保障时间的准确性,最少找两个 NTP Server。我们找到对应的中国 NTP Server:

    image-20211222150302860

  • 也可以在 http://www.ntp.org.cn/ 网站查找 NTP Server,推荐使用域名,而非 IP 地址。后面的 NTP 服务器配置,以下图为准:

    image-20211222151324901

  • 设置时区:

    1
    2
    3
    4
    5
    # 设置东八区
    [root@hadoop102 opt]# timedatectl set-timezone Asia/Shanghai
    # 查看时区
    [root@hadoop102 opt]# timedatectl status | grep 'Time zone'
    Time zone: Asia/Shanghai (CST, +0800)
  • 检查系统是否安装了 NTP 服务:

    1
    2
    3
    4
    5
    [root@hadoop102 opt]# rpm -qa | grep ntp
    python-ntplib-0.3.2-1.el7.noarch
    ntpdate-4.2.6p5-29.el7.centos.2.x86_64
    ntp-4.2.6p5-29.el7.centos.2.x86_64
    fontpackages-filesystem-1.44-8.el7.noarch
  • 如果没有安装,使用下面的命令安装 ntp 和 ntpdate:

    1
    [root@hadoop102 opt]# yum -y install ntp ntpdate
  • 根据 NTP 的设置,如果你的系统时间比正确时间快,那么 NTP 是不会帮你调整的,所以要么你把时间设置回去,要么先做一个手动同步,使用下面的命令:

    1
    2
    [root@hadoop102 opt]# ntpdate cn.ntp.org.cn
    22 Dec 15:09:33 ntpdate[5303]: adjust time server 114.67.237.130 offset -0.010511 sec
  • 配置 NTP 服务器(设定 hadoop102 为 NTP 服务器),NTP 服务器主配置文件 /etc/ntp.conf,配置前做好备份:

    1
    2
    3
    [root@hadoop102 opt]# mkdir /home/backup
    [root@hadoop102 opt]# cp /etc/ntp.conf /home/backup/
    [root@hadoop102 opt]# mv /home/backup/ntp.conf /home/backup/ntp.conf.bak
  • 配置 NTP 服务器端配置文件:

    1
    [root@hadoop102 opt]# vim /etc/ntp.conf

    image-20211222154745752

    • restrict 语法说明:

      image-20211222155420355

    • 如果服务器是内网,不能连接外网,则无法使用网络 NTP Server,此时可以将本机作为 NTP Server,按如下方法配置:

      image-20211222155356339

  • ntp 服务,默认只会同步系统时间。如果想要让 ntp 同时同步硬件时间,可以在 /etc/sysconfig/ntpd 文件中,添加 SYNC_HWCLOCK=yes,这样,就可以让硬件时间与系统时间一起同步:

    1
    [root@hadoop102 opt]# vim /etc/sysconfig/ntpd

    image-20211223154742836

  • 启动 NTP 服务并设置开机自动启动。(Linux 防火墙需要关闭,否则会阻止 NTP 服务端口,NTP 服务默认端口 123)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    # 启动ntp服务
    [root@hadoop102 opt]# systemctl start ntpd
    # 查看ntp服务是否启动
    [root@hadoop102 opt]# systemctl status ntpd
    ● ntpd.service - Network Time Service
    Loaded: loaded (/usr/lib/systemd/system/ntpd.service; disabled; vendor preset: disabled)
    Active: active (running) since 三 2021-12-22 16:00:12 CST; 1min 27s ago
    Process: 5883 ExecStart=/usr/sbin/ntpd -u ntp:ntp $OPTIONS (code=exited, status=0/SUCCESS)
    Main PID: 5884 (ntpd)
    Tasks: 1
    CGroup: /system.slice/ntpd.service
    └─5884 /usr/sbin/ntpd -u ntp:ntp -g

    12月 22 16:00:13 hadoop102 ntpd[5884]: Listen and drop on 1 v6wildcard :: UDP 123
    12月 22 16:00:13 hadoop102 ntpd[5884]: Listen normally on 2 lo 127.0.0.1 UDP 123
    12月 22 16:00:13 hadoop102 ntpd[5884]: Listen normally on 3 ens33 192.168.10.102 UDP 123
    12月 22 16:00:13 hadoop102 ntpd[5884]: Listen normally on 4 virbr0 192.168.122.1 UDP 123
    12月 22 16:00:13 hadoop102 ntpd[5884]: Listen normally on 5 lo ::1 UDP 123
    12月 22 16:00:13 hadoop102 ntpd[5884]: Listen normally on 6 ens33 fe80::ac1e:7fe1:a566:2670 UDP 123
    12月 22 16:00:13 hadoop102 ntpd[5884]: Listening on routing socket on fd #23 for interface updates
    12月 22 16:00:13 hadoop102 ntpd[5884]: 0.0.0.0 c016 06 restart
    12月 22 16:00:13 hadoop102 ntpd[5884]: 0.0.0.0 c012 02 freq_set kernel 0.000 PPM
    12月 22 16:00:13 hadoop102 ntpd[5884]: 0.0.0.0 c011 01 freq_not_set
    # 查看ntpd端口
    [root@hadoop102 opt]# netstat -ln | grep 123
    udp 0 0 192.168.122.1:123 0.0.0.0:*
    udp 0 0 192.168.10.102:123 0.0.0.0:*
    udp 0 0 127.0.0.1:123 0.0.0.0:*
    udp 0 0 0.0.0.0:123 0.0.0.0:*
    udp6 0 0 fe80::ac1e:7fe1:a56:123 :::*
    udp6 0 0 ::1:123 :::*
    udp6 0 0 :::123 :::*
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 查看ntp服务是否开机启动
    [root@hadoop102 opt]# systemctl list-unit-files | grep ntpd
    ntpd.service disabled
    ntpdate.service disabled
    # 设置开机启动ntp服务
    [root@hadoop102 opt]# systemctl enable ntpd
    Created symlink from /etc/systemd/system/multi-user.target.wants/ntpd.service to /usr/lib/systemd/system/ntpd.service.
    # 确认ntp服务开机启动设置成功
    [root@hadoop102 opt]# systemctl list-unit-files | grep ntpd
    ntpd.service enabled
    ntpdate.service disabled
    • 如果是重启 ntpd 服务,使用下面的命令:

      1
      [root@hadoop102 opt]# systemctl restart ntpd
  • 查看 NTP 服务器与外部 NTP 服务器同步情况:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 静态查看
    [root@hadoop102 opt]# ntpq -p
    remote refid st t when poll reach delay offset jitter
    ==============================================================================
    2001:da8:9000:: .STEP. 16 - - 512 0 0.000 0.000 0.000
    *202.118.1.130 .PTP. 1 u 14 64 277 39.772 -39.060 5.282

    # 动态查看,一般ntp启动后,需要等5~10分钟左右,NTP服务器才会与外部NTP服务器同步
    [root@hadoop102 opt]# watch ntpq -p

    image-20211222162602332

    • remote:即网络 NTP 服务器的 IP 或主机名称。注意最左边的符号,如果有 +,则代表目前正在作用中的上层 NTP 服务器;如果是 *,则表示也有连上线,不过是作为次要联机的 NTP 服务器。
    • refid:参考的上一层 NTP 服务器的地址。
    • st:即 stratum 阶层,值越小表示 NTP Server 的精准度越高。
    • when:几秒前曾做过时间同步更新的操作。
    • poll:每隔多少毫秒与 NTP Server 同步一次。
    • reach:已经向上层 NTP 服务器要求更新的次数。
    • delay:网络传输过程中延迟的时间。
    • offset:时间补偿的结果。
    • jitter:Linux 系统时间与 BIOS 硬件时间的差异时间。
  • 查看系统时间和硬件时间:

    1
    2
    3
    4
    5
    6
    # 系统时间
    [root@hadoop102 opt]# date
    2021年 12月 23日 星期四 16:28:10 CST
    # 硬件时间
    [root@hadoop102 opt]# hwclock --show
    2021年12月23日 星期四 16时28分15秒 -0.631618 秒

客户端配置

  • 设置时区:

    1
    2
    3
    4
    5
    # 设置东八区
    [root@hadoop103 opt]# timedatectl set-timezone Asia/Shanghai
    # 查看时区
    [root@hadoop103 opt]# timedatectl status | grep 'Time zone'
    Time zone: Asia/Shanghai (CST, +0800)
  • 客户端向 NTP 服务器(192.168.10.102)更新时间时,客户端不需要开启 NTP 服务:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    [root@hadoop103 opt]# systemctl stop ntpd
    [root@hadoop103 opt]# systemctl status ntpd
    ● ntpd.service - Network Time Service
    Loaded: loaded (/usr/lib/systemd/system/ntpd.service; disabled; vendor preset: disabled)
    Active: inactive (dead)

    12月 23 11:11:08 hadoop103 ntpd[18278]: Listening on routing socket on fd #24 for interface updates
    12月 23 11:11:10 hadoop103 ntpd[18278]: 0.0.0.0 c016 06 restart
    12月 23 11:11:10 hadoop103 ntpd[18278]: 0.0.0.0 c012 02 freq_set kernel 0.000 PPM
    12月 23 11:11:10 hadoop103 ntpd[18278]: 0.0.0.0 c011 01 freq_not_set
    12月 23 11:11:16 hadoop103 ntpd[18278]: 0.0.0.0 c61c 0c clock_step -3.147226 s
    12月 23 11:11:13 hadoop103 ntpd[18278]: 0.0.0.0 c614 04 freq_mode
    12月 23 11:11:14 hadoop103 ntpd[18278]: 0.0.0.0 c618 08 no_sys_peer
    12月 23 11:16:42 hadoop103 ntpd[18278]: ntpd exiting on signal 15
    12月 23 11:16:42 hadoop103 systemd[1]: Stopping Network Time Service...
    12月 23 11:16:42 hadoop103 systemd[1]: Stopped Network Time Service.
  • 客户端向 NTP 服务器(192.168.10.102)进行时间同步:

    1
    2
    [root@hadoop103 opt]# ntpdate -u 192.168.10.102
    23 Dec 11:16:57 ntpdate[18349]: adjust time server 192.168.10.102 offset -0.003982 sec
  • 设置 ntpdate 每次同步系统时间之后,也一并同步硬件时间:

    1
    [root@hadoop103 opt]# vim /etc/sysconfig/ntpdate
    • 修改 ntpdate 文件最后一行 SYNC_HWCLOCK=noSYNC_HWCLOCK=yes

      image-20211223115230538

  • 设置客户端定时向 NTP 服务器(192.168.10.102)进行时间同步:

    1
    [root@hadoop103 opt]# vim /etc/crontab
    • 向 crontab 文件中添加配置,每天早晨 6 点同步一次时间:

      image-20211223134042762

  • 重启 crond 服务:

    1
    [root@hadoop103 opt]# systemctl restart crond.service
  • 查看 crond 服务执行情况:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    [root@hadoop103 opt]# systemctl status crond.service 
    ● crond.service - Command Scheduler
    Loaded: loaded (/usr/lib/systemd/system/crond.service; enabled; vendor preset: enabled)
    Active: active (running) since 四 2021-12-23 13:41:42 CST; 4min 33s ago
    Main PID: 20442 (crond)
    Tasks: 1
    Memory: 644.0K
    CGroup: /system.slice/crond.service
    └─20442 /usr/sbin/crond -n

    12月 23 13:41:42 hadoop103 systemd[1]: Started Command Scheduler.
    12月 23 13:41:42 hadoop103 crond[20442]: (CRON) INFO (RANDOM_DELAY will be scaled with factor 33% if used.)
    12月 23 13:41:43 hadoop103 crond[20442]: (CRON) INFO (running with inotify support)
    12月 23 13:41:43 hadoop103 crond[20442]: (CRON) INFO (@reboot jobs will be run at computer's startup.)
  • 查看系统时间和硬件时间:

    1
    2
    3
    4
    5
    6
    # 系统时间
    [root@hadoop103 opt]# date
    2021年 12月 23日 星期四 16:30:22 CST
    # 硬件时间
    [root@hadoop103 opt]# hwclock
    2021年12月23日 星期四 16时30分29秒 -1.020610 秒

参考

安装 Python3

  • Ceph 的 Octopus 版本需要 Python3 支持。

  • 各节点检查是否有 GCC:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    # 查看gcc版本
    [root@hadoop101 software]# gcc --version
    bash: gcc: 未找到命令...
    # 安装gcc
    [root@hadoop101 software]# yum -y install gcc
    已加载插件:fastestmirror, langpacks
    Loading mirror speeds from cached hostfile
    Could not get metalink https://mirrors.fedoraproject.org/metalink?repo=epel-7&arch=x86_64&infra=stock&content=centos error was
    14: curl#7 - "Failed to connect to 2406:da18:39f:a01:35a2:d9e9:8164:a209: 网络不可达"
    * base: mirrors.aliyun.com
    * epel: mirror.sjtu.edu.cn
    * extras: mirrors.aliyun.com
    * updates: mirrors.aliyun.com
    正在解决依赖关系
    --> 正在检查事务
    ---> 软件包 gcc.x86_64.0.4.8.5-44.el7 将被 安装
    --> 正在处理依赖关系 cpp = 4.8.5-44.el7,它被软件包 gcc-4.8.5-44.el7.x86_64 需要
    --> 正在处理依赖关系 glibc-devel >= 2.2.90-12,它被软件包 gcc-4.8.5-44.el7.x86_64 需要
    --> 正在检查事务
    ---> 软件包 cpp.x86_64.0.4.8.5-44.el7 将被 安装
    ---> 软件包 glibc-devel.x86_64.0.2.17-325.el7_9 将被 安装
    --> 正在处理依赖关系 glibc-headers = 2.17-325.el7_9,它被软件包 glibc-devel-2.17-325.el7_9.x86_64 需要
    --> 正在处理依赖关系 glibc-headers,它被软件包 glibc-devel-2.17-325.el7_9.x86_64 需要
    --> 正在检查事务
    ---> 软件包 glibc-headers.x86_64.0.2.17-325.el7_9 将被 安装
    --> 正在处理依赖关系 kernel-headers >= 2.2.1,它被软件包 glibc-headers-2.17-325.el7_9.x86_64 需要
    --> 正在处理依赖关系 kernel-headers,它被软件包 glibc-headers-2.17-325.el7_9.x86_64 需要
    --> 正在检查事务
    ---> 软件包 kernel-headers.x86_64.0.3.10.0-1160.49.1.el7 将被 安装
    --> 解决依赖关系完成

    依赖关系解决

    ========================================================================================================================================================================================================
    Package 架构 版本 源 大小
    ========================================================================================================================================================================================================
    正在安装:
    gcc x86_64 4.8.5-44.el7 base 16 M
    为依赖而安装:
    cpp x86_64 4.8.5-44.el7 base 5.9 M
    glibc-devel x86_64 2.17-325.el7_9 updates 1.1 M
    glibc-headers x86_64 2.17-325.el7_9 updates 691 k
    kernel-headers x86_64 3.10.0-1160.49.1.el7 updates 9.0 M

    事务概要
    ========================================================================================================================================================================================================
    安装 1 软件包 (+4 依赖软件包)

    总计:33 M
    总下载量:1.1 M
    安装大小:59 M
    Downloading packages:
    No Presto metadata available for updates
    glibc-devel-2.17-325.el7_9.x86_64.rpm | 1.1 MB 00:00:00
    Running transaction check
    Running transaction test
    Transaction test succeeded
    Running transaction
    正在安装 : cpp-4.8.5-44.el7.x86_64 1/5
    正在安装 : kernel-headers-3.10.0-1160.49.1.el7.x86_64 2/5
    正在安装 : glibc-headers-2.17-325.el7_9.x86_64 3/5
    正在安装 : glibc-devel-2.17-325.el7_9.x86_64 4/5
    正在安装 : gcc-4.8.5-44.el7.x86_64 5/5
    验证中 : gcc-4.8.5-44.el7.x86_64 1/5
    验证中 : glibc-headers-2.17-325.el7_9.x86_64 2/5
    验证中 : kernel-headers-3.10.0-1160.49.1.el7.x86_64 3/5
    验证中 : glibc-devel-2.17-325.el7_9.x86_64 4/5
    验证中 : cpp-4.8.5-44.el7.x86_64 5/5

    已安装:
    gcc.x86_64 0:4.8.5-44.el7

    作为依赖被安装:
    cpp.x86_64 0:4.8.5-44.el7 glibc-devel.x86_64 0:2.17-325.el7_9 glibc-headers.x86_64 0:2.17-325.el7_9 kernel-headers.x86_64 0:3.10.0-1160.49.1.el7

    完毕!
    [root@hadoop102 software]# gcc --version
    gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44)
    Copyright © 2015 Free Software Foundation, Inc.
    本程序是自由软件;请参看源代码的版权声明。本软件没有任何担保;
    包括没有适销性和某一专用目的下的适用性担保。
  • 各节点下载相应版本的 Python 包:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    [root@hadoop101 software]# wget https://www.python.org/ftp/python/3.9.9/Python-3.9.9.tar.xz
    --2021-12-24 10:16:02-- https://www.python.org/ftp/python/3.9.9/Python-3.9.9.tar.xz
    正在解析主机 www.python.org (www.python.org)... 151.101.72.223
    正在连接 www.python.org (www.python.org)|151.101.72.223|:443... 已连接。
    已发出 HTTP 请求,正在等待回应... 200 OK
    长度:19144372 (18M) [application/octet-stream]
    正在保存至: “Python-3.9.9.tar.xz”

    100%[==============================================================================================================================================================>] 19,144,372 7.20MB/s 用时 2.5s

    2021-12-24 10:16:05 (7.20 MB/s) - 已保存 “Python-3.9.9.tar.xz” [19144372/19144372])

    [root@hadoop101 software]# ls -l
    总用量 18696
    -rw-r--r--. 1 root root 19144372 11月 16 02:49 Python-3.9.9.tar.xz
  • 解压到指定目录:

    1
    2
    3
    4
    [root@hadoop101 software]# tar -xvJf Python-3.9.9.tar.xz -C /opt/module/
    [root@hadoop101 software]# ls -l /opt/module/
    总用量 2
    drwxrwxr-x. 16 xisun xisun 4096 11月 16 02:05 Python-3.9.9
  • 各节点安装依赖,否则会报错:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    [root@hadoop101 software]# yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel
    ...
    已安装:
    bzip2-devel.x86_64 0:1.0.6-13.el7 gdbm-devel.x86_64 0:1.10-8.el7 libdb4-devel.x86_64 0:4.8.30-13.el7 libpcap-devel.x86_64 14:1.5.3-12.el7 ncurses-devel.x86_64 0:5.9-14.20130511.el7_4
    openssl-devel.x86_64 1:1.0.2k-22.el7_9 readline-devel.x86_64 0:6.2-11.el7 sqlite-devel.x86_64 0:3.7.17-8.el7_7.1 tk-devel.x86_64 1:8.5.13-6.el7 xz-devel.x86_64 0:5.2.2-1.el7
    zlib-devel.x86_64 0:1.2.7-19.el7_9

    作为依赖被安装:
    expat-devel.x86_64 0:2.1.0-12.el7 fontconfig-devel.x86_64 0:2.13.0-4.3.el7 freetype-devel.x86_64 0:2.8-14.el7_9.1 keyutils-libs-devel.x86_64 0:1.5.8-3.el7 krb5-devel.x86_64 0:1.15.1-51.el7_9
    libXft-devel.x86_64 0:2.3.2-2.el7 libXrender-devel.x86_64 0:0.9.10-1.el7 libcom_err-devel.x86_64 0:1.42.9-19.el7 libdb4.x86_64 0:4.8.30-13.el7 libpng-devel.x86_64 2:1.5.13-8.el7
    libselinux-devel.x86_64 0:2.5-15.el7 libsepol-devel.x86_64 0:2.5-10.el7 libuuid-devel.x86_64 0:2.23.2-65.el7_9.1 libverto-devel.x86_64 0:0.2.5-4.el7 pcre-devel.x86_64 0:8.32-17.el7
  • 各节点安装 Python3:

    1
    2
    3
    4
    5
    6
    7
    # 指定安装的路径,不指定的话,安装过程中可能软件所需要的文件复制到其他不同目录,删除软件很不方便,复制软件也不方便
    [root@hadoop101 software]# mkdir /usr/local/python3
    [root@hadoop101 software]# cd /opt/module/Python-3.9.9/
    # 配置,指定安装目录
    [root@hadoop101 Python-3.9.9]# ./configure --prefix=/usr/local/python3
    # 编译安装
    [root@hadoop101 Python-3.9.9]# make && make install
    • 在安装过程中,如果出现错误,在重新安装之前先执行下面的命令,清空缓存:

      1
      [root@hadoop101 Python-3.9.9]# make clean
  • 各节点添加软链接:

    1
    2
    [root@hadoop102 Python-3.9.9]# ln -s /usr/local/python3/bin/python3 /usr/bin/python3
    [root@hadoop102 Python-3.9.9]# ln -s /usr/local/python3/bin/pip3 /usr/bin/pip3
    • 软链接位置定为 /usr/bin/python3/usr/bin/pip3
  • 各节点查看版本:

    1
    2
    3
    4
    [root@hadoop102 Python-3.9.9]# python3 --version
    Python 3.9.9
    [root@hadoop102 Python-3.9.9]# pip3 --version
    pip 21.2.4 from /usr/local/python3/lib/python3.9/site-packages/pip (python 3.9)

安装 Docker

  • Cephadm 基于容器运行所有 Ceph 组件,各节点需要安装 Docker 或 Podman,此处安装 Docker。

  • 各节点卸载旧版本 Docker(如果之前有安装过):

    1
    [root@hadoop102 opt]# yum remove docker docker-client docker-client-latest docker-common docker-latest docker-latest-logrotate docker-logrotate docker-engine
  • 各节点安装需要的软件包,yum-util 提供 yum-config-manager 功能:

    1
    [root@hadoop102 opt]# yum install -y yum-utils
  • 各节点设置 yum 的 Docker 源(下面两个都可以用):

    1
    2
    3
    4
    5
    # 中央仓库
    [root@hadoop102 opt]# yum-config-manager --add-repo http://download.docker.com/linux/centos/docker-ce.repo

    # 阿里仓库
    [root@hadoop102 opt]# yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
  • 各节点安装最新版本 Docker:

    1
    [root@hadoop102 opt]# yum install docker-ce docker-ce-cli containerd.io
    • 安装特定版本:

      1
      2
      3
      4
      5
      # 查看不同版本
      [root@hadoop102 opt]# yum list docker-ce --showduplicates | sort -r

      # 安装特定版本
      [root@hadoop102 opt]# yum install docker-ce-<VERSION_STRING> docker-ce-cli-<VERSION_STRING> containerd.io
  • 各节点启动 Docker,并设置开机启动:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    # 启动
    [root@hadoop102 opt]# systemctl start docker
    # 查看docker版本
    [root@hadoop102 opt]# docker --version
    Docker version 20.10.12, build e91ed57
    # 开机启动
    [root@hadoop102 opt]# systemctl enable docker
    Created symlink from /etc/systemd/system/multi-user.target.wants/docker.service to /usr/lib/systemd/system/docker.service.
    # 查看docker是否开机启动
    [root@hadoop102 opt]# systemctl list-unit-files | grep docker
    docker.service enabled
    docker.socket disabled
  • 各节点测试:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    [root@hadoop102 opt]# docker run hello-world

    Hello from Docker!
    This message shows that your installation appears to be working correctly.

    To generate this message, Docker took the following steps:
    1. The Docker client contacted the Docker daemon.
    2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
    3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
    4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

    To try something more ambitious, you can run an Ubuntu container with:
    $ docker run -it ubuntu bash

    Share images, automate workflows, and more with a free Docker ID:
    https://hub.docker.com/

    For more examples and ideas, visit:
    https://docs.docker.com/get-started/
  • 参考:https://docs.docker.com/engine/install/centos/

安装 Cephadm

  • 各节点使用 curl 获取 Cephadm 独立脚本的最新版本:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    # 下载
    [root@hadoop102 opt]# curl --remote-name --location https://github.com/ceph/ceph/raw/octopus/src/cephadm/cephadm
    % Total % Received % Xferd Average Speed Time Time Time Current
    Dload Upload Total Spent Left Speed
    100 137 100 137 0 0 15 0 0:00:09 0:00:09 --:--:-- 18
    100 218k 100 218k 0 0 17210 0 0:00:12 0:00:12 --:--:-- 93775
    [root@hadoop102 opt]# ll
    总用量 220
    -rw-r--r--. 1 root root 223468 12月 26 15:42 cephadm
    drwx--x--x. 4 root root 28 12月 21 14:56 containerd
    drwxr-xr-x. 4 xisun xisun 46 12月 24 10:32 module
    drwxr-xr-x. 2 xisun xisun 33 12月 24 10:30 software
    # 赋权可执行
    [root@hadoop102 opt]# chmod +x cephadm
    [root@hadoop102 opt]# ll
    总用量 220
    -rwxr-xr-x. 1 root root 223468 12月 26 15:42 cephadm
    drwx--x--x. 4 root root 28 12月 21 14:56 containerd
    drwxr-xr-x. 4 xisun xisun 46 12月 24 10:32 module
    drwxr-xr-x. 2 xisun xisun 33 12月 24 10:30 software
    • 下载可能需要执行多次。
  • 各节点添加源信息,指定为 Octopus 版本:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    # 添加Ceph源,这个是官方源
    [root@hadoop102 opt]# ./cephadm add-repo --release octopus
    Writing repo to /etc/yum.repos.d/ceph.repo...
    Enabling EPEL...
    # 查看Ceph源信息
    [root@hadoop102 opt]# ll /etc/yum.repos.d/
    总用量 56
    -rw-r--r--. 1 root root 2523 12月 21 14:16 CentOS-Base.repo
    -rw-r--r--. 1 root root 1309 11月 23 2020 CentOS-CR.repo
    -rw-r--r--. 1 root root 649 11月 23 2020 CentOS-Debuginfo.repo
    -rw-r--r--. 1 root root 314 11月 23 2020 CentOS-fasttrack.repo
    -rw-r--r--. 1 root root 630 11月 23 2020 CentOS-Media.repo
    -rw-r--r--. 1 root root 1331 11月 23 2020 CentOS-Sources.repo
    -rw-r--r--. 1 root root 8515 11月 23 2020 CentOS-Vault.repo
    -rw-r--r--. 1 root root 616 11月 23 2020 CentOS-x86_64-kernel.repo
    -rw-r--r--. 1 root root 477 12月 26 15:49 ceph.repo # Ceph源
    -rw-r--r--. 1 root root 2081 12月 21 12:38 docker-ce.repo
    -rw-r--r--. 1 root root 1358 9月 5 01:37 epel.repo
    -rw-r--r--. 1 root root 1457 9月 5 01:37 epel-testing.repo
    [root@hadoop102 opt]# cat /etc/yum.repos.d/ceph.repo
    [Ceph]
    name=Ceph $basearch
    baseurl=https://download.ceph.com/rpm-octopus/el7/$basearch
    enabled=1
    gpgcheck=1
    gpgkey=https://download.ceph.com/keys/release.asc

    [Ceph-noarch]
    name=Ceph noarch
    baseurl=https://download.ceph.com/rpm-octopus/el7/noarch
    enabled=1
    gpgcheck=1
    gpgkey=https://download.ceph.com/keys/release.asc

    [Ceph-source]
    name=Ceph SRPMS
    baseurl=https://download.ceph.com/rpm-octopus/el7/SRPMS
    enabled=1
    gpgcheck=1
    gpgkey=https://download.ceph.com/keys/release.asc
    • 添加 Ceph 源可能需要执行多次,或重启。

    • 如果官方源下载较慢,可以使用阿里云 Ceph 源:

      image-20211227113311642

  • 各节点安装 Cephadm:

    1
    2
    [root@hadoop102 opt]# ./cephadm install
    Installing packages ['cephadm']...
  • 各节点验证 Cephadm 安装完成:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    [root@hadoop102 opt]# which cephadm
    /usr/sbin/cephadm
    [root@hadoop102 opt]# cephadm version
    Using recent ceph image quay.io/ceph/ceph@sha256:a2c23b6942f7fbc1e15d8cfacd6655a681fe0e44f288e4a158db22030b8d58e3
    ceph version 15.2.15 (2dfb18841cfecc2f7eb7eb2afd65986ca4d95985) octopus (stable)
    [root@hadoop102 opt]# cephadm --help
    usage: cephadm [-h] [--image IMAGE] [--docker] [--data-dir DATA_DIR] [--log-dir LOG_DIR] [--logrotate-dir LOGROTATE_DIR] [--unit-dir UNIT_DIR] [--verbose] [--timeout TIMEOUT] [--retry RETRY]
    [--env ENV] [--no-container-init]
    {version,pull,inspect-image,ls,list-networks,adopt,rm-daemon,rm-cluster,run,shell,enter,ceph-volume,unit,logs,bootstrap,deploy,check-host,prepare-host,add-repo,rm-repo,install,registry-login,gather-facts}
    ...

    Bootstrap Ceph daemons with systemd and containers.

    positional arguments:
    {version,pull,inspect-image,ls,list-networks,adopt,rm-daemon,rm-cluster,run,shell,enter,ceph-volume,unit,logs,bootstrap,deploy,check-host,prepare-host,add-repo,rm-repo,install,registry-login,gather-facts}
    sub-command
    version get ceph version from container
    pull pull latest image version
    inspect-image inspect local container image
    ls list daemon instances on this host
    list-networks list IP networks
    adopt adopt daemon deployed with a different tool
    rm-daemon remove daemon instance
    rm-cluster remove all daemons for a cluster
    run run a ceph daemon, in a container, in the foreground
    shell run an interactive shell inside a daemon container
    enter run an interactive shell inside a running daemon container
    ceph-volume run ceph-volume inside a container
    unit operate on the daemon's systemd unit
    logs print journald logs for a daemon container
    bootstrap bootstrap a cluster (mon + mgr daemons)
    deploy deploy a daemon
    check-host check host configuration
    prepare-host prepare a host for cephadm use
    add-repo configure package repository
    rm-repo remove package repository configuration
    install install ceph package(s)
    registry-login log host into authenticated registry
    gather-facts gather and return host related information (JSON format)

    optional arguments:
    -h, --help show this help message and exit
    --image IMAGE container image. Can also be set via the "CEPHADM_IMAGE" env var (default: None)
    --docker use docker instead of podman (default: False)
    --data-dir DATA_DIR base directory for daemon data (default: /var/lib/ceph)
    --log-dir LOG_DIR base directory for daemon logs (default: /var/log/ceph)
    --logrotate-dir LOGROTATE_DIR
    location of logrotate configuration files (default: /etc/logrotate.d)
    --unit-dir UNIT_DIR base directory for systemd units (default: /etc/systemd/system)
    --verbose, -v Show debug-level log messages (default: False)
    --timeout TIMEOUT timeout in seconds (default: None)
    --retry RETRY max number of retries (default: 10)
    --env ENV, -e ENV set environment variable (default: [])
    --no-container-init Do not run podman/docker with `--init` (default: True)
  • 为方便后续使用,各节点安装 ceph-common 包,里面包含了所有的 ceph 命令,其中包括 ceph,rbd,mount.ceph(用于安装 CephFS 文件系统)等:

    1
    2
    3
    4
    5
    6
    # 安装
    [root@hadoop102 opt]# cephadm install ceph-common
    Installing packages ['ceph-common']...
    # 确认可以使用
    [root@hadoop102 opt]# ceph -v
    ceph version 15.2.15 (2dfb18841cfecc2f7eb7eb2afd65986ca4d95985) octopus (stable)

创建 Ceph 新集群

  • 在 hadoop102 上创建一个可以被任何访问 Ceph 集群的主机访问的网络,指定 mon-ip,并将生成的配置文件写进 /etc/ceph 目录里:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    [root@hadoop102 opt]# cephadm bootstrap --mon-ip 192.168.10.102
    Verifying podman|docker is present...
    Verifying lvm2 is present...
    Verifying time synchronization is in place...
    Unit ntpd.service is enabled and running
    Repeating the final host check...
    podman|docker (/usr/bin/docker) is present
    systemctl is present
    lvcreate is present
    Unit ntpd.service is enabled and running
    Host looks OK
    Cluster fsid: 81b469b6-662d-11ec-b2eb-000c29c51d96
    Verifying IP 192.168.10.102 port 3300 ...
    Verifying IP 192.168.10.102 port 6789 ...
    Mon IP 192.168.10.102 is in CIDR network 192.168.10.0/24
    Pulling container image quay.io/ceph/ceph:v15...
    Extracting ceph user uid/gid from container image...
    Creating initial keys...
    Creating initial monmap...
    Creating mon...
    Waiting for mon to start...
    Waiting for mon...
    mon is available
    Assimilating anything we can from ceph.conf...
    Generating new minimal ceph.conf...
    Restarting the monitor...
    Setting mon public_network...
    Creating mgr...
    Verifying port 9283 ...
    Wrote keyring to /etc/ceph/ceph.client.admin.keyring
    Wrote config to /etc/ceph/ceph.conf
    Waiting for mgr to start...
    Waiting for mgr...
    mgr not available, waiting (1/10)...
    mgr not available, waiting (2/10)...
    mgr not available, waiting (3/10)...
    mgr not available, waiting (4/10)...
    mgr not available, waiting (5/10)...
    mgr is available
    Enabling cephadm module...
    Waiting for the mgr to restart...
    Waiting for Mgr epoch 5...
    Mgr epoch 5 is available
    Setting orchestrator backend to cephadm...
    Generating ssh key...
    Wrote public SSH key to to /etc/ceph/ceph.pub
    Adding key to root@localhost's authorized_keys...
    Adding host hadoop102...
    Deploying mon service with default placement...
    Deploying mgr service with default placement...
    Deploying crash service with default placement...
    Enabling mgr prometheus module...
    Deploying prometheus service with default placement...
    Deploying grafana service with default placement...
    Deploying node-exporter service with default placement...
    Deploying alertmanager service with default placement...
    Enabling the dashboard module...
    Waiting for the mgr to restart...
    Waiting for Mgr epoch 13...
    Mgr epoch 13 is available
    Generating a dashboard self-signed certificate...
    Creating initial admin user...
    Fetching dashboard port number...
    Ceph Dashboard is now available at:

    URL: https://hadoop102:8443/
    User: admin
    Password: v5b0064nc4

    You can access the Ceph CLI with:

    sudo /usr/sbin/cephadm shell --fsid 81b469b6-662d-11ec-b2eb-000c29c51d96 -c /etc/ceph/ceph.conf -k /etc/ceph/ceph.client.admin.keyring

    Please consider enabling telemetry to help improve Ceph:

    ceph telemetry on

    For more information see:

    https://docs.ceph.com/docs/master/mgr/telemetry/

    Bootstrap complete.
    • 该命令执行如下操作:

      • 在本地主机上为新集群创建 monitor 和 manager daemon 守护程序。

      • 为 Ceph 集群生成一个新的 SSH 密钥,并将其添加到 root 用户的 /root/.ssh/authorized_keys 文件中。

        1
        2
        3
        4
        5
        [root@hadoop102 opt]# cat /root/.ssh/authorized_keys 
        ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDkEXI7QySiz2VlLNrYW7OypfS9ZtMXS2h725W+pTpv71e4z6YjjxIpt6DvggtuD/UhktL1HxIvAREYKQ5vNYhGuV9jHI4VU+y4evpPEMR8GJ8OTlhfwhwovsik4TfYW0SmHUw01bxBpH2BjX4u/dSpyN9KG9710WXTIGJQ6zbHjxPg0JQX4C1KLuaD1WMVo1z6xscRGs7RAZ7sYAIQdf8LOI4IYVzO1n66NJNY4vpAJx1wCLajoGN0689Do42jX6t0/Qn6RGddXermTbbPW+hcD20pRIHO4f9VCQwqSNdcEVDUS74VMJRuOxd+N0uAxvHz8lTdCSfUnfPeKEvEH+cr root@hadoop102
        ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC9lRXTDUhUKdfu5PznYhoFsJFw1n6qXKJXCgFmuFCBB3T75na5xSgGbUEcQ5HYIWk8ywjynGjzCQMlyG+DTaQVvxOcpNNyKv57sm2quegFzu+c86Q726npspidr8Knl7dJALXF3q8k3eQrscWrRyJEA6vh1PikrNtDwzdB92WoYkAH5dJj3MxuHPJXoX+UbOZ8jWV7dARBT2LXFiS09bJy+7P2QZSa5BVirWFzoRjAD4JlEeaW2OPcujHTe+IjHXale4fjNh0tUDtteMRcwLnfMpTl6M7qgpUXm/IrlJHfAqtPmYPQUiDCVFQ9wntTeF5ph6WM9qk/2BJni5BX44VH root@hadoop103
        ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsgI3CnXcTkQkSHxvhGvBGY1Fh7gaIXqhI5n7rtEM3fmJ2k8/VoWjLwxE1xqSm7tsGufabIhpLdUJBfj4cpqa+PazgSVF59cPlYArp115YFOCGWv2z9tZ5Cq70i9EEfNCyhWNhNUEd9cqiei/G1by4yQzOwvpiuDhiGlDtQk3pRGvvdjGQV3YVDVjDv6JG3QQkxPY+oYQFjDBy+usGEvcuIFDJXmS4hlB8xDMZCw8R0gcvBEnA9RxIIb0N0jLf0uZt0varFZqlguwJJdT6nBCWJ+NYxu5aggX7PGgHB+F97gCoIRusqjT/scoS+jSK8yx4WzJ6ZfCp1wQEXJ+XgrbX root@hadoop104
        ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDCfFd837abQYj+trazR8y5OSOc7ET+vzn0o6pR+JF3N1knD5JGKXyB0umMsYehwcU55XkMARHRS+jothz0PAqWUpdV73pVZyy+Nxhu/5rySf+NiaoYd8IYAtcgbw174E5deudPF5Ac7IIUxJAgPxEb/NnrpYEPFLHg31ZCKUvzHkEbP9I1iMgM9LtKN3M/aAbaHY2Pd046joVhOo7DsIlYyd147X1MgFhwTeVThpu+zdjPwNoenQGIhrH1J46thBL8TyTC0Wjui5YVwim9Nxoet7E46BiuqrAS6TBvLOTAZlD/g2UB+6NbGYdQKpOs8k2XQqrEBtPB4Wo/hZ0efg8gvCs4AaOqICaMOUt52lfJHInnsycB99nxh95sLDhkHfQIlqTEvGPQDiJVU8tPS5mo7+oeqpCTsvnIINQTMlCtA6eR6kmNumCdSpwbCMkuwVxHjGgNxMy3ykBRItU0vH9mAv/5OxyfjKQutELHQn+5fb5v0lrDq/WZ60jMJYGpTh8= ceph-81b469b6-662d-11ec-b2eb-000c29c51d96
      • 将与新群集进行通信所需的最小配置文件保存到 /etc/ceph/ceph.conf

      • /etc/ceph/ceph.client.admin.keyring 写入 client.admin 管理 secret key 的副本(特权!)。

      • 将 public key 的副本写入 /etc/ceph/ceph.pub

    • 查看当前配置文件:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      [root@hadoop102 opt]# ll /etc/ceph/
      总用量 12
      -rw-------. 1 root root 63 12月 26 17:23 ceph.client.admin.keyring
      -rw-r--r--. 1 root root 179 12月 26 17:23 ceph.conf
      -rw-r--r--. 1 root root 595 12月 26 17:24 ceph.pub
      [root@hadoop102 opt]# cat /etc/ceph/ceph.conf
      # minimal ceph.conf for 81b469b6-662d-11ec-b2eb-000c29c51d96
      [global]
      fsid = 81b469b6-662d-11ec-b2eb-000c29c51d96
      mon_host = [v2:192.168.10.102:3300/0,v1:192.168.10.102:6789/0]
    • 查看拉取的镜像和启动的容器:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      # 安装之前
      [root@hadoop104 opt]# docker images
      REPOSITORY TAG IMAGE ID CREATED SIZE
      hello-world latest feb5d9fea6a5 3 months ago 13.3kB
      [root@hadoop104 opt]# docker ps -a
      CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
      72c655a613fc hello-world "/hello" 41 hours ago Created gallant_cohen
      de6240f04135 hello-world "/hello" 5 days ago Exited (0) 5 days ago priceless_nash

      # 安装之后
      [root@hadoop102 opt]# docker images
      REPOSITORY TAG IMAGE ID CREATED SIZE
      quay.io/ceph/ceph v15 3437f7bed968 2 months ago 1.08GB # Ceph组件
      hello-world latest feb5d9fea6a5 3 months ago 13.3kB
      quay.io/ceph/ceph-grafana 6.7.4 557c83e11646 4 months ago 486MB # Ceph组件
      quay.io/prometheus/prometheus v2.18.1 de242295e225 19 months ago 140MB # Ceph组件
      quay.io/prometheus/alertmanager v0.20.0 0881eb8f169f 2 years ago 52.1MB # Ceph组件
      quay.io/prometheus/node-exporter v0.18.1 e5a616e4b9cf 2 years ago 22.9MB # Ceph组件
      [root@hadoop102 opt]# docker ps -a
      CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
      5e62fe89c60f quay.io/ceph/ceph-grafana:6.7.4 "/bin/sh -c 'grafana…" 45 minutes ago Up 45 minutes ceph-81b469b6-662d-11ec-b2eb-000c29c51d96-grafana.hadoop102 # Ceph组件
      fcf1abbde49f quay.io/prometheus/alertmanager:v0.20.0 "/bin/alertmanager -…" 45 minutes ago Up 45 minutes ceph-81b469b6-662d-11ec-b2eb-000c29c51d96-alertmanager.hadoop102 # Ceph组件
      ee65841914dd quay.io/prometheus/prometheus:v2.18.1 "/bin/prometheus --c…" 45 minutes ago Up 45 minutes ceph-81b469b6-662d-11ec-b2eb-000c29c51d96-prometheus.hadoop102 # Ceph组件
      b248a474c78e quay.io/prometheus/node-exporter:v0.18.1 "/bin/node_exporter …" 46 minutes ago Up 46 minutes ceph-81b469b6-662d-11ec-b2eb-000c29c51d96-node-exporter.hadoop102 # Ceph组件
      31dd5f2a7479 quay.io/ceph/ceph:v15 "/usr/bin/ceph-crash…" 50 minutes ago Up 50 minutes ceph-81b469b6-662d-11ec-b2eb-000c29c51d96-crash.hadoop102 # Ceph组件
      443c33b517e0 quay.io/ceph/ceph:v15 "/usr/bin/ceph-mgr -…" 52 minutes ago Up 52 minutes ceph-81b469b6-662d-11ec-b2eb-000c29c51d96-mgr.hadoop102.kwrjaw # Ceph组件
      895542296c01 quay.io/ceph/ceph:v15 "/usr/bin/ceph-mon -…" 52 minutes ago Up 52 minutes ceph-81b469b6-662d-11ec-b2eb-000c29c51d96-mon.hadoop102 # Ceph组件
      7213f1a0510a hello-world "/hello" 27 hours ago Exited (0) 27 hours ago hungry_driscoll
      ad4e221a918b hello-world "/hello" 5 days ago Exited (0) 5 days ago kind_elbakyan
      • 此时已经运行了以下组件:
        • ceph-mgr:Ceph 管理程序。
        • ceph-monitor:Ceph 监视器。
        • ceph-crash:崩溃数据收集模块。
        • prometheus:prometheus 监控组件。
        • grafana:监控数据展示 dashboard。
        • alertmanager:prometheus 告警组件。
        • node_exporter:prometheus 节点数据收集组件。
    • 参阅下面的一些对某些用户可能有用的选项,或者运行 cephadm bootstrap -h 命令查看所有可用选项:

      • 为了方便起见,Bootstrap 会将访问新集群所需的文件写入 /etc/ceph,以便主机上安装的任何 Ceph 软件包(例如,访问命令行界面)都可以轻松找到它们。
      • 但是使用 cephadm 部署的 daemon 容器根本不需要 /etc/ceph。避免与同一主机上的现有 Ceph 配置(cephadm 或其他方式)存在潜在冲突,可以使用 –output-dir 选项将它们放置在不同的目录中。
      • 可以使用 –config 选项将任何初始 Ceph 配置选项传递到新集群,方法是将它们放在标准 ini 样式的配置文件中。
    • 查看容器状态:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      [root@hadoop102 opt]# cephadm ls
      [
      {
      "style": "cephadm:v1",
      "name": "mon.hadoop102",
      "fsid": "81b469b6-662d-11ec-b2eb-000c29c51d96",
      "systemd_unit": "ceph-81b469b6-662d-11ec-b2eb-000c29c51d96@mon.hadoop102",
      "enabled": true,
      "state": "running",
      "container_id": "db378568f82337811eff2c7c44ad1a713d955a5b04fcde47c18674671e735704",
      "container_image_name": "quay.io/ceph/ceph:v15",
      "container_image_id": "3437f7bed9688a799444b439e1947a6f00d1f9b1fc986e843aec7e3ac8acd12b",
      "version": "15.2.15",
      "started": "2021-12-27T09:11:27.486408Z",
      "created": "2021-12-26T09:23:53.780886Z",
      "deployed": "2021-12-26T09:23:52.866923Z",
      "configured": "2021-12-26T09:30:45.494492Z"
      },
      {
      "style": "cephadm:v1",
      "name": "mgr.hadoop102.kwrjaw",
      "fsid": "81b469b6-662d-11ec-b2eb-000c29c51d96",
      "systemd_unit": "ceph-81b469b6-662d-11ec-b2eb-000c29c51d96@mgr.hadoop102.kwrjaw",
      "enabled": true,
      "state": "running",
      "container_id": "32e7e6a303b2af413b90739fde7e1f3b60c26214a1a5fe8d34d36133f733ea61",
      "container_image_name": "quay.io/ceph/ceph:v15",
      "container_image_id": "3437f7bed9688a799444b439e1947a6f00d1f9b1fc986e843aec7e3ac8acd12b",
      "version": "15.2.15",
      "started": "2021-12-27T09:11:24.388823Z",
      "created": "2021-12-26T09:23:57.956720Z",
      "deployed": "2021-12-26T09:23:57.302746Z",
      "configured": "2021-12-26T09:30:46.551456Z"
      },
      {
      "style": "cephadm:v1",
      "name": "alertmanager.hadoop102",
      "fsid": "81b469b6-662d-11ec-b2eb-000c29c51d96",
      "systemd_unit": "ceph-81b469b6-662d-11ec-b2eb-000c29c51d96@alertmanager.hadoop102",
      "enabled": true,
      "state": "running",
      "container_id": "843d8e781d923fa302322c78e5251ab1fa4b7b3d5a5998906ee30e089cc2e506",
      "container_image_name": "quay.io/prometheus/alertmanager:v0.20.0",
      "container_image_id": "0881eb8f169f5556a292b4e2c01d683172b12830a62a9225a98a8e206bb734f0",
      "version": "0.20.0",
      "started": "2021-12-27T09:11:30.498509Z",
      "created": "2021-12-26T09:25:51.990176Z",
      "deployed": "2021-12-26T09:25:51.485197Z",
      "configured": "2021-12-26T09:30:48.260398Z"
      },
      {
      "style": "cephadm:v1",
      "name": "crash.hadoop102",
      "fsid": "81b469b6-662d-11ec-b2eb-000c29c51d96",
      "systemd_unit": "ceph-81b469b6-662d-11ec-b2eb-000c29c51d96@crash.hadoop102",
      "enabled": true,
      "state": "running",
      "container_id": "2d08d2614605c2a4350c56cf1733f85cd5916afc03a899ce65c600a437c36184",
      "container_image_name": "quay.io/ceph/ceph:v15",
      "container_image_id": "3437f7bed9688a799444b439e1947a6f00d1f9b1fc986e843aec7e3ac8acd12b",
      "version": "15.2.15",
      "started": "2021-12-27T09:11:28.253480Z",
      "created": "2021-12-26T09:25:54.341083Z",
      "deployed": "2021-12-26T09:25:53.839103Z",
      "configured": "2021-12-26T09:25:54.341083Z"
      },
      {
      "style": "cephadm:v1",
      "name": "grafana.hadoop102",
      "fsid": "81b469b6-662d-11ec-b2eb-000c29c51d96",
      "systemd_unit": "ceph-81b469b6-662d-11ec-b2eb-000c29c51d96@grafana.hadoop102",
      "enabled": true,
      "state": "running",
      "container_id": "cbb4a8a923e2f3205e02e9dd026d3fdcf1a07c55a3eda6b9de13408dadc0465a",
      "container_image_name": "quay.io/ceph/ceph-grafana:6.7.4",
      "container_image_id": "557c83e11646f123a27b5e4b62ac6c45e7bb8b2e90d6044034d0db5b7019415c",
      "version": "6.7.4",
      "started": "2021-12-27T09:11:27.676553Z",
      "created": "2021-12-26T09:29:44.175925Z",
      "deployed": "2021-12-26T09:29:42.555990Z",
      "configured": "2021-12-26T09:30:51.194299Z"
      },
      {
      "style": "cephadm:v1",
      "name": "node-exporter.hadoop102",
      "fsid": "81b469b6-662d-11ec-b2eb-000c29c51d96",
      "systemd_unit": "ceph-81b469b6-662d-11ec-b2eb-000c29c51d96@node-exporter.hadoop102",
      "enabled": true,
      "state": "running",
      "container_id": "ee29b873a834252d1d55c20c67ecfbff9a3b6acf8621063efd9070a79cb1cba5",
      "container_image_name": "quay.io/prometheus/node-exporter:v0.18.1",
      "container_image_id": "e5a616e4b9cf68dfcad7782b78e118be4310022e874d52da85c55923fb615f87",
      "version": "0.18.1",
      "started": "2021-12-27T09:11:21.758252Z",
      "created": "2021-12-26T09:29:47.899777Z",
      "deployed": "2021-12-26T09:29:47.307801Z",
      "configured": "2021-12-26T09:29:47.899777Z"
      },
      {
      "style": "cephadm:v1",
      "name": "prometheus.hadoop102",
      "fsid": "81b469b6-662d-11ec-b2eb-000c29c51d96",
      "systemd_unit": "ceph-81b469b6-662d-11ec-b2eb-000c29c51d96@prometheus.hadoop102",
      "enabled": true,
      "state": "running",
      "container_id": "f236295847bf07d2db2b3c79d3a209f5db369cf2a61ae7bb7d2ef7597982eb23",
      "container_image_name": "quay.io/prometheus/prometheus:v2.18.1",
      "container_image_id": "de242295e2257c37c8cadfd962369228f8f10b2d48a44259b65fef44ad4f6490",
      "version": "2.18.1",
      "started": "2021-12-27T09:11:25.545626Z",
      "created": "2021-12-26T09:30:36.125856Z",
      "deployed": "2021-12-26T09:30:35.546879Z",
      "configured": "2021-12-26T09:30:36.125856Z"
      }
      ]
    • 根据初始化完成的提示使用浏览器访问 dashboard:

      image-20211227141903939

      • 使用虚拟机自带的火狐浏览器登陆 dashboard,初次登陆需要修改密码(admin,xisun_ceph001):

        image-20211227172731909

    • 如果上述引导集群的命令执行过程发生了异常,需要删除已经添加的配置文件,并关闭已经启动的 Ceph 组件进程,然后重新执行命令:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      # 查看已经添加的配置文件
      [root@hadoop102 opt]# ll /etc/ceph/
      总用量 12
      -rw-------. 1 root root 63 12月 26 17:23 ceph.client.admin.keyring
      -rw-r--r--. 1 root root 179 12月 26 17:23 ceph.conf
      -rw-r--r--. 1 root root 595 12月 26 17:24 ceph.pub
      # 删除已经添加的配置文件,或者重新执行命令时,添加--allow-overwrite参数
      [root@hadoop102 opt]# rm /etc/ceph/*

      # 查看已经启动的Ceph组件所占用的端口
      [root@hadoop102 opt]# netstat -ntlp
      Active Internet connections (only servers)
      Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
      tcp 0 0 0.0.0.0:111 0.0.0.0:* LISTEN 713/rpcbind
      tcp 0 0 0.0.0.0:6800 0.0.0.0:* LISTEN 2864/ceph-mgr # 删除
      tcp 0 0 0.0.0.0:6801 0.0.0.0:* LISTEN 2864/ceph-mgr # 删除
      tcp 0 0 192.168.122.1:53 0.0.0.0:* LISTEN 1467/dnsmasq
      tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1041/sshd
      tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN 1044/cupsd
      tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1234/master
      tcp 0 0 127.0.0.1:6010 0.0.0.0:* LISTEN 2131/sshd: xisun@pt
      tcp 0 0 192.168.10.102:3300 0.0.0.0:* LISTEN 3026/ceph-mon # 删除
      tcp 0 0 192.168.10.102:6789 0.0.0.0:* LISTEN 3026/ceph-mon # 删除
      tcp6 0 0 :::111 :::* LISTEN 713/rpcbind
      tcp6 0 0 :::22 :::* LISTEN 1041/sshd
      tcp6 0 0 ::1:631 :::* LISTEN 1044/cupsd
      tcp6 0 0 ::1:25 :::* LISTEN 1234/master
      tcp6 0 0 ::1:6010 :::* LISTEN 2131/sshd: xisun@pt
      # 同时删除ceph-mgr和ceph-mon这两个进程
      [root@hadoop102 opt]# kill -9 2864 3026

启用 Ceph 命令

  • Cephadm 不需要在主机上安装任何 Ceph 包。但是,建议启用对 Ceph 命令的简单访问。

  • cephadm shell 命令在安装了所有 Ceph 包的容器中启动一个 bash shell。默认情况下,如果在主机上的 /etc/ceph 路径中找到配置和 keyring 文件,则会将它们传递到容器环境中,这样 shell 就可以完全正常工作。注意,在 MON 主机上执行时,cephadm shell 将从 MON 容器推断配置,而不是使用默认配置。如果给定 –mount,则主机(文件或目录)将显示在容器中的 /mnt 下。在 hadoop102 上执行下面的命令:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    # 启动一个bash shell
    [root@hadoop102 opt]# cephadm shell
    Inferring fsid 81b469b6-662d-11ec-b2eb-000c29c51d96
    Inferring config /var/lib/ceph/81b469b6-662d-11ec-b2eb-000c29c51d96/mon.hadoop102/config
    Using recent ceph image quay.io/ceph/ceph@sha256:a2c23b6942f7fbc1e15d8cfacd6655a681fe0e44f288e4a158db22030b8d58e3
    # 创建别名
    [ceph: root@hadoop102 /]# alias ceph='cephadm shell -- ceph'
    # 退出
    [ceph: root@hadoop102 /]# exit
    exit
    # 查看集群状态,使用ceph -s 或者 ceph status命令
    [root@hadoop102 opt]# ceph -s
    cluster:
    id: 81b469b6-662d-11ec-b2eb-000c29c51d96
    health: HEALTH_WARN
    Reduced data availability: 1 pg inactive
    OSD count 0 < osd_pool_default_size 3

    services:
    mon: 1 daemons, quorum hadoop102 (age 17m)
    mgr: hadoop102.kwrjaw(active, since 15m)
    osd: 0 osds: 0 up, 0 in

    data:
    pools: 1 pools, 1 pgs
    objects: 0 objects, 0 B
    usage: 0 B used, 0 B / 0 B avail
    pgs: 100.000% pgs unknown
    1 unknown

    [root@hadoop102 opt]# ceph status
    cluster:
    id: 81b469b6-662d-11ec-b2eb-000c29c51d96
    health: HEALTH_WARN
    Reduced data availability: 1 pg inactive
    OSD count 0 < osd_pool_default_size 3

    services:
    mon: 1 daemons, quorum hadoop102 (age 17m)
    mgr: hadoop102.kwrjaw(active, since 15m)
    osd: 0 osds: 0 up, 0 in

    data:
    pools: 1 pools, 1 pgs
    objects: 0 objects, 0 B
    usage: 0 B used, 0 B / 0 B avail
    pgs: 100.000% pgs unknown
    1 unknown

    [root@hadoop102 opt]# ceph health
    HEALTH_WARN Reduced data availability: 1 pg inactive; OSD count 0 < osd_pool_default_size 3
    • 在执行过程中发生了异常,解决如下:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      [root@hadoop102 ceph]# ceph shell
      2021-12-27T14:45:22.661+0800 7faad8e1c700 -1 monclient(hunting): handle_auth_bad_method server allowed_methods [2] but i only support [2,1]
      [errno 13] RADOS permission denied (error connecting to the cluster)
      # 查看所有的集群数据文件夹
      [root@hadoop102 ceph]# ll /var/lib/ceph
      总用量 0
      drwx------. 5 ceph ceph 68 12月 26 16:42 6f08de88-6627-11ec-ad8e-000c29c51d96
      drwx------. 10 libstoragemgmt cgred 205 12月 26 17:30 81b469b6-662d-11ec-b2eb-000c29c51d96
      # 查看配置中的集群数据文件夹
      [root@hadoop102 ceph]# cat /etc/ceph/ceph.conf
      # minimal ceph.conf for 81b469b6-662d-11ec-b2eb-000c29c51d96
      [global]
      fsid = 81b469b6-662d-11ec-b2eb-000c29c51d96
      mon_host = [v2:192.168.10.102:3300/0,v1:192.168.10.102:6789/0]
      # 删除旧的集群数据文件夹,然后重新执行命令
      [root@hadoop102 ceph]# rm -rf /var/lib/ceph/6f08de88-6627-11ec-ad8e-000c29c51d96/

添加新主机到集群中

  • 第一步,在 hadoop102 上执行命令,将集群的公共 SSH 密钥添加到新主机的根用户 authorized_keys 文件中:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    [root@hadoop102 opt]# ssh-copy-id -f -i /etc/ceph/ceph.pub root@hadoop103
    /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/etc/ceph/ceph.pub"

    Number of key(s) added: 1

    Now try logging into the machine, with: "ssh 'root@hadoop103'"
    and check to make sure that only the key(s) you wanted were added.

    [root@hadoop102 opt]# ssh-copy-id -f -i /etc/ceph/ceph.pub root@hadoop104
    /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/etc/ceph/ceph.pub"

    Number of key(s) added: 1

    Now try logging into the machine, with: "ssh 'root@hadoop104'"
    and check to make sure that only the key(s) you wanted were added.
    [root@hadoop102 opt]# cat /root/.ssh/authorized_keys
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDkEXI7QySiz2VlLNrYW7OypfS9ZtMXS2h725W+pTpv71e4z6YjjxIpt6DvggtuD/UhktL1HxIvAREYKQ5vNYhGuV9jHI4VU+y4evpPEMR8GJ8OTlhfwhwovsik4TfYW0SmHUw01bxBpH2BjX4u/dSpyN9KG9710WXTIGJQ6zbHjxPg0JQX4C1KLuaD1WMVo1z6xscRGs7RAZ7sYAIQdf8LOI4IYVzO1n66NJNY4vpAJx1wCLajoGN0689Do42jX6t0/Qn6RGddXermTbbPW+hcD20pRIHO4f9VCQwqSNdcEVDUS74VMJRuOxd+N0uAxvHz8lTdCSfUnfPeKEvEH+cr root@hadoop102
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC9lRXTDUhUKdfu5PznYhoFsJFw1n6qXKJXCgFmuFCBB3T75na5xSgGbUEcQ5HYIWk8ywjynGjzCQMlyG+DTaQVvxOcpNNyKv57sm2quegFzu+c86Q726npspidr8Knl7dJALXF3q8k3eQrscWrRyJEA6vh1PikrNtDwzdB92WoYkAH5dJj3MxuHPJXoX+UbOZ8jWV7dARBT2LXFiS09bJy+7P2QZSa5BVirWFzoRjAD4JlEeaW2OPcujHTe+IjHXale4fjNh0tUDtteMRcwLnfMpTl6M7qgpUXm/IrlJHfAqtPmYPQUiDCVFQ9wntTeF5ph6WM9qk/2BJni5BX44VH root@hadoop103
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsgI3CnXcTkQkSHxvhGvBGY1Fh7gaIXqhI5n7rtEM3fmJ2k8/VoWjLwxE1xqSm7tsGufabIhpLdUJBfj4cpqa+PazgSVF59cPlYArp115YFOCGWv2z9tZ5Cq70i9EEfNCyhWNhNUEd9cqiei/G1by4yQzOwvpiuDhiGlDtQk3pRGvvdjGQV3YVDVjDv6JG3QQkxPY+oYQFjDBy+usGEvcuIFDJXmS4hlB8xDMZCw8R0gcvBEnA9RxIIb0N0jLf0uZt0varFZqlguwJJdT6nBCWJ+NYxu5aggX7PGgHB+F97gCoIRusqjT/scoS+jSK8yx4WzJ6ZfCp1wQEXJ+XgrbX root@hadoop104
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDCfFd837abQYj+trazR8y5OSOc7ET+vzn0o6pR+JF3N1knD5JGKXyB0umMsYehwcU55XkMARHRS+jothz0PAqWUpdV73pVZyy+Nxhu/5rySf+NiaoYd8IYAtcgbw174E5deudPF5Ac7IIUxJAgPxEb/NnrpYEPFLHg31ZCKUvzHkEbP9I1iMgM9LtKN3M/aAbaHY2Pd046joVhOo7DsIlYyd147X1MgFhwTeVThpu+zdjPwNoenQGIhrH1J46thBL8TyTC0Wjui5YVwim9Nxoet7E46BiuqrAS6TBvLOTAZlD/g2UB+6NbGYdQKpOs8k2XQqrEBtPB4Wo/hZ0efg8gvCs4AaOqICaMOUt52lfJHInnsycB99nxh95sLDhkHfQIlqTEvGPQDiJVU8tPS5mo7+oeqpCTsvnIINQTMlCtA6eR6kmNumCdSpwbCMkuwVxHjGgNxMy3ykBRItU0vH9mAv/5OxyfjKQutELHQn+5fb5v0lrDq/WZ60jMJYGpTh8= ceph-81b469b6-662d-11ec-b2eb-000c29c51d96
  • 在新结点上查看密钥是否添加成功:

    1
    2
    3
    4
    5
    [root@hadoop103 opt]# cat /root/.ssh/authorized_keys 
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDkEXI7QySiz2VlLNrYW7OypfS9ZtMXS2h725W+pTpv71e4z6YjjxIpt6DvggtuD/UhktL1HxIvAREYKQ5vNYhGuV9jHI4VU+y4evpPEMR8GJ8OTlhfwhwovsik4TfYW0SmHUw01bxBpH2BjX4u/dSpyN9KG9710WXTIGJQ6zbHjxPg0JQX4C1KLuaD1WMVo1z6xscRGs7RAZ7sYAIQdf8LOI4IYVzO1n66NJNY4vpAJx1wCLajoGN0689Do42jX6t0/Qn6RGddXermTbbPW+hcD20pRIHO4f9VCQwqSNdcEVDUS74VMJRuOxd+N0uAxvHz8lTdCSfUnfPeKEvEH+cr root@hadoop102
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC9lRXTDUhUKdfu5PznYhoFsJFw1n6qXKJXCgFmuFCBB3T75na5xSgGbUEcQ5HYIWk8ywjynGjzCQMlyG+DTaQVvxOcpNNyKv57sm2quegFzu+c86Q726npspidr8Knl7dJALXF3q8k3eQrscWrRyJEA6vh1PikrNtDwzdB92WoYkAH5dJj3MxuHPJXoX+UbOZ8jWV7dARBT2LXFiS09bJy+7P2QZSa5BVirWFzoRjAD4JlEeaW2OPcujHTe+IjHXale4fjNh0tUDtteMRcwLnfMpTl6M7qgpUXm/IrlJHfAqtPmYPQUiDCVFQ9wntTeF5ph6WM9qk/2BJni5BX44VH root@hadoop103
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsgI3CnXcTkQkSHxvhGvBGY1Fh7gaIXqhI5n7rtEM3fmJ2k8/VoWjLwxE1xqSm7tsGufabIhpLdUJBfj4cpqa+PazgSVF59cPlYArp115YFOCGWv2z9tZ5Cq70i9EEfNCyhWNhNUEd9cqiei/G1by4yQzOwvpiuDhiGlDtQk3pRGvvdjGQV3YVDVjDv6JG3QQkxPY+oYQFjDBy+usGEvcuIFDJXmS4hlB8xDMZCw8R0gcvBEnA9RxIIb0N0jLf0uZt0varFZqlguwJJdT6nBCWJ+NYxu5aggX7PGgHB+F97gCoIRusqjT/scoS+jSK8yx4WzJ6ZfCp1wQEXJ+XgrbX root@hadoop104
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDCfFd837abQYj+trazR8y5OSOc7ET+vzn0o6pR+JF3N1knD5JGKXyB0umMsYehwcU55XkMARHRS+jothz0PAqWUpdV73pVZyy+Nxhu/5rySf+NiaoYd8IYAtcgbw174E5deudPF5Ac7IIUxJAgPxEb/NnrpYEPFLHg31ZCKUvzHkEbP9I1iMgM9LtKN3M/aAbaHY2Pd046joVhOo7DsIlYyd147X1MgFhwTeVThpu+zdjPwNoenQGIhrH1J46thBL8TyTC0Wjui5YVwim9Nxoet7E46BiuqrAS6TBvLOTAZlD/g2UB+6NbGYdQKpOs8k2XQqrEBtPB4Wo/hZ0efg8gvCs4AaOqICaMOUt52lfJHInnsycB99nxh95sLDhkHfQIlqTEvGPQDiJVU8tPS5mo7+oeqpCTsvnIINQTMlCtA6eR6kmNumCdSpwbCMkuwVxHjGgNxMy3ykBRItU0vH9mAv/5OxyfjKQutELHQn+5fb5v0lrDq/WZ60jMJYGpTh8= ceph-81b469b6-662d-11ec-b2eb-000c29c51d96 # 公共SSH密钥
    1
    2
    3
    4
    5
    [root@hadoop104 opt]# cat /root/.ssh/authorized_keys 
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDkEXI7QySiz2VlLNrYW7OypfS9ZtMXS2h725W+pTpv71e4z6YjjxIpt6DvggtuD/UhktL1HxIvAREYKQ5vNYhGuV9jHI4VU+y4evpPEMR8GJ8OTlhfwhwovsik4TfYW0SmHUw01bxBpH2BjX4u/dSpyN9KG9710WXTIGJQ6zbHjxPg0JQX4C1KLuaD1WMVo1z6xscRGs7RAZ7sYAIQdf8LOI4IYVzO1n66NJNY4vpAJx1wCLajoGN0689Do42jX6t0/Qn6RGddXermTbbPW+hcD20pRIHO4f9VCQwqSNdcEVDUS74VMJRuOxd+N0uAxvHz8lTdCSfUnfPeKEvEH+cr root@hadoop102
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQC9lRXTDUhUKdfu5PznYhoFsJFw1n6qXKJXCgFmuFCBB3T75na5xSgGbUEcQ5HYIWk8ywjynGjzCQMlyG+DTaQVvxOcpNNyKv57sm2quegFzu+c86Q726npspidr8Knl7dJALXF3q8k3eQrscWrRyJEA6vh1PikrNtDwzdB92WoYkAH5dJj3MxuHPJXoX+UbOZ8jWV7dARBT2LXFiS09bJy+7P2QZSa5BVirWFzoRjAD4JlEeaW2OPcujHTe+IjHXale4fjNh0tUDtteMRcwLnfMpTl6M7qgpUXm/IrlJHfAqtPmYPQUiDCVFQ9wntTeF5ph6WM9qk/2BJni5BX44VH root@hadoop103
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDsgI3CnXcTkQkSHxvhGvBGY1Fh7gaIXqhI5n7rtEM3fmJ2k8/VoWjLwxE1xqSm7tsGufabIhpLdUJBfj4cpqa+PazgSVF59cPlYArp115YFOCGWv2z9tZ5Cq70i9EEfNCyhWNhNUEd9cqiei/G1by4yQzOwvpiuDhiGlDtQk3pRGvvdjGQV3YVDVjDv6JG3QQkxPY+oYQFjDBy+usGEvcuIFDJXmS4hlB8xDMZCw8R0gcvBEnA9RxIIb0N0jLf0uZt0varFZqlguwJJdT6nBCWJ+NYxu5aggX7PGgHB+F97gCoIRusqjT/scoS+jSK8yx4WzJ6ZfCp1wQEXJ+XgrbX root@hadoop104
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDCfFd837abQYj+trazR8y5OSOc7ET+vzn0o6pR+JF3N1knD5JGKXyB0umMsYehwcU55XkMARHRS+jothz0PAqWUpdV73pVZyy+Nxhu/5rySf+NiaoYd8IYAtcgbw174E5deudPF5Ac7IIUxJAgPxEb/NnrpYEPFLHg31ZCKUvzHkEbP9I1iMgM9LtKN3M/aAbaHY2Pd046joVhOo7DsIlYyd147X1MgFhwTeVThpu+zdjPwNoenQGIhrH1J46thBL8TyTC0Wjui5YVwim9Nxoet7E46BiuqrAS6TBvLOTAZlD/g2UB+6NbGYdQKpOs8k2XQqrEBtPB4Wo/hZ0efg8gvCs4AaOqICaMOUt52lfJHInnsycB99nxh95sLDhkHfQIlqTEvGPQDiJVU8tPS5mo7+oeqpCTsvnIINQTMlCtA6eR6kmNumCdSpwbCMkuwVxHjGgNxMy3ykBRItU0vH9mAv/5OxyfjKQutELHQn+5fb5v0lrDq/WZ60jMJYGpTh8= ceph-81b469b6-662d-11ec-b2eb-000c29c51d96 # 公共SSH密钥
  • 第二步,告诉 Ceph,新节点是集群的一部分:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
      ```



    - s

    ## Ubuntu 安装 Ceph

    ### 节点规划

    - 各节点规划:

    | 主机名 | ip | 磁盘 | 角色 |
    | ------ | ------------ | --------------------------- | ----------------------------------------- |
    | ceph1 | 192.168.1.91 | 系统盘:sda<br/>osd盘:sdb | cephadm,monitor,mgr,rgw,mds,osd,nfs |
    | ceph2 | 192.168.1.92 | 系统盘:sda<br/>osd盘:sdb | monitor,mgr,rgw,mds,osd,nfs |
    | ceph3 | 192.168.1.93 | 系统盘:sda<br/>osd盘:sdb | monitor,mgr,rgw,mds,osd,nfs |
    | ceph4 | 192.168.1.94 | 系统盘:sda<br />osd盘:sdb | monitor,mgr,rgw,mds,osd,nfs |

    - 各节点版本:

    ```shell
    # 内核版本
    root@ceph1:/home# uname -r
    5.4.0-91-generic

    # Ubuntu版本,方法一
    root@ceph1:/home# cat /etc/issue
    Ubuntu 20.04.3 LTS \n \l

    # Ubuntu版本,方法二,查看所有信息
    root@ceph1:/home# lsb_release -a
    No LSB modules are available.
    Distributor ID: Ubuntu
    Description: Ubuntu 20.04.3 LTS
    Release: 20.04
    Codename: focal

    # Ubuntu版本代号
    root@ceph4:/home# lsb_release -c
    Codename: focal
  • 各节点配置 Ubuntu 20.04 apt 阿里云镜像源:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    root@ceph1:/home# ll /etc/apt/
    total 40
    drwxr-xr-x 7 root root 4096 Dec 29 15:23 ./
    drwxr-xr-x 105 root root 4096 Dec 29 10:52 ../
    drwxr-xr-x 2 root root 4096 Aug 24 16:47 apt.conf.d/
    drwxr-xr-x 2 root root 4096 Apr 9 2020 auth.conf.d/
    drwxr-xr-x 2 root root 4096 Dec 17 17:04 preferences.d/
    -rw-r--r-- 1 root root 2777 Dec 8 10:29 sources.list
    -rw-r--r-- 1 root root 2743 Aug 24 16:47 sources.list.curtin.old
    drwxr-xr-x 2 root root 4096 Dec 17 17:04 sources.list.d/
    -rw-r--r-- 1 root root 1143 Dec 8 15:43 trusted.gpg
    drwxr-xr-x 2 root root 4096 Dec 17 17:04 trusted.gpg.d/
    # 备份默认的源
    root@ceph1:/home# cp /etc/apt/sources.list /etc/apt/sources.list.bak
    # 替换阿里云镜像源,将默认源cn.archive.ubuntu.com替换成mirrors.aliyun.com(先验证下默认apt源是不是cn.archive.ubuntu.com)
    root@ceph1:/home# sed -i "s/cn.archive.ubuntu.com/mirrors.aliyun.com/g" /etc/apt/sources.list
    # 更新软件包列表
    root@ceph1:/home# apt update
    # 更新已安装的软件包
    root@ceph1:/home# apt upgrade

    image-20211229155618530

    • 说明:生产环境不要随意使用 apt updateapt upgrade 命令,因为生产环境下可能要求使用特定的软件版本,不要轻易的更新。
  • 各节点配置主机名:

    1
    2
    3
    root@ceph1:/home# vim /etc/hostname 
    root@ceph1:/home# cat /etc/hostname
    ceph1
  • 各节点配置 host 解析:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    root@ceph1:/home# vim /etc/hosts
    root@ceph1:/home# cat /etc/hosts
    127.0.0.1 localhost
    127.0.0.1 ceph1

    # The following lines are desirable for IPv6 capable hosts
    ::1 ip6-localhost ip6-loopback
    fe00::0 ip6-localnet
    ff00::0 ip6-mcastprefix
    ff02::1 ip6-allnodes
    ff02::2 ip6-allrouters

    192.168.1.91 ceph1
    192.168.1.92 ceph2
    192.168.1.93 ceph3
    192.168.1.94 ceph4
  • 各节点网络信息:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    # 配置文件
    root@ceph1:/opt# cat /etc/netplan/00-installer-config.yaml
    # This is the network config written by 'subiquity'
    network:
    ethernets:
    ens160:
    dhcp4: false
    addresses:
    - 192.168.1.91/24
    gateway4: 192.168.1.1
    nameservers:
    addresses: [114.114.114.114, 8.8.8.8]
    version: 2
    # 网络信息
    root@ceph1:/opt# ifconfig
    docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
    inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
    ether 02:42:31:45:9c:e4 txqueuelen 0 (Ethernet)
    RX packets 0 bytes 0 (0.0 B)
    RX errors 0 dropped 0 overruns 0 frame 0
    TX packets 0 bytes 0 (0.0 B)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

    ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
    inet 192.168.1.91 netmask 255.255.255.0 broadcast 192.168.1.255
    inet6 fe80::250:56ff:fe9e:7c0f prefixlen 64 scopeid 0x20<link>
    ether 00:50:56:9e:7c:0f txqueuelen 1000 (Ethernet)
    RX packets 1493933 bytes 708616888 (708.6 MB)
    RX errors 0 dropped 62 overruns 0 frame 0
    TX packets 215266 bytes 15560179 (15.5 MB)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

    lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
    inet 127.0.0.1 netmask 255.0.0.0
    inet6 ::1 prefixlen 128 scopeid 0x10<host>
    loop txqueuelen 1000 (Local Loopback)
    RX packets 400 bytes 38180 (38.1 KB)
    RX errors 0 dropped 0 overruns 0 frame 0
    TX packets 400 bytes 38180 (38.1 KB)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    # 配置文件
    root@ceph2:/opt# cat /etc/netplan/00-installer-config.yaml
    # This is the network config written by 'subiquity'
    network:
    ethernets:
    ens160:
    dhcp4: false
    addresses:
    - 192.168.1.92/24
    gateway4: 192.168.1.1
    nameservers:
    addresses: [114.114.114.114, 8.8.8.8]
    version: 2
    # 网络信息
    root@ceph2:/opt# ifconfig
    docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
    inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
    ether 02:42:07:d8:d7:04 txqueuelen 0 (Ethernet)
    RX packets 0 bytes 0 (0.0 B)
    RX errors 0 dropped 0 overruns 0 frame 0
    TX packets 0 bytes 0 (0.0 B)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

    ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
    inet 192.168.1.92 netmask 255.255.255.0 broadcast 192.168.1.255
    inet6 fe80::250:56ff:fe9e:e4e8 prefixlen 64 scopeid 0x20<link>
    ether 00:50:56:9e:e4:e8 txqueuelen 1000 (Ethernet)
    RX packets 1474736 bytes 708635562 (708.6 MB)
    RX errors 0 dropped 1 overruns 0 frame 0
    TX packets 219015 bytes 16146130 (16.1 MB)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

    lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
    inet 127.0.0.1 netmask 255.0.0.0
    inet6 ::1 prefixlen 128 scopeid 0x10<host>
    loop txqueuelen 1000 (Local Loopback)
    RX packets 588 bytes 56542 (56.5 KB)
    RX errors 0 dropped 0 overruns 0 frame 0
    TX packets 588 bytes 56542 (56.5 KB)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    # 配置文件
    root@ceph3:/opt# cat /etc/netplan/00-installer-config.yaml
    # This is the network config written by 'subiquity'
    network:
    ethernets:
    ens160:
    dhcp4: false
    addresses:
    - 192.168.1.93/24
    gateway4: 192.168.1.1
    nameservers:
    addresses: [114.114.114.114, 8.8.8.8]
    version: 2
    # 网络信息
    root@ceph3:/opt# ifconfig
    docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
    inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
    ether 02:42:e2:11:a5:b9 txqueuelen 0 (Ethernet)
    RX packets 0 bytes 0 (0.0 B)
    RX errors 0 dropped 0 overruns 0 frame 0
    TX packets 0 bytes 0 (0.0 B)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

    ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
    inet 192.168.1.93 netmask 255.255.255.0 broadcast 192.168.1.255
    inet6 fe80::250:56ff:fe9e:7d03 prefixlen 64 scopeid 0x20<link>
    ether 00:50:56:9e:7d:03 txqueuelen 1000 (Ethernet)
    RX packets 1490677 bytes 706047066 (706.0 MB)
    RX errors 0 dropped 46 overruns 0 frame 0
    TX packets 208014 bytes 14700697 (14.7 MB)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

    lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
    inet 127.0.0.1 netmask 255.0.0.0
    inet6 ::1 prefixlen 128 scopeid 0x10<host>
    loop txqueuelen 1000 (Local Loopback)
    RX packets 620 bytes 60174 (60.1 KB)
    RX errors 0 dropped 0 overruns 0 frame 0
    TX packets 620 bytes 60174 (60.1 KB)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    # 配置文件
    root@ceph4:/opt# cat /etc/netplan/00-installer-config.yaml
    # This is the network config written by 'subiquity'
    network:
    ethernets:
    ens160:
    dhcp4: false
    addresses:
    - 192.168.1.94/24
    gateway4: 192.168.1.1
    nameservers:
    addresses: [114.114.114.114, 8.8.8.8]
    version: 2
    # 网络信息
    root@ceph4:/opt# ifconfig
    docker0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
    inet 172.17.0.1 netmask 255.255.0.0 broadcast 172.17.255.255
    inet6 fe80::42:78ff:febe:2005 prefixlen 64 scopeid 0x20<link>
    ether 02:42:78:be:20:05 txqueuelen 0 (Ethernet)
    RX packets 0 bytes 0 (0.0 B)
    RX errors 0 dropped 0 overruns 0 frame 0
    TX packets 2 bytes 196 (196.0 B)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

    ens160: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
    inet 192.168.1.94 netmask 255.255.255.0 broadcast 192.168.1.255
    inet6 fe80::250:56ff:fe9e:7855 prefixlen 64 scopeid 0x20<link>
    ether 00:50:56:9e:78:55 txqueuelen 1000 (Ethernet)
    RX packets 1572297 bytes 814622359 (814.6 MB)
    RX errors 0 dropped 50 overruns 0 frame 0
    TX packets 250469 bytes 17903836 (17.9 MB)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

    lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
    inet 127.0.0.1 netmask 255.0.0.0
    inet6 ::1 prefixlen 128 scopeid 0x10<host>
    loop txqueuelen 1000 (Local Loopback)
    RX packets 826 bytes 84430 (84.4 KB)
    RX errors 0 dropped 0 overruns 0 frame 0
    TX packets 826 bytes 84430 (84.4 KB)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

关闭防火墙

  • 各节点关闭防火墙:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    # 安装ufw
    root@ceph1:/opt# apt install -y ufw
    # 防火墙版本
    root@ceph1:/home# ufw version
    ufw 0.36
    Copyright 2008-2015 Canonical Ltd.
    # 开启防火墙
    root@ceph1:/home# ufw enable
    Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
    Firewall is active and enabled on system startup
    # 查看防火墙状态
    root@ceph1:/home# ufw status
    Status: active
    # 关闭防火墙
    root@ceph1:/home# ufw disable
    Firewall stopped and disabled on system startup
    root@ceph1:/home# ufw status
    Status: inactive
    # 重启防火墙
    root@ceph1:/home# ufw reload

SSH 免密登录

  • 各节点执行如下命令:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    root@ceph1:/home# sed -i '/PermitRootLogin/d' /etc/ssh/sshd_config
    root@ceph1:/home# echo "PermitRootLogin yes" >> /etc/ssh/sshd_config
    root@ceph1:/home# service sshd reload
    root@ceph1:/home# ssh-keygen
    root@ceph1:/home# ssh-copy-id -o StrictHostKeyChecking=no root@ceph1
    root@ceph1:/home# ssh-copy-id -o StrictHostKeyChecking=no root@ceph2
    root@ceph1:/home# ssh-copy-id -o StrictHostKeyChecking=no root@ceph3
    root@ceph1:/home# ssh-copy-id -o StrictHostKeyChecking=no root@ceph4
    # 测试是否能免密登录其他节点
    root@ceph1:/home# ssh ceph1
    root@ceph1:/home# ssh ceph2
    root@ceph1:/home# ssh ceph3
    root@ceph1:/home# ssh ceph4
    • ceph2,ceph3 和 ceph4 参考 ceph1 配置。

服务器时间同步

  • NTP 是通过网络来同步时间的一种 TCP/IP 协议。通常客户端向服务器请求当前的时间,并根据结果来设置其时钟。这个描述是挺简单的,实现这一功能却是极为复杂的:首先要有多层 NTP 服务器,第一层 NTP 服务器连接原子时钟,第二层、第三层服务器则担起负载均衡的责任,以处理因特网传来的所有请求。另外,客户端可能也超乎你想象的复杂:它必须排除通讯延迟,调整时间的同时不干扰其它在服务器中运行的进程。幸运的是,所有的这些复杂性都进行了封装,你是不可见也不需要见到的。

  • 在 Ubuntu 中,可以使用 ntpdate 和 ntpd 来同步时间。而在最新的 Ubuntu 版本中,timedatectl 替代了老旧的 ntpdate。默认情况下,timedatectl 在系统启动的时候会立刻同步时间,并在稍后网络连接激活后通过 Socket 再次检查一次。

  • 各节点查看时间:

    1
    2
    root@ceph1:/home# date
    Thu 30 Dec 2021 10:32:19 AM CST
  • 各节点设置时间同步服务器:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    # 查看时间同步服务器状态
    root@ceph1:/opt# systemctl status systemd-timesyncd.service
    ● systemd-timesyncd.service - Network Time Synchronization
    Loaded: loaded (/lib/systemd/system/systemd-timesyncd.service; enabled; vendor preset: enabled)
    Active: active (running) since Thu 2021-12-30 11:02:44 CST; 36min ago
    Docs: man:systemd-timesyncd.service(8)
    Main PID: 719 (systemd-timesyn)
    Status: "Initial synchronization to time server 91.189.91.157:123 (ntp.ubuntu.com)." # 默认ntp.ubuntu.com
    Tasks: 2 (limit: 19110)
    Memory: 1.7M
    CGroup: /system.slice/systemd-timesyncd.service
    └─719 /lib/systemd/systemd-timesyncd
    # 添加阿里云NTP服务器地址
    root@ceph1:/opt# vim /etc/systemd/timesyncd.conf
    root@ceph1:/opt# cat /etc/systemd/timesyncd.conf
    # This file is part of systemd.
    #
    # systemd is free software; you can redistribute it and/or modify it
    # under the terms of the GNU Lesser General Public License as published by
    # the Free Software Foundation; either version 2.1 of the License, or
    # (at your option) any later version.
    #
    # Entries in this file show the compile time defaults.
    # You can change settings by editing this file.
    # Defaults can be restored by simply deleting this file.
    #
    # See timesyncd.conf(5) for details.

    [Time]
    #NTP=
    #FallbackNTP=ntp.ubuntu.com
    #RootDistanceMaxSec=5
    #PollIntervalMinSec=32
    #PollIntervalMaxSec=2048
    NTP=ntp1.aliyun.com
    # 重启时间同步服务
    root@ceph1:/opt# systemctl restart systemd-timesyncd.service
    # 查询时间同步服务状态,确认服务是否正常启动,是否从指定的NTP服务器上进行校时
    root@ceph1:/opt# systemctl status systemd-timesyncd.service
    ● systemd-timesyncd.service - Network Time Synchronization
    Loaded: loaded (/lib/systemd/system/systemd-timesyncd.service; enabled; vendor preset: enabled)
    Active: active (running) since Thu 2021-12-30 11:50:14 CST; 14s ago
    Docs: man:systemd-timesyncd.service(8)
    Main PID: 3966 (systemd-timesyn)
    Status: "Initial synchronization to time server 120.25.115.20:123 (ntp1.aliyun.com)." # 修改为阿里云服务器
    Tasks: 2 (limit: 19110)
    Memory: 1.4M
    CGroup: /system.slice/systemd-timesyncd.service
    └─3966 /lib/systemd/systemd-timesyncd

    Dec 30 11:50:14 ceph2 systemd[1]: Starting Network Time Synchronization...
    Dec 30 11:50:14 ceph2 systemd[1]: Started Network Time Synchronization.
    Dec 30 11:50:14 ceph2 systemd-timesyncd[3966]: Initial synchronization to time server 120.25.115.20:123 (ntp1.aliyun.com).
    • 系统默认同步的 NTP 服务器为 ntp.ubuntu.com。

    • 添加一个阿里云 NTP 服务器地址,如果需要添加多个 NTP 服务器地址,则中间用空格隔开:

      image-20211230114924366

  • 各节点设置时区:

    1
    2
    3
    4
    5
    6
    7
    8
    # 设置东八区
    root@ceph1:/home# timedatectl set-timezone Asia/Shanghai
    # 查看时区
    root@ceph1:/home# cat /etc/timezone
    Asia/Shanghai
    root@ceph1:/home# timedatectl status | grep 'Time zone'
    Time zone: Asia/Shanghai (CST, +0800)

  • 各节点查看时钟是否与互联网同步:

    1
    2
    3
    4
    5
    6
    7
    8
    root@ceph1:/home# timedatectl 
    Local time: Thu 2021-12-30 10:33:17 CST # 本地时间
    Universal time: Thu 2021-12-30 02:33:17 UTC # 协调世界时
    RTC time: Thu 2021-12-30 02:33:17 # 硬件时间
    Time zone: Asia/Shanghai (CST, +0800) # 时区
    System clock synchronized: yes # 如果和远程NTP服务器成功同步,则显示为yes
    NTP service: active # NTP时间同步是否开启,systemd-timesyncd服务活跃即开启了NTP时间同步
    RTC in local TZ: no # no表示硬件时钟设置为协调世界时(UTC),yes表示硬件时钟设置为本地时间
    • timedatectl 命令会显示本地时间、世界时、时区、系统时钟是否与互联网服务器同步,以及 systemd-timesyncd.service 是处于活跃状态还是非活跃状态。

安装 Python3

  • 各节点查看 Python3 版本,服务器已安装 Python3,此处省略安装步骤:

    1
    2
    root@ceph1:/opt# python3 --version
    Python 3.8.10

安装 Docker

  • 各节点卸载旧版本:

    1
    2
    3
    4
    5
    # 卸载旧版本
    root@ceph1:/opt# apt remove docker docker-engine docker.io containerd runc
    # 删除旧版本数据
    root@ceph1:/opt# rm -rf /var/lib/docker/
    root@ceph1:/opt# rm -rf /var/lib/containerd/
  • 各节点安装需要的软件包:

    1
    root@ceph1:/opt# apt install ca-certificates curl gnupg lsb-release
  • 各节点添加 Docker 的官方 GPG key:

    1
    2
    3
    root@ceph1:/opt# curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
    OK
    W: The key(s) in the keyring /etc/apt/trusted.gpg.d/ceph.release.gpg are ignored as the file has an unsupported filetype.
  • 各节点添加 apt 的 Docker 源:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    root@ceph1:/opt# add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
    Hit:1 http://mirrors.aliyun.com/ubuntu focal InRelease
    Hit:2 http://mirrors.aliyun.com/ubuntu focal-updates InRelease
    Hit:3 http://mirrors.aliyun.com/ubuntu focal-backports InRelease
    Hit:4 http://mirrors.aliyun.com/ubuntu focal-security InRelease
    Get:5 https://download.docker.com/linux/ubuntu focal InRelease [57.7 kB]
    Get:6 https://download.docker.com/linux/ubuntu focal/stable amd64 Packages [13.5 kB]
    Get:7 https://download.ceph.com/debian-octopus focal InRelease [8,571 B]
    Get:8 https://download.ceph.com/debian-octopus focal/main amd64 Packages [15.9 kB]
    Fetched 95.7 kB in 2s (50.4 kB/s)
    Reading package lists... Done
    W: http://mirrors.aliyun.com/ubuntu/dists/focal/InRelease: The key(s) in the keyring /etc/apt/trusted.gpg.d/ceph.release.gpg are ignored as the file has an unsupported filetype.
    W: http://mirrors.aliyun.com/ubuntu/dists/focal-updates/InRelease: The key(s) in the keyring /etc/apt/trusted.gpg.d/ceph.release.gpg are ignored as the file has an unsupported filetype.
    W: http://mirrors.aliyun.com/ubuntu/dists/focal-backports/InRelease: The key(s) in the keyring /etc/apt/trusted.gpg.d/ceph.release.gpg are ignored as the file has an unsupported filetype.
    W: http://mirrors.aliyun.com/ubuntu/dists/focal-security/InRelease: The key(s) in the keyring /etc/apt/trusted.gpg.d/ceph.release.gpg are ignored as the file has an unsupported filetype.
    W: https://download.docker.com/linux/ubuntu/dists/focal/InRelease: The key(s) in the keyring /etc/apt/trusted.gpg.d/ceph.release.gpg are ignored as the file has an unsupported filetype.
    W: https://download.ceph.com/debian-octopus/dists/focal/InRelease: The key(s) in the keyring /etc/apt/trusted.gpg.d/ceph.release.gpg are ignored as the file has an unsupported filetype.
    • 如果提示 bash: add-apt-repository: command not found,执行下面命令安装:

      1
      2
      root@ceph1:/opt# apt install -y software-properties-common
      root@ceph1:/opt# apt update
  • 各节点安装最新版本:

    1
    root@ceph1:/opt# apt install docker-ce docker-ce-cli containerd.io
  • Docker 安装完成后会自动启动:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # 查看docker状态
    root@ceph1:/opt# systemctl status docker
    ● docker.service - Docker Application Container Engine
    Loaded: loaded (/lib/systemd/system/docker.service; enabled; vendor preset: enabled)
    Active: active (running) since Thu 2021-12-30 17:28:18 CST; 34s ago
    TriggeredBy: ● docker.socket
    Docs: https://docs.docker.com
    Main PID: 24185 (dockerd)
    Tasks: 11
    Memory: 29.1M
    CGroup: /system.slice/docker.service
    └─24185 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
    # 查看docker版本
    root@ceph1:/opt# docker --version
    Docker version 20.10.12, build e91ed57
  • 各节点测试:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    root@ceph1:/opt# docker run hello-world
    Unable to find image 'hello-world:latest' locally
    latest: Pulling from library/hello-world
    2db29710123e: Pull complete
    Digest: sha256:2498fce14358aa50ead0cc6c19990fc6ff866ce72aeb5546e1d59caac3d0d60f
    Status: Downloaded newer image for hello-world:latest

    Hello from Docker!
    This message shows that your installation appears to be working correctly.

    To generate this message, Docker took the following steps:
    1. The Docker client contacted the Docker daemon.
    2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
    3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
    4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

    To try something more ambitious, you can run an Ubuntu container with:
    $ docker run -it ubuntu bash

    Share images, automate workflows, and more with a free Docker ID:
    https://hub.docker.com/

    For more examples and ideas, visit:
    https://docs.docker.com/get-started/

    root@ceph1:/opt# docker images
    REPOSITORY TAG IMAGE ID CREATED SIZE
    hello-world latest feb5d9fea6a5 3 months ago 13.3kB
    root@ceph1:/opt# docker ps -a
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    acf9377ed00d hello-world "/hello" About a minute ago Exited (0) About a minute ago ecstatic_gould
  • 参考:https://docs.docker.com/engine/install/ubuntu/

安装 Cephadm

  • 各节点使用 apt 安装 Cephadm:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    # 安装
    root@ceph1:/opt# apt install -y cephadm
    Reading package lists... Done
    Building dependency tree
    Reading state information... Done
    Recommended packages:
    podman | docker.io
    The following NEW packages will be installed:
    cephadm
    0 upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
    Need to get 53.2 kB of archives.
    After this operation, 245 kB of additional disk space will be used.
    Get:1 https://download.ceph.com/debian-octopus focal/main amd64 cephadm amd64 15.2.15-1focal [53.2 kB]
    Fetched 53.2 kB in 2s (31.4 kB/s)
    Selecting previously unselected package cephadm.
    (Reading database ... 115380 files and directories currently installed.)
    Preparing to unpack .../cephadm_15.2.15-1focal_amd64.deb ...
    Unpacking cephadm (15.2.15-1focal) ...
    Setting up cephadm (15.2.15-1focal) ...
    Adding system user cephadm....done
    Processing triggers for man-db (2.9.1-1) ...
  • 各节点验证 Cephadm 安装成功:

    1
    2
    3
    4
    root@ceph1:/opt# which cephadm
    /usr/sbin/cephadm
    root@ceph1:/opt# cephadm version
    ceph version 15.2.15 (2dfb18841cfecc2f7eb7eb2afd65986ca4d95985) octopus (stable)
  • 各节点安装 ceph-common 工具:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 添加源
    root@ceph1:/opt# cephadm add-repo --release octopus
    Installing repo GPG key from https://download.ceph.com/keys/release.asc...
    Installing repo file at /etc/apt/sources.list.d/ceph.list...
    # 安装
    root@ceph1:/opt# cephadm install ceph-common
    Installing packages ['ceph-common']...
    # 验证
    root@ceph1:/opt# ceph -v
    ceph version 15.2.15 (2dfb18841cfecc2f7eb7eb2afd65986ca4d95985) octopus (stable)

创建 Ceph 新集群

  • 在 ceph1 上创建一个可以被任何访问 Ceph 集群的主机访问的网络,指定 mon-ip,并将生成的配置文件写进 /etc/ceph 目录里:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    root@ceph1:/opt# cephadm bootstrap --mon-ip 192.168.1.91
    Verifying podman|docker is present...
    Verifying lvm2 is present...
    Verifying time synchronization is in place...
    Unit systemd-timesyncd.service is enabled and running
    Repeating the final host check...
    podman|docker (/usr/bin/docker) is present
    systemctl is present
    lvcreate is present
    Unit systemd-timesyncd.service is enabled and running
    Host looks OK
    Cluster fsid: 79a6cb92-6f92-11ec-b1e0-6f6f27397286
    Verifying IP 192.168.1.91 port 3300 ...
    Verifying IP 192.168.1.91 port 6789 ...
    Mon IP 192.168.1.91 is in CIDR network 192.168.1.0/24
    Pulling container image quay.io/ceph/ceph:v15...
    Extracting ceph user uid/gid from container image...
    Creating initial keys...
    Creating initial monmap...
    Creating mon...
    Waiting for mon to start...
    Waiting for mon...
    mon is available
    Assimilating anything we can from ceph.conf...
    Generating new minimal ceph.conf...
    Restarting the monitor...
    Setting mon public_network...
    Creating mgr...
    Verifying port 9283 ...
    Wrote keyring to /etc/ceph/ceph.client.admin.keyring
    Wrote config to /etc/ceph/ceph.conf
    Waiting for mgr to start...
    Waiting for mgr...
    mgr not available, waiting (1/10)...
    mgr not available, waiting (2/10)...
    mgr not available, waiting (3/10)...
    mgr not available, waiting (4/10)...
    mgr is available
    Enabling cephadm module...
    Waiting for the mgr to restart...
    Waiting for Mgr epoch 5...
    Mgr epoch 5 is available
    Setting orchestrator backend to cephadm...
    Generating ssh key...
    Wrote public SSH key to to /etc/ceph/ceph.pub
    Adding key to root@localhost's authorized_keys...
    Adding host ceph1...
    Deploying mon service with default placement...
    Deploying mgr service with default placement...
    Deploying crash service with default placement...
    Enabling mgr prometheus module...
    Deploying prometheus service with default placement...
    Deploying grafana service with default placement...
    Deploying node-exporter service with default placement...
    Deploying alertmanager service with default placement...
    Enabling the dashboard module...
    Waiting for the mgr to restart...
    Waiting for Mgr epoch 13...
    Mgr epoch 13 is available
    Generating a dashboard self-signed certificate...
    Creating initial admin user...
    Fetching dashboard port number...
    Ceph Dashboard is now available at:

    URL: https://localhost:8443/
    User: admin
    Password: vzmh8b8mp6

    You can access the Ceph CLI with:

    sudo /usr/sbin/cephadm shell --fsid 79a6cb92-6f92-11ec-b1e0-6f6f27397286 -c /etc/ceph/ceph.conf -k /etc/ceph/ceph.client.admin.keyring

    Please consider enabling telemetry to help improve Ceph:

    ceph telemetry on

    For more information see:

    https://docs.ceph.com/docs/master/mgr/telemetry/

    Bootstrap complete.
    • 该命令执行如下操作:

      • 在本地主机上为新集群创建 monitor 和 manager daemon 守护程序。

      • 为 Ceph 集群生成一个新的公共 SSH 密钥,并将其添加到 root 用户的 /root/.ssh/authorized_keys 文件中。

        1
        2
        3
        4
        5
        6
        root@ceph1:/opt# cat /root/.ssh/authorized_keys 
        ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC9iDQVKo2J9hNGVjq6XegDCAlLRuweTxbHruBauegj+7i5lTwJx0inpRcnshbPJxqRNimH54lr8mDYzQ2kVuVgFqpftB9Q+Y5VnMnvZWnlzaJgEQ0BOj4RmydRHKztbhay9YNyQebUxmSC/EYPCBRloM86A4gGGEoU4uroV9d6QZZ8memabUQRLuATygXEWK0upU9B5bRtoyEsHg+R9Ypc12/rz9sssOOwABmFd+ushouvF7oIdXmKQ4ehOY8t86YZV4PmOnEmuF/tfTYu+oLRkLro13Q0AmmmtTTjOiI5baekeldxiHf26DlFFxkzpAx7obTl+JrsS9DAiAwc/W51q2J70hRuVfSpA+U+TO7bUip+O8fpMwY3xDv2CZch0i7VN+MF8v/uB89ecW1AGz7Fu4xhaauTqlDXgJ1pG9jw6UnJRXwZI4UdAGaG0/tPUWMqOJ+HSnt8kjFa/U7Jp1t6W6ryHZTZXt+1JeuV4clAL0f3ic1R9d4k1jpnH4QsObM= root@ceph1 # ceph1免密登录
        ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCnzZyF16dJR8DpOTzyBwd4YbVE60blx7TOjn3VwPhPkU4f2lcJ2uPmFApEwHOTHvFi6Mz9jnE6BymrAHAUIzXPU5D8fasoJ5tNOKODYEtaETsdimEN1hLiLFKET8JLU/EUoy7pgHllxDlCsfwZvFoJ2XUvX1ab5rCs5AB4c/pU3IG24zN/UBsl7pynIA8XLAWFSSg2KHPEAYwNMF/oBLt4+/z5xBGDYBtdLId1lB/UrYyj9RamJywuSMEZckUbEEo8AqZeGzXbXKFwHcy2dxUesCFT0C5B95c71HU6g/3zOu/hYjXLUU/NeX7ggsPwKDr19p18JNxX+iyjpfrupK1PxgALniuZXKaHpiC7geGoosb8P0SR1Cq0RJhs/PWwPFpPqTRI2svUWLskb5WG2xIYVE6uuRhJAdTirKSX/+l8Bw5iau8BEYZ4zCT8g/qMhb+tpYeM7lGh8usr0RtsK/U/Z48zu1HqYMKVvK5olmwFKgRe6Ss5JqJ7GqX3T37UYL0= root@ceph2 # ceph1免密登录
        ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCiBgLpJH5BcUdTG4tT/6ln++GnCoMIpKlV3rjlYoWAa5efn60d1JKqgTBMRusa79D9kIihGCWjxBio2o0QplrKyHtjLKNLLaNShVOCZESJATrSf2ZwGmj6pS2RT4Bg0xchByZlQXIBwEyeLQ0T4hC45JYoXDeiPEezp+pPYqTIxDoks/wbb4IqUtsdtoXI1m/3GT1KCl1FofWWoc5PaXSiFwg+YZ5QAW2y6i5oRZH2cTyPpcrCtlqPRa1h8V8+C/vN8EcEMMxofW0sS4XCrtqYUcZcoPjcbHofQlC6cTf5/IhSNBME7Re2bMSFvn68n5vdS0z6fITSjCZdkm8I9V4omXpbGoztbbK4J7TDPL2IZWw6bh/LP7L4YuaUFPWmkHAWrckVtNEciYpXBgE9cKWgxpq0/UWXRFmMUgYmejz126/mtSwGpXV+VhjlXlw/wFsIS6k8BYEYsrFZrdYNgQA+6L0DenEwPqcfFb3NEqRH66Urgen3NCibBzYtpI5PlR8= root@ceph3 # ceph3免密登录
        ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCzntkcguxOqBlvUxBX0S80BzQd36MGxg3TkDLJWq5D/gi6hcUpQOrFwMtXctQWv+8AK708fXssaj07SwF939rxQFBrU83M59ZdrILAFH3dSZNOh4YYj30weHOmsj/uBkH9rQOYoc2JApVDV76OSjTm8Uztez8cQ0r355rd0wwHmX1eVkL1mgCu7PAemD64a4J7fZUOl0eYdz1HyqjGNprYZItAeqldAFwMfi8wQZubyfzeQX2hM5rWehaP5OxhvlCrHUdGhwM3m82fyNWzJcfCexnIfoaJkyYcEXrcjtvWfUeUcoLmYd6jSa19jhr2AkkDSxyxZ43p/73d5tgzJFzX5etjBK33P/zDfIG1HIiD56Tn9jOXJ/Kud9JF+RLGmEaVsvqWwZJLJIN8bin/S+Viv9kVtytOWFpilea1LQGg2Sap2Y/8oQJbDCk24wCHGKbRFmFYOalqEuX9GwM3h0mRwt+UBVv7M3x/JsliyA7tKlN9V+oPH+3LxVpw+Wfq8rU= root@ceph4 # ceph4免密登录
        ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDGii1dKJdramvUhkqwyix/G39kAEw+CGt1NNdM78QmrumLlWqtToO6TwmfgMqu/2geBafkOs9fhLJB+qV/oQ8mpBaGgzXgBOthtCMyEWBtBB78wJJ+cgn2EkkQLsmJmMfwbp+dnMJMvqWKPKYZoyODyZvhnS4uofFfpBqMI9xLjpnNgVerQbyN1DIH+WkBnrhonirzr78DPlsU3zpEdB5wlVduIqaPNrnW4DUNje5quhFcTd7D40kQeAKZBm5Py94R93BqEUyhRUYaz5dHAF4Wh/dTcD/aA3aq7fiOcdxNjOBD9Z/bCG5B32Eb+4iehzk3O4JoTNnl3FtYMVz50MaPphWQh9yBTbrUY/pxupvvderhDNz7yAxmSzM6MKVPlVaSpSaQf2MKUqWRNzcJDaOw8/aQi6GuJe/Iljpbvse1NO3cTtZF0IRuTjham90DptKyHfDgms9+gmhiDg6uLzM8jLmY74He8W8FOtalXBhALCYFP2lX9IYx1HFSnt42UdE= ceph-79a6cb92-6f92-11ec-b1e0-6f6f27397286 # 公共SSH密钥
      • 将与新群集进行通信所需的最小配置文件保存到 /etc/ceph/ceph.conf

      • /etc/ceph/ceph.client.admin.keyring 写入 client.admin 管理 secret key 的副本(特权!)。

      • 将 public key 的副本写入 /etc/ceph/ceph.pub

  • 查看当前配置文件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    root@ceph1:/opt# ll /etc/ceph/
    total 24
    drwxr-xr-x 2 root root 4096 Jan 7 16:19 ./
    drwxr-xr-x 104 root root 4096 Jan 7 16:02 ../
    -rw------- 1 root root 63 Jan 7 16:19 ceph.client.admin.keyring
    -rw-r--r-- 1 root root 175 Jan 7 16:19 ceph.conf
    -rw-r--r-- 1 root root 595 Jan 7 16:19 ceph.pub
    -rw-r--r-- 1 root root 92 Oct 20 22:31 rbdmap
    root@ceph1:/opt# cat /etc/ceph/ceph.conf
    # minimal ceph.conf for 79a6cb92-6f92-11ec-b1e0-6f6f27397286
    [global]
    fsid = 79a6cb92-6f92-11ec-b1e0-6f6f27397286
    mon_host = [v2:192.168.1.91:3300/0,v1:192.168.1.91:6789/0]
  • 查看当前拉取的镜像和启动的容器:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    root@ceph1:/opt# docker images
    REPOSITORY TAG IMAGE ID CREATED SIZE
    quay.io/ceph/ceph v15 3437f7bed968 2 months ago 1.08GB
    hello-world latest feb5d9fea6a5 3 months ago 13.3kB
    quay.io/ceph/ceph-grafana 6.7.4 557c83e11646 5 months ago 486MB
    quay.io/prometheus/prometheus v2.18.1 de242295e225 20 months ago 140MB
    quay.io/prometheus/alertmanager v0.20.0 0881eb8f169f 2 years ago 52.1MB
    quay.io/prometheus/node-exporter v0.18.1 e5a616e4b9cf 2 years ago 22.9MB
    root@ceph1:/opt# docker ps -a
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    1fdde1918435 quay.io/prometheus/alertmanager:v0.20.0 "/bin/alertmanager -…" 47 minutes ago Up 47 minutes ceph-79a6cb92-6f92-11ec-b1e0-6f6f27397286-alertmanager.ceph1
    5fc44d4adaa8 quay.io/ceph/ceph-grafana:6.7.4 "/bin/sh -c 'grafana…" 47 minutes ago Up 47 minutes ceph-79a6cb92-6f92-11ec-b1e0-6f6f27397286-grafana.ceph1
    85cac2612c10 quay.io/prometheus/prometheus:v2.18.1 "/bin/prometheus --c…" 47 minutes ago Up 47 minutes ceph-79a6cb92-6f92-11ec-b1e0-6f6f27397286-prometheus.ceph1
    d1aa75b76a39 quay.io/prometheus/node-exporter:v0.18.1 "/bin/node_exporter …" 48 minutes ago Up 48 minutes ceph-79a6cb92-6f92-11ec-b1e0-6f6f27397286-node-exporter.ceph1
    c20775682c08 quay.io/ceph/ceph:v15 "/usr/bin/ceph-crash…" 48 minutes ago Up 48 minutes ceph-79a6cb92-6f92-11ec-b1e0-6f6f27397286-crash.ceph1
    7c3cf4e445d1 quay.io/ceph/ceph:v15 "/usr/bin/ceph-mgr -…" 54 minutes ago Up 54 minutes ceph-79a6cb92-6f92-11ec-b1e0-6f6f27397286-mgr.ceph1.tlpgcb
    6410679d498a quay.io/ceph/ceph:v15 "/usr/bin/ceph-mon -…" 55 minutes ago Up 54 minutes ceph-79a6cb92-6f92-11ec-b1e0-6f6f27397286-mon.ceph1
    acf9377ed00d hello-world "/hello" 6 hours ago Exited (0) 6 hours ago ecstatic_gould
    • alertmanager 组件:prometheus 告警组件。
    • grafana 组件:监控数据展示 dashboard。
    • prometheus 组件:prometheus 监控组件。
    • node_exporter 组件:prometheus 节点数据收集组件。
    • ceph-crash 组件:崩溃数据收集模块。
    • ceph-mgr 组件:Ceph 管理程序。
    • ceph-monitor 组件:Ceph 监视器。
  • 查看所有组件运行状态:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    root@ceph1:/opt# ceph orch ps
    NAME HOST STATUS REFRESHED AGE VERSION IMAGE NAME IMAGE ID CONTAINER ID
    alertmanager.ceph1 ceph1 running (5h) 8m ago 5h 0.20.0 quay.io/prometheus/alertmanager:v0.20.0 0881eb8f169f 1fdde1918435
    crash.ceph1 ceph1 running (5h) 8m ago 5h 15.2.15 quay.io/ceph/ceph:v15 3437f7bed968 c20775682c08
    grafana.ceph1 ceph1 running (5h) 8m ago 5h 6.7.4 quay.io/ceph/ceph-grafana:6.7.4 557c83e11646 5fc44d4adaa8
    mgr.ceph1.tlpgcb ceph1 running (5h) 8m ago 5h 15.2.15 quay.io/ceph/ceph:v15 3437f7bed968 7c3cf4e445d1
    mon.ceph1 ceph1 running (5h) 8m ago 5h 15.2.15 quay.io/ceph/ceph:v15 3437f7bed968 6410679d498a
    node-exporter.ceph1 ceph1 running (5h) 8m ago 5h 0.18.1 quay.io/prometheus/node-exporter:v0.18.1 e5a616e4b9cf d1aa75b76a39
    prometheus.ceph1 ceph1 running (5h) 8m ago 5h 2.18.1 quay.io/prometheus/prometheus:v2.18.1 de242295e225 85cac2612c10
  • 查看某个组件运行状态:

    1
    2
    3
    root@ceph1:/opt# ceph orch ps --daemon-type mgr
    NAME HOST STATUS REFRESHED AGE VERSION IMAGE NAME IMAGE ID CONTAINER ID
    mgr.ceph1.tlpgcb ceph1 running (5h) 4m ago 5h 15.2.15 quay.io/ceph/ceph:v15 3437f7bed968 7c3cf4e445d1
  • 查看容器状态:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    root@ceph1:/opt# cephadm ls
    [
    {
    "style": "cephadm:v1",
    "name": "crash.ceph1",
    "fsid": "79a6cb92-6f92-11ec-b1e0-6f6f27397286",
    "systemd_unit": "ceph-79a6cb92-6f92-11ec-b1e0-6f6f27397286@crash.ceph1",
    "enabled": true,
    "state": "running",
    "container_id": "c20775682c087aaf8d1dc25802386ac4fbaf40b3ab8a4ae7ef54843e26725d94",
    "container_image_name": "quay.io/ceph/ceph:v15",
    "container_image_id": "3437f7bed9688a799444b439e1947a6f00d1f9b1fc986e843aec7e3ac8acd12b",
    "version": "15.2.15",
    "started": "2022-01-07T08:25:11.762461Z",
    "created": "2022-01-07T08:25:11.702112Z",
    "deployed": "2022-01-07T08:25:11.318096Z",
    "configured": "2022-01-07T08:25:11.702112Z"
    },
    {
    "style": "cephadm:v1",
    "name": "grafana.ceph1",
    "fsid": "79a6cb92-6f92-11ec-b1e0-6f6f27397286",
    "systemd_unit": "ceph-79a6cb92-6f92-11ec-b1e0-6f6f27397286@grafana.ceph1",
    "enabled": true,
    "state": "running",
    "container_id": "5fc44d4adaa8365aa4a290d769fd08b25a2dee4c5235f4ef377aff0ced55ef2b",
    "container_image_name": "quay.io/ceph/ceph-grafana:6.7.4",
    "container_image_id": "557c83e11646f123a27b5e4b62ac6c45e7bb8b2e90d6044034d0db5b7019415c",
    "version": "6.7.4",
    "started": "2022-01-07T08:26:37.418809Z",
    "created": "2022-01-07T08:25:51.875753Z",
    "deployed": "2022-01-07T08:25:51.487738Z",
    "configured": "2022-01-07T08:26:37.229606Z"
    },
    {
    "style": "cephadm:v1",
    "name": "mgr.ceph1.tlpgcb",
    "fsid": "79a6cb92-6f92-11ec-b1e0-6f6f27397286",
    "systemd_unit": "ceph-79a6cb92-6f92-11ec-b1e0-6f6f27397286@mgr.ceph1.tlpgcb",
    "enabled": true,
    "state": "running",
    "container_id": "7c3cf4e445d1113caa67c7502ffd5265961ecba5430e909f34f853b1fc021f1e",
    "container_image_name": "quay.io/ceph/ceph:v15",
    "container_image_id": "3437f7bed9688a799444b439e1947a6f00d1f9b1fc986e843aec7e3ac8acd12b",
    "version": "15.2.15",
    "started": "2022-01-07T08:19:10.362590Z",
    "created": "2022-01-07T08:19:10.279314Z",
    "deployed": "2022-01-07T08:19:09.911299Z",
    "configured": "2022-01-07T08:26:37.749627Z"
    },
    {
    "style": "cephadm:v1",
    "name": "alertmanager.ceph1",
    "fsid": "79a6cb92-6f92-11ec-b1e0-6f6f27397286",
    "systemd_unit": "ceph-79a6cb92-6f92-11ec-b1e0-6f6f27397286@alertmanager.ceph1",
    "enabled": true,
    "state": "running",
    "container_id": "1fdde19184350e4c731b484bf10b3943e95f0ec27a306daa7ff547414e9e587e",
    "container_image_name": "quay.io/prometheus/alertmanager:v0.20.0",
    "container_image_id": "0881eb8f169f5556a292b4e2c01d683172b12830a62a9225a98a8e206bb734f0",
    "version": "0.20.0",
    "started": "2022-01-07T08:26:38.462159Z",
    "created": "2022-01-07T08:25:09.854037Z",
    "deployed": "2022-01-07T08:25:09.486022Z",
    "configured": "2022-01-07T08:26:38.297650Z"
    },
    {
    "style": "cephadm:v1",
    "name": "prometheus.ceph1",
    "fsid": "79a6cb92-6f92-11ec-b1e0-6f6f27397286",
    "systemd_unit": "ceph-79a6cb92-6f92-11ec-b1e0-6f6f27397286@prometheus.ceph1",
    "enabled": true,
    "state": "running",
    "container_id": "85cac2612c105ec9809a88fa97f99633b50b50ba12ee0a9b2beb95c608be73ff",
    "container_image_name": "quay.io/prometheus/prometheus:v2.18.1",
    "container_image_id": "de242295e2257c37c8cadfd962369228f8f10b2d48a44259b65fef44ad4f6490",
    "version": "2.18.1",
    "started": "2022-01-07T08:26:35.419299Z",
    "created": "2022-01-07T08:26:35.361530Z",
    "deployed": "2022-01-07T08:26:34.993515Z",
    "configured": "2022-01-07T08:26:35.361530Z"
    },
    {
    "style": "cephadm:v1",
    "name": "mon.ceph1",
    "fsid": "79a6cb92-6f92-11ec-b1e0-6f6f27397286",
    "systemd_unit": "ceph-79a6cb92-6f92-11ec-b1e0-6f6f27397286@mon.ceph1",
    "enabled": true,
    "state": "running",
    "container_id": "6410679d498a31428927c7a532548d39f5261c80f94c867849902a6bea12208b",
    "container_image_name": "quay.io/ceph/ceph:v15",
    "container_image_id": "3437f7bed9688a799444b439e1947a6f00d1f9b1fc986e843aec7e3ac8acd12b",
    "version": "15.2.15",
    "started": "2022-01-07T08:19:09.667576Z",
    "created": "2022-01-07T08:19:08.539242Z",
    "deployed": "2022-01-07T08:19:07.699208Z",
    "configured": "2022-01-07T08:26:38.785670Z"
    },
    {
    "style": "cephadm:v1",
    "name": "node-exporter.ceph1",
    "fsid": "79a6cb92-6f92-11ec-b1e0-6f6f27397286",
    "systemd_unit": "ceph-79a6cb92-6f92-11ec-b1e0-6f6f27397286@node-exporter.ceph1",
    "enabled": true,
    "state": "running",
    "container_id": "d1aa75b76a39554b9b5cc7b5e9c4cf9c4ca4d00b9401af79b3c8eda6009fc215",
    "container_image_name": "quay.io/prometheus/node-exporter:v0.18.1",
    "container_image_id": "e5a616e4b9cf68dfcad7782b78e118be4310022e874d52da85c55923fb615f87",
    "version": "0.18.1",
    "started": "2022-01-07T08:26:02.530410Z",
    "created": "2022-01-07T08:25:52.639785Z",
    "deployed": "2022-01-07T08:25:52.179766Z",
    "configured": "2022-01-07T08:25:52.639785Z"
    }
    ]
  • 根据初始化完成的提示使用浏览器访问 dashboard:略。

启用 Ceph 命令

  • 在 ceph1 上执行命令:

    1
    2
    3
    4
    5
    6
    7
    root@ceph1:/opt# cephadm shell
    Inferring fsid 79a6cb92-6f92-11ec-b1e0-6f6f27397286
    Inferring config /var/lib/ceph/79a6cb92-6f92-11ec-b1e0-6f6f27397286/mon.ceph1/config
    Using recent ceph image quay.io/ceph/ceph@sha256:a2c23b6942f7fbc1e15d8cfacd6655a681fe0e44f288e4a158db22030b8d58e3
    root@ceph1:/# alias ceph='cephadm shell -- ceph'
    root@ceph1:/# exit
    exit
  • 查看集群状态:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    root@ceph1:/opt# ceph -s
    cluster:
    id: 79a6cb92-6f92-11ec-b1e0-6f6f27397286
    health: HEALTH_WARN
    OSD count 0 < osd_pool_default_size 3

    services:
    mon: 1 daemons, quorum ceph1 (age 21h)
    mgr: ceph1.tlpgcb(active, since 21h)
    osd: 0 osds: 0 up, 0 in

    data:
    pools: 0 pools, 0 pgs
    objects: 0 objects, 0 B
    usage: 0 B used, 0 B / 0 B avail
    pgs:

    root@ceph1:/opt# ceph status
    cluster:
    id: 79a6cb92-6f92-11ec-b1e0-6f6f27397286
    health: HEALTH_WARN
    OSD count 0 < osd_pool_default_size 3

    services:
    mon: 1 daemons, quorum ceph1 (age 21h)
    mgr: ceph1.tlpgcb(active, since 21h)
    osd: 0 osds: 0 up, 0 in

    data:
    pools: 0 pools, 0 pgs
    objects: 0 objects, 0 B
    usage: 0 B used, 0 B / 0 B avail
    pgs:

    添加新主机到集群中

  • 第一步,在 ceph1 上执行命令,将集群的公共 SSH 密钥添加到新主机的根用户 authorized_keys 文件中:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    root@ceph1:/opt# ssh-copy-id -f -i /etc/ceph/ceph.pub root@ceph2
    /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/etc/ceph/ceph.pub"

    Number of key(s) added: 1

    Now try logging into the machine, with: "ssh 'root@ceph2'"
    and check to make sure that only the key(s) you wanted were added.

    root@ceph1:/opt# ll /etc/ceph/
    total 24
    drwxr-xr-x 2 root root 4096 Jan 7 16:19 ./
    drwxr-xr-x 104 root root 4096 Jan 7 16:02 ../
    -rw------- 1 root root 63 Jan 7 16:19 ceph.client.admin.keyring
    -rw-r--r-- 1 root root 175 Jan 7 16:19 ceph.conf
    -rw-r--r-- 1 root root 595 Jan 7 16:19 ceph.pub
    -rw-r--r-- 1 root root 92 Oct 20 22:31 rbdmap
    root@ceph1:/opt# ssh-copy-id -f -i /etc/ceph/ceph.pub root@ceph3
    /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/etc/ceph/ceph.pub"

    Number of key(s) added: 1

    Now try logging into the machine, with: "ssh 'root@ceph3'"
    and check to make sure that only the key(s) you wanted were added.

    root@ceph1:/opt# ssh-copy-id -f -i /etc/ceph/ceph.pub root@ceph4
    /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/etc/ceph/ceph.pub"

    Number of key(s) added: 1

    Now try logging into the machine, with: "ssh 'root@ceph4'"
    and check to make sure that only the key(s) you wanted were added.
    root@ceph1:/opt# cat /root/.ssh/authorized_keys
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC9iDQVKo2J9hNGVjq6XegDCAlLRuweTxbHruBauegj+7i5lTwJx0inpRcnshbPJxqRNimH54lr8mDYzQ2kVuVgFqpftB9Q+Y5VnMnvZWnlzaJgEQ0BOj4RmydRHKztbhay9YNyQebUxmSC/EYPCBRloM86A4gGGEoU4uroV9d6QZZ8memabUQRLuATygXEWK0upU9B5bRtoyEsHg+R9Ypc12/rz9sssOOwABmFd+ushouvF7oIdXmKQ4ehOY8t86YZV4PmOnEmuF/tfTYu+oLRkLro13Q0AmmmtTTjOiI5baekeldxiHf26DlFFxkzpAx7obTl+JrsS9DAiAwc/W51q2J70hRuVfSpA+U+TO7bUip+O8fpMwY3xDv2CZch0i7VN+MF8v/uB89ecW1AGz7Fu4xhaauTqlDXgJ1pG9jw6UnJRXwZI4UdAGaG0/tPUWMqOJ+HSnt8kjFa/U7Jp1t6W6ryHZTZXt+1JeuV4clAL0f3ic1R9d4k1jpnH4QsObM= root@ceph1
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCnzZyF16dJR8DpOTzyBwd4YbVE60blx7TOjn3VwPhPkU4f2lcJ2uPmFApEwHOTHvFi6Mz9jnE6BymrAHAUIzXPU5D8fasoJ5tNOKODYEtaETsdimEN1hLiLFKET8JLU/EUoy7pgHllxDlCsfwZvFoJ2XUvX1ab5rCs5AB4c/pU3IG24zN/UBsl7pynIA8XLAWFSSg2KHPEAYwNMF/oBLt4+/z5xBGDYBtdLId1lB/UrYyj9RamJywuSMEZckUbEEo8AqZeGzXbXKFwHcy2dxUesCFT0C5B95c71HU6g/3zOu/hYjXLUU/NeX7ggsPwKDr19p18JNxX+iyjpfrupK1PxgALniuZXKaHpiC7geGoosb8P0SR1Cq0RJhs/PWwPFpPqTRI2svUWLskb5WG2xIYVE6uuRhJAdTirKSX/+l8Bw5iau8BEYZ4zCT8g/qMhb+tpYeM7lGh8usr0RtsK/U/Z48zu1HqYMKVvK5olmwFKgRe6Ss5JqJ7GqX3T37UYL0= root@ceph2
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCiBgLpJH5BcUdTG4tT/6ln++GnCoMIpKlV3rjlYoWAa5efn60d1JKqgTBMRusa79D9kIihGCWjxBio2o0QplrKyHtjLKNLLaNShVOCZESJATrSf2ZwGmj6pS2RT4Bg0xchByZlQXIBwEyeLQ0T4hC45JYoXDeiPEezp+pPYqTIxDoks/wbb4IqUtsdtoXI1m/3GT1KCl1FofWWoc5PaXSiFwg+YZ5QAW2y6i5oRZH2cTyPpcrCtlqPRa1h8V8+C/vN8EcEMMxofW0sS4XCrtqYUcZcoPjcbHofQlC6cTf5/IhSNBME7Re2bMSFvn68n5vdS0z6fITSjCZdkm8I9V4omXpbGoztbbK4J7TDPL2IZWw6bh/LP7L4YuaUFPWmkHAWrckVtNEciYpXBgE9cKWgxpq0/UWXRFmMUgYmejz126/mtSwGpXV+VhjlXlw/wFsIS6k8BYEYsrFZrdYNgQA+6L0DenEwPqcfFb3NEqRH66Urgen3NCibBzYtpI5PlR8= root@ceph3
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCzntkcguxOqBlvUxBX0S80BzQd36MGxg3TkDLJWq5D/gi6hcUpQOrFwMtXctQWv+8AK708fXssaj07SwF939rxQFBrU83M59ZdrILAFH3dSZNOh4YYj30weHOmsj/uBkH9rQOYoc2JApVDV76OSjTm8Uztez8cQ0r355rd0wwHmX1eVkL1mgCu7PAemD64a4J7fZUOl0eYdz1HyqjGNprYZItAeqldAFwMfi8wQZubyfzeQX2hM5rWehaP5OxhvlCrHUdGhwM3m82fyNWzJcfCexnIfoaJkyYcEXrcjtvWfUeUcoLmYd6jSa19jhr2AkkDSxyxZ43p/73d5tgzJFzX5etjBK33P/zDfIG1HIiD56Tn9jOXJ/Kud9JF+RLGmEaVsvqWwZJLJIN8bin/S+Viv9kVtytOWFpilea1LQGg2Sap2Y/8oQJbDCk24wCHGKbRFmFYOalqEuX9GwM3h0mRwt+UBVv7M3x/JsliyA7tKlN9V+oPH+3LxVpw+Wfq8rU= root@ceph4
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDGii1dKJdramvUhkqwyix/G39kAEw+CGt1NNdM78QmrumLlWqtToO6TwmfgMqu/2geBafkOs9fhLJB+qV/oQ8mpBaGgzXgBOthtCMyEWBtBB78wJJ+cgn2EkkQLsmJmMfwbp+dnMJMvqWKPKYZoyODyZvhnS4uofFfpBqMI9xLjpnNgVerQbyN1DIH+WkBnrhonirzr78DPlsU3zpEdB5wlVduIqaPNrnW4DUNje5quhFcTd7D40kQeAKZBm5Py94R93BqEUyhRUYaz5dHAF4Wh/dTcD/aA3aq7fiOcdxNjOBD9Z/bCG5B32Eb+4iehzk3O4JoTNnl3FtYMVz50MaPphWQh9yBTbrUY/pxupvvderhDNz7yAxmSzM6MKVPlVaSpSaQf2MKUqWRNzcJDaOw8/aQi6GuJe/Iljpbvse1NO3cTtZF0IRuTjham90DptKyHfDgms9+gmhiDg6uLzM8jLmY74He8W8FOtalXBhALCYFP2lX9IYx1HFSnt42UdE= ceph-79a6cb92-6f92-11ec-b1e0-6f6f27397286 # 公共SSH密钥
  • 在新结点上查看密钥是否添加成功:

    1
    2
    3
    4
    5
    6
    root@ceph2:/opt# cat /root/.ssh/authorized_keys 
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC9iDQVKo2J9hNGVjq6XegDCAlLRuweTxbHruBauegj+7i5lTwJx0inpRcnshbPJxqRNimH54lr8mDYzQ2kVuVgFqpftB9Q+Y5VnMnvZWnlzaJgEQ0BOj4RmydRHKztbhay9YNyQebUxmSC/EYPCBRloM86A4gGGEoU4uroV9d6QZZ8memabUQRLuATygXEWK0upU9B5bRtoyEsHg+R9Ypc12/rz9sssOOwABmFd+ushouvF7oIdXmKQ4ehOY8t86YZV4PmOnEmuF/tfTYu+oLRkLro13Q0AmmmtTTjOiI5baekeldxiHf26DlFFxkzpAx7obTl+JrsS9DAiAwc/W51q2J70hRuVfSpA+U+TO7bUip+O8fpMwY3xDv2CZch0i7VN+MF8v/uB89ecW1AGz7Fu4xhaauTqlDXgJ1pG9jw6UnJRXwZI4UdAGaG0/tPUWMqOJ+HSnt8kjFa/U7Jp1t6W6ryHZTZXt+1JeuV4clAL0f3ic1R9d4k1jpnH4QsObM= root@ceph1
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCnzZyF16dJR8DpOTzyBwd4YbVE60blx7TOjn3VwPhPkU4f2lcJ2uPmFApEwHOTHvFi6Mz9jnE6BymrAHAUIzXPU5D8fasoJ5tNOKODYEtaETsdimEN1hLiLFKET8JLU/EUoy7pgHllxDlCsfwZvFoJ2XUvX1ab5rCs5AB4c/pU3IG24zN/UBsl7pynIA8XLAWFSSg2KHPEAYwNMF/oBLt4+/z5xBGDYBtdLId1lB/UrYyj9RamJywuSMEZckUbEEo8AqZeGzXbXKFwHcy2dxUesCFT0C5B95c71HU6g/3zOu/hYjXLUU/NeX7ggsPwKDr19p18JNxX+iyjpfrupK1PxgALniuZXKaHpiC7geGoosb8P0SR1Cq0RJhs/PWwPFpPqTRI2svUWLskb5WG2xIYVE6uuRhJAdTirKSX/+l8Bw5iau8BEYZ4zCT8g/qMhb+tpYeM7lGh8usr0RtsK/U/Z48zu1HqYMKVvK5olmwFKgRe6Ss5JqJ7GqX3T37UYL0= root@ceph2
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCiBgLpJH5BcUdTG4tT/6ln++GnCoMIpKlV3rjlYoWAa5efn60d1JKqgTBMRusa79D9kIihGCWjxBio2o0QplrKyHtjLKNLLaNShVOCZESJATrSf2ZwGmj6pS2RT4Bg0xchByZlQXIBwEyeLQ0T4hC45JYoXDeiPEezp+pPYqTIxDoks/wbb4IqUtsdtoXI1m/3GT1KCl1FofWWoc5PaXSiFwg+YZ5QAW2y6i5oRZH2cTyPpcrCtlqPRa1h8V8+C/vN8EcEMMxofW0sS4XCrtqYUcZcoPjcbHofQlC6cTf5/IhSNBME7Re2bMSFvn68n5vdS0z6fITSjCZdkm8I9V4omXpbGoztbbK4J7TDPL2IZWw6bh/LP7L4YuaUFPWmkHAWrckVtNEciYpXBgE9cKWgxpq0/UWXRFmMUgYmejz126/mtSwGpXV+VhjlXlw/wFsIS6k8BYEYsrFZrdYNgQA+6L0DenEwPqcfFb3NEqRH66Urgen3NCibBzYtpI5PlR8= root@ceph3
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCzntkcguxOqBlvUxBX0S80BzQd36MGxg3TkDLJWq5D/gi6hcUpQOrFwMtXctQWv+8AK708fXssaj07SwF939rxQFBrU83M59ZdrILAFH3dSZNOh4YYj30weHOmsj/uBkH9rQOYoc2JApVDV76OSjTm8Uztez8cQ0r355rd0wwHmX1eVkL1mgCu7PAemD64a4J7fZUOl0eYdz1HyqjGNprYZItAeqldAFwMfi8wQZubyfzeQX2hM5rWehaP5OxhvlCrHUdGhwM3m82fyNWzJcfCexnIfoaJkyYcEXrcjtvWfUeUcoLmYd6jSa19jhr2AkkDSxyxZ43p/73d5tgzJFzX5etjBK33P/zDfIG1HIiD56Tn9jOXJ/Kud9JF+RLGmEaVsvqWwZJLJIN8bin/S+Viv9kVtytOWFpilea1LQGg2Sap2Y/8oQJbDCk24wCHGKbRFmFYOalqEuX9GwM3h0mRwt+UBVv7M3x/JsliyA7tKlN9V+oPH+3LxVpw+Wfq8rU= root@ceph4
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDGii1dKJdramvUhkqwyix/G39kAEw+CGt1NNdM78QmrumLlWqtToO6TwmfgMqu/2geBafkOs9fhLJB+qV/oQ8mpBaGgzXgBOthtCMyEWBtBB78wJJ+cgn2EkkQLsmJmMfwbp+dnMJMvqWKPKYZoyODyZvhnS4uofFfpBqMI9xLjpnNgVerQbyN1DIH+WkBnrhonirzr78DPlsU3zpEdB5wlVduIqaPNrnW4DUNje5quhFcTd7D40kQeAKZBm5Py94R93BqEUyhRUYaz5dHAF4Wh/dTcD/aA3aq7fiOcdxNjOBD9Z/bCG5B32Eb+4iehzk3O4JoTNnl3FtYMVz50MaPphWQh9yBTbrUY/pxupvvderhDNz7yAxmSzM6MKVPlVaSpSaQf2MKUqWRNzcJDaOw8/aQi6GuJe/Iljpbvse1NO3cTtZF0IRuTjham90DptKyHfDgms9+gmhiDg6uLzM8jLmY74He8W8FOtalXBhALCYFP2lX9IYx1HFSnt42UdE= ceph-79a6cb92-6f92-11ec-b1e0-6f6f27397286 # 公共SSH密钥
    1
    2
    3
    4
    5
    6
    root@ceph3:/opt# cat /root/.ssh/authorized_keys 
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC9iDQVKo2J9hNGVjq6XegDCAlLRuweTxbHruBauegj+7i5lTwJx0inpRcnshbPJxqRNimH54lr8mDYzQ2kVuVgFqpftB9Q+Y5VnMnvZWnlzaJgEQ0BOj4RmydRHKztbhay9YNyQebUxmSC/EYPCBRloM86A4gGGEoU4uroV9d6QZZ8memabUQRLuATygXEWK0upU9B5bRtoyEsHg+R9Ypc12/rz9sssOOwABmFd+ushouvF7oIdXmKQ4ehOY8t86YZV4PmOnEmuF/tfTYu+oLRkLro13Q0AmmmtTTjOiI5baekeldxiHf26DlFFxkzpAx7obTl+JrsS9DAiAwc/W51q2J70hRuVfSpA+U+TO7bUip+O8fpMwY3xDv2CZch0i7VN+MF8v/uB89ecW1AGz7Fu4xhaauTqlDXgJ1pG9jw6UnJRXwZI4UdAGaG0/tPUWMqOJ+HSnt8kjFa/U7Jp1t6W6ryHZTZXt+1JeuV4clAL0f3ic1R9d4k1jpnH4QsObM= root@ceph1
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCnzZyF16dJR8DpOTzyBwd4YbVE60blx7TOjn3VwPhPkU4f2lcJ2uPmFApEwHOTHvFi6Mz9jnE6BymrAHAUIzXPU5D8fasoJ5tNOKODYEtaETsdimEN1hLiLFKET8JLU/EUoy7pgHllxDlCsfwZvFoJ2XUvX1ab5rCs5AB4c/pU3IG24zN/UBsl7pynIA8XLAWFSSg2KHPEAYwNMF/oBLt4+/z5xBGDYBtdLId1lB/UrYyj9RamJywuSMEZckUbEEo8AqZeGzXbXKFwHcy2dxUesCFT0C5B95c71HU6g/3zOu/hYjXLUU/NeX7ggsPwKDr19p18JNxX+iyjpfrupK1PxgALniuZXKaHpiC7geGoosb8P0SR1Cq0RJhs/PWwPFpPqTRI2svUWLskb5WG2xIYVE6uuRhJAdTirKSX/+l8Bw5iau8BEYZ4zCT8g/qMhb+tpYeM7lGh8usr0RtsK/U/Z48zu1HqYMKVvK5olmwFKgRe6Ss5JqJ7GqX3T37UYL0= root@ceph2
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCiBgLpJH5BcUdTG4tT/6ln++GnCoMIpKlV3rjlYoWAa5efn60d1JKqgTBMRusa79D9kIihGCWjxBio2o0QplrKyHtjLKNLLaNShVOCZESJATrSf2ZwGmj6pS2RT4Bg0xchByZlQXIBwEyeLQ0T4hC45JYoXDeiPEezp+pPYqTIxDoks/wbb4IqUtsdtoXI1m/3GT1KCl1FofWWoc5PaXSiFwg+YZ5QAW2y6i5oRZH2cTyPpcrCtlqPRa1h8V8+C/vN8EcEMMxofW0sS4XCrtqYUcZcoPjcbHofQlC6cTf5/IhSNBME7Re2bMSFvn68n5vdS0z6fITSjCZdkm8I9V4omXpbGoztbbK4J7TDPL2IZWw6bh/LP7L4YuaUFPWmkHAWrckVtNEciYpXBgE9cKWgxpq0/UWXRFmMUgYmejz126/mtSwGpXV+VhjlXlw/wFsIS6k8BYEYsrFZrdYNgQA+6L0DenEwPqcfFb3NEqRH66Urgen3NCibBzYtpI5PlR8= root@ceph3
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCzntkcguxOqBlvUxBX0S80BzQd36MGxg3TkDLJWq5D/gi6hcUpQOrFwMtXctQWv+8AK708fXssaj07SwF939rxQFBrU83M59ZdrILAFH3dSZNOh4YYj30weHOmsj/uBkH9rQOYoc2JApVDV76OSjTm8Uztez8cQ0r355rd0wwHmX1eVkL1mgCu7PAemD64a4J7fZUOl0eYdz1HyqjGNprYZItAeqldAFwMfi8wQZubyfzeQX2hM5rWehaP5OxhvlCrHUdGhwM3m82fyNWzJcfCexnIfoaJkyYcEXrcjtvWfUeUcoLmYd6jSa19jhr2AkkDSxyxZ43p/73d5tgzJFzX5etjBK33P/zDfIG1HIiD56Tn9jOXJ/Kud9JF+RLGmEaVsvqWwZJLJIN8bin/S+Viv9kVtytOWFpilea1LQGg2Sap2Y/8oQJbDCk24wCHGKbRFmFYOalqEuX9GwM3h0mRwt+UBVv7M3x/JsliyA7tKlN9V+oPH+3LxVpw+Wfq8rU= root@ceph4
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDGii1dKJdramvUhkqwyix/G39kAEw+CGt1NNdM78QmrumLlWqtToO6TwmfgMqu/2geBafkOs9fhLJB+qV/oQ8mpBaGgzXgBOthtCMyEWBtBB78wJJ+cgn2EkkQLsmJmMfwbp+dnMJMvqWKPKYZoyODyZvhnS4uofFfpBqMI9xLjpnNgVerQbyN1DIH+WkBnrhonirzr78DPlsU3zpEdB5wlVduIqaPNrnW4DUNje5quhFcTd7D40kQeAKZBm5Py94R93BqEUyhRUYaz5dHAF4Wh/dTcD/aA3aq7fiOcdxNjOBD9Z/bCG5B32Eb+4iehzk3O4JoTNnl3FtYMVz50MaPphWQh9yBTbrUY/pxupvvderhDNz7yAxmSzM6MKVPlVaSpSaQf2MKUqWRNzcJDaOw8/aQi6GuJe/Iljpbvse1NO3cTtZF0IRuTjham90DptKyHfDgms9+gmhiDg6uLzM8jLmY74He8W8FOtalXBhALCYFP2lX9IYx1HFSnt42UdE= ceph-79a6cb92-6f92-11ec-b1e0-6f6f27397286 # 公共SSH密钥
    1
    2
    3
    4
    5
    6
    root@ceph4:/opt# cat /root/.ssh/authorized_keys 
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC9iDQVKo2J9hNGVjq6XegDCAlLRuweTxbHruBauegj+7i5lTwJx0inpRcnshbPJxqRNimH54lr8mDYzQ2kVuVgFqpftB9Q+Y5VnMnvZWnlzaJgEQ0BOj4RmydRHKztbhay9YNyQebUxmSC/EYPCBRloM86A4gGGEoU4uroV9d6QZZ8memabUQRLuATygXEWK0upU9B5bRtoyEsHg+R9Ypc12/rz9sssOOwABmFd+ushouvF7oIdXmKQ4ehOY8t86YZV4PmOnEmuF/tfTYu+oLRkLro13Q0AmmmtTTjOiI5baekeldxiHf26DlFFxkzpAx7obTl+JrsS9DAiAwc/W51q2J70hRuVfSpA+U+TO7bUip+O8fpMwY3xDv2CZch0i7VN+MF8v/uB89ecW1AGz7Fu4xhaauTqlDXgJ1pG9jw6UnJRXwZI4UdAGaG0/tPUWMqOJ+HSnt8kjFa/U7Jp1t6W6ryHZTZXt+1JeuV4clAL0f3ic1R9d4k1jpnH4QsObM= root@ceph1
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCnzZyF16dJR8DpOTzyBwd4YbVE60blx7TOjn3VwPhPkU4f2lcJ2uPmFApEwHOTHvFi6Mz9jnE6BymrAHAUIzXPU5D8fasoJ5tNOKODYEtaETsdimEN1hLiLFKET8JLU/EUoy7pgHllxDlCsfwZvFoJ2XUvX1ab5rCs5AB4c/pU3IG24zN/UBsl7pynIA8XLAWFSSg2KHPEAYwNMF/oBLt4+/z5xBGDYBtdLId1lB/UrYyj9RamJywuSMEZckUbEEo8AqZeGzXbXKFwHcy2dxUesCFT0C5B95c71HU6g/3zOu/hYjXLUU/NeX7ggsPwKDr19p18JNxX+iyjpfrupK1PxgALniuZXKaHpiC7geGoosb8P0SR1Cq0RJhs/PWwPFpPqTRI2svUWLskb5WG2xIYVE6uuRhJAdTirKSX/+l8Bw5iau8BEYZ4zCT8g/qMhb+tpYeM7lGh8usr0RtsK/U/Z48zu1HqYMKVvK5olmwFKgRe6Ss5JqJ7GqX3T37UYL0= root@ceph2
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCiBgLpJH5BcUdTG4tT/6ln++GnCoMIpKlV3rjlYoWAa5efn60d1JKqgTBMRusa79D9kIihGCWjxBio2o0QplrKyHtjLKNLLaNShVOCZESJATrSf2ZwGmj6pS2RT4Bg0xchByZlQXIBwEyeLQ0T4hC45JYoXDeiPEezp+pPYqTIxDoks/wbb4IqUtsdtoXI1m/3GT1KCl1FofWWoc5PaXSiFwg+YZ5QAW2y6i5oRZH2cTyPpcrCtlqPRa1h8V8+C/vN8EcEMMxofW0sS4XCrtqYUcZcoPjcbHofQlC6cTf5/IhSNBME7Re2bMSFvn68n5vdS0z6fITSjCZdkm8I9V4omXpbGoztbbK4J7TDPL2IZWw6bh/LP7L4YuaUFPWmkHAWrckVtNEciYpXBgE9cKWgxpq0/UWXRFmMUgYmejz126/mtSwGpXV+VhjlXlw/wFsIS6k8BYEYsrFZrdYNgQA+6L0DenEwPqcfFb3NEqRH66Urgen3NCibBzYtpI5PlR8= root@ceph3
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCzntkcguxOqBlvUxBX0S80BzQd36MGxg3TkDLJWq5D/gi6hcUpQOrFwMtXctQWv+8AK708fXssaj07SwF939rxQFBrU83M59ZdrILAFH3dSZNOh4YYj30weHOmsj/uBkH9rQOYoc2JApVDV76OSjTm8Uztez8cQ0r355rd0wwHmX1eVkL1mgCu7PAemD64a4J7fZUOl0eYdz1HyqjGNprYZItAeqldAFwMfi8wQZubyfzeQX2hM5rWehaP5OxhvlCrHUdGhwM3m82fyNWzJcfCexnIfoaJkyYcEXrcjtvWfUeUcoLmYd6jSa19jhr2AkkDSxyxZ43p/73d5tgzJFzX5etjBK33P/zDfIG1HIiD56Tn9jOXJ/Kud9JF+RLGmEaVsvqWwZJLJIN8bin/S+Viv9kVtytOWFpilea1LQGg2Sap2Y/8oQJbDCk24wCHGKbRFmFYOalqEuX9GwM3h0mRwt+UBVv7M3x/JsliyA7tKlN9V+oPH+3LxVpw+Wfq8rU= root@ceph4
    ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDGii1dKJdramvUhkqwyix/G39kAEw+CGt1NNdM78QmrumLlWqtToO6TwmfgMqu/2geBafkOs9fhLJB+qV/oQ8mpBaGgzXgBOthtCMyEWBtBB78wJJ+cgn2EkkQLsmJmMfwbp+dnMJMvqWKPKYZoyODyZvhnS4uofFfpBqMI9xLjpnNgVerQbyN1DIH+WkBnrhonirzr78DPlsU3zpEdB5wlVduIqaPNrnW4DUNje5quhFcTd7D40kQeAKZBm5Py94R93BqEUyhRUYaz5dHAF4Wh/dTcD/aA3aq7fiOcdxNjOBD9Z/bCG5B32Eb+4iehzk3O4JoTNnl3FtYMVz50MaPphWQh9yBTbrUY/pxupvvderhDNz7yAxmSzM6MKVPlVaSpSaQf2MKUqWRNzcJDaOw8/aQi6GuJe/Iljpbvse1NO3cTtZF0IRuTjham90DptKyHfDgms9+gmhiDg6uLzM8jLmY74He8W8FOtalXBhALCYFP2lX9IYx1HFSnt42UdE= ceph-79a6cb92-6f92-11ec-b1e0-6f6f27397286 # 公共SSH密钥
  • 第二步,在 ceph1 上执行命令,告诉 Ceph,新节点是集群的一部分:

    1
    2
    3
    4
    5
    6
    root@ceph1:/opt# ceph orch host add ceph2
    Added host 'ceph2'
    root@ceph1:/opt# ceph orch host add ceph3
    Added host 'ceph3'
    root@ceph1:/opt# ceph orch host add ceph4
    Added host 'ceph4'
  • 查看 Ceph 纳管的所有节点:

    1
    2
    3
    4
    5
    6
    root@ceph1:/opt# ceph orch host ls
    HOST ADDR LABELS STATUS
    ceph1 ceph1
    ceph2 ceph2
    ceph3 ceph3
    ceph4 ceph4
  • 添加完成后 Ceph 会自动扩展 monitor 和 manager 到另外 3 个节点,在另外 3 个节点查看,自动运行了以下容器:

    1
    2
    3
    4
    5
    root@ceph2:/opt# docker ps
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    9631037be5f4 quay.io/prometheus/node-exporter:v0.18.1 "/bin/node_exporter …" 13 hours ago Up 13 hours ceph-79a6cb92-6f92-11ec-b1e0-6f6f27397286-node-exporter.ceph2
    08b248e6e233 quay.io/ceph/ceph:v15 "/usr/bin/ceph-mgr -…" 13 hours ago Up 13 hours ceph-79a6cb92-6f92-11ec-b1e0-6f6f27397286-mgr.ceph2.nxltpk
    9a57743caf61 quay.io/ceph/ceph:v15 "/usr/bin/ceph-crash…" 13 hours ago Up 13 hours ceph-79a6cb92-6f92-11ec-b1e0-6f6f27397286-crash.ceph2
    1
    2
    3
    4
    5
    root@ceph3:/opt# docker ps
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    f9ed0005d967 quay.io/prometheus/node-exporter:v0.18.1 "/bin/node_exporter …" 14 hours ago Up 14 hours ceph-79a6cb92-6f92-11ec-b1e0-6f6f27397286-node-exporter.ceph3
    57c0c9ba4221 quay.io/ceph/ceph:v15 "/usr/bin/ceph-mon -…" 14 hours ago Up 14 hours ceph-79a6cb92-6f92-11ec-b1e0-6f6f27397286-mon.ceph3
    6ad0d2342d96 quay.io/ceph/ceph:v15 "/usr/bin/ceph-crash…" 14 hours ago Up 14 hours ceph-79a6cb92-6f92-11ec-b1e0-6f6f27397286-crash.ceph3
    1
    2
    3
    4
    5
    root@ceph4:/opt# docker ps
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    fedc448936a7 quay.io/prometheus/node-exporter:v0.18.1 "/bin/node_exporter …" 14 hours ago Up 14 hours ceph-79a6cb92-6f92-11ec-b1e0-6f6f27397286-node-exporter.ceph4
    028820a77622 quay.io/ceph/ceph:v15 "/usr/bin/ceph-mon -…" 14 hours ago Up 14 hours ceph-79a6cb92-6f92-11ec-b1e0-6f6f27397286-mon.ceph4
    d2cee165f5de quay.io/ceph/ceph:v15 "/usr/bin/ceph-crash…" 14 hours ago Up 14 hours ceph-79a6cb92-6f92-11ec-b1e0-6f6f27397286-crash.ceph4
  • 查看 Ceph 集群状态:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    root@ceph1:/opt# ceph -s
    cluster:
    id: 79a6cb92-6f92-11ec-b1e0-6f6f27397286
    health: HEALTH_WARN
    Reduced data availability: 1 pg inactive
    OSD count 0 < osd_pool_default_size 3

    services:
    mon: 3 daemons, quorum ceph1,ceph4,ceph3 (age 14h)
    mgr: ceph1.tlpgcb(active, since 2d), standbys: ceph2.nxltpk
    osd: 0 osds: 0 up, 0 in

    data:
    pools: 1 pools, 1 pgs
    objects: 0 objects, 0 B
    usage: 0 B used, 0 B / 0 B avail
    pgs: 100.000% pgs unknown
    1 unknown

本文参考

Numpy

安装

1
2
3
4
5
6
7
8
9
(base) PS C:\Users\XiSun> conda env list
# conda environments:
#
base * D:\Program\Miniconda3
py38 D:\Program\Miniconda3\envs\py38

(base) PS C:\Users\XiSun> conda activate py38
(py38) PS C:\Users\XiSun> conda init
(py38) PS C:\Users\XiSun> conda install numpy -y

使用

Pandas

https://blog.csdn.net/qq_43060552/article/details/104862200

https://www.cnblogs.com/zzay/p/13157863.html

https://www.cnblogs.com/wenqiangit/p/11252859.html

本文参考

正则:

https://github.com/memect/kg-beijing/wiki/%E7%AC%AC%E4%B8%80%E6%9C%9Fw1%EF%BC%9A%E7%9F%A5%E8%AF%86%E6%8F%90%E5%8F%96

计算机基础知识

Windows 的命令行

  • 用户界面分成两种:TUI(文本交互界面)和 GUI(图形化交互界面)。

  • 命令行就是文本交互界面,通过命令行可以使用一个一个的指令来操作计算机。

  • 任何计算机的操作系统中都包含有命令行(Windows、Linux、MacOS),命令行有多个不同的名字:命令行、命令行窗口、DOS 窗口、命令提示符、CMD 窗口、Shell、终端、Terminal。

  • 命令行的进入方式:win 键 + R,出现运行窗口,输入cmd,然后回车。

  • 命令行的结构

    1
    2
    3
    4
    Microsoft Windows [版本 10.0.19042.1165]
    (c) Microsoft Corporation。保留所有权利。

    C:\Users\Xisun>
    • 上面两行为版本及版权声明(一般没有什么用)
    • 最下面一行为命令提示符
        - `C`:当前所在的磁盘根目录,通过 `x:` 来切换盘符(x 表示你的盘符)。
        - `\Users\Xisun`:当前所在磁盘的路径,通过 `cd` 来切换目录。
        - `>`:命令提示符,在符号后边可以直接输入指令。
  • 常用的 DOS 命令

    • 语法:命令 [参数] [选项]
    • dir:查看当前目录下的所有文件(夹)
    • cd:进入到指定的目录
      • .:表示当前目录。
      • ..:表示上一级目录。
    • md:创建一个目录。
    • rd:删除一个目录。
    • del:删除一个文件。
    • cls:清除屏幕。
    • 小技巧:方向键上下,查看命令的历史记录;tab 键自动补全命令。

环境变量

  • 环境变量指的就是操作系统当中的一些变量。可以通过修改环境变量,来对计算机进行配置(主要是来配置一些路径的)。
  • 查看环境变量
    • 右键计算机(此电脑)—> 选择属性 —> 系统界面左侧选择高级系统设置 —> 选择环境变量。
    • 环境变量界面分成了两个部分,上边是用户环境变量,下边是系统环境变量。
    • 用户环境变量只对当前用户有效,系统环境变量对所有用户有效。
  • 添加环境变量
    • 通过新建按钮添加环境变量。
    • 一个环境变量可以由多个值,值与值之间使用 ; 隔开。
  • 修改环境变量
    • 通过编辑按钮来修改环境变量。
  • 删除环境变量
    • 通过删除按钮来删除环境变量。

path 环境变量

  • path 环境变量中保存的是一个一个的路径。当我们在命令行中输入一个命令(或访问一个文件时),系统会首先在当前目录下寻找,如果找到了则直接执行或打开;如果没有找到,则会依次去 path 环境变量的路径中去寻找,直到找到为止;如果 path 环境变量中的路径都没有找到,则报错:'xxx' 不是内部或外部命令,也不是可运行的程序或批处理文件
  • 将一些经常需要访问到的文件或程序的路径,添加到 path 环境变量中,这样就可以在任意的位置访问到这些文件或程序。
  • 注意事项:
    • 如果环境变量中没有 path,可以手动添加。
    • path 环境变量不区分大小写:PATH、Path 或 path。
    • 修改完环境变量必须重新启动命令行窗口。
    • 多个路径之间使用 ; 隔开。

进制

  • 十进制
    • 十进制是最常用的进制。
    • 十进制算法:满十进一。
    • 十进制当中一共有 10 个数字:0,1,2,3,4,5,6,7,8,9。
    • 十进制如何计数:0,1,2,3,4,5,6,7,8,9;10,11,12,。。。,19;20,。。。,29;30,…
      • 个位表示有几个 1,十位表示有几个 10,百位表示有几个 100,千位表示有几个 1000,以此类推。如:5421。
  • 二进制
    • 二进制是计算机底层使用的进制。
      • 所有的数据在计算机底层都是以二进制的形式保存的,计算机只认二进制。
      • 可以将内存想象为一个一个的小格子,小格子中可以存储一个 0 或一个 1。
      • 内存中的每一个小格子,我们称为 1 bit(1 位)。
        • bit 是计算机中的最小的单位。
        • byte 是我们可操作的最小的单位。
          • 8 bit = 1 byte(字节)
          • 1024 byte = 1 kb(千字节)
          • 1024 kb = 1 mb(兆字节)
          • 1024 mb = 1 gb(吉字节)
          • 1024 gb = 1 tb(太字节)
    • 二进制算法:满二进一。
    • 二进制中一共有 2 个数字:0,1。
    • 二进制如何计数:0,1;10,11;100,101,110,111;1000,…
      • 第一位表示有几个 1,第二位表示有几个 2,第三位表示有几个 4,第四位表示有几个 8,依次类推。如:1011。
  • 八进制
    • 一般不用。
    • 八进制算法:满八进一。
    • 八进制中一共有 8 个数字:0,1,2,3,4,5,6,7。
    • 八进制如何计数:0,1,2,3,4,5,6,7;10,11,…,17;20,21,…,27;…
  • 十六进制
    • 在查看二进制数据时,一般会以十六进制的形式显示。
    • 十六进制算法:满十六进一。
    • 十六进制中一共有 16 个数字:0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f 。
      • 由于十六进制是满 16 才进位,所以十六进制中引入了 a,b,c,d,e,f 来表示 10,11,12,13,14,15。
    • 十六进制如何计数:0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f ;10,11,12 ,…,1a,1b,1c,1d,1e,1f,20,21,22,…,2a,2b,2c,2d,2e,2f;30,…

文本文件和字符集

  • 文本分成两种,一种叫做纯文本,还有一种叫做富文本。

  • 纯文本中只能保存单一的文本内容,无法保存内容无关的东西(如字体、颜色、图片等)。常见的纯文本如记事本。

  • 富文本中可以保存文本以外的内容。常见的富文本如 word 文档。

  • 在开发时,编写程序使用的全都是纯文本!

  • 纯文本在计算机底层也会转换为二进制保存:

    • 将字符转换为二进制码的过程,称为编码。
    • 将二进制码转换为字符的过程,称为解码。
    • 编码和解码时所采用的规则,称为字符集。
  • 常见的字符集:

    • ASCII
      • 美国人编码,使用 7 位来对美国常用的字符进行编码。
      • 包含 128 个字符。
    • ISO-8859-1
      • 欧洲的编码,使用 8 位来对欧洲常用的字符进行编码。
      • 包含 256 个字符。
    • GB2312,GBK
      • 国标码,中国的编码。
    • Unicode
      • 万国码,包含世界上所有的语言和符号,编写程序时一般都会使用 Unicode 编码。
      • Unicode 编码有多种实现,如 UTF-8,UTF-16,UTF-32,最常用的就是 UTF-8。
  • 乱码:编写程序时,如果发现程序代码出现乱码的情况,就要马上去检查字符集是否正确。

计算机语言

  • 计算机语言就是用来控制计算机的编程语言。
  • 计算机语言发展经历了三个阶段:
    • 机器语言
      • 机器语言通过二进制编码来编写程序。
      • 执行效率好,但编写起来太麻烦。
    • 符号语言/汇编语言
      • 使用符号来代替机器码。
      • 编写程序时,不需要使用二进制,而是直接编写符号。
      • 编写完成后,需要将符号转换为机器码,然后再由计算机执行。
      • 将符号转换为机器码的过程,称为汇编。
      • 将机器码转换为符号的过程,称为反汇编。
      • 汇编语言一般只适用于某些硬件,兼容性比较差。
    • 高级语言
      • 高级语言的语法基本和现在英语语法类似,并且和硬件的关系没有那么紧密了。
      • 也就是说我们通过高级语言开发的程序,可以在不同的硬件系统中执行。
      • 并且高级语言学习起来也更加的容易,现在我们知道的语言基本都是高级语言。比如:C、C++、C#、Java、JavaScript、Python等。

编译型语言和解释型语言

  • 计算机只能识别二进制编码(机器码),所以任何的语言在交由计算机执行时必须要先转换为机器码,也就是像 print('hello') 必需要转换为类似 1010101 这样的机器码。

  • 根据转换时机的不同,语言分成了两大类:

    • 编译型语言

      • 会在代码执行前将代码编译为机器码,然后将机器码交由计算机执行。最典型的就是 C 语言。
      • 过程:a(源码)—> 编译 —> b(编译后的机器码)。
      • 特点:
        • 执行速度特别快。
        • 跨平台性比较差。
    • 解释型语言

      • 不会在执行前对代码进行编译,而是在执行的同时一边执行一边编译。比如 Python,JS,Java 等。

      • 过程:a(源码)—> 解释器 —> 解释执行。

      • 特点:

        • 执行速度比较慢。
        • 跨平台性比较好 。

Python 简介

  • 现在,全世界差不多有 600 多种编程语言,但流行的编程语言也就那么 20 来种。
  • 总的来说,每种编程语言各有千秋。C 语言是可以用来编写操作系统的贴近硬件的语言,所以,C 语言适合开发那些追求运行速度、充分发挥硬件性能的程序。而 Python 是用来编写应用程序的高级编程语言。
  • Python 提供了非常完善的基础代码库,覆盖了网络、文件、GUI、数据库、文本等大量内容,被形象地称作“内置电池(batteries included)”。用 Python 开发,许多功能不必从零编写,直接使用现成的即可。
  • 除了内置的库外,Python 还有大量的第三方库,也就是别人开发的,供你直接使用的东西。当然,如果你开发的代码通过很好的封装,也可以作为第三方库给别人使用。
  • Python 的定位是“优雅”、“明确”、“简单”。Python 的哲学就是简单优雅,尽量写容易看明白的代码,尽量写少的代码。
  • Python 适合开发的应用类型:
    • 首选是网络应用,包括网站、后台服务等等。
    • 其次是许多日常需要的小工具,包括系统管理员需要的脚本任务等等。
    • 另外就是把其他语言开发的程序再包装起来,方便使用。
  • Python 的缺点:
    • 第一个缺点就是运行速度慢,和 C 程序相比非常慢,因为 Python 是解释型语言,编写的代码在执行时会一行一行地翻译成 CPU 能理解的机器码,这个翻译过程非常耗时,所以很慢。而 C 程序是运行前直接编译成 CPU 能执行的机器码,所以非常快。
    • 第二个缺点就是代码不能加密。如果要发布编写的 Python 程序,实际上就是发布源代码,这一点跟 C 语言不同,C 语言不用发布源代码,只需要把编译后的机器码(也就是在 Windows 上常见的 xxx.exe 文件)发布出去。要从机器码反推出 C 代码是不可能的,所以,凡是编译型的语言,都没有这个问题,而解释型的语言,则必须把源码发布出去。

Python 安装

  • Python 是跨平台的,它可以运行在 Windows、Mac 和各种 Linux/Unix 系统上。在 Windows 上写 Python 程序,放到 Linux 上也是能够运行的。

  • 要开始学习 Python 编程,首先就得把 Python 安装到你的电脑里。安装后,你会得到 Python 解释器(就是负责运行 Python 程序的),一个命令行交互环境,还有一个简单的集成开发环境。

  • 目前,Python 有两个版本,一个是 2.x 版,一个是 3.x 版,这两个版本是不兼容的。由于 3.x 版越来越普及,此处选择安装 Windows 系统的 3.8 版本。

官方安装包安装

  • Python 官网:https://www.python.org/

  • Python 下载:

    image-20210906103336559

    image-20210906110140935

  • Python 安装:

    image-20210906111014938

    image-20210906111414435

  • 验证 Python 是否安装完成:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    Windows PowerShell
    版权所有 (C) Microsoft Corporation。保留所有权利。

    尝试新的跨平台 PowerShell https://aka.ms/pscore6

    PS C:\Users\Xisun> python
    Python 3.8.3 (default, May 19 2020, 06:50:17) [MSC v.1916 64 bit (AMD64)] :: Anaconda, Inc. on win32
    Type "help", "copyright", "credits" or "license" for more information.
    >>> exit()
    PS C:\Users\Xisun>
    • 提示符 >>> 表示已经处于 Python 的交互模式中,可以输入任何 Python 代码,输入完的指令将会被 Python 的解释器立即执行。
    • 输入 exit() 并回车,可以退出 Python 交互模式(直接关掉命令行窗口也可以)。
  • 安装 Python 的同时,会自动安装一个 Python 的开发工具 IDLE,通过 IDLE 也可以进入到交互模式。IDLE 中可以通过 tab 键来查看语句的提示,并且可以将代码保存。

    image-20211008172411453

  • 交互模式下只能输入一行代码,执行一行,所以不适用于我们日常的开发,仅可以用来做一些日常的简单的测试!

  • 我们一般会将 Python 代码编写到一个 .py 文件中,然后通过 python 指令来执行文件中的代码。

Miniconda 安装

  • Miniconda 是一款小巧的 Python 环境管理工具,其安装程序中包含 conda 软件包管理器和 Python。一旦安装了 Miniconda,就可以使用 conda 命令安装任何其他软件工具包并创建环境等。

  • 官网:https://conda.io/en/latest/miniconda.html

Windows 环境

  • 官网下载 Miniconda:

    image-20211008200831511

  • 安装 Minicoda:

    image-20211008202344037

    image-20211008202554151

  • 添加系统环境变量:

    image-20211008204725711

  • Windows PowerShell 中创建 Python 3.8 环境:

    • 打开 Windows PowerShell:

      1
      2
      3
      4
      5
      6
      7
      Windows PowerShell
      版权所有 (C) Microsoft Corporation。保留所有权利。

      尝试新的跨平台 PowerShell https://aka.ms/pscore6

      加载个人及系统配置文件用了 907 毫秒。
      (base) PS C:\Users\XiSun>
    • 查看所有的环境:

      1
      2
      3
      4
      (base) PS C:\Users\XiSun>conda env list
      # conda environments:
      #
      base * D:\Program\Miniconda3
    • 创建一个新环境:

      1
      PS C:\Users\XiSun>conda create -n py38 python=3.8

      建议针对不同的 Python 版本,创建不同的环境,-n 参数后是环境的名字,可以自取。

      Miniconda 自身的 Python 环境,不建议直接使用,避免污染。

      新环境位于 Miniconda 安装目录下,如 D:\miniconda3\envs\py38

    • 激活新创建的环境:

      1
      PS C:\Users\XiSun> conda activate py38
  • 安装模块,可以多个一起安装:

    1
    2
    PS C:\Users\XiSun> conda init
    PS C:\Users\XiSun> conda install numpy scipy pandas jupyter -y

    -y 参数表示安装过程中询问是否继续操作时,默认输入 y

    • 使用 jupyter,首先创建一个目录,用于存放文件,如 D:\notebook

      1
      PS C:\Users\XiSun>  jupyter notebook --notebook-dir D:\notebook\

      image-20211008232457805

      • jupyter 的部分操作:

        image-20211008232723547

        image-20211008232622015

        image-20211008233557395

        image-20211009142625478

  • Pycharm 引用创建的 py38 环境:

    image-20211009104033079

    image-20211009104233732

Linux 环境

  • 某些时候,可能会存在一些依赖包不支持 Windows 环境下载安装,这时候就需要在 Linux 环境下载安装使用。

  • WSL 中创建 Python 3.8 环境:

    • 以管理员身份打开 Windows PowerShell:

      1
      2
      3
      4
      5
      6
      7
      Windows PowerShell
      版权所有 (C) Microsoft Corporation。保留所有权利。

      尝试新的跨平台 PowerShell https://aka.ms/pscore6

      加载个人及系统配置文件用了 869 毫秒。
      (base) PS C:\XiSun\Ziyoo>
    • 开启 WSL:

      1
      2
      (base) PS C:\Users\XiSun> wsl
      (base) xisun@DESKTOP-OM8IACS:/mnt/c/Users/XiSun$
    • 安装 Miniconda:

      1
      2
      3
      4
      5
      6
      7
      (base) xisun@DESKTOP-OM8IACS:/mnt/c/Users/XiSun$ cd /mnt/d/Program\ Files/
      (base) xisun@DESKTOP-OM8IACS:/mnt/d/Program Files$ ll
      total 380636
      drwxrwxrwx 1 xisun xisun 4096 Jan 25 10:29 ./
      drwxrwxrwx 1 xisun xisun 4096 Jan 19 16:16 ../
      -rwxrwxrwx 1 xisun xisun 85055499 Jun 10 2020 Miniconda3-latest-Linux-x86_64.sh*
      (base) xisun@DESKTOP-OM8IACS:/mnt/d/Program Files$ sh Miniconda3-latest-Linux-x86_64.sh
      • Miniconda3-latest-Linux-x86_64.sh 是 Miniconda 安装程序。
    • 创建一个新环境:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117
      118
      119
      120
      121
      122
      123
      124
      125
      126
      127
      128
      129
      130
      131
      132
      133
      134
      135
      136
      137
      138
      139
      140
      (base) xisun@DESKTOP-OM8IACS:/mnt/c/Users/Ziyoo$ cd
      (base) xisun@DESKTOP-OM8IACS:~$ ll
      total 108
      drwxr-xr-x 9 xisun xisun 4096 Jan 25 10:32 ./
      drwxr-xr-x 3 root root 4096 Apr 26 2021 ../
      -rw------- 1 xisun xisun 19888 Jan 25 10:33 .bash_history
      -rw-r--r-- 1 xisun xisun 220 Apr 26 2021 .bash_logout
      -rw-r--r-- 1 xisun xisun 4250 Jan 25 10:32 .bashrc
      drwxr-xr-x 2 xisun xisun 4096 Jan 25 10:32 .conda/
      drwxr-xr-x 8 xisun xisun 4096 Jun 3 2021 .dotnet/
      drwxr-xr-x 2 xisun xisun 4096 Apr 26 2021 .landscape/
      -rw------- 1 xisun xisun 32 May 21 2021 .lesshst
      -rw-r--r-- 1 xisun xisun 0 Jan 25 10:26 .motd_shown
      -rw-r--r-- 1 xisun xisun 807 Apr 26 2021 .profile
      drwx------ 2 xisun xisun 4096 Jul 13 2021 .ssh/
      -rw-r--r-- 1 xisun xisun 0 Apr 26 2021 .sudo_as_admin_successful
      drwxr-xr-x 2 xisun xisun 4096 Jul 6 2021 .vim/
      -rw------- 1 xisun xisun 9488 Jul 22 2021 .viminfo
      drwxr-xr-x 5 xisun xisun 4096 Jun 3 2021 .vscode-server/
      -rw-r--r-- 1 xisun xisun 183 Jan 14 10:08 .wget-hsts
      -rw-rw-r-- 1 xisun xisun 14750 Jun 3 2021 get-docker.sh
      drwxr-xr-x 15 xisun xisun 4096 Jan 25 10:32 miniconda3/
      (base) xisun@DESKTOP-OM8IACS:~$ conda env list
      # conda environments:
      #
      base * /home/xisun/miniconda3

      (base) xisun@DESKTOP-OM8IACS:~$ conda create -n py38 python=3.8
      Collecting package metadata (current_repodata.json): done
      Solving environment: done


      ==> WARNING: A newer version of conda exists. <==
      current version: 4.8.2
      latest version: 4.11.0

      Please update conda by running

      $ conda update -n base -c defaults conda



      ## Package Plan ##

      environment location: /home/xisun/miniconda3/envs/py38

      added / updated specs:
      - python=3.8


      The following packages will be downloaded:

      package | build
      ---------------------------|-----------------
      _openmp_mutex-4.5 | 1_gnu 22 KB
      ca-certificates-2021.10.26 | h06a4308_2 115 KB
      certifi-2021.10.8 | py38h06a4308_2 152 KB
      ld_impl_linux-64-2.35.1 | h7274673_9 586 KB
      libffi-3.3 | he6710b0_2 50 KB
      libgcc-ng-9.3.0 | h5101ec6_17 4.8 MB
      libgomp-9.3.0 | h5101ec6_17 311 KB
      libstdcxx-ng-9.3.0 | hd4cf53a_17 3.1 MB
      ncurses-6.3 | h7f8727e_2 782 KB
      openssl-1.1.1m | h7f8727e_0 2.5 MB
      pip-21.2.4 | py38h06a4308_0 1.8 MB
      python-3.8.12 | h12debd9_0 18.3 MB
      readline-8.1.2 | h7f8727e_1 354 KB
      setuptools-58.0.4 | py38h06a4308_0 790 KB
      sqlite-3.37.0 | hc218d9a_0 999 KB
      tk-8.6.11 | h1ccaba5_0 3.0 MB
      wheel-0.37.1 | pyhd3eb1b0_0 33 KB
      xz-5.2.5 | h7b6447c_0 341 KB
      zlib-1.2.11 | h7f8727e_4 108 KB
      ------------------------------------------------------------
      Total: 38.0 MB

      The following NEW packages will be INSTALLED:

      _libgcc_mutex pkgs/main/linux-64::_libgcc_mutex-0.1-main
      _openmp_mutex pkgs/main/linux-64::_openmp_mutex-4.5-1_gnu
      ca-certificates pkgs/main/linux-64::ca-certificates-2021.10.26-h06a4308_2
      certifi pkgs/main/linux-64::certifi-2021.10.8-py38h06a4308_2
      ld_impl_linux-64 pkgs/main/linux-64::ld_impl_linux-64-2.35.1-h7274673_9
      libffi pkgs/main/linux-64::libffi-3.3-he6710b0_2
      libgcc-ng pkgs/main/linux-64::libgcc-ng-9.3.0-h5101ec6_17
      libgomp pkgs/main/linux-64::libgomp-9.3.0-h5101ec6_17
      libstdcxx-ng pkgs/main/linux-64::libstdcxx-ng-9.3.0-hd4cf53a_17
      ncurses pkgs/main/linux-64::ncurses-6.3-h7f8727e_2
      openssl pkgs/main/linux-64::openssl-1.1.1m-h7f8727e_0
      pip pkgs/main/linux-64::pip-21.2.4-py38h06a4308_0
      python pkgs/main/linux-64::python-3.8.12-h12debd9_0
      readline pkgs/main/linux-64::readline-8.1.2-h7f8727e_1
      setuptools pkgs/main/linux-64::setuptools-58.0.4-py38h06a4308_0
      sqlite pkgs/main/linux-64::sqlite-3.37.0-hc218d9a_0
      tk pkgs/main/linux-64::tk-8.6.11-h1ccaba5_0
      wheel pkgs/main/noarch::wheel-0.37.1-pyhd3eb1b0_0
      xz pkgs/main/linux-64::xz-5.2.5-h7b6447c_0
      zlib pkgs/main/linux-64::zlib-1.2.11-h7f8727e_4


      Proceed ([y]/n)? y


      Downloading and Extracting Packages
      _openmp_mutex-4.5 | 22 KB | ############################################################################# | 100%
      libgomp-9.3.0 | 311 KB | ############################################################################# | 100%
      ld_impl_linux-64-2.3 | 586 KB | ############################################################################# | 100%
      python-3.8.12 | 18.3 MB | ############################################################################# | 100%
      zlib-1.2.11 | 108 KB | ############################################################################# | 100%
      openssl-1.1.1m | 2.5 MB | ############################################################################# | 100%
      libstdcxx-ng-9.3.0 | 3.1 MB | ############################################################################# | 100%
      tk-8.6.11 | 3.0 MB | ############################################################################# | 100%
      wheel-0.37.1 | 33 KB | ############################################################################# | 100%
      sqlite-3.37.0 | 999 KB | ############################################################################# | 100%
      setuptools-58.0.4 | 790 KB | ############################################################################# | 100%
      pip-21.2.4 | 1.8 MB | ############################################################################# | 100%
      libffi-3.3 | 50 KB | ############################################################################# | 100%
      libgcc-ng-9.3.0 | 4.8 MB | ############################################################################# | 100%
      ncurses-6.3 | 782 KB | ############################################################################# | 100%
      certifi-2021.10.8 | 152 KB | ############################################################################# | 100%
      readline-8.1.2 | 354 KB | ############################################################################# | 100%
      xz-5.2.5 | 341 KB | ############################################################################# | 100%
      ca-certificates-2021 | 115 KB | ############################################################################# | 100%
      Preparing transaction: done
      Verifying transaction: done
      Executing transaction: done
      #
      # To activate this environment, use
      #
      # $ conda activate py38
      #
      # To deactivate an active environment, use
      #
      # $ conda deactivate

      (base) xisun@DESKTOP-OM8IACS:~$ conda env list
      # conda environments:
      #
      base * /home/xisun/miniconda3
      py38 /home/xisun/miniconda3/envs/py38
    • 激活新创建的环境:

      1
      2
      (base) xisun@DESKTOP-OM8IACS:~$ conda activate py38
      (py38) xisun@DESKTOP-OM8IACS:~$
  • 安装模块:

    • pip 安装 pip-search:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      84
      85
      86
      87
      88
      89
      90
      91
      92
      93
      94
      95
      96
      97
      98
      99
      100
      101
      102
      103
      104
      105
      106
      107
      108
      109
      110
      111
      112
      113
      114
      115
      116
      117
      118
      119
      120
      121
      122
      123
      (base) xisun@DESKTOP-OM8IACS:~$ pip install pip_search
      Collecting pip_search
      Downloading pip_search-0.0.10-py3-none-any.whl (4.4 kB)
      Collecting bs4
      Downloading bs4-0.0.1.tar.gz (1.1 kB)
      Collecting rich
      Downloading rich-11.0.0-py3-none-any.whl (215 kB)
      |████████████████████████████████| 215 kB 400 kB/s
      Requirement already satisfied: requests in ./miniconda3/lib/python3.7/site-packages (from pip_search) (2.22.0)
      Collecting beautifulsoup4
      Downloading beautifulsoup4-4.10.0-py3-none-any.whl (97 kB)
      |████████████████████████████████| 97 kB 346 kB/s
      Collecting colorama<0.5.0,>=0.4.0
      Downloading colorama-0.4.4-py2.py3-none-any.whl (16 kB)
      Collecting commonmark<0.10.0,>=0.9.0
      Downloading commonmark-0.9.1-py2.py3-none-any.whl (51 kB)
      |████████████████████████████████| 51 kB 315 kB/s
      Collecting typing-extensions<5.0,>=3.7.4; python_version < "3.8"
      Downloading typing_extensions-4.0.1-py3-none-any.whl (22 kB)
      Collecting pygments<3.0.0,>=2.6.0
      Downloading Pygments-2.11.2-py3-none-any.whl (1.1 MB)
      |████████████████████████████████| 1.1 MB 50 kB/s
      Requirement already satisfied: certifi>=2017.4.17 in ./miniconda3/lib/python3.7/site-packages (from requests->pip_search) (2019.11.28)
      Requirement already satisfied: idna<2.9,>=2.5 in ./miniconda3/lib/python3.7/site-packages (from requests->pip_search) (2.8)
      Requirement already satisfied: urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 in ./miniconda3/lib/python3.7/site-packages (from requests->pip_search) (1.25.8)
      Requirement already satisfied: chardet<3.1.0,>=3.0.2 in ./miniconda3/lib/python3.7/site-packages (from requests->pip_search) (3.0.4)
      Collecting soupsieve>1.2
      Downloading soupsieve-2.3.1-py3-none-any.whl (37 kB)
      Building wheels for collected packages: bs4
      Building wheel for bs4 (setup.py) ... done
      Created wheel for bs4: filename=bs4-0.0.1-py3-none-any.whl size=1272 sha256=2811fe699e2c14aff05f0bbf8c2339c40e826130828a85461bb19160564c26c2
      Stored in directory: /home/xisun/.cache/pip/wheels/0a/9e/ba/20e5bbc1afef3a491f0b3bb74d508f99403aabe76eda2167ca
      Successfully built bs4
      Installing collected packages: soupsieve, beautifulsoup4, bs4, colorama, commonmark, typing-extensions, pygments, rich, pip-search
      Successfully installed beautifulsoup4-4.10.0 bs4-0.0.1 colorama-0.4.4 commonmark-0.9.1 pip-search-0.0.10 pygments-2.11.2 rich-11.0.0 soupsieve-2.3.1 typing-extensions-4.0.1
      (base) xisun@DESKTOP-OM8IACS:~$ pip_search dotenv
      🐍 https://pypi.org/search/?q=dotenv 🐍
      ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
      ┃ Package ┃ Version ┃ Released ┃ Description ┃
      ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
      │ 📂 dotenv │ 0.0.5 │ Mar 5, 2015 │ Handle .env files │
      │ 📂 dotenv-config0.1.4 │ Feb 8, 2019 │ Simple dotenv loader with the possibility of casting types │
      │ 📂 typed-dotenv1.0.1 │ Jul 30, 2020 │ Handle .env files with types │
      │ 📂 python-dotenv0.19.2 │ Nov 11, 2021 │ Read key-value pairs from a .env file and set them as │
      │ │ │ │ environment variables │
      │ 📂 dotenv-flow0.2.3 │ Jan 3, 2022 │ Like the dotenv-flow NodeJS library, for Python │
      │ 📂 py-dotenv0.1 │ Dec 13, 2016 │ Read dotenv file │
      │ 📂 dotenv-cli2.2.0 │ Oct 30, 2020 │ Simple dotenv CLI. │
      │ 📂 django-dotenv1.4.2 │ Dec 11, 2017 │ foreman reads from .env. manage.py doesn't. Let's fix that. │
      │ 📂 pythonsite-dotenv0.1 │ Jun 30, 2014 │ Extend environment when invoking python │
      │ 📂 firstclass-dotenv0.0.6 │ Nov 18, 2020 │ Read value of .env(dotenv) into ENV values │
      │ 📂 pytest-dotenv0.5.2 │ Jun 16, 2020 │ A py.test plugin that parses environment files before running │
      │ │ │ │ tests │
      │ 📂 dotenv-linter0.3.0 │ Dec 13, 2021 │ Linting dotenv files like a charm! │
      │ 📂 dotenv-python0.0.1 │ Jan 28, 2017 │ Read .env(-ish) configuration file for python web │
      │ │ │ │ applications. │
      │ 📂 xontrib-dotenv0.1 │ Jun 15, 2016 │ Reads .env files into environment │
      │ 📂 Flask-DotEnv0.1.2 │ Apr 30, 2019 │ The .env file support for Flask │
      │ 📂 dotenv-stripout0.1.0 │ Aug 19, 2021 │ Strip secrets from .env files │
      │ 📂 ssm-dotenv0.1.0 │ Aug 8, 2019 │ manage project dotenv parameters in aws parameter store │
      │ 📂 model-dotenv0.0.0.1 │ Aug 2, 2021 │ A small example package │
      │ 📂 enc-dotenv0.0.3 │ Dec 12, 2019 │ encrypted env │
      │ 📂 json-dotenv0.0.21 │ Dec 19, 2019 │ json-dotenv
      │ 📂 python-dotenv-yaml0.17.1 │ Jun 18, 2021 │ Read key-value pairs from a .env file and set them as │
      │ │ │ │ environment variables -> with support for yaml syntax │
      │ 📂 dotenv-settings-handler0.0.3 │ Jul 5, 2019 │ Settings handler to load settings from a DotEnv file or system │
      │ │ │ │ env variables, using python-dotenv and pydantic. │
      │ 📂 py-sync-dotenv0.1.1 │ Mar 19, 2021 │ Python Sync Dotenv is a Python package for synchronizing .env │
      │ │ │ │ files across projects. │
      │ 📂 poetry-dotenv-plugin0.1.0a2 │ May 30, 2021 │ A Poetry plugin to automatically load environment variables │
      │ │ │ │ from .env files │
      │ 📂 msdss-base-dotenv0.2.9 │ Nov 26, 2021 │ Environmental file management for the Modular Spatial Decision │
      │ │ │ │ Support Systems (MSDSS) framework │
      │ 📂 pytest-django-dotenv0.1.2 │ Nov 26, 2019 │ Pytest plugin used to setup environment variables with │
      │ │ │ │ django-dotenv
      │ 📂 ssm-dotenv-config0.1.1 │ Jun 7, 2019 │ │
      │ 📂 python-dotenv-run0.1.4 │ Dec 23, 2017 │ Run command with environment populated by the .env file. │
      │ 📂 dotenver │ 1.2.1 │ Jun 12, 2021 │ Automatically generate .env files from .env.example template │
      │ │ │ │ files │
      │ 📂 yaenv │ 1.6.1 │ Dec 14, 2021 │ Yet another dotenv parser for Python. │
      │ 📂 pypiwrap │ 0.1.0 │ Mar 14, 2021 │ A simple wrapper for interfacing with PyPi APIs. │
      │ 📂 env-validate0.4 │ Jul 1, 2021 │ │
      │ 📂 td-ameritrade-api1.0.4 │ Oct 5, 2019 │ A python wrapper for the TD ameritrade API │
      │ 📂 trashy-poetry1.0.3 │ Mar 1, 2021 │ Poetry for everyday use │
      │ 📂 dotenvy │ 0.2.0 │ Sep 20, 2017 │ Dotenv handler for Python │
      │ 📂 envirun │ 0.0.1 │ Sep 25, 2021 │ Run any program with environment read from file │
      │ 📂 TickerStore │ 0.0.8 │ Mar 22, 2019 │ Historical data of financial instruments from NSE │
      │ 📂 configureme │ 0.1.2a0 │ Nov 4, 2018Set up configuration for your application or library with │
      │ │ │ │ ease. │
      │ 📂 keyvault │ 0.1.5 │ Sep 21, 2021 │ A small package for handling project secrets │
      │ 📂 envex │ 1.1.2 │ Oct 28, 2021 │ An extended os.environ interface │
      └────────────────────────────┴─────────┴──────────────┴────────────────────────────────────────────────────────────────┘
      (base) xisun@DESKTOP-OM8IACS:~$ pip list
      Package Version
      ---------------------- -------------------
      asn1crypto 1.3.0
      beautifulsoup4 4.10.0
      bs4 0.0.1
      certifi 2019.11.28
      cffi 1.14.0
      chardet 3.0.4
      colorama 0.4.4
      commonmark 0.9.1
      conda 4.8.2
      conda-package-handling 1.6.0
      cryptography 2.8
      idna 2.8
      pip 20.0.2
      pycosat 0.6.3
      pycparser 2.19
      Pygments 2.11.2
      pyOpenSSL 19.1.0
      PySocks 1.7.1
      requests 2.22.0
      rich 11.0.0
      ruamel-yaml 0.15.87
      setuptools 45.2.0.post20200210
      six 1.14.0
      soupsieve 2.3.1
      tqdm 4.42.1
      typing-extensions 4.0.1
      urllib3 1.25.8
      wheel 0.34.2
    • pipx 安装 pip-search:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      (py38) xisun@DESKTOP-OM8IACS:/etc/apt$ pip install pipx
      Collecting pipx
      Downloading pipx-1.0.0-py3-none-any.whl (54 kB)
      |████████████████████████████████| 54 kB 47 kB/s
      Collecting packaging>=20.0
      Downloading packaging-21.3-py3-none-any.whl (40 kB)
      |████████████████████████████████| 40 kB 337 kB/s
      Collecting userpath>=1.6.0
      Downloading userpath-1.7.0-py2.py3-none-any.whl (14 kB)
      Collecting argcomplete>=1.9.4
      Downloading argcomplete-2.0.0-py2.py3-none-any.whl (37 kB)
      Collecting pyparsing!=3.0.5,>=2.0.2
      Downloading pyparsing-3.0.7-py3-none-any.whl (98 kB)
      |████████████████████████████████| 98 kB 416 kB/s
      Collecting click
      Downloading click-8.0.3-py3-none-any.whl (97 kB)
      |████████████████████████████████| 97 kB 537 kB/s
      Installing collected packages: pyparsing, click, userpath, packaging, argcomplete, pipx
      Successfully installed argcomplete-2.0.0 click-8.0.3 packaging-21.3 pipx-1.0.0 pyparsing-3.0.7 userpath-1.7.0
      (py38) xisun@DESKTOP-OM8IACS:/etc/apt$ pipx install pip-search
      installed package pip-search 0.0.10, installed using Python 3.8.12
      These apps are now globally available
      - pip_search
      ⚠️ Note: '/home/xisun/.local/bin' is not on your PATH environment variable. These apps will not be globally
      accessible until your PATH is updated. Run `pipx ensurepath` to automatically add it, or manually modify your PATH
      in your shell's config file (i.e. ~/.bashrc).
      done! ✨ 🌟 ✨
      (py38) xisun@DESKTOP-OM8IACS:/etc/apt$ pipx ensurepath
      Success! Added /home/xisun/.local/bin to the PATH environment variable.

      Consider adding shell completions for pipx. Run 'pipx completions' for instructions.

      You will need to open a new terminal or re-login for the PATH changes to take effect.

      Otherwise pipx is ready to go! ✨ 🌟 ✨
      • 重新打开 terminal,即可使用 pip-search 命令。
  • pip 设置镜像源:

    1
    pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/

Python 解释器

  • 当编写 Python 代码时,得到的是一个包含 Python 代码的以 .py 为扩展名的文本文件。要运行代码,就需要 Python 解释器去执行 .py 文件。
  • 由于整个 Python 语言从规范到解释器都是开源的,所以理论上,只要水平够高,任何人都可以编写 Python 解释器来执行 Python 代码(当然难度很大)。事实上,确实存在多种 Python 解释器。
  • Python 的解释器很多,但使用最广泛的还是 CPython。如果要和 Java 或 .Net 平台交互,最好的办法不是用 Jython 或 IronPython,而是通过网络调用来交互,确保各程序之间的独立性。

CPython

  • 从 Python 官网下载并安装好 Python 3.x 后,我们就直接获得了一个官方版本的解释器:CPython。这个解释器是用 C 语言开发的,所以叫 CPython。在命令行下运行 python 命令就是启动 CPython 解释器。
  • CPython 是使用最广的 Python 解释器。

IPython

  • IPython 是基于 CPython 之上的一个交互式解释器,也就是说,IPython 只是在交互方式上有所增强,但是执行 Python 代码的功能和 CPython 是完全一样的。好比很多国产浏览器虽然外观不同,但内核其实都是调用了 IE。
  • CPython 用 >>> 作为提示符,而 IPython 用 In [序号]: 作为提示符。

PyPy

  • PyPy 是另一个 Python 解释器,它的目标是执行速度。PyPy 采用 JIT 技术,对 Python 代码进行动态编译(注意不是解释),所以可以显著提高 Python 代码的执行速度。
  • 绝大部分 Python 代码都可以在 PyPy 下运行,但是 PyPy 和 CPython 有一些是不同的,这就导致相同的 Python 代码在两种解释器下执行可能会有不同的结果。如果你的代码要放到 PyPy 下执行,就需要了解 PyPy和CPython的不同点

Jython

  • Jython 是运行在 Java 平台上的 Python 解释器,可以直接把 Python 代码编译成 Java 字节码执行。

IronPython

  • IronPython 和 Jython 类似,只不过 IronPython 是运行在微软 .Net 平台上的 Python 解释器,可以直接把 Python 代码编译成 .Net 字节码。

Python 基础

  • Python 的语法比较简单,采用缩进方式,写出来的代码就像下面的样子:

    1
    2
    3
    4
    5
    6
    # print absolute value of an integer:
    a = 100
    if a >= 0:
    print(a)
    else:
    print(-a)
  • Python 程序是大小写敏感的,如果写错了大小写,程序会报错。

  • Python 中的每一行就是一条语句,每条语句以换行结束,每一行语句不要过长(规范中建议每行不要超过 80 个字符)。当语句以冒号 : 结尾时,缩进的语句视为代码块。

  • Python 一条语句可以分多行编写,多行编写时语句后边以 \ 结尾。

  • Python 是缩进严格的语言,所以在 Python 中不要随便写缩进。按照约定俗成的惯例,应该始终坚持使用 4 个空格的缩进。当重构代码时,粘贴过去的代码必须重新检查缩进是否正确。此外,IDE 很难像格式化 Java 代码那样格式化 Python 代码。

  • Python 中使用 # 来表示注释,# 后的内容都属于注释,注释的内容将会被解释器所忽略。注释要求简单明了,一般习惯上 # 后边会跟着一个空格。

字面量和变量

  • 字面量就是一个一个的值,比如:123456‘HELLO’。字面量所表示的意思就是它的字面的值,在程序中可以直接使用字面量。

  • 变量(variable)可以用来保存字面量,并且变量中保存的字面量是不定的。变量本身没有任何意思,它会根据不同的字面量表示不同的意思。

    • 在 Python 中,等号是赋值语句,可以把任意数据类型赋值给变量,同一个变量可以反复赋值,而且可以是不同类型的变量。

      1
      2
      3
      4
      a = 123 # a是整数
      print(a) # 123
      a = 'ABC' # a变为字符串
      print(a) # ABC
      • 这种变量本身类型不固定的语言称之为动态语言,与之对应的是静态语言。静态语言在定义变量时必须指定变量类型,如果赋值的时候类型不匹配,就会报错。例如 Java 是静态语言。
    • 等号也可以把一个变量 a 赋值给另一个变量 b,这个操作实际上是把变量 b 指向变量 a 所指向的数据。

      1
      2
      3
      4
      a = 'ABC'
      b = a
      a = 'XYZ'
      print(b) # ABC,不是XYZ
    • 常量就是不能变的变量,比如常用的数学常数 π 就是一个常量。在 Python 中,通常用全部大写的变量名表示常量:

      1
      PI = 3.14159265359
      • 事实上 PI 仍然是一个变量,Python 根本没有任何机制保证 PI 不会被改变,所以,用全部大写的变量名表示常量只是一个习惯上的用法,如果你一定要改变变量 PI 的值,也没人能拦住你。
  • 一般在开发时,很少直接使用字面量,都是将字面量保存到变量中,通过变量来引用字面量。

变量和标识符

  • Python 中使用变量,不需要声明,直接为变量赋值即可。
  • Python 中不能使用没有进行过赋值的变量,如果使用没有赋值过的变量,会报错 NameError: name 'b' is not defined
  • Python 是一个动态类型的语言,可以为变量赋任意类型的值,也可以任意修改变量的值。
  • Python 中所有可以自主命名的内容都属于标识符,比如变量名、函数名、类名。
  • 标识符必须遵循标识符的规范:
    • 标识符中可以含有字母、数字、_,但是不能使用数字开头。
    • 标识符不能是 Python 中的关键字和保留字,也不建议使用 Python 中的函数名作为标识符,因为这样会导致函数被覆盖。
    • 在 Python 中注意遵循两种命名规范:
      • 下划线命名法:所有字母小写,单词之间使用 _ 分割。如:max_length、min_length、hello_world。
      • 帕斯卡命名法:大驼峰命名法,首字母大写,每个单词开头字母大写,其余字母小写。如:MaxLength、MinLength、HelloWorld。
    • 如果使用不符合标准的标识符,会报错 SyntaxError: invalid syntax

数据类型

  • 数据类型指的就是变量的值的类型,也就是可以为变量赋哪些值。

数值

  • Python 中,数值分成了三种:整数、浮点数(小数)、复数。
整数
  • Python中,所有的整数都是 int 类型。
  • Python 可以处理任意大小的整数,包括负整数,在程序中的表示方法和数学上的写法一模一样,例如:1100-80800,等等。
    • Python 的整数没有大小限制,而某些语言的整数根据其存储长度是有大小限制的,例如 Java 对 32 位整数的范围限制在 -2147483648 ~ 2147483647。
  • 对于很大的数,例如 10000000000,很难数清楚 0 的个数。Python 允许在数字中间以 _ 分隔,因此,写成 10_000_000_00010000000000 是完全一样的。十六进制数也可以写成 0xa1b2_c3d4
  • 计算机由于使用二进制,所以,有时候用十六进制表示整数比较方便,十六进制用 0x 前缀和 0 - 9,a - f 表示,例如:0xff000xa5b4c3d2,等等。
    • 十进制的数,不能以 0 开头。二进制以 0b 开头,八进制以 0o 开头,十六进制以 0x 开头。
    • 其他进制的整数,只要是数字,打印时一定是以十进制的形式显示的。
浮点数
  • Python 中,所有的浮点数都是 float 类型。

  • 浮点数也就是小数,之所以称为浮点数,是因为按照科学记数法表示时,一个浮点数的小数点位置是可变的,比如,1.23 x 10^912.3 x 10^8 是完全相等的。浮点数可以用数学写法,如 1.233.14-9.01,等等。但是对于很大或很小的浮点数,就必须用科学计数法表示,把 10 用 e 替代,1.23 x 10^9 就是 1.23e9,或者 12.3e80.000012 可以写成 1.2e-5,等等。

    • Python 的浮点数也没有大小限制,但是超出一定范围就直接表示为 inf(无限大)。
  • 整数和浮点数在计算机内部存储的方式是不同的,整数运算永远是精确的(除法难道也是精确的?是的!),而浮点数运算则可能会有四舍五入的误差,得到一个不精确的结果。

    • 在Python中,有两种除法,一种除法是 // 除法的计算结果是浮点数,即使是两个整数恰好整除,结果也是浮点数。

      1
      2
      3
      4
      >>> 10 / 3
      3.3333333333333335
      >>> 9 / 3
      3.0
    • 还有一种除法是 //,称为地板除,// 除法只取结果的整数部分。

      1
      2
      3
      4
      >>> 10 // 3
      3
      >>> 9 // 3
      3
    • 相对于取整运算,Python 还提供一个余数运算,可以得到两个整数相除的余数。

      1
      2
      3
      4
      >>> 10 % 3
      1
      >>> 9 % 3
      0
    • 无论整数做 // 除法还是取余数,结果永远是整数,所以,整数运算结果永远是精确的。

字符串

  • 字符串用来表示一段文本信息,字符串是程序中使用的最多的数据类型。

  • 字符串是以单引号 ' 或双引号 " 括起来的任意文本(不要混用),比如 'abc'"xyz" 等等。请注意,''"" 本身只是一种表示方式,不是字符串的一部分,因此,字符串 'abc' 只有 abc 这 3 个字符。如果 ' 本身也是一个字符,那就可以用 "" 括起来,比如 "I'm OK" 包含的字符是 I'm空格OK 这 6 个字符。

  • 相同的引号之间不能嵌套。如果字符串内部既包含 ' 又包含 ",可以用转义字符 \ 来标识,比如 'I\'m \"OK\"!'

  • 转义字符 \ 可以转义很多字符。比如:\t 表示制表符,\n 表示换行符,\uxxxx 表示 Unicode 编码,可以打印出一些特殊的符号。

    1
    2
    3
    4
    5
    6
    7
    8
    >>> print('I\'m ok.')
    I'm ok.
    >>> print('I\'m learning\nPython.')
    I'm learning
    Python.
    >>> print('\\\n\\')
    \
    \
  • 如果字符串里面有很多字符都需要转义,就需要加很多 \,为了简化,Python 还允许用 r'' 表示 ‘ ‘ 内部的字符串默认不转义。

    1
    2
    3
    4
    >>> print('\\\t\\')
    \ \
    >>> print(r'\\\t\\')
    \\\t\\
  • 如果字符串内部有很多换行,用 \n 写在一行里不好阅读,为了简化,Python 允许用 '''...'''"""...""" 的格式表示多行内容。三重引号中可以换行,并且会保留字符串中的格式。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    >>> print('''line1
    ... line2
    ... line3''')
    line1
    line2
    line3
    >>> print(r'''hello,\n
    ... world''')
    hello,\n
    world
    • 上面是在交互式命令行内输入,在输入多行内容时,提示符由 >>> 变为 ...,提示可以接着上一行输入,注意 ... 是提示符,不是代码的一部分。
  • 格式化字符串:

    • 拼串:字符串之间可以进行加法运算,如果将两个字符串进行相加,则会自动将两个字符串拼接为一个。

      1
      2
      3
      name = '孙悟空'

      print('欢迎 ' + name + ' 光临!') # 欢迎 孙悟空 光临!
    • 多参数:字符串只能和字符串拼接,不能和其他的类型进行加法运算。print("a = " + a) 这种写法在 Python 中不常见,因为 a 可能不是字符串,容易出错,常写作 print('a = ', a)

      1
      2
      3
      name = '孙悟空'

      print('欢迎', name, '光临!') # 欢迎 孙悟空 光临!
    • 占位符:在创建字符串时,可以在字符串中指定占位符:%s 在字符串中表示任意字符,%f 表示浮点数占位符,%d 表示整数占位符。

      1
      2
      3
      4
      5
      6
      7
      8
      b = 'Hello %s' % '孙悟空'  # 一个占位符:Hello 孙悟空
      b = 'hello %s 你好 %s' % ('tom', '孙悟空') # 两个占位符:hello tom 你好 孙悟空
      b = 'hello %3s' % 'ab' # 占位符处的字符串长度至少为3,不足3的,在前面填充空格:hello ab
      b = 'hello %3.5s' % 'abcdefg' # 占位符处的字符串的长度限制在3-5之间:hello abcde
      b = 'hello %.2f' % 123.456 # 保留2位小数,四舍五入:hello 123.46
      b = 'hello %d' % 123.95 # 直接舍弃小数位:hello 123

      print(b)
    • 格式化字符串:可以通过在字符串前添加一个 f 来创建一个格式化字符串,在格式化字符串中可以直接嵌入变量。

      1
      2
      3
      4
      5
      6
      a = 123
      b = '呵呵'
      c = f'hello {a} {b}'

      print(f'a = {a}') # a = 123
      print(c) # hello 123 呵呵
  • 字符串的复制:将字符串和数字相乘。* 在语言中表示乘法,如果将字符串和数字相乘,则解释器会将字符串重复指定的次数并返回。

    1
    2
    3
    4
    a = 'abc'
    a = a * 5

    print(a) # abcabcabcabcabc

布尔值

  • 布尔值和布尔代数的表示完全一致,一个布尔值只有 TrueFalse 两种值,要么是 True,要么是 False,在 Python 中,可以直接用 TrueFalse 表示布尔值(请注意大小写),也可以通过布尔运算计算出来。

    1
    2
    3
    4
    5
    6
    7
    8
    >>> True
    True
    >>> False
    False
    >>> 3 > 2
    True
    >>> 2 > 5
    False
  • 布尔值可以用 andor not 运算。

    • and 运算是与运算,只有所有都为 Trueand 运算结果才是 True

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      >>> True and True
      True
      >>> True and False
      False
      >>> False and True
      False
      >>> False and False
      False
      >>> 5 > 3 and 3 > 1
      True
    • or 运算是或运算,只要其中有一个为 Trueor 运算结果就是 True

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      >>> True or True
      True
      >>> True or False
      True
      >>> False or True
      True
      >>> False or False
      False
      >>> 5 > 3 or 1 > 3
      True
    • not 运算是非运算,它是一个单目运算符,把 True 变成 FalseFalse 变成 True

      1
      2
      3
      4
      5
      6
      >>> not True
      False
      >>> not False
      True
      >>> not 5 > 3
      False
  • 布尔值经常用在条件判断中,比如:

    1
    2
    3
    4
    if age >= 18:
    print('adult')
    else:
    print('teenager')
  • 布尔值实际上也属于整型,True 就相当于 1,False 就相当于 0。

    1
    2
    print(1 + False)  # 1
    print(1 + True) # 2

空值

  • 空值是 Python 里一个特殊的值,用 None 表示。None 不能理解为 0,因为 0 是有意义的,而 None 是一个特殊的空值。

类型检查

  • 通过类型检查,可以检查变量对应的值的类型。

  • type() 用来检查值的类型,该函数会将检查的结果作为返回值返回,可以通过变量来接收函数的返回值。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    a = 123  # 数值
    b = '123' # 字符串
    print(type(a)) # <class 'int'>
    print(type(b)) # <class 'str'>
    c = type(a)
    print(c) # <class 'int'>
    c = type('123')
    print(c) # <class 'str'>
    print(type(1)) # <class 'int'>
    print(type(1.5)) # <class 'float'>
    print(type(True)) # <class 'bool'>
    print(type('hello')) # <class 'str'>
    print(type(None)) # <class 'NoneType'>

对象

  • Python 是一门面向对象的语言。
  • 一切皆对象!
  • 程序运行当中,所有的数据都是存储到内存当中然后再运行的!
  • 对象就是内存中专门用来存储指定数据的一块区域。
  • 对象实际上就是一个容器,专门用来存储数据。
  • 像我们之前学习的数值、字符串、布尔值、None 都是对象。

对象的结构

  • 每个对象中都要保存三种数据:

    • id(标识)

      • id 用来标识对象的唯一性,每一个对象都有唯一的 id。

      • 对象的 id 就相当于人的身份证号一样。

      • 可以通过 id() 函数来查看对象的 id。

        1
        2
        print(id(123))  # 140708231919200
        print(id('a')) # 2270491024176
      • id 是由解析器生成的,在 CPython 中,id 就是对象的内存地址。

      • 对象一旦创建,则它的 id 永远不能再改变。

    • type(类型)

      • 类型用来标识当前对象所属的类型,比如:int,str,float,bool。

      • 类型决定了对象有哪些功能。

      • 通过 type() 函数来查看对象的 type。

        1
        2
        print(type(123))  # <class 'int'>
        print(type('a')) # <class 'str'>
      • Python 是一门强类型的语言,对象一旦创建类型便不能修改。

    • value(值)

      • 值就是对象中存储的具体的数据。
      • 对于有些对象,值是可以改变的。
      • 对象分成两大类:可变对象和不可变对象。
        • 可变对象的值可以改变。
        • 不可变对象的值不能改变,之前学习的数值、字符串等都是不可变对象。

变量和对象

  • 对象并没有直接存储到变量中,在 Python 中变量更像是给对象起了一个别名。

  • 变量中存储的不是对象的值,而是对象的 id(内存地址),当我们使用变量时,实际上就是在通过对象 id 在查找对象。

  • 变量中保存的对象,只有在为变量重新赋值时才会改变。

  • 变量和变量之间是相互独立的,修改一个变量不会影响另一个变量。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    print(a)  # 10
    print(b) # 10
    print(id(a)) # 140708432125984
    print(id(b)) # 140708432125984
    a = 456
    print(a) # 456
    print(b) # 10
    print(id(a)) # 2898418807216
    print(id(b)) # 140708432125984

类型转换

  • 所谓的类型转换,是将一个类型的对象转换为其他对象。

  • 类型转换不是改变对象本身的类型,而是根据当前对象的值来创建一个新对象。

  • 类型转换四个函数:int()float()str()bool()

  • int() 可以用来将其他的对象转换为整型。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    a = True
    a = int(a)
    print(a) # 1

    a = False
    a = int(a)
    print(a) # 0

    a = '123'
    a = int(a)
    print(a) # 123

    a = 11.6
    a = int(a)
    print(a) # 11

    a = '11.5'
    a = int(a) # ValueError
    print(a)

    a = None
    a = int(a) # TypeError
    print(a)
    • 布尔值:True —> 1,False —> 0。
    • 浮点数:直接取整,省略小数点后的内容。
    • 字符串:如果是一个合法的整数字符串,则直接转换为对应的数字。如果不是一个合法的整数字符串,则报错 ValueError: invalid literal for int() with base 10: '11.5'
    • 对于其他不可转换为整型的对象,直接抛出异常 TypeError
    • int() 函数不会对原来的变量产生影响,他是将对象转换为指定的类型并将其作为返回值返回,如果希望修改原来的变量,则需要对变量进行重新赋值。
  • float()int() 基本一致,不同的是它会将对象转换为浮点数。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    a = 1
    a = float(a)
    print(a) # 1.0

    a = False
    a = float(a)
    print(a) # 0.0

    a = True
    a = float(a)
    print(a) # 1.0
  • str() 可以将对象转换为字符串。

    1
    2
    3
    4
    5
    6
    a = 123
    a = str(a)
    print(a) # 123

    b = 456
    print('hello' + str(b)) # hello456
    • True —> ‘True’。
    • False —> ‘False’。
    • 123 —> ‘123’ 。
    • 。。。
  • bool() 可以将对象转换为布尔值,任何对象都可以转换为布尔值。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    a = None
    a = bool(a)
    print(a) # False

    a = 0
    a = bool(a)
    print(a) # False

    a = ''
    a = bool(a)
    print(a) # False
    • 规则:对于所有表示空性的对象都会转换为 False,其余的转换为 True。表示空性的对象:0None'' 等。

运算符(操作符)

  • 运算符可以对一个值或多个值进行运算或各种操作。比如 +-= 都属于运算符。
  • 常用运算符的分类:
    • 算术运算符
    • 赋值运算符
    • 关系运算符(比较运算符)
    • 逻辑运算符
    • 条件运算符(三元运算符)

算术运算符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# 加法运算符
a = 10 + 5 # 15
a = 'hello' + ' ' + 'world' # hello world,拼串

# 减法运算符
a = 10 - 5 # 5
a = 5 - True # 4
a = a - 2 # 2,用变量a的值减去2,然后再赋值给a
# a = 'hello' - 'h' # TypeError

# 乘法运算符
a = 5 * 5 # 25

# 除法运算符
a = 10 / 5 # 2.0
a = 5 / 2 # 2.5
# a = 5 / 0 # ZeroDivisionError: division by zero
a = 10 / 3 # 3.33333...

# 幂运算
a = 2 ** 2 # 4
a = 10 ** 5 # 100000
a = 16 ** 0.5 # 4.0,求16的平方根

# 整除
a = 10 // 3 # 3
a = 5 // 2 # 2
a = 10 // -3 # -4
a = -5 // 2 # -3

# 取模
a = 10 % 5 # 0
a = 10 % 4 # 2
a = 10 % 3 # 1
a = 10 % 2 # 0

print("a =", a)
  • 加法运算符:+。如果是两个字符串之间进行加法运算,则会进行拼串操作。

  • 减法运算符:-

  • 乘法运算符:*。如果将字符串和数字相乘,则会对字符串进行复制操作,将字符串重复指定次数。

  • 除法运算符:/。运算时结果总会返回一个浮点类型。

  • 幂运算:**。求一个值的几次幂。

  • 整除://。向下取整,只会保留计算后的整数位,总会返回一个整型。

  • 取模:%。即取余,求两个数相除的余数。

  • 运算时,注意正负号的问题。

  • 在对浮点数做算术运算时,结果也会返回一个浮点数。

    1
    2
    b = 25.0 / 5
    print(b) # 5.0

赋值运算符

  • 赋值运算符 = 可以将等号右侧的值赋值给等号左侧的变量。
  • +=a += 5 相当于 a = a + 5
  • -=a -= 5 相当于 a = a - 5
  • *=a *= 5 相当于 a = a * 5
  • /=a /= 5 相当于 a = a / 5
  • **=a **= 5 相当于 a = a ** 5
  • //=a //= 5 相当于 a = a // 5
  • %=a %= 5 相当于 a = a % 5

关系运算符(比较运算符)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
result = 10 > 20  # False
result = 10 >= 10 # True
result = 2 > True # True
# result = 2 > '1' # TypeError: '>' not supported between instances of 'int' and 'str'
result = 30 < 20 # False

# 在Python中可以对两个字符串进行大于(等于)或小于(等于)的运算,
# 当对字符串进行比较时,实际上比较的是字符串的Unicode编码
# 比较两个字符串的Unicode编码时,是逐位比较的,比较出现结果时,直接返回,后续不再比较
# 利用该特性可以对字符串按照字母顺序进行排序,但是对于中文来说意义不是特别大
# 注意:如果不希望比较两个字符串的Unicode编码,则需要将其转换为数字然后再比较

result = '2' > '1' # True,2的unicode编码为0032,1的unicode编码为0031
result = '2' > '11' # True,逐位比较,先拿2和1比,结果为True,直接返回,后续不再比较
result = 'a' > 'b' # False,a的unicode编码为0061,b的unicode编码为0062
result = 'c' < 'd' # True
result = 'ab' > 'b' # False,逐位比较,先拿a和b比,结果为False,直接返回,后续不再比较

print(int('2') > int('11')) # False

result = 1 == 1 # True
result = 'hello' == 'hello' # True
result = 'abc' == 'bcd' # False
result = 'abc' != 'bcd' # True
result = 1 == True # True
result = 1 is True # False
result = 1 is not True # True
print(id(1), id(True)) # 140708473153312 140708472870736
  • 关系运算符用来比较两个值之间的关系,总会返回一个布尔值。如果关系成立,返回 True,否则返回 False。
  • >:比较左侧值是否大于右侧值。
  • >=:比较左侧的值是否大于或等于右侧的值。
  • <:比较左侧值是否小于右侧值。
  • <=:比较左侧的值是否小于或等于右侧的值。
  • ==:比较两个对象的值是否相等,比较的是对象的值。
  • !=:比较两个对象的值是否不相等,比较的是对象的值。
  • is:比较两个对象是否是同一个对象,比较的是对象的 id。
  • is not:比较两个对象是否不是同一个对象,比较的是对象的 id。

逻辑运算符

  • 逻辑运算符主要用来做一些逻辑判断。

  • and:逻辑与。

    • and 可以对符号两侧的值进行与运算。

    • 只有在符号两侧的值都为 True 时,才会返回 True,只要有一个 False 就返回 False。

    • Python 中的与运算是短路的与,如果第一个值为 False,则不再看第二个值,直接返回 False。

      1
      2
      True and print('男:你猜我出来吗?')  # 第一个值是True,会看第二个值,所以print()会执行
      False and print('女:你猜我出来吗?') # 第一个值是False,不会看第二个值,所以print()不会执行
  • or:逻辑或。

    • or 可以对符号两侧的值进行或运算。

    • 或运算两个值中只要有一个 True,就会返回 True。

    • Python 中的或运算是短路的或,如果第一个值为 True,则不再看第二个值,直接返回 True。

      1
      2
      False or print('男:你猜我出来吗?')  # 第一个值为False,继续看第二个,所以打印语句执行
      True or print('女:你猜我出来吗?') # 第一个值为True,不看第二个,所以打印语句不执行
  • not:逻辑非。

    • not 可以对符号右侧的值进行非运算。
    • 对于布尔值,非运算会对其进行取反操作,True 变 False,False 变 True。
    • 对于非布尔值,非运算会先将其转换为布尔值,然后再取反。
  • 非布尔值的与或运算:当我们对非布尔值进行与或运算时,Python 会将其当做布尔值运算,最终会返回原值。

    • 与运算的规则:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      # True and True
      result = 1 and 2 # 2

      # True and False
      result = 1 and 0 # 0

      # False and True
      result = 0 and 1 # 0

      # False and False
      result = None and 0 # None
      • 与运算是找 False 的,如果第一个值是 False,则不看第二个值。
      • 如果第一个值是 False,则直接返回第一个值,否则返回第二个值。
    • 或运算的规则:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      # True or True
      result = 1 or 2 # 1

      # True or False
      result = 1 or 0 # 1

      # False or True
      result = 0 or 1 # 1

      # False or False
      result = None or 0 # 0
      • 或运算是找 True 的,如果第一个值是 True,则不看第二个值。
      • 如果第一个值是 True,则直接返回第一个值,否则返回第二个值。

条件运算符(三元运算符)

1
2
3
4
5
6
7
a = 30
b = 50
print('a的值比较大!') if a > b else print('b的值比较大!')

# 获取a和b之间的较大值
maxNum = a if a > b else b
print(maxNum)
  • 语法:语句1 if 条件表达式 else 语句2

  • na = input(‘请输入任意内容:’)
    print(‘用户输入的内容是:’, a)

    获取用户输入的用户名

    username = input(‘请输入你的用户名: ‘)

    判断用户名是否是admin

    if username == ‘admin’:

    print('欢迎管理员光临!')
  • 该函数用来获取用户的输入。

  • input() 调用后,程序会立即暂停,等待用户输入,用户输入完内容以后,点击回车程序才会继续向下执行。用户输入完成以后,其所输入的的内容会以返回值的形式返回。

  • 注意:input() 的返回值是一个字符串。

  • input() 函数中可以设置一个字符串作为参数,这个字符串将会作为提示文字显示。

  • input() 也可以用于暂时阻止程序结束。

Python 流程控制语句

  • Python代码在执行时是按照自上向下顺序执行的。
  • 通过流程控制语句,可以改变程序的执行顺序,也可以让指定的程序反复执行多次。
  • 流程控制语句分成两大类:条件判断语句,循环语句。

条件判断语句(if 语句)

1
2
3
4
5
6
7
8
9
num = 10
if num > 10:
print('num比10大!')

if num > 10 and num < 20:
print('num比10大, num比20小!')

if 10 < num < 20:
print('num比10大, num比20小!')
  • 语法:

    1
    2
    if 条件表达式: 
    代码块
  • 执行的流程:if 语句在执行时,会先对条件表达式进行求值判断,如果为 True,则执行 if 后的语句;如果为 False,则不执行。

  • 默认情况下,if 语句只会控制紧随其后的那条语句,如果希望 if 可以控制多条语句,则可以在 if 后跟着一个代码块。

  • 代码块:

    • 代码块中保存着一组代码,同一个代码块中的代码,要么都执行要么都不执行。
    • 代码块就是一种为代码分组的机制。
    • 如果要编写代码块,语句就不能紧随在 : 后边,而是要写在下一行。
    • 代码块以缩进开始,直到代码恢复到之前的缩进级别时结束。
    • 缩进有两种方式,一种是使用 tab 键,一种是使用空格(四个)。
      • Python 代码中使用的缩进方式必须统一。
      • Python 的官方文档中推荐我们使用空格来缩进。
  • 可以使用逻辑运算符来连接多个条件,如果希望所有条件同时满足,则需要使用 and;如果希望只要有一个条件满足即可,则需要使用 or

if - else

1
2
3
4
5
6
7
8
9
10
11
12
age = 7
if age > 17:
print('你已经成年了~~')
else:
print('你还未成年~~')

# 如果一个年份可以被4整除不能被100整除,或者可以被400整除,这个年份就是闰年
year = int(input('请输入一个任意的年份:'))
if year % 4 == 0 and year % 100 != 0 or year % 400 == 0:
print(year, '是闰年')
else:
print(year, '是平年')
  • 语法:

    1
    2
    3
    4
    if 条件表达式:
    代码块1
    else:
    代码块2
  • 执行流程:if - else 语句在执行时,先对 if 后的条件表达式进行求值判断,如果为 True,则执行 if 后的代码块 1;如果为 False,则执行 else 后的代码块 2。

if - elif - else

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
age = 210

if age > 200:
print('活的可真久!')
elif age > 100:
print('你也是老大不小了!')
elif age >= 60:
print('你已经退休了!')
elif age >= 30:
print('你已经是中年了!')
elif age >= 18:
print('你已经成年了!')
else:
print('你还是个小孩!')

age = 68

if 18 <= age < 30:
print('你已经成年了!')
elif 30 <= age < 60:
print('你已经中年了!')
else:
print('你已经退休了!')
  • 语法:

    1
    2
    3
    4
    5
    6
    7
    8
    if 条件表达式:
    代码块
    elif 条件表达式:
    代码块
    elif 条件表达式:
    代码块
    else:
    代码块
  • 执行流程:if - elif - else 语句在执行时,会自上向下依次对条件表达式进行求值判断,如果表达式的结果为 True,则执行当前代码块,然后语句结束;如果表达式的结果为 False,则继续向下判断,直到找到 True 为止;如果所有的表达式都是 False,则执行 else 后的代码块。

  • if - elif - else 中只会有一个代码块会执行。

循环语句

  • 循环语句可以使指定的代码块重复指定的次数。
  • 循环语句分成两种,while 循环和 for 循环。

while 循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# 创建一个执行十次的循环
i = 0
while i < 10:
i += 1
print(i, 'hello')
else:
print('else中的代码块')


# 水仙花数是指一个 n 位数(n≥3 ),它的每个位上的数字的 n 次幂之和等于它本身(例如:1**3 + 5**3 + 3**3 = 153)。
# 求1000以内所有的水仙花数

# 获取1000以内的三位数
i = 100
while i < 1000:

# 假设,i的百位数是a,十位数b,个位数c
# 求i的百位数
a = i // 100
# 求i的十位数
# b = i // 10 % 10
b = (i - a * 100) // 10
# 求i的个位数字
c = i % 10
# print(i , a , b , c)

# 判断i是否是水仙花数
if a**3 + b**3 + c**3 == i :
print(i)
i += 1
  • 语法:

    1
    2
    3
    4
    while 条件表达式:
    代码块
    else:
    代码块
  • 执行流程:while 语句在执行时,会先对 while 后的条件表达式进行求值判断,如果判断结果为 True,则执行循环体(代码块),循环体执行完毕,继续对条件表达式进行求值判断,以此类推,直到判断结果为 False,则循环终止,如果循环有对应的 else,则执行 else 后的代码块。

  • 条件表达式恒为 True 的循环语句,称为死循环。

  • 循环的三个要件:

    • 初始化表达式:通过初始化表达式初始化一个变量。
    • 条件表达式:条件表达式用来设置循环执行的条件。
    • 更新表达式:修改初始化变量的值。

循环嵌套

  • 打印图形:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    # 在控制台中打印如下图形
    # *****
    # *****
    # *****
    # *****
    # *****
    #

    # 创建一个循环来控制图形的高度
    # 循环嵌套时,外层循环没执行一次,内存循环就要执行一圈
    i = 0
    while i < 5:
    # 创建一个内层循环来控制图形的宽度
    j = 0
    while j < 5:
    # print()默认在结尾打印\n换行符,添加end参数,打印时不要换行
    print("* ", end='')
    j += 1
    # 每一行打印完毕后,再打印一个换行符
    print()
    i += 1

    #
    # * j<1 i=0
    # ** j<2 i=1
    # *** j<3 i=2
    # **** j<4 i=3
    # ***** j<5 i=4
    #
    # *****
    # ****
    # ***
    # **
    # *
    i = 0
    while i < 5:
    j = 0
    while j < i + 1:
    print("* ", end='')
    j += 1
    print()
    i += 1
  • 99 乘法表:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    # 打印99乘法表
    # 1*1=1
    # 1*2=2 2*2=4
    # 1*3=3 2*3=6 3*3=9
    # ... 9*9=81

    # 创建一个外层循环来控制图形的高度
    i = 0
    while i < 9:
    i += 1

    # 创建一个内层循环来控制图形的宽度
    j = 0
    while j < i:
    j += 1
    print(f"{j}*{i}={i*j} ",end="")

    print()

break 和 continue

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
i = 0
while i < 5:
if i == 3:
break
print(i) # 结束循环,结果:0 1 2
i += 1
else:
print('循环结束')

i = 0
while i < 5:
i += 1
if i == 2:
continue # 跳出当前循环,结果:1 3 4 5 循环结束
print(i)
else:
print('循环结束')

i = 0
if i < 5:
pass
  • break 可以用来立即退出循环语句(包括 else)。
  • continue 可以用来跳过当次循环。
  • break 和 continue 都是只对离他最近的循环起作用。
  • pass 是用来在判断或循环语句中占位的,无实际意义。如果循环体内容没想好怎么写,可以先用 pass 占位,这样不会影响程序执行。

模块引入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# 模块,通过模块可以对Python进行扩展
# 引入一个time模块,来统计程序执行的时间
from time import *

# time()函数可以用来获取当前的时间,返回的单位是秒
# 获取程序开始的时间
# 优化前:
# 10000个数 12.298秒
# 100000个数 没有结果
# 第一次优化:加break
# 10000个数 1.577秒
# 100000个数 170.645秒
# 第二次优化:循环到根号为止
# 10000个数 0.068秒
# 100000个数 1.646秒
#
# 36的因数
# 2 18
# 3 12
# 4 9
# 6 6
#
begin = time()

i = 2
while i <= 100000:
flag = True
j = 2
while j <= i ** 0.5:
if i % j == 0:
flag = False
# 一旦进入判断,则证明i一定不是质数,此时内层循环没有继续执行的必要
# 使用break来退出内层的循环
break
j += 1
if flag:
# print(i)
pass
i += 1

# 获取程序结束的时间
end = time()

# 计算程序执行的时间
print("程序执行花费了:", end - begin, "秒")

for 循环

  • 语法:

    1
    2
    for 变量 in 序列 :
    代码块
  • for 循环除了创建方式以外,其余的都和 while 循环一样,包括 else、break、continue 都可以在 for 循环中使用。

Python 数据结构

序列(sequence)

  • 计算机中数据存储的方式叫数据结构,序列是 Python 中最基本的一种数据结构。

  • 序列用于保存一组有序的数据,所有的数据在序列当中都有一个唯一的位置(索引),并且序列中的数据会按照添加的顺序来分配索引。

  • 序列存储的数据,称为元素。

  • 序列的分类:

    • 可变序列(序列中的元素可以改变)
      • 列表(list)
    • 不可变序列(序列中的元素不能改变)
      • 元组(tuple)
      • 字符串(str)
  • range() 函数:用来生成一个自然数的序列。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # range()是一个函数,可以用来生成一个自然数的序列
    # 该函数需要三个参数
    # 1.起始位置(包含,可以省略,默认是0)
    # 2.结束位置(不包含)
    # 3.步长(可以省略,默认是1)
    r = range(5)
    print(list(r)) # [0, 1, 2, 3, 4]
    r = range(0, 10, 2)
    print(list(r)) # [0, 2, 4, 6, 8]
    r = range(10, 0, -1)
    print(list(r)) # [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]

    # 通过range()可以创建一个执行指定次数的for循环
    for i in range(30):
    print(i)

通用操作

  • + 可以将两个序列拼接为一个序列。
  • * 可以将序列重复指定的次数。
  • in 用来检查指定元素是否存在于序列中,如果存在,返回 True,否则返回 False。
  • not in 用来检查指定元素是否不在序列中,如果不在,返回 True,否则返回 False。
  • len() 函数获取序列的长度,即序列中的元素的个数。该长度值,是序列的最大索引加 1。
  • min() 函数获取序列中的最小值。
  • max() 函数获取序列中的最大值。
  • 可以通过索引(index)来获取序列中的元素:
    • 语法:序列[索引]
    • 索引是元素在序列中的位置,序列中的每一个元素都有一个索引。
    • 索引是从 0 开始的整数,序列第一个位置索引为 0,第二个位置索引为 1,第三个位置索引为 2,以此类推。
    • 索引可以是负数,表示从后向前获取元素,-1 表示倒数第一个元素,-2 表示倒数第二个元素,以此类推。
    • 如果使用的索引超过了序列最大的范围,会抛出异常 IndexError: list index out of range
  • s.index() 方法获取指定元素在序列中的第一次出现时索引。
    • 方法和函数基本上是一样,只不过方法必须通过 对象.方法() 的形式调用,方法实际上就是和对象关系紧密的函数。
    • index() 的第二个参数,表示查找的起始位置,第三个参数,表示查找的结束位置。
    • 如果要获取序列中没有的元素,会抛出异常。
  • s.count() 方法统计指定元素在序列中出现的次数。

切片

  • 切片指从现有序列中,获取一个子序列。
  • 语法一:序列[起始:结束]
    • 通过切片获取元素时,会包括起始位置的元素,不会包括结束位置的元素。
    • 做切片操作时,总会返回一个新的序列,但不会影响原来的序列。
    • 起始和结束位置的索引都可以省略不写。
      • 如果省略起始位置,则会从第一个元素开始截取。
      • 如果省略结束位置,则会一直截取到最后。
      • 如果起始位置和结束位置全部省略,则相当于创建了一个序列的副本。
  • 语法二:序列[起始:结束:步长]
    • 步长表示,每次获取元素的间隔,默认值是 1。
    • 步长不能是 0,但可以是负数。
    • 步长如果是负数,则从序列的后边向前边取元素。

分类

列表(list)
  • 列表是 Python 中的一个对象。

  • 对象(object)就是内存中专门用来存储数据的一块区域,之前我们学习的对象,像数值,它只能保存一个单一的数据。

  • 列表是用来存储对象的对象,列表中可以保存多个有序的数据。

  • 列表中可以保存任意的对象,但一般不会这样操作,尽可能保证列表中元素属性一致。

  • 列表的创建

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    my_list = []  # 创建了一个空列表
    print(my_list, type(my_list)) # [] <class 'list'>

    my_list = [10] # 创建一个只包含一个元素的列表

    my_list = [10, 20, 30, 40, 50] # 创建了一个包含有5个元素的列表

    # my_list = [10, 'hello', True, None, [1, 2, 3], print] # 列表可以保存任意对象,但一般不会这样操作

    print(my_list[4]) # 50

    print((my_list[-2])) # 40

    print(len(my_list)) # 5
    • 使用 [] 来创建列表。
  • 一个列表中可以存储多个元素,也可以在创建列表时,来指定列表中的元素。
  • 当向列表中添加多个元素时,多个元素之间使用 , 隔开。
  • 列表中的对象都会按照插入的顺序存储到列表中,第一个插入的对象保存到第一个位置,第二个保存到第二个位置,以此类推。
  • 列表的通用操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    my_list = [1, 2, 3] + [4, 5, 6]
    print(len(my_list)) # 6

    my_list = [1, 2, 3] * 5
    print(len(my_list)) # 15

    stus = ['孙悟空', '猪八戒', '沙和尚', '唐僧', '蜘蛛精', '白骨精', '沙和尚', '沙和尚']
    print('牛魔王' in stus) # False
    print('牛魔王' not in stus) # True

    arr = [10, 1, 2, 5, 100, 77]
    print(min(arr), max(arr)) # 1 100

    print(stus.index('沙和尚')) # 2
    print(stus.index('沙和尚', 3, 7)) # 6
    # print(stus.index('牛魔王')) # ValueError: '牛魔王' is not in list
    print(stus.count('牛魔王')) # 0
  • 列表的切片操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    stus = ['孙悟空', '猪八戒', '沙和尚', '唐僧', '蜘蛛精', '白骨精']
    print(stus[1:]) # ['猪八戒', '沙和尚', '唐僧', '蜘蛛精', '白骨精']
    print(stus[:3]) # ['孙悟空', '猪八戒', '沙和尚']
    print(stus[:]) # ['孙悟空', '猪八戒', '沙和尚', '唐僧', '蜘蛛精', '白骨精']
    print(stus) # ['孙悟空', '猪八戒', '沙和尚', '唐僧', '蜘蛛精', '白骨精']

    print(stus[0:5:3]) # ['孙悟空', '唐僧']
    # print(stus[::0]) # ValueError: slice step cannot be zero
    print(stus[::-1]) # ['白骨精', '蜘蛛精', '唐僧', '沙和尚', '猪八戒', '孙悟空'],列表反转
  • 列表元素的修改

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    stus = ['孙悟空', '猪八戒', '沙和尚', '唐僧', '蜘蛛精', '白骨精']

    # 通过索引来修改元素
    stus[0] = 'sunwukong'
    stus[2] = '哈哈'
    print(stus) # ['sunwukong', '猪八戒', '哈哈', '唐僧', '蜘蛛精', '白骨精']

    # 通过del来删除元素
    del stus[2] # 删除索引为2的元素
    print(stus) # ['sunwukong', '猪八戒', '唐僧', '蜘蛛精', '白骨精']

    # 通过切片来修改列表
    # 在给切片进行赋值时,只能使用序列
    stus[0:2] = ['牛魔王', '红孩儿'] # 使用新的元素替换旧元素
    print(stus) # ['牛魔王', '红孩儿', '唐僧', '蜘蛛精', '白骨精']
    stus[0:2] = ['牛魔王', '红孩儿', '二郎神', "sda"] # 新元素的个数可以超过旧元素
    print(stus) # ['牛魔王', '红孩儿', '二郎神', 'sda', '唐僧', '蜘蛛精', '白骨精']
    stus[0:0] = ['牛魔王'] # 向索引为0的位置插入元素
    print(stus) # ['牛魔王', '牛魔王', '红孩儿', '二郎神', 'sda', '唐僧', '蜘蛛精', '白骨精']

    # 当设置了步长时,序列中元素的个数必须和切片中元素的个数一致
    print(stus[::2]) # ['牛魔王', '红孩儿', 'sda', '蜘蛛精'],指定步长,切片中元素个数为4
    # stus[::2] = ['牛魔王', '红孩儿', '二郎神'] # 报错,序列中元素只有3个,ValueError: attempt to assign sequence of size 3 to extended slice of size 4

    # 通过切片来删除元素
    del stus[0:2] # 删除头两个元素
    print(stus) # ['红孩儿', '二郎神', 'sda', '唐僧', '蜘蛛精', '白骨精']
    del stus[::2] # 隔一个删一个
    print(stus) # ['二郎神', '唐僧', '白骨精']
    stus[1:3] = [] # 修改位置1和2的元素为空
    print(stus) # ['二郎神']

    # 以上操作,只适用于可变序列
    s = 'hello'
    # s[1] = 'a' # 不可变序列,无法通过索引来修改
    # 可以通过list()函数将其他的序列转换为list
    s = list(s)
    print(s) # ['h', 'e', 'l', 'l', 'o']
  • 列表的方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    stus = ['孙悟空', '猪八戒', '沙和尚', '唐僧']

    # append()
    # 向列表的最后添加一个元素
    stus.append('唐僧1')
    print(stus) # ['孙悟空', '猪八戒', '沙和尚', '唐僧', '唐僧1']

    # insert()
    # 向列表的指定位置插入一个元素
    # 参数:
    # 1.要插入的位置
    # 2.要插入的元素
    stus.insert(2, '唐僧2')
    print(stus) # ['孙悟空', '猪八戒', '唐僧2', '沙和尚', '唐僧', '唐僧1']

    # extend()
    # 使用新的序列来扩展当前序列
    # 需要一个序列作为参数,它会将该序列中的元素添加到当前列表中
    stus.extend(['唐僧3', '白骨精']) # 等同于:stus += ['唐僧3','白骨精']
    print(stus) # ['孙悟空', '猪八戒', '唐僧2', '沙和尚', '唐僧', '唐僧1', '唐僧3', '白骨精']

    # pop()
    # 根据索引删除并返回被删除的元素
    result = stus.pop(2)
    print(result) # 唐僧2
    print(stus) # ['孙悟空', '猪八戒', '沙和尚', '唐僧', '唐僧1', '唐僧3', '白骨精']
    result = stus.pop() # 删除最后一个元素
    print(result) # 白骨精
    print(stus) # ['孙悟空', '猪八戒', '沙和尚', '唐僧', '唐僧1', '唐僧3']

    # remove()
    # 删除指定值的元素,如果相同值的元素有多个,只会删除第一个
    stus.remove('猪八戒')
    print(stus) # ['孙悟空', '沙和尚', '唐僧', '唐僧1', '唐僧3']

    # reverse()
    # 用来反转列表
    stus.reverse()
    print(stus) # ['唐僧3', '唐僧1', '唐僧', '沙和尚', '孙悟空']

    # clear()
    # 清空序列
    stus.clear()
    print(stus) # []

    # sort()
    # 用来对列表中的元素进行排序,默认是升序排列
    # 如果需要降序排列,则需要传递一个reverse=True作为参数
    my_list = list('asnbdnbasdabd')
    my_list.sort()
    print(my_list) # ['a', 'a', 'a', 'b', 'b', 'b', 'd', 'd', 'd', 'n', 'n', 's', 's']

    my_list = [10, 1, 20, 3, 4, 5, 0, -2]
    my_list.sort()
    print(my_list) # 升序:[-2, 0, 1, 3, 4, 5, 10, 20]
    my_list.sort(reverse=True)
    print(my_list) # 降序:[20, 10, 5, 4, 3, 1, 0, -2]
  • 列表的遍历

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    # 遍历列表,指的就是将列表中的所有元素取出来
    # 创建列表
    stus = ['孙悟空', '猪八戒', '沙和尚', '唐僧', '白骨精', '蜘蛛精']

    # 遍历列表
    # print(stus[0])
    # print(stus[1])
    # print(stus[2])
    # print(stus[3])

    # 通过while循环来遍历列表
    i = 0
    while i < len(stus):
    print(stus[i])
    i += 1

    # 通过for循环来遍历列表
    # 语法:
    # for 变量 in 序列 :
    # 代码块
    # for循环的代码块会执行多次,序列中有几个元素就会执行几次
    # 每执行一次就会将序列中的一个元素赋值给变量,
    # 所以我们可以通过变量,来获取列表中的元素
    for s in stus:
    print(s)
元组(tuple)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
my_tuple = ()  # 创建了一个空元组
print(my_tuple, type(my_tuple)) # () <class 'tuple'>

my_tuple = (1, 2, 3, 4, 5) # 创建了一个5个元素的元组
# 元组是不可变对象,不能尝试为元组中的元素重新赋值
# my_tuple[3] = 10 # TypeError: 'tuple' object does not support item assignment
# print(my_tuple[3])

# 当元组不是空元组时,括号可以省略
# 如果元组不是空元组,它里边至少要有一个,
my_tuple = 10, 20, 30, 40
print(my_tuple, type(my_tuple)) # (10, 20, 30, 40) <class 'tuple'>
my_tuple = 40,
print(my_tuple, type(my_tuple)) # (40,) <class 'tuple'>

my_tuple = 10, 20, 30, 40

# 元组的解包(解构)
# 解包指的是将元组当中每一个元素都赋值给一个变量
a, b, c, d = my_tuple
print("a =", a) # a = 10
print("b =", b) # b = 20
print("c =", c) # c = 30
print("d =", d) # d = 40

# 利用元组的解包特性,可以直接交换a和b的值
a = 100
b = 300
a, b = b, a # b, a 就是一个元组,通过解包赋值给 a, b
print(a, b) # 300 100

my_tuple = 10, 20, 30, 40

# 在对一个元组进行解包时,变量的数量必须和元组中的元素的数量一致
# 也可以在变量前边添加一个*,这样变量将会获取元组中所有剩余的元素
a, b, *c = my_tuple
a, *b, c = my_tuple
*a, b, c = my_tuple
a, b, *c = [1, 2, 3, 4, 5, 6, 7] # 对列表也可以解包
a, b, *c = 'hello world' # 对字符串也可以解包
# 不能同时出现两个或以上的*变量
# *a, *b, c = my_tuple # SyntaxError: two starred expressions in assignment
print('a =', a) # a = h
print('b =', b) # b = e
print('c =', c) # c = ['l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd']
  • 元组是一个不可变的序列,它的操作的方式基本上和列表是一致的。在操作元组时,可以把元组当成是一个不可变的列表。
  • 一般当我们希望数据不改变时,就使用元组,其余情况都使用列表。
  • 使用 () 来创建元组。
  • 元组是不可变对象,不能尝试为元组中的元素重新赋值。
  • 当元组不是空元组时,括号可以省略。如果元组不是空元组,它里边至少要有一个 ,
  • 元组的解包(解构):指的是将元组当中每一个元素都赋值给一个变量。利用元组的解包特性,可以直接交换 a 和 b 的值。说明:不光是元组,列表和字符串都能解包。
  • 在对一个元组进行解包时,变量的数量必须和元组中的元素的数量一致。也可以在变量前边添加一个 *,这样该变量将会获取元组中所有剩余的元素,但不能同时出现两个或以上的带 * 变量。

可变对象说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 列表是可变对象
a = [1, 2, 3]
print('修改前:', a, id(a)) # 修改前: [1, 2, 3] 1322105181888

# 通过索引修改列表的值
a[0] = 10
print('修改后:', a, id(a)) # 修改后: [10, 2, 3] 1322105181888

# 为变量重新赋值
a = [4, 5, 6]
print('重新赋值:', a, id(a)) # 重新赋值: [4, 5, 6] 1322105180928

a = [1, 2, 3]
b = a # a和b指向同一个对象
print("a", a, id(a)) # a [1, 2, 3] 2222727763648
print("b", b, id(b)) # b [1, 2, 3] 2222727763648
b[0] = 10
print("a", a, id(a)) # a [10, 2, 3] 2222727763648
print("b", b, id(b)) # b [10, 2, 3] 2222727763648

b = [10, 2, 3] # b和a指向的不再是同一个对象
print("a", a, id(a)) # a [10, 2, 3] 2222727763648
print("b", b, id(b)) # b [10, 2, 3] 2222727762688
  • 每个对象中都保存了三个数据:id(标识),type(类型)和 value(值)。

  • 列表就是一个可变对象,比如 a = [1, 2, 3]

  • a[0] = 10:改对象。

    • 这个操作是在通过变量去修改对象的值。
    • 这种操作不会改变变量所指向的对象。
    • 当我们去修改对象时,如果有其他变量也指向了该对象,则修改也会在其他的变量中体现。
  • a = [4, 5, 6]:改变量。

    • 这个操作是在给变量重新赋值。
    • 这种操作会改变变量所指向的对象。
    • 为一个变量重新赋值时,不会影响其他的变量。
  • 一般只有在为变量赋值时才是修改变量,其余的都是修改对象。

比较符
1
2
3
4
5
6
a = [1, 2, 3]
b = [1, 2, 3]
print(a, b) # [1, 2, 3] [1, 2, 3]
print(id(a), id(b)) # 2081830016896 2081830015936
print(a == b) # a和b的值相等,使用==会返回True
print(a is b) # a和b不是同一个对象,内存地址不同,使用is会返回False
  • ==!= 比较的是对象的值是否相等。
  • isis not 比较的是对象的 id 是否相等(比较两个对象是否是同一个对象)。

字典(dict)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
d = {}  # 创建了一个空字典

# 创建一个包含有数据的字典
d = {
'name': '孙悟空',
'age': 18,
'gender': '男'
}
print(d, type(d)) # {'name': '孙悟空', 'age': 18, 'gender': '男'} <class 'dict'>

# 根据键来获取值
print(d['name'], d['age'], d['gender']) # 孙悟空 18 男

# 如果使用了字典中不存在的键,会报错
# print(d['hello']) # KeyError: 'hello'
  • 字典属于一种新的数据结构,称为映射(mapping)。

  • 字典的作用和列表类似,都是用来存储对象的容器。

  • 列表存储数据的性能很好,但是查询数据的性能的很差。

  • 在字典中每一个元素都有一个唯一的名字,通过这个唯一的名字可以快速的查找到指定的元素。

  • 在查询元素时,字典的效率是非常快的。

  • 在字典中可以保存多个对象,每个对象都会有一个唯一的名字。

    • 这个唯一的名字,我们称其为键(key),通过 key 可以快速的查询 value。
    • 这个对象,我们称其为值(value)。
    • 所以字典,我们也称为键值对(key - value)结构。
    • 每个字典中都可以有多个键值对,而每一个键值对我们称其为一项(item)。
  • 使用 {} 来创建字典。

    • 创建一个包含有数据的字典:{key: value, key: value, key: value}
    • 字典的键可以是任意的不可变对象(int、str、bool、tuple …),但是一般我们都会使用 str。
    • 字典的值可以是任意对象。
    • 字典的键是不能重复的,如果出现重复,后边的会替换前边的。

字典的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# 创建字典
# 方式一:使用{}
# 语法:{k1: v1, k2: v2, k3: v3}

# 方式二:使用dict()函数来创建字典
# 每一个参数都是一个键值对,参数名就是键,参数名就是值(这种方式创建的字典,key都是字符串)
d = dict(name='孙悟空', age=18, gender='男')

# 也可以将一个包含有双值子序列的序列转换为字典
# 双值序列:序列中只有两个值,比如[1, 2],('a', 3),'ab'
# 子序列:如果序列中的元素也是序列,那么我们就称这个元素为子序列,比如[(1, 2), (3, 5)]
d = dict([('name', '孙悟空'), ('age', 18)])

####################################################################

d = dict(name='孙悟空', age=18, gender='男')

# len()获取字典中键值对的个数
print(len(d)) # 3

# in 检查字典中是否包含指定的键
# not in 检查字典中是否不包含指定的键
print('hello' in d) # False
print('age' not in d) # False

# 获取字典中的值,根据键来获取值
# 方式一:语法:d[key]
# 通过[]来获取值时,如果键不存在,会抛出异常KeyError
print(d['age']) # 18
n = 'name'
print(d[n]) # 孙悟空

# 方式二:get(key[, default]) 该方法用来根据键来获取字典中的值
# 如果获取的键在字典中不存在,会返回None,不会报错
# 也可以指定一个默认值,来作为第二个参数,这样获取不到值时将会返回默认值
print(d.get('name')) # 孙悟空
print(d.get('hello')) # None
print(d.get('hello', '默认值')) # 默认值

# 修改字典
# d[key] = value 如果key存在则覆盖,不存在则添加
d['name'] = 'sunwukong' # 修改字典的key-value
d['address'] = '花果山' # 向字典中添加key-value

# setdefault(key[, default]) 可以用来向字典中添加key-value
# 如果key已经存在于字典中,则返回key的值,不会对字典做任何操作
# 如果key不存在,则向字典中添加这个key,并设置value
result = d.setdefault('name', '猪八戒')
print('result =', result) # result = sunwukong
result = d.setdefault('hello', '猪八戒')
print(d) # {'name': 'sunwukong', 'age': 18, 'gender': '男', 'address': '花果山', 'hello': '猪八戒'}

# update([other])
# 将其他的字典中的key-value添加到当前字典中
# 如果有重复的key,则后边的会替换到当前的
d = {'a': 1, 'b': 2, 'c': 3}
d2 = {'d': 4, 'e': 5, 'f': 6, 'a': 7}
d.update(d2)
print(d) # {'a': 7, 'b': 2, 'c': 3, 'd': 4, 'e': 5, 'f': 6}

# 删除,可以使用del来删除字典中的key-value
del d['a']
del d['b']
print(d) # {'c': 3, 'd': 4, 'e': 5, 'f': 6}
# del d['z'] # z不存在,报错,KeyError: 'z'

# popitem()
# 随机删除字典中的一个键值对,一般都会删除最后一个键值对
# 删除之后,它会将删除的key-value作为返回值返回
# 返回的是一个元组,元组中有两个元素,第一个元素是删除的key,第二个是删除的value
# 当使用popitem()删除一个空字典时,会抛出异常 KeyError: 'popitem(): dictionary is empty'
# d.popitem()
result = d.popitem()
print(result) # ('f', 6)
print(d) # {'c': 3, 'd': 4, 'e': 5}

# pop(key[, default])
# 根据key删除字典中的key-value
# 会将被删除的value返回!
# 如果删除不存在的key,会抛出异常
# 如果指定了默认值,再删除不存在的key时,不会报错,而是直接返回默认值
result = d.pop('d')
print(result) # 4
print(d) # {'c': 3, 'e': 5}
result = d.pop('z', '这是默认值')
print(result) # 这是默认值
print(d) # {'c': 3, 'e': 5}

# clear()用来清空字典
d.clear()
print(d) # {}

# print('result =',result)
# print(d)

# copy()
# 该方法用于对字典进行浅复制
# 复制以后的对象,和原对象是独立的,修改一个不会影响另一个
d = {'a': 1, 'b': 2, 'c': 3}
d2 = d.copy() # d和d2指向的是两个对象,这两个对象的值相同,id不同
print('d = ', d, id(d)) # d = {'a': 1, 'b': 2, 'c': 3} 1507616638400
print('d2 = ', d2, id(d2)) # d2 = {'a': 1, 'b': 2, 'c': 3} 1507616638464

# 注意,浅复制会简单复制对象内部的值,如果值也是一个可变对象,这个可变对象不会被复制
# 深复制性能差,使用较少
d = {'a': {'name': '孙悟空', 'age': 18}, 'b': 2, 'c': 3}
d2 = d.copy()
print('d = ', d, id(d)) # d = {'a': {'name': '孙悟空', 'age': 18}, 'b': 2, 'c': 3} 2538203734848
print('d2 = ', d2, id(d2)) # d2 = {'a': {'name': '孙悟空', 'age': 18}, 'b': 2, 'c': 3} 2538210096768
# d的a值也是一个字典,修改d2中a值列表中name的值,d也会受到影响,说明浅复制不修改是可变对象的值
d2['a']['name'] = '猪八戒'
print('d = ', d, id(d)) # d = {'a': {'name': '猪八戒', 'age': 18}, 'b': 2, 'c': 3} 2538203734848
print('d2 = ', d2, id(d2)) # d2 = {'a': {'name': '猪八戒', 'age': 18}, 'b': 2, 'c': 3} 2538210096768

# d的a值是一个列表
d = {'a': ['孙悟空', '猪八戒', '沙和尚'], 'b': 2, 'c': 3}
d2 = d.copy()
print('d = ', d, id(d)) # d = {'a': ['孙悟空', '猪八戒', '沙和尚'], 'b': 2, 'c': 3} 2053189928960
print('d2 = ', d2, id(d2)) # d2 = {'a': ['孙悟空', '猪八戒', '沙和尚'], 'b': 2, 'c': 3} 2053187068736
d2['a'][0] = '唐僧'
print('d = ', d, id(d)) # d = {'a': ['唐僧', '猪八戒', '沙和尚'], 'b': 2, 'c': 3} 2053189928960
print('d2 = ', d2, id(d2)) # d2 = {'a': ['唐僧', '猪八戒', '沙和尚'], 'b': 2, 'c': 3} 2053187068736

字典的遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
d = {'name': '孙悟空', 'age': 18, 'gender': '男'}

# 方式一:keys()
# 该方法会返回一个序列,序列中是字典中所有的键
for k in d.keys():
print(k, d[k])

# 方式二:values()
# 该方法会返回一个序列,序列中是字典中所有的值
for v in d.values():
print(v)

# 方式三:items()
# 该方法会返回字典中所有的项,它会返回一个序列,序列中是双值子序列
# 双值分别是,字典中的key和value
print(d.items()) # dict_items([('name', '孙悟空'), ('age', 18), ('gender', '男')])
for k, v in d.items(): # 元组解包特性
print(k, '=', v)

集合(set)

  • 集合和列表非常相似。
  • 不同点:
    • 集合中只能存储不可变对象。
    • 集合中存储的对象是无序(不是按照元素的插入顺序保存)。
    • 集合中不能出现重复的元素。

集合的使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# 集合的创建
# 方式一:使用{}来创建集合
s = {10, 3, 5, 1, 2, 1, 2, 3, 1, 1, 1, 1}
print(s, type(s)) # {1, 2, 3, 5, 10} <class 'set'>
# s = {[1, 2, 3], [4, 6, 7]} # TypeError: unhashable type: 'list',集合中只能存储不可变对象
# 方式二:使用set()函数来创建集合
s = set() # 空集合只能通过set()来创建,{}创建的是字典
# 可以通过set()来将序列和字典转换为集合
s = set([1, 2, 3, 4, 5, 1, 1, 2, 3, 4, 5]) # 转换列表
print(s) # {1, 2, 3, 4, 5}
s = set('hello') # 转换字符串
print(s) # {'e', 'h', 'o', 'l'}
s = set({'a': 1, 'b': 2, 'c': 3}) # 转换字典,使用set()将字典转换为集合时,只会包含字典中的键
print(s) # {'b', 'a', 'c'}

############################################################################

s = {'a', 'b', 1, 2, 3, 1}
print(s) # {1, 2, 3, 'a', 'b'}

# 使用in和not in来检查集合中的元素
print('a' in s) # True
print('b' not in s) # False

# 使用len()来获取集合中元素的数量
print(len(s)) # 5

# add()向集合中添加元素
s.add(10)
s.add(30)
s.add(1) # 集合中已存在的元素,添加无效
print(s) # {1, 2, 3, 'a', 10, 'b', 30}

############################################################################
s = {'a', 'b', 1, 2, 3}

# update()可以将一个集合中的元素添加到当前集合中
# update()也可以传递序列或字典作为参数,字典只会添加键倒集合中
s2 = set('hello') # 集合
s.update(s2)
print(s) # {'a', 2, 3, 1, 'h', 'o', 'l', 'e', 'b'}

s = {'a', 'b', 1, 2, 3}
s.update((10, 20, 30, 40, 50)) # 元组
print(s) # {'a', 2, 3, 1, 40, 10, 50, 20, 'b', 30}

s = {'a', 'b', 1, 2, 3}
s.update({10: 'ab', 20: 'bc', 100: 'cd', 1000: 'ef'}) # 字典
print(s) # {'a', 2, 3, 1, 100, 1000, 10, 20, 'b'}

############################################################################
s = {'a', 'b', 1, 2, 3}

# {1, 2, 3, 100, 40, 'o', 10, 1000, 'a', 'h', 'b', 'l', 20, 50, 'e', 30}
# pop()随机删除并返回一个集合中的元素
result = s.pop()
print(result) # 1
print(s) # {'a', 3, 2, 'b'}

# remove()删除集合中的指定元素
s.remove('a')
print(s) # {2, 3, 'b'}

# clear()清空集合
s.clear()
print(s) # set()

# copy()对集合进行浅复制

集合的运算

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
# 在对集合做运算时,不会影响原来的集合,而是返回一个运算结果

# 创建两个集合
s = {1, 2, 3, 4, 5}
s2 = {3, 4, 5, 6, 7}

# & 交集运算
result = s & s2
print(result) # {3, 4, 5}

# | 并集运算
result = s | s2
print(result) # {1, 2, 3, 4, 5, 6, 7}

# - 差集
result = s - s2
print(result) # {1, 2}

# ^ 异或集,获取两个集合中只出现一次的元素
result = s ^ s2
print(result) # {1, 2, 6, 7}

# <= 检查一个集合是否是另一个集合的子集
# 如果a集合中的元素全部都在b集合中出现,那么a集合就是b集合的子集,b集合是a集合超集
a = {1, 2, 3}
b = {1, 2, 3, 4, 5}
result = a <= b
print(result) # True
result = {1, 2, 3} <= {1, 2, 3}
print(result) # True
result = {1, 2, 3, 4, 5} <= {1, 2, 3}
print(result) # False

# < 检查一个集合是否是另一个集合的真子集
# 如果超集b中含有子集a中所有元素,并且b中还有a中没有的元素,则b就是a的真超集,a是b的真子集
result = {1, 2, 3} < {1, 2, 3}
print(result) # False
result = {1, 2, 3} < {1, 2, 3, 4, 5}
print(result) # True

# >= 检查一个集合是否是另一个的超集
result = {1, 2, 3, 4, 5} >= {1, 2, 3, 4, 5}
print(result) # True

# > 检查一个集合是否是另一个的真超集
result = {1, 2, 3, 4, 5} > {1, 2, 3, 4, 5}
print(result) # False

函数(function)

函数简介

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# 定义一个函数
def fn():
print('这是我的第一个函数!')
print('hello')
print('今天天气真不错!')


# 打印fn
print(fn) # <function fn at 0x00000175FD0261F0>
print(type(fn)) # <class 'function'>

# fn是函数对象,fn()调用函数
# print是函数对象,print()调用函数
fn()


# 定义一个函数,可以用来求任意两个数的和
def sum():
a = 123
b = 456
print(a + b)


sum() # 579


# 定义函数时指定形参
def fn2(a, b):
print(a, "+", b, "=", a + b)


# 调用函数时,来传递实参
fn2(10, 20) # 10 + 20 = 30
fn2(123, 456) # 123 + 456 = 579
  • 函数也是一个对象,对象是内存中专门用来存储数据的一块区域。

  • 函数可以用来保存一些可执行的代码,并且可以在需要时,对这些语句进行多次的调用。

  • 创建函数:

    1
    2
    def 函数名([形参1, 形参2, ... 形参n]):
    代码块
    • 函数名必须要符号标识符的规范(可以包含字母、数字、下划线,但是不能以数字开头)。
    • 函数中保存的代码不会立即执行,需要调用函数代码才会执行。
  • 调用函数:

    1
    函数对象()
  • 定义函数一般都是要实现某种功能的。

函数的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 求任意三个数的乘积
def mul(a, b, c):
print(a * b * c)


mul(1, 2, 3) # 6


# 根据不同的用户名显示不同的欢迎信息
def welcome(username):
print('欢迎', username, '光临')


welcome('孙悟空') # 欢迎 孙悟空 光临
  • 在定义函数时,可以在函数名后的 () 中定义数量不等的形参,多个形参之间使用 , 隔开。
  • 形参(形式参数),定义形参就相当于在函数内部声明了变量,但是并不赋值。
  • 实参(实际参数)。
  • 如果函数定义时,指定了形参,那么在调用函数时也必须传递实参, 实参将会赋值给对应的形参,简单来说,有几个形参就得传几个实参。

参数的传递方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# 定义函数,并为形参指定默认值
def fn(a=5, b=10, c=20):
print('a =', a)
print('b =', b)
print('c =', c)


fn(1, 2, 3)
fn(1, 2)
fn()

# 位置参数
fn(1, 2, 3)

# 关键字参数
fn(b=1, c=2, a=3)
print('hello', end='')

# 位置参数和关键字参数混合使用
fn(1, c=30)


def fn2(a):
print('a =', a)


# 函数在调用时,解析器不会检查实参的类型
# 实参可以传递任意类型的对象
b = 123
fn2(b) # a = 123
b = True
fn2(b) # a = True
b = 'hello'
fn2(b) # a = hello
b = None
fn2(b) # a = None
b = [1, 2, 3]
fn2(b) # a = [1, 2, 3]
fn2(fn) # a = <function fn at 0x0000025AB8B561F0>


# 类型不检查的缺陷,在传参时需要额外注意
def fn3(a, b):
print(a + b)


# fn3(123, "456") # TypeError: unsupported operand type(s) for +: 'int' and 'str'

# 在函数中对形参进行重新赋值,不会影响其他的变量
def fn4(a):
a = 20
print('a =', a, id(a)) # a = 20 140708519029120


c = 10
fn4(c)
print(c) # 10


# 如果形参指向的是一个对象,当我们通过形参去修改对象时,会影响到所有指向该对象的变量
def fn5(a):
# a是一个列表,尝试修改列表中的元素
a[0] = 30
print('a =', a, id(a)) # a = [30, 2, 3] 2056358531968


c = [1, 2, 3]
fn5(c)
print('c =', c, id(c)) # c = [30, 2, 3] 2056358531968

# 通过浅复制,或者切片,实现不修改c本身
fn4(c.copy())
fn4(c[:])
  • 定义形参时,可以为形参指定默认值。指定了默认值以后,如果用户传递了参数,则默认值没有任何作用;如果用户没有传递参数,则默认值就会生效。
  • 位置参数:即将对应位置的实参复制给对应位置的形参。
  • 关键字参数:可以不按照形参定义的顺序去传递,而直接根据参数名去传递参数。
  • 位置参数和关键字参数可以混合使用,混合使用时,必须将位置参数写到前面。
  • 函数在调用时,解析器不会检查实参的类型,实参可以传递任意类型的对象。
  • 在函数中对形参进行重新赋值,不会影响其他的变量。
  • 如果形参指向的是一个对象,当我们通过形参去修改对象时,会影响到所有指向该对象的变量。

不定长的参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# 定义一个函数,可以求任意个数字的和
def sum(*nums):
# 定义一个变量,来保存结果
result = 0
# 遍历元组,并将元组中的数进行累加
for n in nums:
result += n
print(result)


sum(10, 20, 30, 40) # 100
sum(10, 20, 30, 40, 50, 60, 70) # 280


# *a会接受所有的位置实参,并且会将这些实参统一保存到一个元组中(装包)
def fn(*a):
print("a =", a, type(a))


fn(1, 2, 3) # a = (1, 2, 3) <class 'tuple'>
fn(1, 2, 3, 4, 5) # a = (1, 2, 3, 4, 5) <class 'tuple'>


# 带星号的形参只能有一个
# 带星号的参数,可以和其他参数配合使用
# 下面的函数,第一个参数给a,第二个参数给b,剩下的都保存到c的元组中
def fn2(a, b, *c):
print('a =', a)
print('b =', b)
print('c =', c)


fn2(1, 2, 3, 4, 5)


# 可变参数不是必须写在最后,但是注意,带*的参数后的所有参数,必须以关键字参数的形式传递
# 下面的函数,第一个参数给a,剩下的位置参数给b的元组,c必须使用关键字参数
def fn3(a, *b, c):
print('a =', a)
print('b =', b)
print('c =', c)


fn3(1, 2, 3, 4, c=5)


# 下面的函数,所有的位置参数都给a,b和c必须使用关键字参数
def fn4(*a, b, c):
print('a =', a)
print('b =', b)
print('c =', c)


fn4(1, 2, 3, b=4, c=5)


# 如果在形参的开头直接写一个*,则要求我们的所有的参数必须以关键字参数的形式传递
def fn5(*, a, b, c):
print('a =', a)
print('b =', b)
print('c =', c)


fn5(a=3, b=4, c=5)


# *形参只能接收位置参数,而不能接收关键字参数
# def fn3(*a) :
# print('a =',a)

# **形参可以接收其他的关键字参数,它会将这些参数统一保存到一个字典中
# 字典的key就是参数的名字,字典的value就是参数的值
# **形参只能有一个,并且必须写在所有参数的最后
def fn6(b, c, **a):
print('a =', a, type(a))
print('b =', b)
print('c =', c)


fn6(b=1, c=2, h=3, e=10, f=20)
fn6(6, 7, g=1, d=2, h=3, e=10, f=20)

print('##########################################################')


# 参数的解包(拆包)

def fn7(a, b, c):
print('a =', a)
print('b =', b)
print('c =', c)


# 传递实参时,也可以在序列类型的参数前添加星号,这样他会自动将序列中的元素依次作为参数传递给函数
# 这里要求序列中元素的个数必须和形参的个数的一致
t = (10, 20, 30)
fn7(*t)

# 通过 **来对一个字典进行解包操作
d = {'a': 100, 'b': 200, 'c': 300}
fn7(**d)
  • 在定义函数时,可以在形参前边加上一个 *,这样这个形参将会获取到所有的实参,并将所有的实参保存到一个元组中。
  • * 的形参只能有一个。
  • * 的参数,可以和其他参数配合使用。
  • 可变参数不是必须写在最后,但是注意,带 * 的参数后的所有参数,必须以关键字参数的形式传递,否则报错。
  • 如果在形参的开头直接写一个 *,则要求所有的参数必须以关键字参数的形式传递。
  • * 形参只能接收位置参数,而不能接收关键字参数。
  • ** 形参可以接收其他的关键字参数,它会将这些参数统一保存到一个字典中。字典的 key 就是参数的名字,字典的 value 就是参数的值。
  • ** 形参只能有一个,并且必须写在所有参数的最后。
  • 传递实参时,也可以在序列类型的参数前添加 *,这样会自动将序列中的元素依次作为参数传递给函数,但要求序列中元素的个数必须和形参的个数一致。
  • 如果是字典,通过 ** 来进行解包操作。

函数的返回值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# return 后边跟什么值,函数就会返回什么值
# return 后边可以跟任意的对象,返回值甚至可以是一个函数
def fn():
# return 'Hello'
# return [1, 2, 3]
# return {'k': 'v'}
def fn1():
print('hello')

return fn1 # 返回值也可以是一个函数


r = fn() # 这个函数的执行结果就是它的返回值
print(r) # <function fn.<locals>.fn1 at 0x000001F3430BCF70>
r() # hello


# 如果仅仅写一个return或者不写return,则相当于return None
# 在函数中,return后的代码都不会执行,return一旦执行函数自动结束
def fn2():
a = 10
return
print('abc') # 不会执行


r = fn2()
print(r) # None


def fn3():
for i in range(5):
if i == 3:
# break 用来退出当前循环
# continue 用来跳过当次循环
return # return 用来结束函数
print(i)
print('循环执行完毕!')


fn3()


def fn4():
return 10


# fn4 和 fn4()的区别
print(fn4) # fn4是函数对象,打印fn4实际是在打印函数对象:<function fn5 at 0x00000229B3CFD670>
print(fn4()) # fn4()是在调用函数,打印fn4()实际上是在打印fn4()函数的返回值:10
  • 返回值就是函数执行以后返回的结果,可以通过 return 来指定函数的返回值。
  • return 后边可以跟任意的对象,甚至可以是一个函数。return 后边跟什么值,函数就会返回什么值。
  • 如果仅仅写一个 return 或者不写 return,则相当于 return None
  • 在函数中,return 后的代码都不会执行,return 一旦执行函数自动结束。

文档字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# help()是Python中的内置函数
# 通过help()函数可以查询python中的函数的用法
# 语法:help(函数对象)
help(print) # 获取print()函数的使用说明


# 文档字符串(doc str)
# 在定义函数时,可以在函数内部编写文档字符串,文档字符串就是函数的说明
# 当我们编写了文档字符串时,就可以通过help()函数来查看函数的说明
# 文档字符串非常简单,其实直接在函数的第一行写一个字符串就是文档字符串
def fn(a: int, b: bool, c: str = 'hello') -> int: # 函数参数后跟着类型,返回值是一个int
"""
这是一个文档字符串的示例

函数的作用:。。。。。。
函数的参数:
a,作用,类型,默认值。。。
b,作用,类型,默认值。。。
c,作用,类型,默认值。。。
"""
return 10


help(fn)

作用域

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# 作用域(scope)
# 作用域指的是变量生效的区域

b = 20 # 全局变量


def fn():
a = 10 # a定义在了函数内部,所以他的作用域就是函数内部,函数外部无法访问
print('函数内部:', 'a =', a)
print('函数内部:', 'b =', b)


fn()

# print('函数外部:', 'a =', a) # NameError: name 'a' is not defined
print('函数外部:', 'b =', b)


# 在Python中一共有两种作用域
# 全局作用域
# - 全局作用域在程序执行时创建,在程序执行结束时销毁
# - 所有函数以外的区域都是全局作用域
# - 在全局作用域中定义的变量,都属于全局变量,全局变量可以在程序的任意位置被访问
#
# 函数作用域
# - 函数作用域在函数调用时创建,在调用结束时销毁
# - 函数每调用一次就会产生一个新的函数作用域
# - 在函数作用域中定义的变量,都是局部变量,它只能在函数内部被访问
#
# 变量的查找
# - 当我们使用变量时,会优先在当前作用域中寻找该变量,如果有则使用,
# 如果没有则继续去上一级作用域中寻找,如果有则使用,
# 如果依然没有则继续去上一级作用域中寻找,以此类推
# 直到找到全局作用域,依然没有找到,则会抛出异常
# NameError: name 'a' is not defined

def fn1():
def fn2():
print('fn3中:', 'a =', a)

fn2()


# fn1() # fn1中的嵌套函数fn2,找不到a,报错NameError: name 'a' is not defined

a = 20


def fn3():
# a = 10 # 在函数中为变量赋值时,默认都是为局部变量赋值
# 如果希望在函数内部修改全局变量,则需要使用global关键字,来声明变量
global a # 声明在函数内部的使用a是全局变量,此时再去修改a时,就是在修改全局的a
a = 10 # 修改全局变量
print('函数内部:', 'a =', a)


fn3()
print('函数外部:', 'a =', a) # 函数外部: a = 10

命名空间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# 命名空间(namespace)
# 命名空间指的是变量存储的位置,每一个变量都需要存储到指定的命名空间当中
# 每一个作用域都会有一个它对应的命名空间
# 全局命名空间,用来保存全局变量。函数命名空间用来保存函数中的变量
# 命名空间实际上就是一个字典,是一个专门用来存储变量的字典

# locals()用来获取当前作用域的命名空间
# 如果在全局作用域中调用locals()则获取全局命名空间,如果在函数作用域中调用locals()则获取函数命名空间
# 返回的是一个字典
scope = locals() # 当前命名空间
print(type(scope)) # <class 'dict'>
# 下面两个打印效果相同
a = 20
print(a) # 20
print(scope['a']) # 20


# 向scope中添加一个key-value
# scope['c'] = 1000 # 向字典中添加key-value就相当于在全局中创建了一个变量(一般不建议这么做)
# print(c) # 1000


def fn():
a = 10
scope = locals() # 在函数内部调用locals()会获取到函数的命名空间
print(type(scope)) # <class 'dict'>

# scope['b'] = 90 # 可以通过scope来操作函数的命名空间,但是也是不建议这么做
# print(b)

# globals()函数可以用来在任意位置获取全局命名空间
# 函数外面无法获得函数的命名空间
global_scope = globals()
print(global_scope['a']) # 20
# global_scope['a'] = 30 # 不建议这么做
# print(global_scope['a']) # 30


fn()

递归

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
# 10的阶乘
n = 10
for i in range(1, 10):
n *= i

print(n)


# 创建一个函数,可以用来求任意数的阶乘
def factorial(n):
'''
该函数用来求任意数的阶乘

参数:
n 要求阶乘的数字
'''

# 创建一个变量,来保存结果
result = n

for i in range(1, n):
result *= i

return result


print(factorial(10))


# 递归简单理解就是自己去引用自己!
# 递归式函数,在函数中自己调用自己!

# 下面这个是无穷递归,如果这个函数被调用,程序的内存会溢出,效果类似于死循环
# def fn():
# fn()
# fn()


# 递归是解决问题的一种方式,它和循环很像
# 它的整体思想是,将一个大问题分解为一个个的小问题,直到问题无法分解时,再去解决问题
# 递归式函数的两个要件
# 1.基线条件
# - 问题可以被分解为的最小问题,当满足基线条件时,递归就不在执行了
# 2.递归条件
# - 将问题继续分解的条件
# 递归和循环类似,基本是可以互相代替的,
# 循环编写起来比较容易,阅读起来稍难
# 递归编写起来难,但是方便阅读

def factorial(n):
# 基线条件 判断n是否为1,如果为1则此时不能再继续递归
if n == 1:
# 1的阶乘就是1,直接返回1
return 1
# 递归条件
return n * factorial((n - 1))


print(factorial(10))


# 创建一个函数power,来为任意数字做幂运算 n ** i
def power(n, i):
'''
power()用来为任意的数字做幂运算

参数:
n 要做幂运算的数字
i 做幂运算的次数
'''
# 基线条件
if i == 1:
# 求1次幂
return n
# 递归条件
return n * power(n, i - 1)


print(pow(3, 4))


# 创建一个函数,用来检查一个任意的字符串是否是回文字符串,如果是返回True,否则返回False
# 回文字符串,字符串从前往后念和从后往前念是一样的
# abcba
# abcdefgfedcba
# 先检查第一个字符和最后一个字符是否一致,如果不一致则不是回文字符串
# 如果一致,则看剩余的部分是否是回文字符串
# 检查 abcdefgfedcba 是不是回文
# 检查 bcdefgfedcb 是不是回文
# 检查 cdefgfedc 是不是回文
# 检查 defgfed 是不是回文
# 检查 efgfe 是不是回文
# 检查 fgf 是不是回文
# 检查 g 是不是回文
def hui_wen(s):
'''
该函数用来检查指定的字符串是否回文字符串,如果是返回True,否则返回False

参数:
s:就是要检查的字符串
'''
# 基线条件
if len(s) < 2:
# 字符串的长度小于2,则字符串一定是回文
return True
elif s[0] != s[-1]:
# 第一个字符和最后一个字符不相等,不是回文字符串
return False
# 递归条件
return hui_wen(s[1:-1])


# def hui_wen(s):
# '''
# 该函数用来检查指定的字符串是否回文字符串,如果是返回True,否则返回False

# 参数:
# s:就是要检查的字符串
# '''
# # 基线条件
# if len(s) < 2 :
# # 字符串的长度小于2,则字符串一定是回文
# return True
# # 递归条件
# return s[0] == s[-1] and hui_wen(s[1:-1])

print(hui_wen('abba'))
print(hui_wen('abcdefgfedcba'))

高阶函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# 高阶函数
# 接收函数作为参数,或者将函数作为返回值的函数是高阶函数
# 当我们使用一个函数作为参数时,实际上是将指定的代码传递进了目标函数

# 定义一个函数,功能:可以将指定列表中的所有的偶数,保存到一个新的列表中返回

# 待提取列表
l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]


# 常规写法

def fn(lst):
'''
fn()函数可以将指定列表中的所有偶数提取出来,并保存到一个新列表中返回

参数:
lst:指定的要筛选的列表
'''
new_list = []
for n in lst:
if n % 2 == 0:
new_list.append(n)
return new_list


print(fn(l)) # [2, 4, 6, 8, 10]


# 高阶函数

# 功能1:定义一个函数,用来检查一个任意的数字是否是偶数
def fn1(i):
if i % 2 == 0:
return True

return False


# 功能2:定义一个函数,用来检查指定的数字是否大于5
def fn2(i):
if i > 5:
return True
return False


# 功能2:定义一个函数,用来检查一个任意的数字是否能被3整除
def fn3(i):
return i % 3 == 0


# 多功能的高阶函数

def fn(func, lst):
'''
fn()函数可以将指定列表中的数据按指定函数要求提取出来,并保存到一个新列表中返回

参数:
func:指定的提取要求
lst:指定的要筛选的列表
'''
new_list = []
for n in lst:
if func(n):
new_list.append(n)
return new_list


print(fn(fn1, l)) # 获取偶数:[2, 4, 6, 8, 10]
print(fn(fn2, l)) # 获取大于5的数:[6, 7, 8, 9, 10]
print(fn(fn3, l)) # 获取能被3整除的数:[3, 6, 9]

# filter()函数的功能,就如上面自定义的fn()函数
# filter()可以从序列中过滤出符合条件的元素,保存到一个新的序列中
# 参数:
# 1.函数,根据该函数来过滤序列(可迭代的结构)
# 2.需要过滤的序列(可迭代的结构)
# 返回值:
# 过滤后的新序列(可迭代的结构)

iterator = filter(fn1, l)
# for n in iterator:
# print(n)
print(list(iterator)) # 返回的是一个可迭代的结构,需要转换成list才能直接打印出来数据
print(list(filter(fn2, l)))
print(list(filter(fn3, l)))
  • 在 Python 中,函数是一等对象。一等对象一般都会具有如下特点:

    • 对象是在运行时创建的。
    • 能赋值给变量或作为数据结构中的元素。
    • 能作为参数传递。
    • 能作为返回值返回。
  • 高阶函数至少要符合以下两个特点中的一个:

    • 能接收一个或多个函数作为参数。
    • 能将函数作为返回值返回。
  • 当我们使用一个函数作为参数时,实际上是将指定的代码传递进了目标函数。

匿名函数

  • 匿名函数是将一个或多个函数作为参数来接收。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    # fn1~fn3是作为参数传递进filter()函数中
    # 而fn1~fn3实际上只有一个作用,就是作为filter()的参数
    # filter()调用完毕以后,fn1~fn3就已经没用
    # 这种情况可以用匿名函数简化
    # 匿名函数lambda函数表达式(语法糖)
    # lambda函数表达式专门用来创建一些简单的函数,他是函数创建的又一种方式
    # 语法:lambda 参数列表 : 返回值
    # 匿名函数一般都是作为参数使用,其他地方一般不会使用

    # 待提取列表
    l = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]


    # 常规写法
    def fn5(a, b):
    return a + b


    print(fn5(10, 20)) # 常规写法
    print((lambda a, b: a + b)(10, 20)) # lambad表达式写法
    fn6 = lambda a, b: a + b # 也可以将匿名函数赋值给一个变量,一般不会这么做
    print(fn6(10, 20))

    # filter()函数中可以很方便的使用lambda表达式
    # 此时,lambda表达式只会使用一次,使用完后内存中自动回收
    r = filter(lambda i: i % 2 == 0, l)
    print(list(r)) # [2, 4, 6, 8, 10]
    print(list(filter(lambda i: i > 5, l))) # [6, 7, 8, 9, 10]

    # map()函数可以对可迭代对象中的所有元素做指定的操作,然后将其添加到一个新的对象中返回

    print(list(map(lambda i: i ** 2, l))) # 对列表中的每一个元素求平方,[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]

    # sort()函数用来对列表中的元素进行排序:
    # sotr()只能排序列表
    # 默认是直接比较列表中的元素的大小
    # 在sort()可以接收一个关键字参数key:
    # key需要一个函数作为参数,当设置了函数作为参数
    # 每次都会以列表中的一个元素作为参数来调用该函数
    # 并且使用函数的返回值来比较元素的大小
    l = ['bb', 'aaaa', 'c', 'ddddddddd', 'fff']
    l.sort()
    print(l) # 默认比较:['aaaa', 'bb', 'c', 'ddddddddd', 'fff']

    l = ['bb', 'aaaa', 'c', 'ddddddddd', 'fff']
    l.sort(key=len)
    print(l) # 按长度比较:['c', 'bb', 'fff', 'aaaa', 'ddddddddd']

    l = [2, 5, '1', 3, '6', '4']
    l.sort(key=int)
    print(l) # 把每一个元素转换成整形后再比较:['1', 2, 3, '4', 5, '6']

    l = [2, 5, '1', 3, '6', '4']
    l.sort(key=str)
    print(l) # 把每一个元素转换成字符串后再比较:['1', 2, 3, '4', 5, '6']

    # sorted()函数和sort()的用法基本一致,但是sorted()可以对任意的序列进行排序
    # 并且使用sorted()排序不会影响原来的对象,而是返回一个新对象

    l = [2, 5, '1', 3, '6', '4'] # 排序列表
    print('排序前:', l) # 排序前: [2, 5, '1', 3, '6', '4']
    print('排序中:', sorted(l, key=int)) # 排序中: ['1', 2, 3, '4', 5, '6']
    print('排序后:', l) # 排序后: [2, 5, '1', 3, '6', '4']

    l = '123765816742634781' # 排序字符串
    print('排序前:', l) # 排序前: 123765816742634781
    print('排序中:', sorted(l,
    key=int)) # 排序中: ['1', '1', '1', '2', '2', '3', '3', '4', '4', '5', '6', '6', '6', '7', '7', '7', '8', '8']
    print('排序后:', l) # 排序后: 123765816742634781

闭包

  • 闭包是将函数作为返回值返回。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    # 将函数作为返回值返回,也是一种高阶函数
    # 这种高阶函数我们也称为叫做闭包,通过闭包可以创建一些只有当前函数能访问的变量
    # 可以将一些私有的数据藏到闭包中

    def fn():
    a = 10

    # 函数内部再定义一个函数
    def inner():
    print('我是fn2', a)

    # 将内部函数 inner作为返回值返回
    return inner


    # r是一个函数,是调用fn()后返回的函数
    # 而且这个函数是在fn()内部定义,并不是全局函数
    # 所以这个函数总是能访问到fn()函数内的变量
    r = fn()
    print(r) # <function fn.<locals>.inner at 0x000001CEC1142430>
    r() # 我是fn2 10

    # 求多个数的平均值
    nums = [50, 30, 20, 10, 77]

    # 常规写法:sum()用来求一个列表中所有元素的和
    print(sum(nums) / len(nums)) # 37.4


    # 如果nums中的数据是变化的,可以使用闭包
    # 形成闭包的要件
    # ① 函数嵌套
    # ② 将内部函数作为返回值返回
    # ③ 内部函数必须要使用到外部函数的变量
    def make_averager():
    # 创建一个列表,用来保存数值
    nums = []

    # 创建一个函数,用来计算平均值
    def averager(n):
    # 将n添加到列表中
    nums.append(n)
    # 求平均值
    return sum(nums) / len(nums)

    return averager


    # 函数返回的是make_averager()中定义的averager()函数
    # 并创建了一个nums列表,这个列表外界无法访问,只有averager对象可以访问
    averager = make_averager()

    print(averager(10)) # 10/1=10
    print(averager(20)) # (10+20)/2=15
    print(averager(30)) # (10+20+30)/3=20
    print(averager(40)) # (10+20+30+40)/4=25

装饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
# 创建几个函数

def add(a, b):
'''
求任意两个数的和
'''
r = a + b
return r


def mul(a, b):
'''
求任意两个数的积
'''
r = a * b
return r


print(add(123, 456)) # 579
print(mul(10, 20)) # 200


# 现在,希望函数可以在计算前,打印开始计算,计算结束后打印计算完毕
# 我们可以直接通过修改函数中的代码来完成这个需求,但是会产生以下一些问题
# ① 如果要修改的函数过多,修改起来会比较麻烦
# ② 并且不方便后期的维护
# ③ 并且这样做会违反开闭原则(OCP)
# 程序的设计,要求开发对程序的扩展,要关闭对程序的修改


# 我们希望在不修改原函数的情况下,来对函数进行扩展
def fn():
print('我是fn函数....')


# 只需要根据现有的函数,来创建一个新的函数
def fn2():
print('函数开始执行~~~')
fn()
print('函数执行结束~~~')


fn2()


# 创建新函数,扩展add()
def new_add(a, b):
print('计算开始~~~')
r = add(a, b)
print('计算结束~~~')
return r


r = new_add(111, 222)
print(r)

print('##############################################################')


# 上边的方式,已经可以在不修改源代码的情况下对函数进行扩展了
# 但是,这种方式要求我们每扩展一个函数就要手动创建一个新的函数,实在是太麻烦了
# 为了解决这个问题,我们创建一个函数,让这个函数可以自动的帮助我们生产函数

def begin_end(old):
'''
用来对其他函数进行扩展,使其他函数可以在执行前打印开始执行,执行后打印执行结束

参数:
old 要扩展的函数对象
'''

# 创建一个新函数,参数的个数是不确定的,使用*和**
def new_function(*args, **kwargs):
print('开始执行~~~~')
# 调用被扩展的函数
result = old(*args, **kwargs)
print('执行结束~~~~')
# 返回函数的执行结果
return result

# 返回新函数
return new_function


f = begin_end(fn) # 包装fn()
f2 = begin_end(add) # 包装add()
f3 = begin_end(mul) # 包装mul()

r = f()
print(r)
r = f2(123, 456)
print(r)
r = f3(123, 456)
print(r)

print('##############################################################')


# 像begin_end()这种函数我们就称它为装饰器
# 通过装饰器,可以在不修改原来函数的情况下来对函数进行扩展
# 在开发中,我们都是通过装饰器来扩展函数的功能的
# 在定义函数时,可以通过@装饰器,来使用指定的装饰器,来装饰当前的函数
# 可以同时为一个函数指定多个装饰器,这样函数将会安装从内向外的顺序被装饰

def fn3(old):
'''
用来对其他函数进行扩展,使其他函数可以在执行前打印开始执行,执行后打印执行结束

参数:
old 要扩展的函数对象
'''

# 创建一个新函数
# *args:old函数中的位置参数(形如:'a, b'),全都存放其中
# **kwargs:old函数中的字典参数(形如:'a=x, b=y'),全部存放其中
def new_function(*args, **kwargs):
print('fn3装饰~开始执行~~~~')
# 调用被扩展的函数
result = old(*args, **kwargs)
print('fn3装饰~执行结束~~~~')
# 返回函数的执行结果
return result

# 返回新函数
return new_function


@fn3 # 第一层:fn3装饰
@begin_end # :第二层:begin_end装饰
def say_hello():
print('大家好~~~')


say_hello()

对象(object)

什么是对象

  • 对象是内存中专门用来存储数据的一块区域。
  • 对象中可以存放各种数据,比如:数字、布尔值、代码。
  • 对象由三部分组成:
    • 对象的标识(id)
    • 对象的类型(type)
    • 对象的值(value)

面向对象(oop)

  • Python 是一门面向对象的编程语言。

  • 所谓的面向对象的语言,简单理解就是语言中的所有操作都是通过对象来进行的。

  • 面向过程的编程的语言:

    • 面向过程指将我们的程序的逻辑分解为一个一个的步骤,通过对每个步骤的抽象,来完成程序。
    • 例子:孩子上学,可能有以下过程。
      1. 妈妈起床。
      2. 妈妈洗漱。
      3. 妈妈做早饭。
      4. 妈妈叫孩子起床。
      5. 孩子要洗漱。
      6. 孩子吃饭。
      7. 孩子背着书包上学校。
    • 面向过程的编程思想将一个功能分解为一个一个小的步骤,我们通过完成一个一个的小的步骤来完成一个程序。
    • 这种编程方式,符合我们人类的思维,编写起来相对比较简单。
    • 但是这种方式编写代码的往往只适用于一个功能,如果要在实现别的功能,即使功能相差极小,也往往要重新编写代码,所以它可复用性比较低,并且难于维护 。
  • 面向对象的编程语言:

    • 面向对象的编程语言,关注的是对象,而不关注过程。
    • 对于面向对象的语言来说,一切都是对象。
    • 面向对象的编程思想,将所有的功能统一保存到对应的对象中。比如,妈妈的功能保存到妈妈的对象中,孩子的功能保存到孩子对象中,要使用某个功能,直接找到对应的对象即可。
    • 这种方式编写的代码,比较容易阅读,并且比较易于维护,容易复用。
    • 但是这种方式编写,不太符合常规的思维,编写起来稍微麻烦一点。
  • 简单归纳一下,面向对象的思想:

    • 第一步:创建对象。
    • 第二步:处理对象。

类的简介

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
a = int(10)  # 创建一个int类的实例
b = str('hello') # 创建一个str类的实例
print(a, type(a)) # 10 <class 'int'>
print(b, type(b)) # hello <class 'str'>


# 定义一个简单的类
# 使用class关键字来定义类,语法和函数很像!
# class 类名([父类]):
# 代码块
# <class '__main__.MyClass'>
class MyClass(): # 如果没有父类,()可以省略
pass


print(MyClass) # <class '__main__.MyClass'>

# 使用MyClass创建一个对象
# 使用类来创建对象,就像调用一个函数一样
mc = MyClass() # mc就是通过MyClass创建的对象,mc是MyClass的实例
print(mc, type(mc)) # <__main__.MyClass object at 0x000001B009813E50> <class '__main__.MyClass'>
mc_2 = MyClass()
mc_3 = MyClass()
mc_4 = MyClass()
# mc mc_2 mc_3 mc_4 都是MyClass的实例,他们都是一类对象
# isinstance()用来检查一个对象是否是一个类的实例
result = isinstance(mc_2, MyClass)
print(result) # True
result = isinstance(mc_2, str)
print(result) # False

# 类是一个type类型的对象
print(id(MyClass), type(MyClass)) # 1560257906784 <class 'type'>

# 现在我们通过MyClass这个类创建的对象都是一个空对象
# 也就是对象中实际上什么都没有,就相当于是一个空的盒子
# 可以向对象中添加变量,对象中的变量称为属性
# 语法:对象.属性名 = 属性值
mc.name = '孙悟空'
print(mc.name) # 孙悟空
mc_2.name = '猪八戒'
print(mc_2.name) # 猪八戒
  • 我们目前所学习的对象都是 Python 内置的对象。

  • 但是内置对象并不能满足所有的需求,所以我们在开发中经常需要自定义一些对象。

  • 类,简单理解它就相当于一个图纸。在程序中我们需要根据类来创建对象。

  • 类就是对象的图纸!

  • 我们也称对象是类的实例(instance)。

  • 如果多个对象是通过一个类创建的,我们称这些对象是一类对象。

  • int()float()bool()str()list()dict() 等,这些都是类。

  • a = int(10) # 创建一个int类的实例 等价于 a = 10

  • 我们自定义的类都需要使用大写字母开头,使用大驼峰命名法(帕斯卡命名法)来对类命名。

  • 类也是一个对象!

  • 类就是一个用来创建对象的对象!

  • 类是 type 类型的对象,定义类实际上就是定义了一个 type 类型的对象。

  • 使用类创建对象的流程:

    image-20210926155702330
    • 第一步:创建一个变量。
    • 第二步:在内存中创建一个新对象。
    • 第三步:将对象的 id 赋值给变量。

类的定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
# 尝试定义一个表示人的类
class Person:
# 在类的代码块中,我们可以定义变量和函数
# 在类中我们所定义的变量,将会成为所有的实例的公共属性
# 所有实例都可以访问这些变量
name = 'swk' # 公共属性,所有实例都可以访问

# 在类中也可以定义函数,类中的定义的函数,我们称为方法
# 这些方法可以通过该类的所有实例来访问

def say_hello(self):
# 方法每次被调用时,解析器都会自动传递第一个实参
# 第一个参数,就是调用方法的对象本身,
# 如果是p1调的,则第一个参数就是p1对象
# 如果是p2调的,则第一个参数就是p2对象
# 一般我们都会将这个参数命名为self

# say_hello()这个方法,可以显示如下格式的数据:
# 你好!我是 xxx
# 在方法中不能直接访问类中的属性
print('你好!我是 %s' % self.name) # 类似Java中的this


# 创建Person的实例
p1 = Person()
p2 = Person()

# 调用属性:对象.属性名
print(p1.name) # swk
print(p2.name) # swk

# 调用方法:对象.方法名()
# 方法调用和函数调用的区别
# 如果是函数调用,则调用时传几个参数,就会有几个实参
# 但是如果是方法调用,默认传递一个参数,所以方法中至少要定义一个形参
p1.say_hello() # 你好!我是 swk
p2.say_hello() # 你好!我是 swk

# 修改p1的name属性
p1.name = '猪八戒'
p2.name = '沙和尚'
print(p1.name)
print(p2.name)
p1.say_hello() # 你好!我是 猪八戒
p2.say_hello() # 你好!我是 沙和尚

del p2.name # 删除p2的name属性
print(p2.name) # swk
  • 类和对象都是对现实生活中的事物或程序中的内容的抽象。
  • 实际上所有的事物都由两部分构成:
    • 数据(属性)
    • 行为(方法)
  • 在类的代码块中,我们可以定义变量和函数:
    • 变量会成为该类实例的公共属性,所有的该类实例都可以通过 对象.属性名 的形式访问。
    • 函数会成为该类实例的公共方法,所有该类实例都可以通过 对象.方法名() 的形式调用方法。
  • 注意:方法调用时,默认第一个参数由解析器自动传递,所以定义方法时,至少要定义一个形参!
  • 实例为什么能访问到类中的属性和方法:
    • 类中定义的属性和方法都是公共的,任何该类实例都可以访问。
    • 属性和方法查找的流程:
      • 当我们调用一个对象的属性时,解析器会先在当前对象中寻找是否含有该属性,如果有,则直接返回当前的对象的属性值;如果没有,则去当前对象的类对象中去寻找,如果有,则返回类对象的属性值,如果类对象中依然没有,则报错!
    • 类对象和实例对象中都可以保存属性(方法):
      • 如果这个属性(方法)是所有的实例共享的,则应该将其保存到类对象中。
      • 如果这个属性(方法)是某个实例独有,则应该保存到实例对象中。
      • 比如,Person 类中,name 属性每个对象都不同,应该保存到各个实例对象中,而国籍假设都是中国人,是一样的,则应该保存到类对象中。
      • 一般情况下,属性保存到实例对象中,而方法需要保存到类对象中。

对象的初始化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
class Person:
# 在类中可以定义一些特殊方法(魔术方法)
# 特殊方法都是以__开头,__结尾的方法
# 特殊方法不需要我们自己调用,不要尝试去调用特殊方法
# 特殊方法将会在特殊的时刻自动调用
# 学习特殊方法:
# 1.特殊方法什么时候调用
# 2.特殊方法有什么作用
# 创建对象的流程
# p1 = Person()的运行流程
# 1.创建一个变量
# 2.在内存中创建一个新对象
# 3.__init__(self)方法执行
# 4.将对象的id赋值给变量

# init会在对象创建以后立刻执行
# init可以用来向新创建的对象中初始化属性
# 调用类创建对象时,类后边的所有参数都会依次传递到init()中
def __init__(self, name):
# print(self)
# 通过self向新建的对象中初始化属性
self.name = name

def say_hello(self):
print('大家好,我是%s' % self.name)


# 目前来讲,对于Person类来说name是必须的,并且每一个对象中的name属性基本上都是不同
# 而我们现在是将name属性在定义为对象以后,手动添加到对象中,这种方式很容易出现错误
# 我们希望,在创建对象时,必须设置name属性,如果不设置对象将无法创建
# 并且属性的创建应该是自动完成的,而不是在创建对象以后手动完成
# p1 = Person()
# 手动向对象添加name属性
# p1.name = '孙悟空'

# p2 = Person()
# p2.name = '猪八戒'

# p3 = Person()
# p3.name = '沙和尚'

# p3.say_hello()

p1 = Person('孙悟空')
p2 = Person('猪八戒')
p3 = Person('沙和尚')
p4 = Person('唐僧')
# p1.__init__() 不要这么做

# print(p1.name)
# print(p2.name)
# print(p3.name)
# print(p4.name)

p4.say_hello()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class Dog:
'''
表示狗的类
'''

def __init__(self, name, age, gender, height):
self.name = name
self.age = age
self.gender = gender
self.height = height

def jiao(self):
'''
狗叫的方法
'''
print('汪汪汪~~~')

def yao(self):
'''
狗咬的方法
'''
print('我咬你~~')

def run(self):
print('%s 快乐的奔跑着~~' % self.name)


d = Dog('小黑', 8, 'male', 30)
print(d.name, d.age, d.gender, d.height)

# 目前我们可以直接通过 对象.属性 的方式来修改属性的值,这种方式导致对象中的属性可以随意修改
# 非常的不安全,值可以任意修改,不论对错
# 现在我们就需要一种方式来增强数据的安全性
# 1.属性不能随意修改(我让你改你才能改,不让你改你就不能改)
# 2.属性不能修改为任意的值(年龄不能是负数)
d.name = '阿黄'
d.age = -10
d.run()

print(d.age)
  • 类的基本结构:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    class 类名([父类]) :

    公共的属性...

    # 对象的初始化方法
    def __init__(self,...):
    ...

    # 其他的方法
    def method_1(self,...):
    ...

    def method_2(self,...):
    ...

    ...
  • 创建对象的流程,p1 = Person()

    • 第一步:创建一个变量。
    • 第二步:在内存中创建一个新对象。
    • 第三步:__init__(self) 方法执行。
    • 第四步:将对象的 id 赋值给变量。

封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# 封装是面向对象的三大特性之一
# 封装指的是隐藏对象中一些不希望被外部所访问到的属性或方法
# 如何隐藏一个对象中的属性?
# - 将对象的属性名,修改为一个外部不知道的名字
# 如何获取(修改)对象中的属性?
# - 需要提供一个getter和setter方法使外部可以访问到属性
# - getter 获取对象中的指定属性(get_属性名)
# - setter 用来设置对象的指定属性(set_属性名)
# 使用封装,确实增加了类的定义的复杂程度,但是它也确保了数据的安全性
# 1.隐藏了属性名,使调用者无法随意的修改对象中的属性
# 2.增加了getter和setter方法,很好的控制的属性是否是只读的
# 如果希望属性是只读的,则可以直接去掉setter方法
# 如果希望属性不能被外部访问,则可以直接去掉getter方法
# 3.使用setter方法设置属性,可以增加数据的验证,确保数据的值是正确的
# 4.使用getter方法获取属性,使用setter方法设置属性
# 可以在读取属性和修改属性的同时做一些其他的处理
# 5.使用getter方法可以表示一些计算的属性

class Dog:
'''
表示狗的类
'''

def __init__(self, name, age):
self.hidden_name = name
self.hidden_age = age

def say_hello(self):
print('大家好,我是 %s' % self.hidden_name)

def get_name(self):
'''
get_name()用来获取对象的name属性
'''
# print('用户读取了属性')
return self.hidden_name

def set_name(self, name):
# print('用户修改了属性')
self.hidden_name = name

def get_age(self):
return self.hidden_age

def set_age(self, age):
if age > 0:
self.hidden_age = age


d = Dog('旺财', 8)

# d.say_hello()

# 调用setter来修改name属性
d.set_name('小黑')
d.set_age(-10)

# d.say_hello()
print(d.get_age())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
class Rectangle:
'''
表示矩形的类
'''

def __init__(self, width, height):
self.hidden_width = width
self.hidden_height = height

def get_width(self):
return self.hidden_width

def get_height(self):
return self.hidden_height

def set_width(self, width):
self.hidden_width = width

def set_height(self, height):
self.hidden_height = height

def get_area(self):
return self.hidden_width * self.hidden_height


# 测试
r = Rectangle(5, 2)
print(r.get_area()) # 10
r.set_width(10)
r.set_height(20)
print(r.get_area()) # 200


# 可以为对象的属性使用双下划线开头,__xxx
# 双下划线开头的属性,是对象的隐藏属性,隐藏属性只能在类的内部访问,无法通过对象访问
# 其实隐藏属性只不过是Python自动为属性改了一个名字
# 实际上是将名字修改为了,_类名__属性名 比如 __name -> _Person__name
class Person:
def __init__(self, name):
self.__name = name

def get_name(self):
return self.__name

def set_name(self, name):
self.__name = name


p = Person('孙悟空')

# print(p.__name) # __开头的属性是隐藏属性,无法通过对象访问
print(p._Person__name) # 能直接访问,孙悟空
p._Person__name = '猪八戒'
print(p.get_name()) # 也能直接更改,猪八戒


# 上面使用__开头的属性,实际上依然可以在外部访问,所以这种方式我们一般不用
# 一般我们会将一些私有属性(不希望被外部访问的属性)以_开头(实际上也可以直接访问和修改)
# 一般情况下,使用_开头的属性都是私有属性,没有特殊需要不要修改私有属性
class Person:
def __init__(self, name):
self._name = name

def get_name(self):
return self._name

def set_name(self, name):
self._name = name


p = Person('孙悟空')

print(p._name) # 能直接访问
p._name = '猪八戒'
print(p._name) # 也能直接修改,猪八戒
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Person:
def __init__(self, name, age):
self._name = name
self._age = age

# property装饰器,用来将一个get方法,转换为对象的属性
# 添加为property装饰器以后,我们就可以像调用属性一样使用get方法
# 使用property装饰的方法,必须和属性名是一样的
@property
def name(self):
print('get方法执行了~~~')
return self._name

# setter方法的装饰器:@属性名.setter
@name.setter
def name(self, name):
print('setter方法调用了')
self._name = name

@property
def age(self):
return self._age

@age.setter
def age(self, age):
self._age = age


p = Person('猪八戒', 18)

print(p.name, p.age) # 调用的就是装饰器装饰的setter和get方法

p.name = '孙悟空'
p.age = 28

print(p.name, p.age)

继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# 继承

# 定义一个类 Animal(动物)
# 这个类中需要两个方法:run() sleep()
class Animal:
def run(self):
print('动物会跑~~~')

def sleep(self):
print('动物睡觉~~~')

# def bark(self):
# print('动物嚎叫~~~')


# 定义一个类 Dog(狗)
# 这个类中需要三个方法:run() sleep() bark()
# class Dog:
# def run(self):
# print('狗会跑~~~')

# def sleep(self):
# print('狗睡觉~~~')

# def bark(self):
# print('汪汪汪~~~')

# 有一个类,能够实现我们需要的大部分功能,但是不能实现全部功能
# 如何能让这个类来实现全部的功能呢?
# ① 直接修改这个类,在这个类中添加我们需要的功能
# - 修改起来会比较麻烦,并且会违反OCP原则
# ② 直接创建一个新的类
# - 创建一个新的类比较麻烦,并且需要大量的进行复制粘贴,会出现大量的重复性代码
# ③ 直接从Animal类中来继承它的属性和方法
# - 继承是面向对象三大特性之一
# - 通过继承我们可以使一个类获取到其他类中的属性和方法
# - 在定义类时,可以在类名后的括号中指定当前类的父类(超类、基类、super)
# 子类(衍生类)可以直接继承父类中的所有的属性和方法
#
# 通过继承可以直接让子类获取到父类的方法或属性,避免编写重复性的代码,并且也符合OCP原则
# 所以我们经常需要通过继承来对一个类进行扩展

class Dog(Animal):
def run(self):
print('狗跑~~~~')

def bark(self):
print('汪汪汪~~~')


class Hashiqi(Dog):
def fan_sha(self):
print('我是一只傻傻的哈士奇')


d = Dog()
d.run() # 狗跑~~~~
d.sleep() # 动物睡觉~~~
d.bark() # 汪汪汪~~~
print(isinstance(d, Dog)) # True
print(isinstance(d, Animal)) # True

h = Hashiqi()
h.run() # 狗跑~~~~
h.fan_sha() # 我是一只傻傻的哈士奇
print(isinstance(h, Hashiqi)) # True
print(isinstance(h, Dog)) # True
print(isinstance(h, Animal)) # True

print('######################################')


# 在创建类时,如果省略了父类,则默认父类为object
# object是所有类的父类,所有类都继承自object
class Person(object):
pass


# issubclass() 检查一个类是否是另一个类的子类
print(issubclass(Animal, Dog)) # False
print(issubclass(Animal, object)) # True
print(issubclass(Person, object)) # True

# isinstance()用来检查一个对象是否是一个类的实例
# 如果这个类是这个对象的父类,也会返回True
# 所有的对象都是object的实例
print(isinstance(print, object)) # True
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class Animal:
def __init__(self, name):
self._name = name

def run(self):
print('动物会跑~~~')

def sleep(self):
print('动物睡觉~~~')

@property
def name(self):
return self._name

@name.setter
def name(self, name):
self._name = name


# 父类中的所有方法都会被子类继承,包括特殊方法,也可以重写特殊方法
class Dog(Animal):

def __init__(self, name, age):
# 希望可以直接调用父类的__init__来初始化父类中定义的属性
# super() 可以用来获取当前类的父类,
# 并且通过super()返回对象调用父类方法时,不需要传递self
super().__init__(name)
self._age = age

def run(self):
print('狗跑~~~~')

def bark(self):
print('汪汪汪~~~')

@property
def age(self):
return self._age

@age.setter
def age(self, age):
self._age = age


d = Dog('旺财', 18)

print(d.name) # 旺财
print(d.age) # 18

重写

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# 继承

# 定义一个类 Animal(动物)
# 这个类中需要两个方法:run() sleep()
class Animal:
def run(self):
print('动物会跑~~~')

def sleep(self):
print('动物睡觉~~~')


class Dog(Animal):
def bark(self):
print('汪汪汪~~~')

def run(self):
print('狗跑~~~~')


# 如果在子类中如果有和父类同名的方法,则通过子类实例去调用方法时,
# 会调用子类的方法而不是父类的方法,这个特点我们成为叫做方法的重写(覆盖,override)

# 创建Dog类的实例
d = Dog()

d.run() # 狗跑~~~~


# 当我们调用一个对象的方法时,
# 会优先去当前对象中寻找是否具有该方法,如果有则直接调用
# 如果没有,则去当前对象的父类中寻找,如果父类中有则直接调用父类中的方法,
# 如果没有,则去父类的父类中寻找,以此类推,直到找到object,如果依然没有找到,则报错
class A(object):
def test(self):
print('AAA')


class B(A):
def test(self):
print('BBB')


class C(B):
def test(self):
print('CCC')


# 创建一个c的实例
c = C()
c.test() # CCC

多重继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class A(object):
def test(self):
print('AAA')


class B(object):
def test(self):
print('B中的test()方法~~')

def test2(self):
print('BBB')


# 在Python中是支持多重继承的,也就是我们可以为一个类同时指定多个父类
# 可以在类名的()后边添加多个类,来实现多重继承
# 多重继承,会使子类同时拥有多个父类,并且会获取到所有父类中的方法
# 在开发中没有特殊的情况,应该尽量避免使用多重继承,因为多重继承会让我们的代码过于复杂
# 如果多个父类中有同名的方法,则会先在第一个父类中寻找,然后找第二个,然后找第三个。。。
# 前边父类的方法会覆盖后边父类的方法
class C(A, B):
pass


c = C()
c.test() # AAA
c.test2() # BBB

# 类名.__bases__ 这个属性可以用来获取当前类的所有父类,返回的是一个元组
print(B.__bases__) # (<class 'object'>,)
print(C.__bases__) # (<class '__main__.A'>, <class '__main__.B'>)

多态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# 多态是面向对象的三大特征之一
# 多态从字面上理解是多种形态
# 狗(狼狗、藏獒、哈士奇、古牧 。。。)
# 一个对象可以以不同的形态去呈现

# 定义两个类
class A:
def __init__(self, name):
self._name = name

@property
def name(self):
return self._name

@name.setter
def name(self, name):
self._name = name


class B:
def __init__(self, name):
self._name = name

def __len__(self):
return 10

@property
def name(self):
return self._name

@name.setter
def name(self, name):
self._name = name


class C:
pass


a = A('孙悟空')
b = B('猪八戒')
c = C()


# 定义一个函数
# 对于say_hello()这个函数来说,只要对象中含有name属性,它就可以作为参数传递
# 这个函数并不会考虑对象的类型,只要有name属性即可 ---> 多态的提现
def say_hello(obj):
print('你好 %s' % obj.name)


# 在say_hello_2中我们做了一个类型检查,也就是只有obj是A类型的对象时,才可以正常使用,
# 其他类型的对象都无法使用该函数,这个函数就违反了多态
# 违反了多态的函数,只适用于一种类型的对象,无法处理其他类型对象,这样导致函数的适应性非常的差
# 注意,像isinstance()这种函数,在开发中一般是不会使用的!(使用这个函数,就表示可能违反了多态)
def say_hello_2(obj):
# 做类型检查
if isinstance(obj, A):
print('你好 %s' % obj.name)
# say_hello(b)


# say_hello_2(b)

# 鸭子类型(多态理论):
# 如果一个东西,走路像鸭子,叫声像鸭子,那么它就是鸭子

# len()
# 之所以一个对象能通过len()来获取长度,是因为对象中具有一个特殊方法__len__
# 换句话说,只要对象中具有__len__特殊方法,就可以通过len()来获取它的长度
# 这就是多态的体现
l = [1, 2, 3]
s = 'hello'

print(len(l)) # 3
print(len(s)) # 5
print(len(b)) # 10
# print(len(c)) # 报错,object of type 'C' has no len()

# 面向对象的三大特征:
# 封装
# - 确保对象中的数据安全
# 继承
# - 保证了对象的可扩展性
# 多态
# - 保证了程序的灵活性

类中的属性和方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# 定义一个类
class A(object):
# 类属性---所有实例公用的
# 实例属性---每个实例私有的
# 类方法
# 实例方法
# 静态方法

# 类属性,直接在类中定义的属性是类属性
# 类属性可以通过类或类的实例访问到
# 但是类属性只能通过类对象来修改,无法通过实例对象修改
count = 0

# __init__也是实例方法
def __init__(self):
# 实例属性,通过实例对象添加的属性属于实例属性
# 实例属性只能通过实例对象来访问和修改,类对象无法访问修改
self.name = '孙悟空' # name也是实例属性

# 实例方法
# 在类中定义,以self为第一个参数的方法都是实例方法
# 实例方法在调用时,Python会将调用对象作为self传入
# 实例方法可以通过实例和类去调用
# 当通过实例调用时,会自动将当前调用对象作为self传入
# 当通过类调用时,不会自动传递self,此时我们必须手动传递self
def test(self):
print('这是test方法~~~ ', self)

# 类方法
# 在类内部使用 @classmethod 来修饰的方法属于类方法
# 类方法的第一个参数是cls,也会被自动传递,cls就是当前的类对象
# 类方法和实例方法的区别,实例方法的第一个参数是self,而类方法的第一个参数是cls
# 类方法可以通过类去调用,也可以通过实例调用,没有区别
@classmethod
def test_2(cls):
print('这是test_2方法,他是一个类方法~~~ ', cls)
print(cls.count) # 这个访问的是类属性,与实例对象无关

# 静态方法
# 在类中使用 @staticmethod 来修饰的方法属于静态方法
# 静态方法不需要指定任何的默认参数,静态方法可以通过类和实例去调用
# 静态方法,基本上是一个和当前类无关的方法,它只是一个保存到当前类中的函数
# 静态方法一般都是一些工具方法,和当前类无关(建议静态方法不要放到某个类中,或者全部放到一个工具类中)
@staticmethod
def test_3():
print('test_3执行了~~~')


print('A ', A.count) # 类访问类属性:0
a = A()
print('a ', a.count) # 类的实例访问类属性:0

a.count = 10 # 类的实例无法修改类属性,此操作是给a这个实例对象,添加了一个实例属性count
print('A ', A.count) # 0
print('a ', a.count) # 10
A.count = 100 # 类可以修改类属性,但不影响类的实例中已存在的同名属性
print('A ', A.count) # 100
print('a ', a.count) # 10
b = A() # b这个实例对象中,没有count实例属性,访问的是A类的属性
print('b ', b.count) # 100

# print('A ', A.name) # 类无法访问实例属性,AttributeError: type object 'A' has no attribute 'name'
print('a ', a.name) # 孙悟空

# 类和类的实例,都可以访问实例方法
a.test() # 等价于 A.test(a):这是test方法~~~ <__main__.A object at 0x000002631BC28310>

# 类和类的实例,都可以访问类方法
A.test_2() # 等价于 a.test_2():这是test_2方法,他是一个类方法~~~ <class '__main__.A'>

# 静态方法,与类和类的实例无关
A.test_3() # test_3执行了~~~
a.test_3() # test_3执行了~~~
b.test_3() # test_3执行了~~~

垃圾回收

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 就像我们生活中会产生垃圾一样,程序在运行过程当中也会产生垃圾
# 程序运行过程中产生的垃圾会影响到程序的运行的运行性能,所以这些垃圾必须被及时清理
# 没用的东西就是垃圾
# 在程序中没有被引用的对象就是垃圾,这种垃圾对象过多以后会影响到程序的运行的性能
# 所以我们必须进行及时的垃圾回收,所谓的垃圾回收就是将垃圾对象从内存中删除
# 在Python中有自动的垃圾回收机制,它会自动将这些没有被引用的对象删除,
# 所以我们不用手动处理垃圾回收

class A:
def __init__(self):
self.name = 'A类'

# del是一个特殊方法,它会在垃圾对象被回收前调用
def __del__(self):
print('A()对象被回收了~~~', self)


a = A()
print(a.name)
# a = None # 将a设置为None,此时没有任何的变量对A()对象进行引用,A()对象变成了垃圾
# 变成垃圾的A()对象会被回收,回收前调用__del__()方法

# del a # del 会把a变量删除,也会导致A()对象变成垃圾

input('回车键退出程序...') # 程序结束后,A()对象即使还在被a变量引用,仍然会被回收

特殊方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# 特殊方法,也称为魔术方法
# 特殊方法都是使用__开头和结尾的
# 特殊方法一般不需要我们手动调用,需要在一些特殊情况下自动执行

# 定义一个Person类
class Person(object):
"""人类"""

def __init__(self, name, age):
self.name = name
self.age = age

# __str__()这个特殊方法会在尝试将对象转换为字符串的时候调用
# 它的作用可以用来指定对象转换为字符串的结果(print函数)
def __str__(self):
return 'Person [name=%s , age=%d]' % (self.name, self.age)

# __repr__()这个特殊方法会在对当前对象使用repr()函数时调用
# 它的作用是指定对象在‘交互模式’中直接输出的效果
def __repr__(self):
return 'Hello, this is repr'

# 重写以下方法,让对象支持比较,以__gt__()为例说明
# object.__lt__(self, other) 小于 <
# object.__le__(self, other) 小于等于 <=
# object.__eq__(self, other) 等于 ==
# object.__ne__(self, other) 不等于 !=
# object.__gt__(self, other) 大于 >
# object.__ge__(self, other) 大于等于 >=

# __gt__()会在对象做大于比较的时候调用,该方法的返回值将会作为比较的结果
# 他需要两个参数,一个self表示当前对象,other表示和当前对象比较的对象
# self > other
def __gt__(self, other):
return self.age > other.age # 以年龄作为比较的指标

# __len__() # 获取对象的长度

# object.__bool__(self)
# 可以通过bool来指定对象转换为布尔值的情况
def __bool__(self):
return self.age > 17

# 运算的方法
# object.__add__(self, other)
# object.__sub__(self, other)
# object.__mul__(self, other)
# object.__matmul__(self, other)
# object.__truediv__(self, other)
# object.__floordiv__(self, other)
# object.__mod__(self, other)
# object.__divmod__(self, other)
# object.__pow__(self, other[, modulo])
# object.__lshift__(self, other)
# object.__rshift__(self, other)
# object.__and__(self, other)
# object.__xor__(self, other)
# object.__or__(self, other)


# 创建两个Person类的实例
p1 = Person('孙悟空', 18)
p2 = Person('猪八戒', 28)

# 打印p1
# 当我们打印一个对象时,实际上打印的是对象的中特殊方法 __str__()的返回值
# print(p1) # 不改写__str__()方法的输出结果:<__main__.Person object at 0x04E95090>
print(p1) # 改写__str__()方法后的输出结果:Person [name=孙悟空 , age=18]

print(repr(p1)) # Hello, this is repr

# 大于比较方法
print(p1 > p2) # False

print(bool(p1)) # True
# 条件不清晰,p1调用的就是__bool__()方法,一般不这样写
# if p1:
# print(p1.name, '已经成年了')
# else:
# print(p1.name, '还未成年了')

模块化

  • 简介:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    # 模块(module)
    # 模块化,模块化指将一个完整的程序分解为一个一个小的模块
    # 通过将模块组合,来搭建出一个完整的程序
    # 不采用模块化:统一将所有的代码编写到一个文件中
    # 采用模块化:将程序分别编写到多个文件中
    # 模块化的优点:
    # ① 方便开发
    # ② 方便维护
    # ③ 模块可以复用!

    # 在Python中一个py文件就是一个模块,要想创建模块,实际上就是创建一个python文件
    # 注意:模块名要符号标识符的规范

    # 在一个模块中引入外部模块:
    # ① import 模块名 (模块名,就是python文件的名字,注意不要.py后缀)
    # ② import 模块名 as 模块别名
    # - 可以引入同一个模块多次,但是模块的实例只会创建一个
    # - import可以在程序的任意位置调用,但是一般情况下,import语句都会统一写在程序的开头
    # - 在每一个模块内部都有一个__name__属性,通过这个属性可以获取到模块的名字
    # - __name__属性值为 __main__的模块是主模块,一个程序中只会有一个主模块
    # 主模块就是我们直接通过 python 执行的模块(当前程序所在的模块)

    import test_module as test

    print(__name__) # 主模块:__main__
    print(test.__name__) # 引入的外部模块:test_module
  • m.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    # 可以在模块中定义变量,在模块中定义的变量,在引入该模块后,就可以直接使用了
    a = 10
    b = 20

    # 添加了_的变量,只能在模块内部访问,在通过 import * 方式引入时,不会引入_开头的变量
    _c = 30


    # 可以在模块中定义函数,同样可以通过模块访问到
    def test():
    print('test')


    def test2():
    print('test2')


    # 也可以定义类
    class Person:
    def __init__(self):
    self.name = '孙悟空'


    # 编写测试代码:
    # 这部分代码,只有当前模块作为主模块的时候才需要被执行
    # 而当前模块被其他模块引入时,不需要被执行
    # 此时,我们就必须要检查当前模块是否是主模块
    if __name__ == '__main__':
    test()
    test2()
    p = Person()
    print(p.name)
  • main.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    import m

    # 访问模块中的变量:模块名.变量名
    print(m.a, m.b) # 10 20.
    # print(m._c) # 此方式可以访问_c属性

    # 访问模块中的方法:模块名.方法名
    m.test() # test
    m.test2() # test2

    # 访问模块中的类:模块名.类名,创建类的实例
    p = m.Person()
    print(p.name) # 孙悟空

    # 也可以只引入模块中的部分内容
    # 语法: from 模块名 import 变量, 变量....
    # from m import Person # 只引入Person
    # from m import test # 只引入test
    from m import Person, test # 引入多个

    # 通过上面方式引入后,可以直接使用
    p1 = Person()
    print(p1) # <m.Person object at 0x00000115DD088160>
    test() # test


    # test2() # test2()没有引入,不能直接使用

    # from m import * # 引入模块中所有内容,一般不会使用

    # 当前模块中,会覆盖被引入模块中的同名方法
    def test2():
    print('这是主模块中的test2')


    test2() # 这是主模块中的test2

    # 也可以为引入的变量使用别名
    # 语法:from 模块名 import 变量 as 别名
    from m import test2 as new_test2

    test2() # 这是主模块中的test2
    new_test2() # test2

    # from m import *

    # print(_c) # _c属性无法访问


    # 总结:
    # import xxx
    # import xxx as yyy
    # from xxx import yyy , zzz , fff
    # from xxx import *
    # from xxx import yyy as zz

  • 结构:

    image-20210929171722079

    image-20210929171809531

    image-20210929171835707

  • hello/__init__.py

    1
    2
    def test():
    print('test')
  • hello/a.py

    1
    c = 30
  • hello/b.py

    1
    d = 40
  • main.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    # 包 Package
    # 包也是一个模块
    # 当我们模块中代码过多时,或者一个模块需要被分解为多个模块时,这时就需要使用到包
    # 普通的模块就是一个py文件,而包是一个文件夹
    # 包中必须要有一个 __init__.py 文件,这个文件中可以包含有包中的主要内容
    from hello import a, b

    print(a.c)
    print(b.d)

    # __pycache__ 是模块的缓存文件
    # .py代码在执行前,需要被解析器先转换为机器码,然后再执行
    # 所以我们在使用模块(包)时,也需要将模块的代码先转换为机器码,然后再交由计算机执行
    # 而为了提高程序运行的性能,python会在编译过一次以后,将代码保存到一个缓存文件中
    # 这样在下次加载这个模块(包)时,就可以不再重新编译而是直接加载缓存中编译好的代码即可

Python 标准库

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# 思想:开箱即用
# 为了实现开箱即用的思想,Python中为我们提供了一个模块的标准库
# 在这个标准库中,有很多很强大的模块我们可以直接使用,并且标准库会随Python的安装一同安装

# sys模块:
# 它里面提供了一些变量和函数,使我们可以获取到Python解析器的信息
# 或者通过函数来操作Python解析器
# 引入sys模块:
import sys

print(sys) # <module 'sys' (built-in)>

# sys.argv:
# 命令行执行代码时,获取命令行中所包含的参数
# 该属性是一个列表,列表中保存了当前命令的所有参数
# 参考IDEA中Java程序main()方法模块参数的引入,注意第一个参数
print(sys.argv) # ['D:/JetBrainsWorkSpace/PycharmProjects/main.py', 'aaa', 'bbb']

# sys.modules:
# 获取当前程序中引入的所有模块
# modules是一个字典,字典的key是模块的名字,字典的value是模块对象
print(sys.modules) # {'sys': <module 'sys' (built-in)>, 'builtins': <module 'builtins' (built-in)>, ......}

# pprint模块:
# print()打印不会格式化数据
# 它给我们提供了一个方法pprint(),该方法可以用来对打印的数据做简单的格式化
# 引入pprint模块:
import pprint

pprint.pprint(sys.modules)

# sys.path:
# 他是一个列表,列表中保存的是模块的搜索路径,不要轻易更改
# ['D:\\JetBrainsWorkSpace\\PycharmProjects',
# 'D:\\JetBrainsWorkSpace\\PycharmProjects',
# 'D:\\Program Files\\PyCharm Professional Edition with Anaconda plugin '
# '2020.1.2\\plugins\\python\\helpers\\pycharm_display',
# 'D:\\Program\\Miniconda3\\python38.zip',
# 'D:\\Program\\Miniconda3\\DLLs',
# 'D:\\Program\\Miniconda3\\lib',
# 'D:\\Program\\Miniconda3',
# 'D:\\Program\\Miniconda3\\lib\\site-packages',
# 'D:\\Program\\Miniconda3\\lib\\site-packages\\win32',
# 'D:\\Program\\Miniconda3\\lib\\site-packages\\win32\\lib',
# 'D:\\Program\\Miniconda3\\lib\\site-packages\\Pythonwin',
# 'D:\\Program Files\\PyCharm Professional Edition with Anaconda plugin '
# '2020.1.2\\plugins\\python\\helpers\\pycharm_matplotlib_backend']
pprint.pprint(sys.path)

# sys.platform:
# 表示当前Python运行的平台
print(sys.platform) # win32

# sys.exit():
# 函数用来退出程序
# sys.exit('程序出现异常,结束!') # 后面的print('hello')语句不再执行
# print('hello')

# os模块:
# 让我们可以对操作系统进行访问
import os

# os.environ:
# 通过这个属性可以获取到系统的环境变量
pprint.pprint(os.environ) # 所有的
pprint.pprint(os.environ['path']) # 只查看path环境变量

# os.system():
# 可以用来执行操作系统的命令
os.system('dir') # dir命令
os.system('notepad') # 打开记事本名令

命令行执行代码时的参数:

1
2
PS D:\JetBrainsWorkSpace\PycharmProjects> python main.py aaa bbb
['main.py', 'aaa', 'bbb']

image-20210930161242203

异常和文件

异常

  • 程序在运行过程当中,不可避免的会出现一些错误,比如:使用了没有赋值过的变量,使用了不存在的索引,除 0 等。这些错误在程序中,我们称其为异常。
  • 程序运行过程中,一旦出现异常将会导致程序立即终止,异常以后的代码全部都不会执行!

处理异常

  • 程序运行时出现异常,目的并不是让我们的程序直接终止!Python 是希望在出现异常时,我们可以编写代码来对异常进行处理!

  • try 语句:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    try:
    代码块(可能出现错误的语句)
    except 异常类型 as 异常名:
    代码块(出现错误以后的处理方式)
    except 异常类型 as 异常名:
    代码块(出现错误以后的处理方式)
    except 异常类型 as 异常名:
    代码块(出现错误以后的处理方式)
    else:
    代码块(没出错时要执行的语句)
    finally:
    代码块(该代码块总会执行)
  • try 是必须的,else 语句有没有都行,except 和 finally 至少有一个。

  • 可以将可能出错的代码放入到 try 语句,这样如果代码没有错误,则会正常执行,如果出现错误,则会执行 expect 子句中的代码,这样我们就可以通过代码来处理异常,避免因为一个异常导致整个程序的终止。

异常的传播

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def fn():
print('Hello fn')
print(a)
print(10 / 0)


def fn2():
print('Hello fn2')
fn()


def fn3():
print('Hello fn3')
fn2()


fn3()
  • 当在函数中出现异常时,如果在函数中对异常进行了处理,则异常不会再继续传播,如果函数中没有对异常进行处理,则异常会继续向函数调用处传播,如果函数调用处处理了异常,则不再传播,如果没有处理则继续向调用处传播,直到传递到全局作用域(主模块),如果依然没有处理,则程序终止,并且显示异常信息。
  • 当程序运行过程中出现异常以后,所有的异常信息会被保存一个专门的异常对象中,而异常传播时,实际上就是异常对象抛给了调用处。比如:
    • ZeroDivisionError 类的对象专门用来表示除 0 的异常。
    • NameError 类的对象专门用来处理变量错误的异常。
  • 在 Python 为我们提供了多个异常对象。

异常对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
print('异常出现前')
l = []
try:
# print(c)
# l[10]
# 1 + 'hello'
print(10 / 0)
except NameError:
# 如果except后不跟任何的内容,则此时它会捕获到所有的异常
# 如果在except后跟着一个异常的类型,那么此时它只会捕获该类型的异常
print('出现 NameError 异常')
except ZeroDivisionError:
print('出现 ZeroDivisionError 异常')
except IndexError:
print('出现 IndexError 异常')
# Exception 是所有异常类的父类,所以如果except后跟的是Exception,他也会捕获到所有的异常
# 可以在异常类后边跟着一个 as xx 此时xx就是异常对象
except Exception as e: # 等同于 except:
print('未知异常', e, type(e))
finally:
print('无论是否出现异常,该子句都会执行')

print('异常出现后')

抛出异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 也可以自定义异常类,只需要创建一个类继承Exception即可
class MyError(Exception):
pass


def add(a, b):
# 如果a和b中有负数,就向调用处抛出异常
if a < 0 or b < 0:
# raise用于向外部抛出异常,后边可以跟一个异常类,或异常类的实例
# raise ExceptioUS20190040060A1-20190207.XMLn
# 抛出异常的目的,告诉调用者这里调用时出现问题,希望你自己处理一下
# raise Exception('两个参数中不能有负数!')
raise MyError('自定义的异常')

# 也可以通过if else来代替异常的处理,但无法考虑到所有可能出异常的条件,难以控制
return a + b


print(add(-123, 456))
  • 可以使用 raise 语句来抛出异常,raise 语句后需要跟一个异常类或异常的实例。

文件

  • 通过 Python 程序来对计算机中的各种文件进行增删改查的操作。
  • 操作文件的步骤:
    • 打开文件。
    • 对文件进行各种操作(读、写),然后保存。
    • 关闭文件。

打开文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# open(file, mode='r', buffering=-1, encoding_=None, errors=None, newline=None, closefd=True, opener=None)
# 使用open函数来打开一个文件
# 参数:
# file 要打开的文件的名字(路径)
# 返回值:
# 返回一个对象,这个对象就代表了当前打开的文件

# 创建一个变量,来保存文件的名字
# 如果目标文件和当前文件在同一级目录下,则直接使用文件名即可
file_name = 'demo.txt'

# 在windows系统使用路径时,可以使用/来代替 \
# 或者可以使用 \\ 来代替 \
# 或者也可以使用原始字符串
# file_name = 'hello\\demo.txt'
# file_name = r'hello\demo.txt'

# 表示路径,可以使用..来返回一级目录
# file_name = '../hello/demo.txt'

# 如果目标文件距离当前文件比较远,此时可以使用绝对路径
# 绝对路径应该从磁盘的根目录开始书写
# file_name = r'C:\Users\XiSun\Desktop\hello.txt'

file_obj = open(file_name) # 打开 file_name 对应的文件
print(file_obj) # <_io.TextIOWrapper name='demo.txt' mode='r' encoding='cp936'>

关闭文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
# 打开文件
file_name = 'demo.txt'

# 调用open()来打开文件
# file_obj = open(file_name)

# 当我们获取了文件对象以后,所有的对文件的操作都应该通过对象来进行

# 读取文件中的内容:
# read()方法,用来读取文件中的内容,它会将内容全部保存为一个字符串返回
# content = file_obj.read()
# print(content)

# 关闭文件:
# 调用close()方法来关闭文件
# file_obj.close()

# 上面的open()和close()是常规写法,可以用下面的方式简化操作
# with ... as 语句:
with open(file_name) as file_obj:
# 在with语句中可以直接使用file_obj来做文件操作
# 此时这个文件只能在with中使用,一旦with结束则文件会自动close()
print(file_obj.read())

# 进一步完善,添加文件读取异常处理
# 文件处理的标准格式:
file_name = 'hello.txt'

try:
with open(file_name) as file_obj:
print(file_obj.read())
except FileNotFoundError:
print(f'{file_name} 文件不存在~~')

读取文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
file_name = 'demo.txt'

try:
# 调用open()来打开一个文件,可以将文件分成两种类型
# 一种,是纯文本文件(使用utf-8等编码编写的文本文件)
# 一种,是二进制文件(图片、mp3、ppt等这些文件)
# open()打开文件时,默认是以文本文件的形式打开的,但是open()默认的编码为None
# 所以处理文本文件时,必须要指定文件的编码
with open(file_name, encoding='utf-8') as file_obj:
# 通过 read() 来读取文件中的内容
# 如果直接调用read()它会将文本文件的所有内容全部都读取出来
# 如果要读取的文件较大的话,会一次性将文件的内容加载到内存中,容易导致内存泄漏
# 所以对于较大的文件,不要直接调用read()
# help(file_obj.read)查看帮助信息
# read()可以接收一个size作为参数,该参数用来指定要读取的字符的数量
# 默认值为-1,它会读取文件中的所有字符
# 可以为size指定一个值,这样read()会读取指定数量的字符,
# 每一次读取都是从上次读取到位置开始读取的
# 如果字符的数量小于size,则会读取剩余所有的
# 如果已经读取到了文件的最后了,则会返回''空串
# content = file_obj.read(-1)
content = file_obj.read(6)
content = file_obj.read(6)
content = file_obj.read(6)
content = file_obj.read(6)
# print(content)
# print(len(content))
except FileNotFoundError:
print(f'{file_name} 这个文件不存在!')

# 读取大文件的方式
file_name = 'demo.txt'

try:
with open(file_name, encoding='utf-8') as file_obj:
# 定义一个变量,来保存文件的内容
file_content = ''
# 定义一个变量,来指定每次读取的大小
chunk = 100
# 创建一个循环来读取文件内容
while True:
# 读取chunk大小的内容
content = file_obj.read(chunk)

# 检查是否读取到了内容
if not content:
# 内容读取完毕,退出循环
break

# 输出内容
# print(content, end='')
file_content += content

except FileNotFoundError:
print(f'{file_name} 这个文件不存在!')

print(file_content)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import pprint

file_name = 'demo.txt'

try:
with open(file_name, encoding='utf-8') as file_obj:
# readline():
# 该方法可以用来读取一行内容
# print(file_obj.readline(), end='') # print()打印自带换行符

# readlines():
# 该方法用于一行一行的读取内容,它会一次性将读取到的内容封装到一个列表中返回
# r = file_obj.readlines()
# pprint.pprint(r[0]) # 'aaa\n'
# pprint.pprint(r[1]) # 'bbb\n'
# pprint.pprint(r[2]) # 'ccc\n'

# 简化写法
for t in file_obj:
print(t, end='')

except FileNotFoundError:
print(f'{file_name} 这个文件不存在!')

写入文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
file_name = 'demo1.txt'

# 使用open()打开文件时必须要指定打开文件所要做的操作:读、写、追加
# 如果不指定操作类型,则默认是 `读取文件` ,而读取文件时是不能向文件中写入的
# r:表示只读的
# w:表示是可写的,使用w来写入文件时,如果文件不存在会创建文件,如果文件存在则会截断文件
# 截断文件指删除原来文件中的所有内容(覆盖原文件内容)
# a:表示追加内容,如果文件不存在会创建文件,如果文件存在则会向文件中追加内容
# x:用来新建文件,如果文件不存在则创建,存在则报错
# +:为操作符增加功能
# r+:即可读又可写,文件不存在会报错
# w+:即可写又可读
# a+:即可追加又可读
# with open(file_name , 'w' , encoding='utf-8') as file_obj:
# with open(file_name , 'r+' , encoding='utf-8') as file_obj:
with open(file_name, 'x', encoding='utf-8') as file_obj:
# write()来向文件中写入内容
# 如果操作的是一个文本文件的话,则write()需要传递一个字符串作为参数
# 该方法会可以分多次向文件中写入内容
# 写入完成以后,该方法会返回写入的字符的个数
file_obj.write('aaa\n')
file_obj.write('bbb\n')
file_obj.write('ccc\n')
file_obj.write(str(123) + '123123\n') # 要转换为字符串,且不会自动换行
r = file_obj.write('今天天气真不错')
print(r) # 7

二进制文件操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
file_name = 'F:/QQMusic/FLOW - Go!!!.flac'

# 读取模式:
# t:读取文本文件(默认值)
# b:读取二进制文件

with open(file_name, 'rb') as file_obj:
# 读取文本文件时,size是以字符为单位的
# 读取二进制文件时,size是以字节为单位
# print(file_obj.read(100))

# 将读取到的内容写出来
# 定义一个新的文件
new_name = 'aa.flac'

with open(new_name, 'wb') as new_obj:

# 定义每次读取的大小
chunk = 1024 * 100 # 100 KB

while True:
# 从已有的对象中读取数据
content = file_obj.read(chunk)

# 内容读取完毕,终止循环
if not content:
break

# 将读取到的数据写入到新对象中
new_obj.write(content)

seek()tell()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 二进制文件
with open('demo.txt', 'rb') as file_obj:
# print(file_obj.read(30))
# print(file_obj.read(100))

# tell()方法用来查看当前读取的位置
print('当前读取到了 -->', file_obj.tell())

# seek()方法可以修改当前读取的位置
# seek()需要两个参数:
# 第一个:要切换到的位置
# 第二个:计算位置的方式
# 可选值:
# 0 从头计算,默认值
# 1 从当前位置计算
# 2 从最后位置开始计算
# file_obj.seek(55)
# file_obj.seek(80, 0)
# file_obj.seek(70, 1)
file_obj.seek(-10, 2) # 从文件的最后往前读10个字符
print(file_obj.read())

# 文本文件
with open('demo.txt', 'rt', encoding='utf-8') as file_obj:
print('当前读取到了 -->', file_obj.tell())

file_obj.seek(9) # 从头开始计算,切换到第9个字节开始读取
print(file_obj.read())

文件的其他操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
import os
from pprint import pprint

# os.listdir():获取指定目录的目录结构
# 需要一个路径作为参数,会获取到该路径下的目录结构,默认路径为 . ,即当前目录
# 该方法会返回一个列表,目录中的每一个文件(夹)的名字都是列表中的一个元素
r = os.listdir()
pprint(r) # ['.idea', 'aa.flac', 'demo.txt', 'hello', 'main.py', '__pycache__']

# os.getcwd():获取当前所在的目录
r = os.getcwd()
pprint(r) # 'D:\\JetBrainsWorkSpace\\PycharmProjects'

# os.chdir():切换当前所在的目录 作用相当于cd命令
# os.chdir('c:/')
# r = os.getcwd()
# pprint(r) # 'c:\\'

# os.mkdir();创建目录
os.mkdir("aaa") # 在当前目录下创建一个名字为 aaa 的目录,如果已存在,则报错

# os.rmdir():删除目录
os.rmdir('aaa') # 在当前目录下删除一个名字为 aaa 的目录,如果不存在,则报错

# open();打开文件
open('aa.txt', 'w')

# os.remove():删除文件
os.remove('aa.flac')

# os.rename('旧名字','新名字'):可以对一个文件进行重命名,也可以用来移动一个文件
os.rename('hello', 'bb.txt')
# os.rename('bb.txt', 'c:/users/lilichao/desktop/bb.txt')

pprint(r)

本文参考

https://www.liaoxuefeng.com/wiki/1016959663602400

https://www.bilibili.com/video/BV1hW41197sB?from=search&seid=1852797992981366365&spm_id_from=333.337.0.0

声明:写作本文初衷是个人学习记录,鉴于本人学识有限,如有侵权或不当之处,请联系 wdshfut@163.com

VMware 安装

CentOS 安装

  • 准备工作,检查 BIOS 虚拟化支持:

    • 打开任务管理器,进入性能,查看虚拟化是否启用。

      image-20210826114631117

    • 若虚拟化未启用,重启电脑,F2 进入 BIOS 模式(不同主板快捷键不同),进入高级模式页面,Advanced —> CPU Configuration,开启虚拟化支持。

  • 下载地址:https://developer.aliyun.com/mirror/centos?spm=a2c6h.13651102.0.0.3e221b11se5c1r

  • 下载版本:dvd 标准安装版。

    image-20210826132225940

  • 安装参考:https://blog.csdn.net/qq_44714603/article/details/88829423

  • Vmware 配置 CentOS 软件,即,向虚拟机插入系统盘:

    image-20210828143341232

  • 开启虚拟机,安装系统盘并配置:

    • 语言环境:

      image-20210828143835803

    • 日期和时间:

      image-20210828144044232

    • 软件选择:

      image-20210828144401900

    • 安装位置,自定义磁盘分区,配置 boot,swap 和根目录:

      image-20210828230742891

      image-20210828145303732

      image-20210828145447647

      image-20210828145847360

      image-20210828230512829

      image-20210828231006455

    • 禁用 kdump 设置,如果是正式开发阶段,应该启用 kdump 设置:

      image-20210828231358785

    • 网络和主机名:

      image-20210828232134005

    • 安全策略:

      image-20210828232312406

    • 等上面配置完成之后,开始安装系统盘:

      image-20210828232519213

      image-20210828232922462

      image-20210828234105781

      image-20210828234207374

      image-20210828234408166

      image-20210828234514646

      image-20210828234649230

      image-20210828234747576

      image-20210828234839063

      image-20210828234935663

      image-20210828235029894

      image-20210828235204876

      image-20210828235429417

      image-20210828235642980

配置 IP 地址和主机名称

  • VMware:

    image-20210829220432882

    image-20210829220525207

    image-20210829220827200

    image-20210829221133759

  • Window 10(即本机):

    image-20210829221518857

    image-20210829221544041

    image-20210829221730077

    如果没有出现 VMnet 8 选项,回到 VMware 的虚拟网络编辑器,点击“更改设置” —> “还原默认设置”,即可。

    image-20210829221917341

    image-20210829222140699

  • 虚拟机:

    • 切换 root 用户:

      1
      2
      3
      4
      5
      6
      7
      8
        [xisun@centos7 ~]$ su root
      密码:
      [root@centos7 xisun]#

      - 设置虚拟机 IP 地址:

      ```sh
      [root@centos7 xisun]# vim /etc/sysconfig/network-scripts/ifcfg-ens33
      • ifcfg-ens33 文件原内容:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        TYPE="Ethernet"
        PROXY_METHOD="none"
        BROWSER_ONLY="no"
        BOOTPROTO="dhcp" # 动态获取IP地址,服务器每次开机时,IP地址可能发生改变
        DEFROUTE="yes"
        IPV4_FAILURE_FATAL="no"
        IPV6INIT="yes"
        IPV6_AUTOCONF="yes"
        IPV6_DEFROUTE="yes"
        IPV6_FAILURE_FATAL="no"
        IPV6_ADDR_GEN_MODE="stable-privacy"
        NAME="ens33"
        UUID="eb503f88-96af-455d-b8f9-dbda02ca79d4"
        DEVICE="ens33"
        ONBOOT="yes"
      • ifcfg-ens33 文件新内容:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        TYPE="Ethernet"
        PROXY_METHOD="none"
        BROWSER_ONLY="no"
        BOOTPROTO="static" # 修改为静态IP地址
        DEFROUTE="yes"
        IPV4_FAILURE_FATAL="no"
        IPV6INIT="yes"
        IPV6_AUTOCONF="yes"
        IPV6_DEFROUTE="yes"
        IPV6_FAILURE_FATAL="no"
        IPV6_ADDR_GEN_MODE="stable-privacy"
        NAME="ens33"
        UUID="eb503f88-96af-455d-b8f9-dbda02ca79d4"
        DEVICE="ens33"
        ONBOOT="yes"

        # 新增
        IPADDR=192.168.10.99 # 静态IP地址,按需自定义
        GATEWAY=192.168.10.2 # 网关
        DNS1=192.168.10.2 # 域名解析器
    • 修改虚拟机的主机名称:

      1
      [root@centos7 xisun]# vim /etc/hostname
      1
      centos7				# 主机名称按需求自定义
      • 修改虚拟机主机的名称映射:

        1
        [root@centos7 xisun]# vim /etc/hosts
        • 原文件内容:

          1
          2
          127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
          ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
        • 新内容:

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          13
          14
          127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
          ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6

          # 按需求添加主机名称映射
          192.168.10.99 centos7
          192.168.10.100 hadoop100
          192.168.10.101 hadoop101
          192.168.10.102 hadoop102
          192.168.10.103 hadoop103
          192.168.10.104 hadoop104
          192.168.10.105 hadoop105
          192.168.10.106 hadoop106
          192.168.10.107 hadoop107
          192.168.10.108 hadoop108
      • 修改 Windows 10 主机的名称映射:C:\Windows\System32\drivers\etc\hosts

        image-20210829232429026

        • 如果操作系统是 Window7,可以直接修改 hosts 文件;如果操作系统是 Window10,需要先将 hosts 文件拷贝出来,修改保存以后,再覆盖原文件即可。

        • hosts 文件新增如下主机映射:

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          192.168.10.99 centos7
          192.168.10.100 hadoop100
          192.168.10.101 hadoop101
          192.168.10.102 hadoop102
          192.168.10.103 hadoop103
          192.168.10.104 hadoop104
          192.168.10.105 hadoop105
          192.168.10.106 hadoop106
          192.168.10.107 hadoop107
          192.168.10.108 hadoop108
    • 重启:

      1
      [root@centos7 xisun]# reboot
    • 重启之后,以 root 用户重新登陆。

      • 验证虚拟机 IP 地址:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        [root@centos7 ~]# ifconfig
        ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
        inet 192.168.10.99 netmask 255.255.255.0 broadcast 192.168.10.255
        inet6 fe80::ac1e:7fe1:a566:2670 prefixlen 64 scopeid 0x20<link>
        ether 00:0c:29:1c:d5:13 txqueuelen 1000 (Ethernet)
        RX packets 2033 bytes 2797234 (2.6 MiB)
        RX errors 0 dropped 0 overruns 0 frame 0
        TX packets 924 bytes 61834 (60.3 KiB)
        TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

        lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
        inet 127.0.0.1 netmask 255.0.0.0
        inet6 ::1 prefixlen 128 scopeid 0x10<host>
        loop txqueuelen 1000 (Local Loopback)
        RX packets 48 bytes 4080 (3.9 KiB)
        RX errors 0 dropped 0 overruns 0 frame 0
        TX packets 48 bytes 4080 (3.9 KiB)
        TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

        virbr0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
        inet 192.168.122.1 netmask 255.255.255.0 broadcast 192.168.122.255
        ether 52:54:00:97:ed:a7 txqueuelen 1000 (Ethernet)
        RX packets 0 bytes 0 (0.0 B)
        RX errors 0 dropped 0 overruns 0 frame 0
        TX packets 0 bytes 0 (0.0 B)
        TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

      • 验证是否能连通外网:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        [root@centos7 ~]# ping www.baidu.com 
        PING www.a.shifen.com (14.215.177.39) 56(84) bytes of data.
        64 bytes from 14.215.177.39 (14.215.177.39): icmp_seq=1 ttl=128 time=38.4 ms
        64 bytes from 14.215.177.39 (14.215.177.39): icmp_seq=2 ttl=128 time=38.6 ms
        64 bytes from 14.215.177.39 (14.215.177.39): icmp_seq=3 ttl=128 time=38.4 ms
        64 bytes from 14.215.177.39 (14.215.177.39): icmp_seq=4 ttl=128 time=39.3 ms
        64 bytes from 14.215.177.39 (14.215.177.39): icmp_seq=5 ttl=128 time=38.3 ms
        64 bytes from 14.215.177.39 (14.215.177.39): icmp_seq=6 ttl=128 time=38.6 ms
        64 bytes from 14.215.177.39 (14.215.177.39): icmp_seq=7 ttl=128 time=38.3 ms
        64 bytes from 14.215.177.39 (14.215.177.39): icmp_seq=8 ttl=128 time=38.4 ms
        64 bytes from 14.215.177.39 (14.215.177.39): icmp_seq=9 ttl=128 time=38.9 ms
        64 bytes from 14.215.177.39 (14.215.177.39): icmp_seq=10 ttl=128 time=38.3 ms
        64 bytes from 14.215.177.39 (14.215.177.39): icmp_seq=11 ttl=128 time=38.7 ms
        64 bytes from 14.215.177.39 (14.215.177.39): icmp_seq=12 ttl=128 time=38.3 ms
        ^C
        --- www.a.shifen.com ping statistics ---
        12 packets transmitted, 12 received, 0% packet loss, time 11035ms
        rtt min/avg/max/mdev = 38.357/38.606/39.328/0.332 ms
      • 查看主机地址:

        1
        2
        [root@centos7 ~]# hostname
        centos7

Xshell 远程连接虚拟机

  • 安装过程略。

  • 远程连接配置:

    image-20210829231009322

    image-20210829231122803

  • 连接成功:

    image-20210829231402711

  • 数据传输:安装 Xftp 工具,或者使用 rzsz 命令。

克隆虚拟机

  • 新配置的 centos7 虚拟机,可以作为一个纯净的虚拟机,在此基础上,克隆出新的虚拟机,在新虚拟机上安装软件,而纯净的虚拟机留作备用。

  • 克隆虚拟机之前,需要正确的关闭虚拟机:

    image-20210830151900185

  • 克隆:

    image-20210830152407112

    image-20210830152532017

    image-20210830153137306

    image-20210830153347287

    image-20210830153523350

    image-20210830154101255

  • 常规操作:

    • 移除,此操作只会在 VMware 列表中移除虚拟机,但不会删除磁盘上的虚拟机:

      image-20210830154158479

    • 添加,通过打开操作,可以添加磁盘上的虚拟机到 VMware 列表中:

      image-20210830154443435

    • 删除,此操作会将磁盘上的虚拟机删除:

      image-20210830154727908

修改克隆机的 IP 地址和主机名称

  • 克隆机的信息,和被克隆机相同,需要修改 IP 地址,以及主机名称。

  • 开启克隆机,以 root 用户登录。

  • 修改 IP 地址:

    1
    [root@centos7 ~]# vim /etc/sysconfig/network-scripts/ifcfg-ens33
    • 修改 ifcfg-ens33 文件中的 IPADDR:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      TYPE="Ethernet"
      PROXY_METHOD="none"
      BROWSER_ONLY="no"
      BOOTPROTO="static"
      DEFROUTE="yes"
      IPV4_FAILURE_FATAL="no"
      IPV6INIT="yes"
      IPV6_AUTOCONF="yes"
      IPV6_DEFROUTE="yes"
      IPV6_FAILURE_FATAL="no"
      IPV6_ADDR_GEN_MODE="stable-privacy"
      NAME="ens33"
      UUID="eb503f88-96af-455d-b8f9-dbda02ca79d4"
      DEVICE="ens33"
      ONBOOT="yes"

      IPADDR=192.168.10.100 # 只需要将IP地址按需修改即可
      GATEWAY=192.168.10.2
      DNS1=192.168.10.2
  • 修改主机名称:

    1
    [root@centos7 ~]# vim /etc/hostname
    1
    hadoop100
  • 重启:

    1
    [root@centos7 ~]# reboot
  • 查看新的 IP 地址和主机名称:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    [root@hadoop100 ~]# ifconfig
    ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
    inet 192.168.10.100 netmask 255.255.255.0 broadcast 192.168.10.255
    inet6 fe80::ac1e:7fe1:a566:2670 prefixlen 64 scopeid 0x20<link>
    ether 00:0c:29:1d:f8:56 txqueuelen 1000 (Ethernet)
    RX packets 604 bytes 804811 (785.9 KiB)
    RX errors 0 dropped 0 overruns 0 frame 0
    TX packets 279 bytes 21418 (20.9 KiB)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

    lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
    inet 127.0.0.1 netmask 255.0.0.0
    inet6 ::1 prefixlen 128 scopeid 0x10<host>
    loop txqueuelen 1000 (Local Loopback)
    RX packets 48 bytes 4080 (3.9 KiB)
    RX errors 0 dropped 0 overruns 0 frame 0
    TX packets 48 bytes 4080 (3.9 KiB)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

    virbr0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
    inet 192.168.122.1 netmask 255.255.255.0 broadcast 192.168.122.255
    ether 52:54:00:97:ed:a7 txqueuelen 1000 (Ethernet)
    RX packets 0 bytes 0 (0.0 B)
    RX errors 0 dropped 0 overruns 0 frame 0
    TX packets 0 bytes 0 (0.0 B)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

    [root@hadoop100 ~]# hostname
    hadoop100

JDK 说明

  • 安装的 centos7 模板机,有自带的 JDK,某些情况,需要删除,按照需求自行安装。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    [xisun@centos7 ~]$ su root
    密码:
    [root@centos7 ~]# rpm -qa | grep -i java
    javapackages-tools-3.4.1-11.el7.noarch
    tzdata-java-2019c-1.el7.noarch
    java-1.8.0-openjdk-headless-1.8.0.242.b08-1.el7.x86_64
    java-1.8.0-openjdk-1.8.0.242.b08-1.el7.x86_64
    java-1.7.0-openjdk-headless-1.7.0.251-2.6.21.1.el7.x86_64
    python-javapackages-3.4.1-11.el7.noarch
    java-1.7.0-openjdk-1.7.0.251-2.6.21.1.el7.x86_64
    [root@centos7 ~]# rpm -qa | grep -i java | xargs -n1 rpm -e --nodeps
    [root@centos7 ~]# rpm -qa | grep -i java

本文参考

https://www.bilibili.com/video/BV1Qp4y1n7EN

声明:写作本文初衷是个人学习记录,鉴于本人学识有限,如有侵权或不当之处,请联系 wdshfut@163.com

大数据

大数据概念

  • 大数据(Big Data):指无法在一定时间范围内用常规软件工具进行捕捉、管理和处理的数据集合,是需要新处理模式才能具有更强的决策力、洞察发现力和流程优化能力的海量、高增长率和多样化的信息资产。
  • 大数据主要解决,海量数据的采集、存储和分析计算问题。
  • 按顺序给出数据存储单位:bit、Byte、KB、MB、GB、TB、PB、EB、ZB、YB、BB、NB、DB。
    • 1 Byte = 8 bit1 KB = 1024 Byte1 MB = 1024 KB1 GB = 1024 MB1 TB = 1024 GB1 PB= 1024 TB

大数据特点

  • Volume(大量)
    • 截至目前,人类生产的所有印刷材料的数据量是 200 PB,而历史上全人类总共说过的话的数据量大约是 5 EB。当前,典型个人计算机硬盘的容量为 TB 量级,而一些大企业的数据量已经接近 EB 量级。
  • Velocity(高速)
    • 这是大数据区分于传统数据挖掘的最显著特征。根据 IDC 的“数字宇宙”的报告,预计到 2025 年,全球数据使用量将达到 163 ZB。在如此海量的数据面前,处理数据的效率就是企业的生命。
    • 天猫双十一:2017 年,3 分 01 秒,天猫交易额超过 100 亿;2020 年,96 秒,天猫交易额超过 100 亿。
  • Variety(多样)
    • 这种类型的多样性也让数据被分为结构化数据和非结构化数据。相对于以往便于存储的以数据库/文本为主的结构化数据,非结构化数据越来越多,包括网络日志、音频、视频、图片、地理位置信息等,这些多类型的数据对数据的处理能力提出了更高要求。
  • Value(低价值密度)
    • 价值密度的高低与数据总量的大小成反比。比如,在一天的监控视频中,我们只关心宋老师晚上在床上健身那一分钟,如何快速对有价值数据“提纯”,成为目前大数据背景下待解决的难题。

Hadoop 概述

Hadoop 是什么

  • Hadoop 是一个由 Apache 基金会所开发的分布式系统基础架构

  • 主要解决,海量数据的存储和海量数据的分析计算问题。

  • 广义上来说,Hadoop 通常是指一个更广泛的概念 — Hadoop 生态圈。

    image-20210825170020065

Hadoop 发展历史

  • Hadoop 创始人 Doug Cutting,为了实现与 Google 类似的全文搜索功能,他在 Lucene 框架基础上进行优化升级,查询引擎和索引引擎。

  • 2001 年年底,Lucene 成为 Apache 基金会的一个子项目。

  • 对于海量数据的场景,Lucene 框架面对与 Google 同样的困难,存储海量数据困难,检索海量速度慢。

  • 学习和模仿 Google 解决这些问题的办法:微型版 Nutch。

  • 可以说 Google 是 Hadoop 的思想之源(Google 在大数据方面的三篇论文):

    • GFS —> HDFS
    • MapReduce —> MR
    • BigTable —> HBase
  • 2003 - 2004 年,Google 公开了部分 GFS 和 MapReduce 思想的细节,以此为基础,Doug Cutting 等人用了 2 年业余时间实现了 DFS 和 MapReduce 机制,使 Nutch 性能飙升。

  • 2005 年,Hadoop 作为 Lucene 的子项目 Nutch 的一部分正式引入 Apache 基金会。

  • 2006 年 3 月份,MapReduce 和 Nutch Distributed File System(NDFS)分别被纳入到 Hadoop 项目中,Hadoop 就此正式诞生,标志着大数据时代来临。

  • 名字来源于 Doug Cutting 儿子的玩具大象:

    image-20210825170536329

Hadoop 三大发行版本

  • Hadoop 三大发行版本:Apache、Cloudera、Hortonworks。
  • Apache 版本是最原始(最基础)的版本,对于入门学习最好。— 2006 年
  • Cloudera 内部集成了很多大数据框架,对应产品 CDH。— 2008 年
  • Hortonworks 文档较好,对应产品 HDP。— 2011 年
    • Hortonworks 现在已经被 Cloudera 公司收购,推出新的品牌 CDP。

Apache Hadoop

Cloudera Hadoop

Hortonworks Hadoop

Hadoop 优势

  • 高可靠性:Hadoop 底层维护多个数据副本,所以即使 Hadoop 某个计算元素或存储出现故障,也不会导致数据的丢失。

    image-20210825171613059

  • 高扩展性:在集群间分配任务数据,可方便的扩展数以千计的节点。

    image-20210825171705459

  • 高效性:在 MapReduce 的思想下,Hadoop 是并行工作的,以加快任务处理速度。

    image-20210825171731759

  • 高容错性:能够自动将失败的任务重新分配。

    image-20210825171816855

Hadoop 组成

image-20210825173206311

  • Hadoop 1.x 时 代 ,Hadoop 中的 MapReduce 同时处理业务逻辑运算和资源的调度,耦合性较大。
  • Hadoop 2.x 时代,增加了 Yarn。Yarn 只负责资源的调度,MapReduce 只负责运算。
  • Hadoop 3.x 时代,在组成上没有变化。

HDFS 架构概述

  • Hadoop Distributed File System,简称 HDFS,是一个分布式文件系统。包含三个模块:
    • NameNode:简称 nn,存储文件的元数据,如文件名,文件目录结构,文件属性(生成时间、副本数、文件权限),以及每个文件的块列表和块所在的 DataNode 等。
    • DataNode:简称 dn,在本地文件系统存储文件块数据,以及块数据的校验和。
    • Secondary NameNode:简称 2nn,每隔一段时间对 NameNode 元数据备份。

YARN 架构概述

  • Yet Another Resource Negotiator,简称 YARN ,另一种资源协调者,是 Hadoop 的资源管理器。有两大组件:

    image-20210826101511233

    • ResourceManager:简称 RM,整个集群资源(内存、CPU 等)的管理者。
    • NodeManager:简称 NM,单个节点服务器资源的管理者。每个 NodeManager 上可以有多个 Container。
      • Container:容器,相当于一台独立的服务器,里面封装了任务运行所需要的资源,如内存、CPU、磁盘、网络等。
      • ApplicationMaster:简称 AM,单个任务运行的管理者。
  • 客户端 client 可以有多个。

  • 集群上可以运行多个 ApplicationMaster。

MapReduce 架构概述

  • MapReduce 将计算过程分为两个阶段:Map 和 Reduce。

    image-20210825232032562

    • Map 阶段并行处理输入数据。
    • Reduce 阶段对 Map 结果进行汇总。

HDFS 、YARN 、MapReduce 三者关系

image-20210825232856313

大数据技术生态体系

image-20210825233533121

  • Sqoop:Sqoop 是一款开源的工具,主要用于在 Hadoop、Hive 与传统的数据库(MySQL)间进行数据的传递,可以将一个关系型数据库(例如:MySQL,Oracle 等)中的数据导进到 Hadoop 的 HDFS 中,也可以将 HDFS 的数据导进到关系型数据库中。
  • Flume:Flume 是一个高可用的,高可靠的,分布式的海量日志采集、聚合和传输的系统,Flume 支持在日志系统中定制各类数据发送方,用于收集数据。
  • Kafka:Kafka 是一种高吞吐量的分布式发布订阅消息系统。
  • Spark:Spark 是当前最流行的开源大数据内存计算框架。可以基于 Hadoop 上存储的大数据进行计算。
  • Flink:Flink 是当前最流行的开源大数据内存计算框架。用于实时计算的场景较多。
  • Oozie:Oozie 是一个管理 Hadoop 作业(job)的工作流程调度管理系统。
  • Hbase:HBase 是一个分布式的、面向列的开源数据库。HBase 不同于一般的关系数据库,它是一个适合于非结构化数据存储的数据库。
  • Hive:Hive 是基于 Hadoop 的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表,并提供简单的 SQL 查询功能,可以将 SQL 语句转换为 MapReduce 任务进行运行。其优点是学习成本低,可以通过类 SQL 语句快速实现简单的 MapReduce 统计,不必开发专门的 MapReduce 应用,十分适合数据仓库的统计分析。
  • ZooKeeper:它是一个针对大型分布式系统的可靠协调系统,提供的功能包括:配置维护、名字服务、分布式同步、组服务等。

推荐系统框架图

image-20210826110750495

Hadoop 运行环境搭建

模板虚拟机环境准备

  • 安装模板虚拟机,IP 地址 192.168.10.100、主机名称 hadoop100、内存 2 G、硬盘 50 G。

    • 主机名称不要起 hadoop,hadoop000 等特殊名称。
  • 开启虚拟机,切换到 root 用户操作下面得命令:

    1
    2
    [xisun@hadoop100 ~]$ su root
    密码:
  • 确保虚拟机可以正常上网:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    [root@hadoop100 xisun]# ping www.baidu.com
    PING www.a.shifen.com (14.215.177.39) 56(84) bytes of data.
    64 bytes from 14.215.177.39 (14.215.177.39): icmp_seq=1 ttl=128 time=41.0 ms
    64 bytes from 14.215.177.39 (14.215.177.39): icmp_seq=2 ttl=128 time=40.9 ms
    64 bytes from 14.215.177.39 (14.215.177.39): icmp_seq=3 ttl=128 time=41.3 ms
    64 bytes from 14.215.177.39 (14.215.177.39): icmp_seq=4 ttl=128 time=42.5 ms
    ^C
    --- www.a.shifen.com ping statistics ---
    4 packets transmitted, 4 received, 0% packet loss, time 3007ms
    rtt min/avg/max/mdev = 40.987/41.495/42.582/0.674 ms
  • 安装 epel-release:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    [root@hadoop100 xisun]# yum install -y epel-release
    已加载插件:fastestmirror, langpacks
    Loading mirror speeds from cached hostfile
    * base: mirrors.njupt.edu.cn
    * extras: mirrors.njupt.edu.cn
    * updates: mirrors.njupt.edu.cn
    base | 3.6 kB 00:00:00
    extras | 2.9 kB 00:00:00
    updates | 2.9 kB 00:00:00
    正在解决依赖关系
    --> 正在检查事务
    ---> 软件包 epel-release.noarch.0.7-11 将被 安装
    --> 解决依赖关系完成

    依赖关系解决

    ===================================================================================================================================================================================================================
    Package 架构 版本 源 大小
    ===================================================================================================================================================================================================================
    正在安装:
    epel-release noarch 7-11 extras 15 k

    事务概要
    ===================================================================================================================================================================================================================
    安装 1 软件包

    总下载量:15 k
    安装大小:24 k
    Downloading packages:
    警告:/var/cache/yum/x86_64/7/extras/packages/epel-release-7-11.noarch.rpm: 头V3 RSA/SHA256 Signature, 密钥 ID f4a80eb5: NOKEY
    epel-release-7-11.noarch.rpm 的公钥尚未安装
    epel-release-7-11.noarch.rpm | 15 kB 00:00:00
    从 file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 检索密钥
    导入 GPG key 0xF4A80EB5:
    用户ID : "CentOS-7 Key (CentOS 7 Official Signing Key) <security@centos.org>"
    指纹 : 6341 ab27 53d7 8a78 a7c2 7bb1 24c6 a8a7 f4a8 0eb5
    软件包 : centos-release-7-8.2003.0.el7.centos.x86_64 (@anaconda)
    来自 : /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
    Running transaction check
    Running transaction test
    Transaction test succeeded
    Running transaction
    正在安装 : epel-release-7-11.noarch 1/1
    验证中 : epel-release-7-11.noarch 1/1

    已安装:
    epel-release.noarch 0:7-11

    完毕!
    • Extra Packages for Enterprise Linux 是为“红帽系”的操作系统提供额外的软件包,适用于 RHEL、CentOS 和 Scientific Linux。相当于是一个软件仓库,大多数 rpm 包在官方 repository 中是找不到的。

    • 如果 Linux 安装的是最小系统版,还需要安装如下工具,如果安装的是 Linux 桌面标准版,不需要执行如下操作(本机安装的是桌面版):

      • net-tool:工具包集合,包含 ifconfig 等命令。

        1
        [root@hadoop100 xisun]# yum install -y net-tools
      • vim:编辑器。

        1
        [root@hadoop100 xisun]# yum install -y vim
  • 关闭防火墙,关闭防火墙开机自启:

    • 查看防火墙状态:

      1
      2
      [root@hadoop100 xisun]# firewall-cmd --state
      running
    • 关闭防火墙:

      1
      2
      3
      [root@hadoop100 xisun]# systemctl stop firewalld.service
      [root@hadoop100 xisun]# firewall-cmd --state
      not running
    • 关闭防火墙开机自启:

      1
      2
      3
      [root@hadoop100 xisun]# systemctl disable firewalld.service 
      Removed symlink /etc/systemd/system/multi-user.target.wants/firewalld.service.
      Removed symlink /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.
    • 在企业开发时,通常单个服务器的防火墙是关闭的,公司整体对外访问时会设置非常安全的防火墙。

  • 创建新用户,并修改新用户的密码(可省略):

    1
    2
    [root@hadoop100 xisun]# useradd xisun
    [root@hadoop100 xisun]# passwd xisun
    • 生产环境下,应避免使用 root 用户直接操作。
  • 配置刚创建的新用户具有 root 权限,方便后期加 sudo 执行 root 权限的命令:

    1
    [root@hadoop100 xisun]# vim /etc/sudoers
    • 修改 /etc/sudoers 文件,在 %wheel 这行下面添加一行,将新用户 xisun 设置为免密使用 root 权限,如下所示:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      ## Allow root to run any commands anywhere 
      root ALL=(ALL) ALL

      ## Allows members of the 'sys' group to run networking, software,
      ## service management apps and more.
      # %sys ALL = NETWORKING, SOFTWARE, SERVICES, STORAGE, DELEGATING, PROCESSES, LOCATE, DRIVERS

      ## Allows people in group wheel to run all commands
      %wheel ALL=(ALL) ALL

      xisun ALL=(ALL) NOPASSWD:ALL
      • xisun 这一行不要直接放到 root 行下面,因为所有用户都属于 wheel 组,如果放在 root 行下面,则是先配置了 xisun 用户在使用 sudo 命令时具有免输入密码功能,但是程序执行到 %wheel 行时,该功能又会被覆盖回需要密码。所以 xisun 这一行要放到 %wheel 这行下面。
  • 从 root 用户退回到 xisun 用户:

    1
    2
    [root@hadoop100 xisun]# exit
    exit
  • /opt 目录下创建文件夹:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    [xisun@hadoop100 ~]$ cd /opt/
    [xisun@hadoop100 opt]$ sudo mkdir module
    [xisun@hadoop100 opt]$ sudo mkdir software
    [xisun@hadoop100 opt]$ ll
    总用量 0
    drwxr-xr-x. 2 root root 6 8月 30 22:08 module
    drwxr-xr-x. 2 root root 6 10月 31 2018 rh
    drwxr-xr-x. 2 root root 6 8月 30 22:09 software
    [xisun@hadoop100 opt]$ sudo rm -r rh
    [xisun@hadoop100 opt]$ ll
    总用量 0
    drwxr-xr-x. 2 root root 6 8月 30 22:08 module
    drwxr-xr-x. 2 root root 6 8月 30 22:09 software
    • /opt 目录下,需要使用 sudo 命令才能创建和删除文件夹:

      1
      2
      [xisun@hadoop100 opt]$ mkdir test
      mkdir: 无法创建目录"test": 权限不够
  • 修改创建的文件夹所属主和所属组为 xisun 用户:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    [xisun@hadoop100 opt]$ ll
    总用量 0
    drwxr-xr-x. 2 root root 6 8月 30 22:08 module
    drwxr-xr-x. 2 root root 6 8月 30 22:09 software
    [xisun@hadoop100 opt]$ sudo chown xisun:xisun module/
    [xisun@hadoop100 opt]$ sudo chown xisun:xisun software/
    [xisun@hadoop100 opt]$ ll
    总用量 0
    drwxr-xr-x. 2 xisun xisun 6 8月 30 22:08 module
    drwxr-xr-x. 2 xisun xisun 6 8月 30 22:09 software
  • 卸载虚拟机自带的 JDK,以 root 用户执行:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    [xisun@hadoop100 opt]$ su root
    密码:
    [root@hadoop100 opt]# rpm -qa | grep -i java
    javapackages-tools-3.4.1-11.el7.noarch
    tzdata-java-2019c-1.el7.noarch
    java-1.8.0-openjdk-headless-1.8.0.242.b08-1.el7.x86_64
    java-1.8.0-openjdk-1.8.0.242.b08-1.el7.x86_64
    java-1.7.0-openjdk-headless-1.7.0.251-2.6.21.1.el7.x86_64
    python-javapackages-3.4.1-11.el7.noarch
    java-1.7.0-openjdk-1.7.0.251-2.6.21.1.el7.x86_64
    [root@hadoop100 opt]# rpm -qa | grep -i java | xargs -n1 rpm -e --nodeps
    [root@hadoop100 opt]# rpm -qa | grep -i java
    • 如果你的虚拟机是最小化安装不需要执行这一步。
    • rpm -qa:查询所安装的所有 rpm 软件包。
    • grep -i:忽略大小写。
    • xargs -n1:表示每次只传递一个参数。
    • rpm -e –nodeps:强制卸载软件。
  • 重启虚拟机:

    1
    [root@hadoop100 opt]# reboot

克隆虚拟机

  • 利用模板机 hadoop100,克隆三台虚拟机:hadoop102,hadoop103,hadoop104。

    • 注意:克隆时,要先关闭 hadoop100。
  • 修改克隆机的 IP 地址和主机名,以 hadoop102 为例,进行说明:

    • 开启 hadoop102,以 root 账户登录。

    • 修改 IP 地址:

      1
      [root@hadoop100 ~]# vim /etc/sysconfig/network-scripts/ifcfg-ens33
      • 修改 ifcfg-ens33 文件中的 IPADDR:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        TYPE="Ethernet"
        PROXY_METHOD="none"
        BROWSER_ONLY="no"
        BOOTPROTO="static"
        DEFROUTE="yes"
        IPV4_FAILURE_FATAL="no"
        IPV6INIT="yes"
        IPV6_AUTOCONF="yes"
        IPV6_DEFROUTE="yes"
        IPV6_FAILURE_FATAL="no"
        IPV6_ADDR_GEN_MODE="stable-privacy"
        NAME="ens33"
        UUID="eb503f88-96af-455d-b8f9-dbda02ca79d4"
        DEVICE="ens33"
        ONBOOT="yes"

        IPADDR=192.168.10.102 # 修改IP地址为192.168.10.102
        GATEWAY=192.168.10.2
        DNS1=192.168.10.2
    • 修改主机名:

      1
      [root@hadoop100 ~]# vim /etc/hostname
      1
      hadoop102
    • 重启:

      1
      [root@hadoop100 ~]# reboot
    • 验证 IP 地址和主机名,以及网络是否正常:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      [root@hadoop102 ~]# ifconfig
      ens33: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
      inet 192.168.10.102 netmask 255.255.255.0 broadcast 192.168.10.255
      inet6 fe80::ac1e:7fe1:a566:2670 prefixlen 64 scopeid 0x20<link>
      ether 00:0c:29:c5:1d:96 txqueuelen 1000 (Ethernet)
      RX packets 1025 bytes 878131 (857.5 KiB)
      RX errors 0 dropped 0 overruns 0 frame 0
      TX packets 442 bytes 35254 (34.4 KiB)
      TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

      lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
      inet 127.0.0.1 netmask 255.0.0.0
      inet6 ::1 prefixlen 128 scopeid 0x10<host>
      loop txqueuelen 1000 (Local Loopback)
      RX packets 48 bytes 4080 (3.9 KiB)
      RX errors 0 dropped 0 overruns 0 frame 0
      TX packets 48 bytes 4080 (3.9 KiB)
      TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

      virbr0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
      inet 192.168.122.1 netmask 255.255.255.0 broadcast 192.168.122.255
      ether 52:54:00:97:ed:a7 txqueuelen 1000 (Ethernet)
      RX packets 0 bytes 0 (0.0 B)
      RX errors 0 dropped 0 overruns 0 frame 0
      TX packets 0 bytes 0 (0.0 B)
      TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

      [root@hadoop102 ~]# hostname
      hadoop102
      [root@hadoop102 ~]# ping www.baidu.com
      PING www.a.shifen.com (14.215.177.39) 56(84) bytes of data.
      64 bytes from 14.215.177.39 (14.215.177.39): icmp_seq=1 ttl=128 time=42.9 ms
      64 bytes from 14.215.177.39 (14.215.177.39): icmp_seq=2 ttl=128 time=42.6 ms
      64 bytes from 14.215.177.39 (14.215.177.39): icmp_seq=3 ttl=128 time=42.7 ms
      64 bytes from 14.215.177.39 (14.215.177.39): icmp_seq=4 ttl=128 time=42.8 ms
      64 bytes from 14.215.177.39 (14.215.177.39): icmp_seq=5 ttl=128 time=42.8 ms
      ^C
      --- www.a.shifen.com ping statistics ---
      5 packets transmitted, 5 received, 0% packet loss, time 4012ms
      rtt min/avg/max/mdev = 42.689/42.814/42.930/0.276 ms
    • 按照相同的步骤,修改 hadoop103 的 IP 地址为 192.168.10.103,主机名为 hadoop103,hadoop104 的 IP 地址为 192.168.10.104,主机名为 hadoop104,并验证。

安装 JDK

  • 下面步骤以 hadoop102 为例,进行说明。

  • 安装 JDK 前,一定确保提前删除了虚拟机自带的 JDK,此步骤在前面已执行。

    1
    [xisun@hadoop102 ~]$ rpm -qa | grep -i java
    1
    [xisun@hadoop100 ~]$ rpm -qa | grep -i java | xargs -n1 sudo rpm -e --nodeps
    1
    2
    [xisun@hadoop102 ~]$ java -version
    bash: java: 未找到命令...
  • 安装 OpenJDK 8。

  • 下载地址:https://openjdk.java.net/,https://openjdk.java.net/install/index.html

    image-20210831115613196

  • 使用 root 权限,以命令行安装:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    [xisun@hadoop102 ~]$ sudo yum install -y java-1.8.0-openjdk-devel
    已加载插件:fastestmirror, langpacks
    Loading mirror speeds from cached hostfile
    * base: mirrors.cqu.edu.cn
    * epel: mirror.sjtu.edu.cn
    * extras: mirrors.cn99.com
    * updates: mirrors.cn99.com
    正在解决依赖关系
    --> 正在检查事务
    ---> 软件包 java-1.8.0-openjdk-devel.x86_64.1.1.8.0.302.b08-0.el7_9 将被 安装
    --> 正在处理依赖关系 java-1.8.0-openjdk(x86-64) = 1:1.8.0.302.b08-0.el7_9,它被软件包 1:java-1.8.0-openjdk-devel-1.8.0.302.b08-0.el7_9.x86_64 需要
    --> 正在处理依赖关系 libjvm.so()(64bit),它被软件包 1:java-1.8.0-openjdk-devel-1.8.0.302.b08-0.el7_9.x86_64 需要
    --> 正在处理依赖关系 libjava.so()(64bit),它被软件包 1:java-1.8.0-openjdk-devel-1.8.0.302.b08-0.el7_9.x86_64 需要
    --> 正在检查事务
    ---> 软件包 java-1.8.0-openjdk.x86_64.1.1.8.0.302.b08-0.el7_9 将被 安装
    ---> 软件包 java-1.8.0-openjdk-headless.x86_64.1.1.8.0.302.b08-0.el7_9 将被 安装
    --> 正在处理依赖关系 tzdata-java >= 2021a,它被软件包 1:java-1.8.0-openjdk-headless-1.8.0.302.b08-0.el7_9.x86_64 需要
    --> 正在处理依赖关系 jpackage-utils,它被软件包 1:java-1.8.0-openjdk-headless-1.8.0.302.b08-0.el7_9.x86_64 需要
    --> 正在检查事务
    ---> 软件包 javapackages-tools.noarch.0.3.4.1-11.el7 将被 安装
    --> 正在处理依赖关系 python-javapackages = 3.4.1-11.el7,它被软件包 javapackages-tools-3.4.1-11.el7.noarch 需要
    ---> 软件包 tzdata-java.noarch.0.2021a-1.el7 将被 安装
    --> 正在检查事务
    ---> 软件包 python-javapackages.noarch.0.3.4.1-11.el7 将被 安装
    --> 解决依赖关系完成

    依赖关系解决

    ===================================================================================================================================================================================================================
    Package 架构 版本 源 大小
    ===================================================================================================================================================================================================================
    正在安装:
    java-1.8.0-openjdk-devel x86_64 1:1.8.0.302.b08-0.el7_9 updates 9.8 M
    为依赖而安装:
    java-1.8.0-openjdk x86_64 1:1.8.0.302.b08-0.el7_9 updates 311 k
    java-1.8.0-openjdk-headless x86_64 1:1.8.0.302.b08-0.el7_9 updates 33 M
    javapackages-tools noarch 3.4.1-11.el7 base 73 k
    python-javapackages noarch 3.4.1-11.el7 base 31 k
    tzdata-java noarch 2021a-1.el7 updates 191 k

    事务概要
    ===================================================================================================================================================================================================================
    安装 1 软件包 (+5 依赖软件包)

    总下载量:43 M
    安装大小:152 M
    Downloading packages:
    (1/6): python-javapackages-3.4.1-11.el7.noarch.rpm | 31 kB 00:00:00
    (2/6): java-1.8.0-openjdk-1.8.0.302.b08-0.el7_9.x86_64.rpm | 311 kB 00:00:00
    (3/6): javapackages-tools-3.4.1-11.el7.noarch.rpm | 73 kB 00:00:00
    (4/6): tzdata-java-2021a-1.el7.noarch.rpm | 191 kB 00:00:01
    (5/6): java-1.8.0-openjdk-headless-1.8.0.302.b08-0.el7_9.x86_64.rpm | 33 MB 00:00:07
    (6/6): java-1.8.0-openjdk-devel-1.8.0.302.b08-0.el7_9.x86_64.rpm | 9.8 MB 00:00:13
    -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    总计 3.1 MB/s | 43 MB 00:00:13
    Running transaction check
    Running transaction test
    Transaction test succeeded
    Running transaction
    警告:RPM 数据库已被非 yum 程序修改。
    ** 发现 9 个已存在的 RPM 数据库问题, 'yum check' 输出如下:
    icedtea-web-1.7.1-2.el7_6.x86_64 有缺少的需求 java-1.8.0-openjdk
    icedtea-web-1.7.1-2.el7_6.x86_64 有缺少的需求 jpackage-utils
    icedtea-web-1.7.1-2.el7_6.x86_64 有缺少的需求 jpackage-utils
    jline-1.0-8.el7.noarch 有缺少的需求 java >= ('0', '1.5', None)
    jline-1.0-8.el7.noarch 有缺少的需求 jpackage-utils
    rhino-1.7R5-1.el7.noarch 有缺少的需求 jpackage-utils
    rhino-1.7R5-1.el7.noarch 有缺少的需求 jpackage-utils
    tagsoup-1.2.1-8.el7.noarch 有缺少的需求 jpackage-utils
    tagsoup-1.2.1-8.el7.noarch 有缺少的需求 jpackage-utils >= ('0', '1.6', None)
    正在安装 : tzdata-java-2021a-1.el7.noarch 1/6
    正在安装 : python-javapackages-3.4.1-11.el7.noarch 2/6
    正在安装 : javapackages-tools-3.4.1-11.el7.noarch 3/6
    正在安装 : 1:java-1.8.0-openjdk-headless-1.8.0.302.b08-0.el7_9.x86_64 4/6
    正在安装 : 1:java-1.8.0-openjdk-1.8.0.302.b08-0.el7_9.x86_64 5/6
    正在安装 : 1:java-1.8.0-openjdk-devel-1.8.0.302.b08-0.el7_9.x86_64 6/6
    验证中 : 1:java-1.8.0-openjdk-headless-1.8.0.302.b08-0.el7_9.x86_64 1/6
    验证中 : python-javapackages-3.4.1-11.el7.noarch 2/6
    验证中 : tzdata-java-2021a-1.el7.noarch 3/6
    验证中 : 1:java-1.8.0-openjdk-devel-1.8.0.302.b08-0.el7_9.x86_64 4/6
    验证中 : 1:java-1.8.0-openjdk-1.8.0.302.b08-0.el7_9.x86_64 5/6
    验证中 : javapackages-tools-3.4.1-11.el7.noarch 6/6

    已安装:
    java-1.8.0-openjdk-devel.x86_64 1:1.8.0.302.b08-0.el7_9

    作为依赖被安装:
    java-1.8.0-openjdk.x86_64 1:1.8.0.302.b08-0.el7_9 java-1.8.0-openjdk-headless.x86_64 1:1.8.0.302.b08-0.el7_9 javapackages-tools.noarch 0:3.4.1-11.el7 python-javapackages.noarch 0:3.4.1-11.el7
    tzdata-java.noarch 0:2021a-1.el7

    完毕!

    公司生产环境使用的是 OpenJDK 8,此处保持一致。

  • 验证 JDK 是否安装成功:

    1
    2
    3
    4
    [xisun@hadoop102 ~]$ java -version
    openjdk version "1.8.0_302"
    OpenJDK Runtime Environment (build 1.8.0_302-b08)
    OpenJDK 64-Bit Server VM (build 25.302-b08, mixed mode)
  • 配置 JDK 环境变量:

    • 查看 jre/bin 路径:

      1
      2
      [xisun@hadoop102 ~]$ dirname $(readlink $(readlink $(which java)))
      /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.302.b08-0.el7_9.x86_64/jre/bin
    • 新建 /etc/profile.d/my_env.sh 文件,添加 Java 环境变量:

      1
      [xisun@hadoop102 ~]$ sudo vim /etc/profile.d/my_env.sh
      1
      2
      3
      # JAVA_HOME
      export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.302.b08-0.el7_9.x86_64
      export PATH=$PATH:$JAVA_HOME/bin
      • 正常情况下,会将 Java 环境变量添加在 /etc/profile 文件的最后,但该文件有如下设置,因此,可以在 /etc/profile.d 路径下自定义一个以 sh 结尾的文件,能达到同样的效果:

        image-20210831143510629

    • source 一下 /etc/profile 文件,让新的环境变量 PATH 生效:

      1
      [xisun@hadoop102 etc]$ source /etc/profile
    • 查看配置是否生效:

      1
      2
      [xisun@hadoop102 etc]$ echo $JAVA_HOME
      /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.302.b08-0.el7_9.x86_64

安装 Hadoop

  • 下面步骤以 hadoop102 为例,进行说明。

  • 下载地址:https://hadoop.apache.org/releases.html

    image-20210831114058447

    image-20210831144645384

    公司生产环境使用的是 hadoop-3.2.1,此处保持一致。

  • opt/software 路径下,使用 wget 命令下载安装包:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    [xisun@hadoop102 software]$ pwd
    /opt/software
    [xisun@hadoop102 software]$ wget https://archive.apache.org/dist/hadoop/common/hadoop-3.2.1/hadoop-3.2.1.tar.gz
    --2021-08-31 11:44:19-- https://archive.apache.org/dist/hadoop/common/hadoop-3.2.1/hadoop-3.2.1.tar.gz
    正在解析主机 archive.apache.org (archive.apache.org)... 138.201.131.134, 2a01:4f8:172:2ec5::2
    正在连接 archive.apache.org (archive.apache.org)|138.201.131.134|:443... 已连接。
    已发出 HTTP 请求,正在等待回应... 200 OK
    长度:359196911 (343M) [application/x-gzip]
    正在保存至: “hadoop-3.2.1.tar.gz”

    100%[=========================================================================================================================================================================>] 359,196,911 57.8KB/s 用时 57m 32s

    2021-08-31 12:41:54 (102 KB/s) - 已保存 “hadoop-3.2.1.tar.gz” [359196911/359196911])
    [xisun@hadoop102 software]$ ll
    总用量 350780
    -rw-rw-r--. 1 xisun xisun 359196911 7月 3 2020 hadoop-3.2.1.tar.gz
  • 解压安装包到 /opt/module 路径下面:

    1
    [xisun@hadoop102 software]$ tar -zxvf hadoop-3.2.1.tar.gz -C /opt/module/
    1
    2
    3
    [xisun@hadoop102 software]$ ll ../module/
    总用量 0
    drwxr-xr-x. 9 xisun xisun 149 9月 11 2019 hadoop-3.2.1
  • 将 Hadoop 添加到环境变量:

    • 获取 Hadoop 安装路径:

      1
      2
      [xisun@hadoop102 hadoop-3.2.1]$ pwd
      /opt/module/hadoop-3.2.1
    • 修改 etc/profile.d/my_env.sh 文件,添加 Hadoop 环境变量:

      1
      [xisun@hadoop102 hadoop-3.2.1]$ sudo vim /etc/profile.d/my_env.sh
      1
      2
      3
      4
      # HADOOP_HOME
      export HADOOP_HOME=/opt/module/hadoop-3.2.1
      export PATH=$PATH:$HADOOP_HOME/bin
      export PATH=$PATH:$HADOOP_HOME/sbin
    • source 一下 /etc/profile 文件,让新的环境变量 PATH 生效:

      1
      [xisun@hadoop102 hadoop-3.2.1]$ source /etc/profile
    • 查看配置是否生效:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      [xisun@hadoop102 hadoop-3.2.1]$ echo $HADOOP_HOME
      /opt/module/hadoop-3.2.1
      [xisun@hadoop102 hadoop-3.2.1]$ hadoop version
      Hadoop 3.2.1
      Source code repository https://gitbox.apache.org/repos/asf/hadoop.git -r b3cbbb467e22ea829b3808f4b7b01d07e0bf3842
      Compiled by rohithsharmaks on 2019-09-10T15:56Z
      Compiled with protoc 2.5.0
      From source with checksum 776eaf9eee9c0ffc370bcbc1888737
      This command was run using /opt/module/hadoop-3.2.1/share/hadoop/common/hadoop-common-3.2.1.jar

Hadoop 目录结构

  • 查看 Hadoop 的目录结构:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    [xisun@hadoop102 hadoop-3.2.1]$ pwd
    /opt/module/hadoop-3.2.1
    [xisun@hadoop102 hadoop-3.2.1]$ ll
    总用量 180
    drwxr-xr-x. 2 xisun xisun 203 9月 11 2019 bin
    drwxr-xr-x. 3 xisun xisun 20 9月 10 2019 etc
    drwxr-xr-x. 2 xisun xisun 106 9月 11 2019 include
    drwxr-xr-x. 3 xisun xisun 20 9月 11 2019 lib
    drwxr-xr-x. 4 xisun xisun 288 9月 11 2019 libexec
    -rw-rw-r--. 1 xisun xisun 150569 9月 10 2019 LICENSE.txt
    -rw-rw-r--. 1 xisun xisun 22125 9月 10 2019 NOTICE.txt
    -rw-rw-r--. 1 xisun xisun 1361 9月 10 2019 README.txt
    drwxr-xr-x. 3 xisun xisun 4096 9月 10 2019 sbin
    drwxr-xr-x. 4 xisun xisun 31 9月 11 2019 share
  • 重要目录

    • bin 目录:存放对 Hadoop 相关服务(hdfs,yarn,mapred)进行操作的脚本。

      1
      2
      [xisun@hadoop102 hadoop-3.2.1]$ ls bin/
      container-executor hadoop hadoop.cmd hdfs hdfs.cmd mapred mapred.cmd oom-listener test-container-executor yarn yarn.cmd

      image-20210831153016702

    • etc 目录:Hadoop 的配置文件目录,存放 Hadoop 的配置文件。

      1
      2
      3
      4
      5
      6
      7
      8
      [xisun@hadoop102 hadoop-3.2.1]$ ls etc/
      hadoop
      [xisun@hadoop102 hadoop-3.2.1]$ ls etc/hadoop/
      capacity-scheduler.xml hadoop-env.sh httpfs-env.sh kms-env.sh mapred-env.sh ssl-server.xml.example yarnservice-log4j.properties
      configuration.xsl hadoop-metrics2.properties httpfs-log4j.properties kms-log4j.properties mapred-queues.xml.template user_ec_policies.xml.template yarn-site.xml
      container-executor.cfg hadoop-policy.xml httpfs-signature.secret kms-site.xml mapred-site.xml workers
      core-site.xml hadoop-user-functions.sh.example httpfs-site.xml log4j.properties shellprofile.d yarn-env.cmd
      hadoop-env.cmd hdfs-site.xml kms-acls.xml mapred-env.cmd ssl-client.xml.example yarn-env.sh

      image-20210831153058005

    • lib 目录:存放 Hadoop 的本地库(对数据进行压缩解压缩功能)。

    • sbin 目录:存放启动或停止 Hadoop 相关服务的脚本。

      1
      2
      3
      4
      [xisun@hadoop102 hadoop-3.2.1]$ ls sbin/
      distribute-exclude.sh hadoop-daemons.sh mr-jobhistory-daemon.sh start-all.sh start-dfs.sh start-yarn.sh stop-balancer.sh stop-secure-dns.sh workers.sh
      FederationStateStore httpfs.sh refresh-namenodes.sh start-balancer.sh start-secure-dns.sh stop-all.cmd stop-dfs.cmd stop-yarn.cmd yarn-daemon.sh
      hadoop-daemon.sh kms.sh start-all.cmd start-dfs.cmd start-yarn.cmd stop-all.sh stop-dfs.sh stop-yarn.sh yarn-daemons.sh

      image-20210831153154765

    • share 目录:存放 Hadoop 的依赖 JAR 包、文档、和官方案例。

Hadoop 运行模式

  • Hadoop 官方网站:http://hadoop.apache.org/

  • Hadoop 运行模式包括:本地模式、伪分布式模式以及完全分布式模式。

    image-20210831154042555

    • 本地模式:单机运行,只是用来演示一下官方案例。
      • 数据存储在 Linux 本地,偶尔测试时使用。
    • 伪分布式模式:也是单机运行,但是具备 Hadoop 集群的所有功能,一台服务器模拟一个分布式的环境。
      • 数据存储在 HDFS 上,个别缺钱的公司用来测试,生产环境一般不用。
    • 完全分布式模式:多台服务器组成分布式环境。
      • 数据存储在 HDFS 上,企业生产环境大量使用。

本地模式

  • 以官方 WordCount 进行说明。

  • 第一步:在 hadoop-3.2.1 文件下面创建一个 wcinput 文件夹。

    1
    [xisun@hadoop102 hadoop-3.2.1]$ mkdir wcinput
  • 第二步:在 wcinput 文件下创建一个 word.txt 文件,并输入一些单词做测试。

    1
    [xisun@hadoop102 wcinput]$ vim word.txt
    1
    2
    3
    4
    hadoop yarn
    hadoop mapreduce
    xisun
    xisun
  • 第三步:回到 Hadoop 目录 /opt/module/hadoop-3.2.1

  • 第四步:执行 wordcount 程序,统计 word.txt 文件中各单词的个数。

    1
    [xisun@hadoop102 hadoop-3.2.1]$ bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.2.1.jar wordcount wcinput/ ./wcoutput

    本地模式下,输入路径 /wcinput 和输出路径 ./wcoutput 都是本地路径。

    注意:结果输出路径 wcoutput 不能已经存在,否则程序会报错 org.apache.hadoop.mapred.FileAlreadyExistsException: Output directory file:/opt/module/hadoop-3.2.1/wcoutput already exists

  • 第五步:查看结果。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    [xisun@hadoop102 hadoop-3.2.1]$ cd wcoutput/
    [xisun@hadoop102 wcoutput]$ ll
    总用量 4
    -rw-r--r--. 1 xisun xisun 36 8月 31 16:04 part-r-00000
    -rw-r--r--. 1 xisun xisun 0 8月 31 16:04 _SUCCESS
    [xisun@hadoop102 wcoutput]$ cat part-r-00000
    hadoop 2
    mapreduce 1
    xisun 2
    yarn 1

完全分布式模式

虚拟机准备

  • 虚拟机 hadoop102 已准备好,参考前面章节。

  • 在 hadoop103 和 hadoop104 安装 OpenJDK:

    1
    [xisun@hadoop103 ~]$ sudo yum install -y java-1.8.0-openjdk-devel
  • hadoop102,hadoop103 和 hadoop104 三台虚拟机,安装的 JDK 环境和 Hadoop 版本相同,因此,环境变量配置也相同。对于这种情况,不需要在每台虚拟机上再配置环境变量,可以使用 scp 或 rsync 命令等,直接拷贝模板虚拟机 hadoop102 上的配置文件到 hadoop103 和 hadoop104 上。在后面章节,也可以使用集群分发脚本 xsync 拷贝。

    • 如果使用 scp 命令,拷贝 hadoop102 上环境变量配置的 etc/profile.d/my_env.sh 文件到 hadoop103 和 hadoop104 的 etc/profile.d 路径下,方式如下。

      • 方式一,在 hadoop102 上使用 scp 命令,拷贝本地文件到 hadoop103 上:

        1
        2
        3
        4
        5
        6
        7
        8
        [xisun@hadoop102 profile.d]$ sudo scp /etc/profile.d/my_env.sh root@hadoop103:/etc/profile.d/
        The authenticity of host 'hadoop103 (192.168.10.103)' can't be established.
        ECDSA key fingerprint is SHA256:AOkUHU40E6uekNRiFpZkT4R2gfoE+s9ujdYTZ5e8kwM.
        ECDSA key fingerprint is MD5:dd:80:45:3e:83:75:92:fe:57:d3:78:fa:af:5a:ca:1b.
        Are you sure you want to continue connecting (yes/no)? yes
        Warning: Permanently added 'hadoop103,192.168.10.103' (ECDSA) to the list of known hosts.
        root@hadoop103's password:
        my_env.sh
      • 方式二,在 hadoop104 上使用 scp 命令,拷贝 hadoop102 上的文件到本地:

        1
        2
        3
        4
        5
        6
        7
        8
        [xisun@hadoop104 profile.d]$ sudo scp root@hadoop102:/etc/profile.d/my_env.sh /etc/profile.d/
        The authenticity of host 'hadoop102 (192.168.10.102)' can't be established.
        ECDSA key fingerprint is SHA256:AOkUHU40E6uekNRiFpZkT4R2gfoE+s9ujdYTZ5e8kwM.
        ECDSA key fingerprint is MD5:dd:80:45:3e:83:75:92:fe:57:d3:78:fa:af:5a:ca:1b.
        Are you sure you want to continue connecting (yes/no)? yes
        Warning: Permanently added 'hadoop102,192.168.10.102' (ECDSA) to the list of known hosts.
        root@hadoop102's password:
        my_env.sh
      • 方式三,在 hadoop103 上使用 scp 命令,拷贝 hadoop102 上的文件到 hadoop104 上:

        1
        [xisun@hadoop103 profile.d]$ sudo scp root@hadoop102:/etc/profile.d/my_env.sh root@hadoop104:/etc/profile.d/
    • 如果使用集群分发脚本 xsync 拷贝,需要注意,my_env.sh 文件是 root 权限的,需要给脚本添加 sudo 命令,同时,xsync 脚本需要补全路径,否则 sudo 识别不出来:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      [xisun@hadoop102 ~]$ sudo /home/xisun/bin/xsync /etc/profile.d/my_env.sh 
      ==================== hadoop102 ====================
      root@hadoop102's password:
      root@hadoop102's password:
      sending incremental file list

      sent 48 bytes received 12 bytes 24.00 bytes/sec
      total size is 253 speedup is 4.22
      ==================== hadoop103 ====================
      root@hadoop103's password:
      root@hadoop103's password:
      sending incremental file list
      my_env.sh

      sent 348 bytes received 35 bytes 153.20 bytes/sec
      total size is 253 speedup is 0.66
      ==================== hadoop104 ====================
      The authenticity of host 'hadoop104 (192.168.10.104)' can't be established.
      ECDSA key fingerprint is SHA256:AOkUHU40E6uekNRiFpZkT4R2gfoE+s9ujdYTZ5e8kwM.
      ECDSA key fingerprint is MD5:dd:80:45:3e:83:75:92:fe:57:d3:78:fa:af:5a:ca:1b.
      Are you sure you want to continue connecting (yes/no)? yes
      Warning: Permanently added 'hadoop104,192.168.10.104' (ECDSA) to the list of known hosts.
      root@hadoop104's password:
      root@hadoop104's password:
      sending incremental file list
      my_env.sh

      sent 348 bytes received 35 bytes 153.20 bytes/sec
      total size is 253 speedup is 0.66

      注意,需要输入的是各主机 root 用户的密码。

  • 在 hadoop103 和 hadoop104 上 source 一下 /etc/profile 文件,让新的环境变量 PATH 生效:

    1
    2
    3
    [xisun@hadoop103 ~]$ source /etc/profile
    [xisun@hadoop103 ~]$ echo $JAVA_HOME
    /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.302.b08-0.el7_9.x86_64
    1
    2
    3
    [xisun@hadoop104 ~]$ source /etc/profile
    [xisun@hadoop104 ~]$ echo $JAVA_HOME
    /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.302.b08-0.el7_9.x86_64

编写集群分发脚本 xsync

scp(secure copy)安全拷贝
  • scp 可以实现服务器与服务器之间的数据拷贝。(from server1 to server2)

  • 基本语法:

    1
    2
    scp    -r        $pdir/$fname         $user@$host:$pdir/$fname
    命令 递归 要拷贝的文件路径/名称 目的地用户@主机:目的地路径/名称
  • 实例:拷贝 hadoop102 上的 Hadoop 安装包到 hadoop103 和 hadoop104 上。

    • 前提:在 hadoop102、hadoop103、hadoop104 三台虚拟机上,都已经创建好 /opt/module/opt/software 两个路径,并且已经把这两个路径的权限修改为 xisun:xisun。

    • 方式一,在 hadoop102 上使用 scp 命令,拷贝本地文件到 hadoop103 上:

      1
      2
      3
      4
      5
      6
      7
      [xisun@hadoop102 opt]$ scp -r /opt/module/hadoop-3.2.1/ xisun@hadoop103:/opt/module/
      The authenticity of host 'hadoop103 (192.168.10.103)' can't be established.
      ECDSA key fingerprint is SHA256:AOkUHU40E6uekNRiFpZkT4R2gfoE+s9ujdYTZ5e8kwM.
      ECDSA key fingerprint is MD5:dd:80:45:3e:83:75:92:fe:57:d3:78:fa:af:5a:ca:1b.
      Are you sure you want to continue connecting (yes/no)? yes
      Warning: Permanently added 'hadoop103,192.168.10.103' (ECDSA) to the list of known hosts.
      xisun@hadoop103's password:
  • 方式二,在 hadoop104 上使用 scp 命令,拷贝 hadoop102 上的文件到本地:

    1
    2
    3
    4
    5
    6
    7
    [xisun@hadoop104 opt]$ scp -r xisun@hadoop102:/opt/module/hadoop-3.2.1/ /opt/module/
    The authenticity of host 'hadoop102 (192.168.10.102)' can't be established.
    ECDSA key fingerprint is SHA256:AOkUHU40E6uekNRiFpZkT4R2gfoE+s9ujdYTZ5e8kwM.
    ECDSA key fingerprint is MD5:dd:80:45:3e:83:75:92:fe:57:d3:78:fa:af:5a:ca:1b.
    Are you sure you want to continue connecting (yes/no)? yes
    Warning: Permanently added 'hadoop104,192.168.10.102' (ECDSA) to the list of known hosts.
    xisun@hadoop102's password:
  • 方式三,在 hadoop103 上使用 scp 命令,拷贝 hadoop102 上的文件到 hadoop104 上:

    1
    [xisun@hadoop103 opt]$ scp -r xisun@hadoop102:/opt/module/hadoop-3.2.1/ xisun@hadoop104:/opt/module/
rsync 远程同步工具
  • rsync 主要用于备份和镜像。具有速度快、避免复制相同内容和支持符号链接的优点。

  • rsync 和 scp 的区别:用 rsync 做文件的复制要比 scp 的速度快,rsync 只对差异文件做更新。scp 是把所有文件都复制过去。

  • rsync 第一次使用,等同于 scp。

  • 基本语法:

    1
    2
    rsync    -av       $pdir/$fname          $user@$host:$pdir/$fname
    命令 选项参数 要拷贝的文件路径/名称 目的地用户@主机:目的地路径/名称
    • 参数说明:

      选项 功能
      -a 归档拷贝
      -v 显示复制过程
  • 实例:

    • 删除 hadoop103 和 hadoop104 上 /opt/module/hadoop-3.2.1 路径下的 wcinput 和 wcoutput 文件夹。

      1
      [xisun@hadoop103 hadoop-3.2.1]$ rm -r wcinput/ wcoutput/
      1
      [xisun@hadoop104 hadoop-3.2.1]$ rm -r wcinput/ wcoutput/
    • 同步 hadoop102 上的 /opt/module/hadoop-3.2.1 到 hadoop103 和 hadoop104 上。

      • 方式一,在 hadoop102 上使用 rsync 命令,同步本地文件到 hadoop103 上:

        1
        2
        [xisun@hadoop102 ~]$ rsync -av /opt/module/hadoop-3.2.1/ xisun@hadoop103:/opt/module/hadoop-3.2.1/
        xisun@hadoop103's password:
      • 方式二,在 hadoop104 上使用 rsync 命令,同步 hadoop102 上的文件到本地:

        1
        2
        3
        4
        5
        6
        7
        [xisun@hadoop104 ~]$ rsync -av xisun@hadoop102:/opt/module/hadoop-3.2.1/ /opt/module/hadoop-3.2.1/
        The authenticity of host 'hadoop102 (192.168.10.102)' can't be established.
        ECDSA key fingerprint is SHA256:AOkUHU40E6uekNRiFpZkT4R2gfoE+s9ujdYTZ5e8kwM.
        ECDSA key fingerprint is MD5:dd:80:45:3e:83:75:92:fe:57:d3:78:fa:af:5a:ca:1b.
        Are you sure you want to continue connecting (yes/no)? yes
        Warning: Permanently added 'hadoop102,192.168.10.102' (ECDSA) to the list of known hosts.
        xisun@hadoop102's password:
      • 方式三,在 hadoop103 上使用 rsync 命令,同步 hadoop102 上的文件到 hadoop104 上:

        1
        [xisun@hadoop103 ~]$ rsync -av xisun@hadoop102:/opt/module/hadoop-3.2.1/ xisun@hadoop104:/opt/module/hadoop-3.2.1/
xsync 集群分发脚本
  • 需求:编写脚本,指定需要同步的文件路径参数,能够循环复制该路径下的所有文件到所有节点的相同路径下。

  • 需求分析:

    • 使用 rsync 命令,实现同步拷贝。

    • 期望脚本格式:xsync 需要同步的文件名称

    • 期望脚本在任何路径都能使用:将脚本放在声明了全局环境变量的路径下。

      • 查看全局变量的路径:

        1
        2
        [xisun@hadoop102 ~]$ echo $PATH
        /usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/xisun/.local/bin:/home/xisun/bin:/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.302.b08-0.el7_9.x86_64/bin
      • 可以看出,在全局变量的路径中,有一个 /home/xisun/bin:,如果把编写的脚本 xsync 放在此路径下,即可在任何路径都能使用。或者,直接把脚本 xsync 所在的路径,配置到全局环境变量中也可以。

  • 脚本实现:

    • /home/xisun 路径下,创建 bin 目录:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      [xisun@hadoop102 ~]$ pwd
      /home/xisun
      [xisun@hadoop102 ~]$ mkdir bin
      [xisun@hadoop102 ~]$ ll
      总用量 0
      drwxrwxr-x. 2 xisun xisun 6 9月 1 11:43 bin
      drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 公共
      drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 模板
      drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 视频
      drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 图片
      drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 文档
      drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 下载
      drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 音乐
      drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 桌面
    • /home/xisun/bin 路径下,创建 xsync 文件,并添加脚本代码:

      1
      2
      3
      [xisun@hadoop102 bin]$ pwd
      /home/xisun/bin
      [xisun@hadoop102 bin]$ vim xsync
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      #!/bin/bash

      # 1.判断参数个数,如果参数个数小于1,直接退出,$#是获得参数个数
      if [ $# -lt 1 ]
      then
      echo Not Enough Arguement!
      exit;
      fi

      # 2.遍历集群所有机器
      for host in hadoop102 hadoop103 hadoop104
      do
      echo ==================== $host ====================
      # 3.遍历所有目录,挨个发送,$@是脚本的参数,可以有多个
      for file in $@
      do
      # 4.判断文件是否存在
      if [ -e $file ]
      then
      # 5.获取父目录
      pdir=$(cd -P $(dirname $file); pwd)
      # 6.获取当前文件的名称
      fname=$(basename $file)
      # 7.在目标主机上,创建目录
      ssh $host "mkdir -p $pdir"
      # 8.同步拷贝
      rsync -av $pdir/$fname $host:$pdir
      else
      echo $file does not exists!
      fi
      done
      done

      image-20210901133253592

    • 修改脚本 xsync,使其具有可执行权限:

      1
      2
      3
      4
      5
      6
      7
      [xisun@hadoop102 bin]$ ll
      总用量 4
      -rw-rw-r--. 1 xisun xisun 908 9月 1 13:33 xsync
      [xisun@hadoop102 bin]$ chmod 777 xsync
      [xisun@hadoop102 bin]$ ll
      总用量 4
      -rwxrwxrwx. 1 xisun xisun 908 9月 1 13:33 xsync
    • 测试脚本,将 hadoop102 上的 /home/xisun/bin 目录,同步到 hadoop103 和 hadoop104 上:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      [xisun@hadoop102 ~]$ pwd
      /home/xisun
      [xisun@hadoop102 ~]$ xsync /home/xisun/bin/
      ==================== hadoop102 ====================
      The authenticity of host 'hadoop102 (192.168.10.102)' can't be established.
      ECDSA key fingerprint is SHA256:AOkUHU40E6uekNRiFpZkT4R2gfoE+s9ujdYTZ5e8kwM.
      ECDSA key fingerprint is MD5:dd:80:45:3e:83:75:92:fe:57:d3:78:fa:af:5a:ca:1b.
      Are you sure you want to continue connecting (yes/no)? yes
      Warning: Permanently added 'hadoop102,192.168.10.102' (ECDSA) to the list of known hosts.
      xisun@hadoop102's password:
      xisun@hadoop102's password:
      sending incremental file list

      sent 90 bytes received 17 bytes 16.46 bytes/sec
      total size is 908 speedup is 8.49
      ==================== hadoop103 ====================
      xisun@hadoop103's password:
      xisun@hadoop103's password:
      sending incremental file list
      bin/
      bin/xsync

      sent 1,044 bytes received 39 bytes 196.91 bytes/sec
      total size is 908 speedup is 0.84
      ==================== hadoop104 ====================
      xisun@hadoop104's password:
      xisun@hadoop104's password:
      sending incremental file list
      bin/
      bin/xsync

      sent 1,044 bytes received 39 bytes 240.67 bytes/sec
      total size is 908 speedup is 0.84

ssh 免密登录配置

  • ssh 命令可以在当前主机上,连接另一台主机,在连接过程中,需要另一台主机的通行密码。

    • 基本语法:ssh 另一台主机的IP地址

    • ssh 连接时出现 Host key verification failed 的解决方法:输入 yes 并回车。

      1
      Are you sure you want to continue connecting (yes/no)? 
    • ssh 连接到另一台主机后,使用 exit 命令可以回到原来的主机:

      1
      2
      3
      4
      5
      6
      7
      [xisun@hadoop102 ~]$ ssh hadoop103
      xisun@hadoop103's password:
      Last login: Tue Aug 31 16:47:43 2021 from 192.168.10.1
      [xisun@hadoop103 ~]$ exit
      登出
      Connection to hadoop103 closed.
      [xisun@hadoop102 ~]$
  • 免密钥配置

    • 免密登录原理:

      image-20210901151616233

    • 在 hadoop102 生成公钥和私钥:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      [xisun@hadoop102 .ssh]$ pwd
      /home/xisun/.ssh
      [xisun@hadoop102 .ssh]$ ssh-keygen -t rsa
      Generating public/private rsa key pair.
      Enter file in which to save the key (/home/xisun/.ssh/id_rsa):
      Enter passphrase (empty for no passphrase):
      Enter same passphrase again:
      Your identification has been saved in /home/xisun/.ssh/id_rsa.
      Your public key has been saved in /home/xisun/.ssh/id_rsa.pub.
      The key fingerprint is:
      SHA256:j9G3rd2/lBjPliez4vXcinw0R5CJy8mja0u7wBWgPDU xisun@hadoop102
      The key's randomart image is:
      +---[RSA 2048]----+
      | E . o |
      | . o o . + |
      | + .o o . |
      | . . .* .|
      | S o..o . |
      | . =.. oB +|
      | + o..o=X.|
      | ooo.=+Bo|
      | .++=o+oO|
      +----[SHA256]-----+
      [xisun@hadoop102 .ssh]$ ll
      总用量 12
      -rw-------. 1 xisun xisun 1675 9月 1 15:59 id_rsa
      -rw-r--r--. 1 xisun xisun 397 9月 1 15:59 id_rsa.pub
      -rw-r--r--. 1 xisun xisun 558 9月 1 14:29 known_hosts
      • /home/xisun/.ssh 路径下,执行 ssh-keygen -t rsa 命令,敲三次回车,即可生成两个文件,私钥和公钥。
      • id_rsa 为 hadoop102 的私钥,id_rsa.pub 为 hadoop102 的公钥。
    • 将 hadoop102 的公钥,拷贝到要免密登录的目标机器上,即 hadoop102,hadoop103 和 hadoop104:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      [xisun@hadoop102 ~]$ ssh-copy-id hadoop102
      /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/xisun/.ssh/id_rsa.pub"
      /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
      /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
      xisun@hadoop102's password:

      Number of key(s) added: 1

      Now try logging into the machine, with: "ssh 'hadoop102'"
      and check to make sure that only the key(s) you wanted were added.

      [xisun@hadoop102 ~]$ ssh hadoop102
      Last login: Wed Sep 1 16:11:59 2021 from hadoop102
      [xisun@hadoop102 ~]$ exit
      登出
      Connection to hadoop102 closed.
      [xisun@hadoop102 ~]$
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      [xisun@hadoop102 .ssh]$ ssh-copy-id hadoop103
      /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/xisun/.ssh/id_rsa.pub"
      /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
      /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
      xisun@hadoop103's password:

      Number of key(s) added: 1

      Now try logging into the machine, with: "ssh 'hadoop103'"
      and check to make sure that only the key(s) you wanted were added.

      [xisun@hadoop102 .ssh]$ ssh hadoop103
      Last login: Wed Sep 1 15:02:49 2021 from hadoop102
      [xisun@hadoop103 ~]$ exit
      登出
      Connection to hadoop103 closed.
      [xisun@hadoop102 .ssh]$
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      [xisun@hadoop102 .ssh]$ ssh-copy-id hadoop104
      /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/xisun/.ssh/id_rsa.pub"
      /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
      /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
      xisun@hadoop104's password:

      Number of key(s) added: 1

      Now try logging into the machine, with: "ssh 'hadoop104'"
      and check to make sure that only the key(s) you wanted were added.

      [xisun@hadoop102 .ssh]$ ssh hadoop104
      Last failed login: Wed Sep 1 14:43:15 CST 2021 from hadoop102 on ssh:notty
      There was 1 failed login attempt since the last successful login.
      Last login: Tue Aug 31 16:48:06 2021 from 192.168.10.1
      [xisun@hadoop104 ~]$ exit
      登出
      Connection to hadoop104 closed.
      [xisun@hadoop102 .ssh]$
    • 按上面同样的步骤,对 hadoop103 和 hadoop104 进行 ssh 免密登录配置。

    • 注意:上面的配置只对 xisun 用户有效,如果希望 root 用户也能免密 ssh 登录,需要切换到 root 账号,做同样的配置:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      74
      75
      76
      77
      78
      79
      80
      81
      82
      83
      [xisun@hadoop102 ~]$ su root
      密码:
      [root@hadoop102 xisun]# cd .ssh/
      [root@hadoop102 .ssh]# pwd
      /home/xisun/.ssh
      [root@hadoop102 .ssh]# ll
      总用量 16
      -rw-------. 1 xisun xisun 1191 9月 1 16:32 authorized_keys
      -rw-------. 1 xisun xisun 1675 9月 1 15:59 id_rsa
      -rw-r--r--. 1 xisun xisun 397 9月 1 15:59 id_rsa.pub
      -rw-r--r--. 1 xisun xisun 558 9月 1 14:29 known_hosts
      [root@hadoop102 .ssh]# ssh-keygen -t rsa
      Generating public/private rsa key pair.
      Enter file in which to save the key (/root/.ssh/id_rsa):
      Enter passphrase (empty for no passphrase):
      Enter same passphrase again:
      Your identification has been saved in /root/.ssh/id_rsa.
      Your public key has been saved in /root/.ssh/id_rsa.pub.
      The key fingerprint is:
      SHA256:AQtFVBbgnBrY8u/vIGgxFUxqHtKOYzKFIVRbHNJoMEw root@hadoop102
      The key's randomart image is:
      +---[RSA 2048]----+
      |*Eo=B*Bo+. |
      |.=.*=B = |
      |o X.+ = . |
      | B = o . |
      |=.= o S |
      |oo + . |
      | o . o |
      | . o . |
      | .oo |
      +----[SHA256]-----+
      [root@hadoop102 .ssh]# ssh-copy-id hadoop102
      /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
      /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
      /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
      root@hadoop102's password:

      Number of key(s) added: 1

      Now try logging into the machine, with: "ssh 'hadoop102'"
      and check to make sure that only the key(s) you wanted were added.

      [root@hadoop102 .ssh]# ssh hadoop102
      Last login: Wed Sep 1 16:41:01 2021
      [root@hadoop102 ~]# exit
      登出
      Connection to hadoop102 closed.
      [root@hadoop102 .ssh]# ssh-copy-id hadoop103
      /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
      /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
      /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
      root@hadoop103's password:

      Number of key(s) added: 1

      Now try logging into the machine, with: "ssh 'hadoop103'"
      and check to make sure that only the key(s) you wanted were added.

      [root@hadoop102 .ssh]# ssh hadoop103
      Last failed login: Wed Sep 1 14:48:11 CST 2021 from hadoop102 on ssh:notty
      There was 1 failed login attempt since the last successful login.
      Last login: Tue Aug 31 10:02:38 2021
      exi[root@hadoop103 ~]# exit
      登出
      Connection to hadoop103 closed.
      [root@hadoop102 .ssh]# ssh-copy-id hadoop104
      /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
      /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
      /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
      root@hadoop104's password:

      Number of key(s) added: 1

      Now try logging into the machine, with: "ssh 'hadoop104'"
      and check to make sure that only the key(s) you wanted were added.

      [root@hadoop102 .ssh]# ssh hadoop104
      Last login: Wed Sep 1 16:39:50 2021
      [root@hadoop104 ~]# exit
      登出
      Connection to hadoop104 closed.
      [root@hadoop102 .ssh]#
    • 配置完免密登录后,测试可以看出,使用 xsync 脚本分发文件时,不需要输入密码:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      [xisun@hadoop102 ~]$ xsync a.txt 
      ==================== hadoop102 ====================
      sending incremental file list

      sent 58 bytes received 12 bytes 46.67 bytes/sec
      total size is 0 speedup is 0.00
      ==================== hadoop103 ====================
      sending incremental file list
      a.txt

      sent 101 bytes received 35 bytes 272.00 bytes/sec
      total size is 0 speedup is 0.00
      ==================== hadoop104 ====================
      sending incremental file list
      a.txt

      sent 101 bytes received 35 bytes 272.00 bytes/sec
      total size is 0 speedup is 0.00
    • /home/xisun/.ssh 路径下的文件功能解释:

      1
      2
      3
      4
      5
      6
      [xisun@hadoop102 .ssh]$ ll
      总用量 16
      -rw-------. 1 xisun xisun 397 9月 1 16:12 authorized_keys
      -rw-------. 1 xisun xisun 1675 9月 1 15:59 id_rsa
      -rw-r--r--. 1 xisun xisun 397 9月 1 15:59 id_rsa.pub
      -rw-r--r--. 1 xisun xisun 558 9月 1 14:29 known_hosts
      文件名 功能
      known_hosts 记录当前主机ssh访问过的计算机的公钥(public key)
      id_rsa 当前主机生成的私钥
      id_rsa.pub 当前主机生成的公钥
      authorized_keys 存放授权过的无密登录服务器公钥

集群配置

集群部署规划
hadoop102 hadoop103 hadoop104
HDFS NameNode
DataNode

DataNode
SecondaryNameNode
DataNode
YARN
NodeManager
ResourceManager
NodeManager

NodeManager
  • NameNode 和 SecondaryNameNode 都比较消耗内存,不要安装在同一台服务器上。
  • ResourceManager 也很消耗内存,不要和 NameNode、SecondaryNameNode 配置在同一台服务器上。
配置文件说明
  • Hadoop 配置文件分两类:默认配置文件和自定义配置文件。只有用户想修改某一默认配置值时,才需要修改自定义配置文件,更改相应属性值。

  • 默认配置文件

    要获取的默认文件 文件存放在Hadoop的JAR包中的位置
    [core-default.xml] hadoop-common-3.2.1.jar/core-default.xml
    [hdfs-default.xml] hadoop-hdfs-3.2.1.jar/hdfs-default.xml
    [yarn-default.xml] hadoop-yarn-common-3.2.1.jar/yarn-default.xml
    [mapred-default.xml] hadoop-mapreduce-client-core-3.2.1.jar/mapred-default.xml
    • core-default.xml:

      image-20210909161942025

    • hdfs-default.xml:

      image-20210909163524558

      • 需要添加依赖才能看到:

        1
        2
        3
        4
        5
        <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-hdfs</artifactId>
        <version>${hadoop.version}</version>
        </dependency>
    • yarn-default.xml:

      image-20210909162213537

    • mapred-default.xml:

      image-20210909162538370

  • 自定义配置文件

    • Hadoop 的四个默认配置文件,分别对应以下四个自定义配置文件:core-site.xml、hdfs-site.xml、yarn-site.xml、mapred-site.xml。这四个自定义配置文件,存放在 $HADOOP_HOME/etc/hadoop 这个路径上,用户可以根据项目需求重新进行修改配置。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      [xisun@hadoop102 hadoop]$ pwd
      /opt/module/hadoop-3.2.1/etc/hadoop
      [xisun@hadoop102 hadoop]$ ll
      总用量 172
      -rw-r--r--. 1 xisun xisun 8260 9月 11 2019 capacity-scheduler.xml
      -rw-r--r--. 1 xisun xisun 1335 9月 11 2019 configuration.xsl
      -rw-r--r--. 1 xisun xisun 1940 9月 11 2019 container-executor.cfg
      -rw-r--r--. 1 xisun xisun 774 9月 10 2019 core-site.xml
      -rw-r--r--. 1 xisun xisun 3999 9月 10 2019 hadoop-env.cmd
      -rw-r--r--. 1 xisun xisun 16235 9月 11 2019 hadoop-env.sh
      -rw-r--r--. 1 xisun xisun 3321 9月 10 2019 hadoop-metrics2.properties
      -rw-r--r--. 1 xisun xisun 11392 9月 10 2019 hadoop-policy.xml
      -rw-r--r--. 1 xisun xisun 3414 9月 10 2019 hadoop-user-functions.sh.example
      -rw-r--r--. 1 xisun xisun 775 9月 11 2019 hdfs-site.xml
      -rw-r--r--. 1 xisun xisun 1484 9月 11 2019 httpfs-env.sh
      -rw-r--r--. 1 xisun xisun 1657 9月 11 2019 httpfs-log4j.properties
      -rw-r--r--. 1 xisun xisun 21 9月 11 2019 httpfs-signature.secret
      -rw-r--r--. 1 xisun xisun 620 9月 11 2019 httpfs-site.xml
      -rw-r--r--. 1 xisun xisun 3518 9月 10 2019 kms-acls.xml
      -rw-r--r--. 1 xisun xisun 1351 9月 10 2019 kms-env.sh
      -rw-r--r--. 1 xisun xisun 1860 9月 10 2019 kms-log4j.properties
      -rw-r--r--. 1 xisun xisun 682 9月 10 2019 kms-site.xml
      -rw-r--r--. 1 xisun xisun 13326 9月 10 2019 log4j.properties
      -rw-r--r--. 1 xisun xisun 951 9月 11 2019 mapred-env.cmd
      -rw-r--r--. 1 xisun xisun 1764 9月 11 2019 mapred-env.sh
      -rw-r--r--. 1 xisun xisun 4113 9月 11 2019 mapred-queues.xml.template
      -rw-r--r--. 1 xisun xisun 758 9月 11 2019 mapred-site.xml
      drwxr-xr-x. 2 xisun xisun 24 9月 10 2019 shellprofile.d
      -rw-r--r--. 1 xisun xisun 2316 9月 10 2019 ssl-client.xml.example
      -rw-r--r--. 1 xisun xisun 2697 9月 10 2019 ssl-server.xml.example
      -rw-r--r--. 1 xisun xisun 2642 9月 11 2019 user_ec_policies.xml.template
      -rw-r--r--. 1 xisun xisun 10 9月 10 2019 workers
      -rw-r--r--. 1 xisun xisun 2250 9月 11 2019 yarn-env.cmd
      -rw-r--r--. 1 xisun xisun 6056 9月 11 2019 yarn-env.sh
      -rw-r--r--. 1 xisun xisun 2591 9月 11 2019 yarnservice-log4j.properties
      -rw-r--r--. 1 xisun xisun 690 9月 11 2019 yarn-site.xml
配置集群
  • 第一步:核心配置文件 — 配置 core-site.xml。

    1
    2
    3
    [xisun@hadoop102 hadoop]$ pwd
    /opt/module/hadoop-3.2.1/etc/hadoop
    [xisun@hadoop102 hadoop]$ vim core-site.xml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    <?xml version="1.0" encoding="UTF-8"?>
    <?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
    <!--
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License. See accompanying LICENSE file.
    -->

    <!-- Put site-specific property overrides in this file. -->

    <configuration>
    <!-- 指定NameNode的地址 -->
    <property>
    <name>fs.defaultFS</name>
    <value>hdfs://hadoop102:8020</value>
    </property>

    <!-- 指定Hadoop数据的存储目录 -->
    <property>
    <name>hadoop.tmp.dir</name>
    <value>/opt/module/hadoop-3.2.1/data</value>
    </property>
    </configuration>
  • 第二步:HDFS 配置文件 — 配置 hdfs-site.xml。

    1
    2
    3
    [xisun@hadoop102 hadoop]$ pwd
    /opt/module/hadoop-3.2.1/etc/hadoop
    [xisun@hadoop102 hadoop]$ vim hdfs-site.xml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    <?xml version="1.0" encoding="UTF-8"?>
    <?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
    <!--
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License. See accompanying LICENSE file.
    -->

    <!-- Put site-specific property overrides in this file. -->

    <configuration>
    <!-- nn web端访问地址 -->
    <property>
    <name>dfs.namenode.http-address</name>
    <value>hadoop102:9870</value>
    </property>

    <!-- 2nn web端访问地址 -->
    <property>
    <name>dfs.namenode.secondary.http-address</name>
    <value>hadoop104:9868</value>
    </property>
    </configuration>
  • 第三步:YARN 配置文件 — 配置 yarn-site.xml。

    1
    2
    3
    [xisun@hadoop102 hadoop]$ pwd
    /opt/module/hadoop-3.2.1/etc/hadoop
    [xisun@hadoop102 hadoop]$ vim yarn-site.xml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    <?xml version="1.0"?>
    <!--
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License. See accompanying LICENSE file.
    -->
    <configuration>

    <!-- Site specific YARN configuration properties -->

    <!-- 指定MapReduce走shuffle -->
    <property>
    <name>yarn.nodemanager.aux-services</name>
    <value>mapreduce_shuffle</value>
    </property>

    <!-- 指定ResourceManager的地址 -->
    <property>
    <name>yarn.resourcemanager.hostname</name>
    <value>hadoop103</value>
    </property>
    </configuration>
  • 第四步:MapReduce 配置文件 — 配置 mapred-site.xml。

    1
    2
    3
    [xisun@hadoop102 hadoop]$ pwd
    /opt/module/hadoop-3.2.1/etc/hadoop
    [xisun@hadoop102 hadoop]$ vim mapred-site.xml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    <?xml version="1.0"?>
    <?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
    <!--
    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License. See accompanying LICENSE file.
    -->

    <!-- Put site-specific property overrides in this file. -->

    <configuration>
    <!-- 指定MapReduce程序运行在Yarn上 -->
    <property>
    <name>mapreduce.framework.name</name>
    <value>yarn</value>
    </property>
    </configuration>
  • 第五步:在集群上分发在 hadoop102 上配置好的 Hadoop 配置文件。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    [xisun@hadoop102 hadoop]$ xsync /opt/module/hadoop-3.2.1/etc/hadoop/
    ==================== hadoop102 ====================
    sending incremental file list

    sent 972 bytes received 18 bytes 1,980.00 bytes/sec
    total size is 107,791 speedup is 108.88
    ==================== hadoop103 ====================
    sending incremental file list
    hadoop/
    hadoop/core-site.xml
    hadoop/hdfs-site.xml
    hadoop/mapred-site.xml
    hadoop/yarn-site.xml

    sent 3,165 bytes received 139 bytes 2,202.67 bytes/sec
    total size is 107,791 speedup is 32.62
    ==================== hadoop104 ====================
    sending incremental file list
    hadoop/
    hadoop/core-site.xml
    hadoop/hdfs-site.xml
    hadoop/mapred-site.xml
    hadoop/yarn-site.xml

    sent 3,165 bytes received 139 bytes 6,608.00 bytes/sec
    total size is 107,791 speedup is 32.62
  • 第六步:到 hadoop103 和 hadoop104 上查看文件分发情况。

    1
    [xisun@hadoop103 ~]$ cat /opt/module/hadoop-3.2.1/etc/hadoop/core-site.xml
    1
    [xisun@hadoop104 ~]$ cat /opt/module/hadoop-3.2.1/etc/hadoop/core-site.xml

群起集群

配置 workers
  • 打开 workers 文件,删除默认值 localhost,然后向 workers 文件中添加如下内容:

    1
    2
    3
    [xisun@hadoop102 hadoop]$ pwd
    /opt/module/hadoop-3.2.1/etc/hadoop
    [xisun@hadoop102 hadoop]$ vim workers
    1
    2
    3
    hadoop102
    hadoop103
    hadoop104
  • workers 文件中添加的主机名,即是 Hadoop 集群中的各个节点。

  • 注意:workers 文件中添加的内容结尾不允许有空格,文件中不允许有空行。

  • 同步所有节点配置文件:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    [xisun@hadoop102 hadoop]$ xsync /opt/module/hadoop-3.2.1/etc/hadoop/workers 
    ==================== hadoop102 ====================
    sending incremental file list

    sent 59 bytes received 12 bytes 142.00 bytes/sec
    total size is 30 speedup is 0.42
    ==================== hadoop103 ====================
    sending incremental file list
    workers

    sent 136 bytes received 41 bytes 354.00 bytes/sec
    total size is 30 speedup is 0.17
    ==================== hadoop104 ====================
    sending incremental file list
    workers

    sent 136 bytes received 41 bytes 354.00 bytes/sec
    total size is 30 speedup is 0.17
启动集群
  • 第一步:如果集群是第一次启动,需要在配置了 NameNode 的节点(hadoop102)上格式化 NameNode。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    [xisun@hadoop102 ~]$ hdfs namenode -format
    WARNING: /opt/module/hadoop-3.2.1/logs does not exist. Creating.
    2021-09-01 22:39:39,794 INFO namenode.NameNode: STARTUP_MSG:
    /************************************************************
    STARTUP_MSG: Starting NameNode
    STARTUP_MSG: host = hadoop102/192.168.10.102
    STARTUP_MSG: args = [-format]
    STARTUP_MSG: version = 3.2.1
    STARTUP_MSG: classpath = /opt/module/hadoop-3.2.1/etc/hadoop:…… ……
    STARTUP_MSG: build = https://gitbox.apache.org/repos/asf/hadoop.git -r b3cbbb467e22ea829b3808f4b7b01d07e0bf3842; compiled by 'rohithsharmaks' on 2019-09-10T15:56Z
    STARTUP_MSG: java = 1.8.0_302
    ************************************************************/
    2021-09-01 22:39:40,092 INFO namenode.NameNode: registered UNIX signal handlers for [TERM, HUP, INT]
    2021-09-01 22:39:42,475 INFO namenode.NameNode: createNameNode [-format]
    Formatting using clusterid: CID-ffd49d0a-1e29-4912-91a7-0d6ce7121fda
    2021-09-01 22:39:49,477 INFO namenode.FSEditLog: Edit logging is async:true
    2021-09-01 22:39:52,982 INFO namenode.FSNamesystem: KeyProvider: null
    2021-09-01 22:39:53,002 INFO namenode.FSNamesystem: fsLock is fair: true
    2021-09-01 22:39:53,037 INFO namenode.FSNamesystem: Detailed lock hold time metrics enabled: false
    2021-09-01 22:39:53,112 INFO namenode.FSNamesystem: fsOwner = xisun (auth:SIMPLE)
    2021-09-01 22:39:53,112 INFO namenode.FSNamesystem: supergroup = supergroup
    2021-09-01 22:39:53,113 INFO namenode.FSNamesystem: isPermissionEnabled = true
    2021-09-01 22:39:53,113 INFO namenode.FSNamesystem: HA Enabled: false
    2021-09-01 22:39:54,396 INFO common.Util: dfs.datanode.fileio.profiling.sampling.percentage set to 0. Disabling file IO profiling
    2021-09-01 22:39:54,448 INFO blockmanagement.DatanodeManager: dfs.block.invalidate.limit: configured=1000, counted=60, effected=1000
    2021-09-01 22:39:54,448 INFO blockmanagement.DatanodeManager: dfs.namenode.datanode.registration.ip-hostname-check=true
    2021-09-01 22:39:54,617 INFO blockmanagement.BlockManager: dfs.namenode.startup.delay.block.deletion.sec is set to 000:00:00:00.000
    2021-09-01 22:39:54,618 INFO blockmanagement.BlockManager: The block deletion will start around 2021 九月 01 22:39:54
    2021-09-01 22:39:54,621 INFO util.GSet: Computing capacity for map BlocksMap
    2021-09-01 22:39:54,621 INFO util.GSet: VM type = 64-bit
    2021-09-01 22:39:54,654 INFO util.GSet: 2.0% max memory 441 MB = 8.8 MB
    2021-09-01 22:39:54,654 INFO util.GSet: capacity = 2^20 = 1048576 entries
    2021-09-01 22:39:54,679 INFO blockmanagement.BlockManager: Storage policy satisfier is disabled
    2021-09-01 22:39:54,679 INFO blockmanagement.BlockManager: dfs.block.access.token.enable = false
    2021-09-01 22:39:54,707 INFO Configuration.deprecation: No unit for dfs.namenode.safemode.extension(30000) assuming MILLISECONDS
    2021-09-01 22:39:54,707 INFO blockmanagement.BlockManagerSafeMode: dfs.namenode.safemode.threshold-pct = 0.9990000128746033
    2021-09-01 22:39:54,708 INFO blockmanagement.BlockManagerSafeMode: dfs.namenode.safemode.min.datanodes = 0
    2021-09-01 22:39:54,708 INFO blockmanagement.BlockManagerSafeMode: dfs.namenode.safemode.extension = 30000
    2021-09-01 22:39:54,708 INFO blockmanagement.BlockManager: defaultReplication = 3
    2021-09-01 22:39:54,709 INFO blockmanagement.BlockManager: maxReplication = 512
    2021-09-01 22:39:54,709 INFO blockmanagement.BlockManager: minReplication = 1
    2021-09-01 22:39:54,709 INFO blockmanagement.BlockManager: maxReplicationStreams = 2
    2021-09-01 22:39:54,709 INFO blockmanagement.BlockManager: redundancyRecheckInterval = 3000ms
    2021-09-01 22:39:54,709 INFO blockmanagement.BlockManager: encryptDataTransfer = false
    2021-09-01 22:39:54,709 INFO blockmanagement.BlockManager: maxNumBlocksToLog = 1000
    2021-09-01 22:39:54,794 INFO namenode.FSDirectory: GLOBAL serial map: bits=29 maxEntries=536870911
    2021-09-01 22:39:54,794 INFO namenode.FSDirectory: USER serial map: bits=24 maxEntries=16777215
    2021-09-01 22:39:54,794 INFO namenode.FSDirectory: GROUP serial map: bits=24 maxEntries=16777215
    2021-09-01 22:39:54,794 INFO namenode.FSDirectory: XATTR serial map: bits=24 maxEntries=16777215
    2021-09-01 22:39:54,831 INFO util.GSet: Computing capacity for map INodeMap
    2021-09-01 22:39:54,832 INFO util.GSet: VM type = 64-bit
    2021-09-01 22:39:54,832 INFO util.GSet: 1.0% max memory 441 MB = 4.4 MB
    2021-09-01 22:39:54,832 INFO util.GSet: capacity = 2^19 = 524288 entries
    2021-09-01 22:39:54,833 INFO namenode.FSDirectory: ACLs enabled? false
    2021-09-01 22:39:54,834 INFO namenode.FSDirectory: POSIX ACL inheritance enabled? true
    2021-09-01 22:39:54,834 INFO namenode.FSDirectory: XAttrs enabled? true
    2021-09-01 22:39:54,834 INFO namenode.NameNode: Caching file names occurring more than 10 times
    2021-09-01 22:39:54,847 INFO snapshot.SnapshotManager: Loaded config captureOpenFiles: false, skipCaptureAccessTimeOnlyChange: false, snapshotDiffAllowSnapRootDescendant: true, maxSnapshotLimit: 65536
    2021-09-01 22:39:54,859 INFO snapshot.SnapshotManager: SkipList is disabled
    2021-09-01 22:39:54,868 INFO util.GSet: Computing capacity for map cachedBlocks
    2021-09-01 22:39:54,868 INFO util.GSet: VM type = 64-bit
    2021-09-01 22:39:54,868 INFO util.GSet: 0.25% max memory 441 MB = 1.1 MB
    2021-09-01 22:39:54,868 INFO util.GSet: capacity = 2^17 = 131072 entries
    2021-09-01 22:39:54,899 INFO metrics.TopMetrics: NNTop conf: dfs.namenode.top.window.num.buckets = 10
    2021-09-01 22:39:54,899 INFO metrics.TopMetrics: NNTop conf: dfs.namenode.top.num.users = 10
    2021-09-01 22:39:54,899 INFO metrics.TopMetrics: NNTop conf: dfs.namenode.top.windows.minutes = 1,5,25
    2021-09-01 22:39:54,914 INFO namenode.FSNamesystem: Retry cache on namenode is enabled
    2021-09-01 22:39:54,914 INFO namenode.FSNamesystem: Retry cache will use 0.03 of total heap and retry cache entry expiry time is 600000 millis
    2021-09-01 22:39:54,917 INFO util.GSet: Computing capacity for map NameNodeRetryCache
    2021-09-01 22:39:54,917 INFO util.GSet: VM type = 64-bit
    2021-09-01 22:39:54,917 INFO util.GSet: 0.029999999329447746% max memory 441 MB = 135.5 KB
    2021-09-01 22:39:54,917 INFO util.GSet: capacity = 2^14 = 16384 entries
    2021-09-01 22:39:55,000 INFO namenode.FSImage: Allocated new BlockPoolId: BP-288566776-192.168.10.102-1630507194979
    2021-09-01 22:39:55,144 INFO common.Storage: Storage directory /opt/module/hadoop-3.2.1/data/dfs/name has been successfully formatted.
    2021-09-01 22:39:57,641 INFO namenode.FSImageFormatProtobuf: Saving image file /opt/module/hadoop-3.2.1/data/dfs/name/current/fsimage.ckpt_0000000000000000000 using no compression
    2021-09-01 22:39:58,078 INFO namenode.FSImageFormatProtobuf: Image file /opt/module/hadoop-3.2.1/data/dfs/name/current/fsimage.ckpt_0000000000000000000 of size 400 bytes saved in 0 seconds .
    2021-09-01 22:39:58,126 INFO namenode.NNStorageRetentionManager: Going to retain 1 images with txid >= 0
    2021-09-01 22:39:58,206 INFO namenode.FSImage: FSImageSaver clean checkpoint: txid=0 when meet shutdown.
    2021-09-01 22:39:58,208 INFO namenode.NameNode: SHUTDOWN_MSG:
    /************************************************************
    SHUTDOWN_MSG: Shutting down NameNode at hadoop102/192.168.10.102
    ************************************************************/
    [xisun@hadoop102 ~]$ ll /opt/module/hadoop-3.2.1/
    总用量 180
    drwxr-xr-x. 2 xisun xisun 203 9月 11 2019 bin
    drwxrwxr-x. 3 xisun xisun 17 9月 1 22:39 data
    drwxr-xr-x. 3 xisun xisun 20 9月 10 2019 etc
    drwxr-xr-x. 2 xisun xisun 106 9月 11 2019 include
    drwxr-xr-x. 3 xisun xisun 20 9月 11 2019 lib
    drwxr-xr-x. 4 xisun xisun 288 9月 11 2019 libexec
    -rw-rw-r--. 1 xisun xisun 150569 9月 10 2019 LICENSE.txt
    drwxrwxr-x. 2 xisun xisun 38 9月 1 22:39 logs
    -rw-rw-r--. 1 xisun xisun 22125 9月 10 2019 NOTICE.txt
    -rw-rw-r--. 1 xisun xisun 1361 9月 10 2019 README.txt
    drwxr-xr-x. 3 xisun xisun 4096 9月 10 2019 sbin
    drwxr-xr-x. 4 xisun xisun 31 9月 11 2019 share
    drwxrwxr-x. 2 xisun xisun 22 8月 31 16:00 wcinput
    drwxr-xr-x. 2 xisun xisun 88 8月 31 16:04 wcoutput
    • 格式化 NameNode 完毕后,会在 Hadoop 安装路径下,生成两个新目录 data 和 logs。

    • 注意:第一次格式化 NameNode 之后,如果再次格式化 NameNode 时,会产生新的集群 id,这会导致与前一次生成的 NameNode 和 DataNode 的集群 id 不一致,集群会找不到已往数据。如果集群在运行过程中发生异常,需要重新格式化 NameNode 的话,一定要先停止 namenode 和 datanode 进程(停止 YARN 和 HDFS),并且删除集群上所有机器的 data 和 logs 目录,然后再进行格式化。最后,重新启动集群。原因如下:

      • NameNode 的版本号:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        19
        20
        21
        22
        23
        24
        25
        26
        27
        28
        29
        30
        31
        32
        33
        34
        35
        36
        37
        38
        39
        40
        41
        42
        43
        [xisun@hadoop102 ~]$ cd /opt/module/hadoop-3.2.1/data/dfs/
        [xisun@hadoop102 dfs]$ ll
        总用量 0
        drwx------. 3 xisun xisun 40 9月 2 14:05 data
        drwxrwxr-x. 3 xisun xisun 40 9月 2 14:05 name
        [xisun@hadoop102 dfs]$ cd name/current/
        [xisun@hadoop102 current]$ ll
        总用量 4196
        -rw-rw-r--. 1 xisun xisun 42 9月 1 22:59 edits_0000000000000000001-0000000000000000002
        -rw-rw-r--. 1 xisun xisun 42 9月 1 23:59 edits_0000000000000000003-0000000000000000004
        -rw-rw-r--. 1 xisun xisun 42 9月 2 00:59 edits_0000000000000000005-0000000000000000006
        -rw-rw-r--. 1 xisun xisun 42 9月 2 01:59 edits_0000000000000000007-0000000000000000008
        -rw-rw-r--. 1 xisun xisun 42 9月 2 02:59 edits_0000000000000000009-0000000000000000010
        -rw-rw-r--. 1 xisun xisun 42 9月 2 03:59 edits_0000000000000000011-0000000000000000012
        -rw-rw-r--. 1 xisun xisun 42 9月 2 04:59 edits_0000000000000000013-0000000000000000014
        -rw-rw-r--. 1 xisun xisun 42 9月 2 05:59 edits_0000000000000000015-0000000000000000016
        -rw-rw-r--. 1 xisun xisun 42 9月 2 06:59 edits_0000000000000000017-0000000000000000018
        -rw-rw-r--. 1 xisun xisun 42 9月 2 07:59 edits_0000000000000000019-0000000000000000020
        -rw-rw-r--. 1 xisun xisun 42 9月 2 08:59 edits_0000000000000000021-0000000000000000022
        -rw-rw-r--. 1 xisun xisun 42 9月 2 09:59 edits_0000000000000000023-0000000000000000024
        -rw-rw-r--. 1 xisun xisun 1500 9月 2 10:59 edits_0000000000000000025-0000000000000000045
        -rw-rw-r--. 1 xisun xisun 1048576 9月 2 11:34 edits_0000000000000000046-0000000000000000110
        -rw-rw-r--. 1 xisun xisun 42 9月 2 11:51 edits_0000000000000000111-0000000000000000112
        -rw-rw-r--. 1 xisun xisun 8888 9月 2 12:51 edits_0000000000000000113-0000000000000000185
        -rw-rw-r--. 1 xisun xisun 1048576 9月 2 12:51 edits_0000000000000000186-0000000000000000186
        -rw-rw-r--. 1 xisun xisun 42 9月 2 13:11 edits_0000000000000000187-0000000000000000188
        -rw-rw-r--. 1 xisun xisun 1048576 9月 2 13:18 edits_0000000000000000189-0000000000000000271
        -rw-rw-r--. 1 xisun xisun 42 9月 2 14:06 edits_0000000000000000272-0000000000000000273
        -rw-rw-r--. 1 xisun xisun 1048576 9月 2 14:10 edits_inprogress_0000000000000000274
        -rw-rw-r--. 1 xisun xisun 2460 9月 2 13:11 fsimage_0000000000000000188
        -rw-rw-r--. 1 xisun xisun 62 9月 2 13:11 fsimage_0000000000000000188.md5
        -rw-rw-r--. 1 xisun xisun 2955 9月 2 14:06 fsimage_0000000000000000273
        -rw-rw-r--. 1 xisun xisun 62 9月 2 14:06 fsimage_0000000000000000273.md5
        -rw-rw-r--. 1 xisun xisun 4 9月 2 14:06 seen_txid
        -rw-rw-r--. 1 xisun xisun 217 9月 1 22:39 VERSION
        [xisun@hadoop102 current]$ cat VERSION
        #Wed Sep 01 22:39:55 CST 2021
        namespaceID=817173371
        clusterID=CID-ffd49d0a-1e29-4912-91a7-0d6ce7121fda
        cTime=1630507194979
        storageType=NAME_NODE
        blockpoolID=BP-288566776-192.168.10.102-1630507194979
        layoutVersion=-65
      • DataNode 的版本号:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        [xisun@hadoop102 ~]$ cd /opt/module/hadoop-3.2.1/data/dfs/
        [xisun@hadoop102 dfs]$ ll
        总用量 0
        drwx------. 3 xisun xisun 40 9月 2 14:05 data
        drwxrwxr-x. 3 xisun xisun 40 9月 2 14:05 name
        [xisun@hadoop102 dfs]$ cd data/current/
        [xisun@hadoop102 current]$ ll
        总用量 4
        drwx------. 4 xisun xisun 54 9月 2 14:05 BP-288566776-192.168.10.102-1630507194979
        -rw-rw-r--. 1 xisun xisun 229 9月 2 14:05 VERSION
        [xisun@hadoop102 current]$ cat VERSION
        #Thu Sep 02 14:05:31 CST 2021
        storageID=DS-7c2f6c8b-80be-44b0-9905-f1621843d7a3
        clusterID=CID-ffd49d0a-1e29-4912-91a7-0d6ce7121fda
        cTime=0
        datanodeUuid=32411bd2-079d-42fb-874a-8e5b492824af
        storageType=DATA_NODE
        layoutVersion=-57
      • 集群正常情况下,DataNode 版本与 NameNode 的版本是对应的,如果重新格式化了 NameNode,NameNode 的版本号发生改变,集群上之前存储的 DataNode 下的数据,版本对应不上新的 NameNode,集群也就无法正常启动。因此,格式化 NameNode 之前,需要先删除集群所有机器的 data 和 logs 目录。

        image-20210903165511703

  • 第二步:在 hadoop102 上启动 HDFS。

    1
    2
    3
    4
    5
    6
    [xisun@hadoop102 ~]$ /opt/module/hadoop-3.2.1/sbin/start-dfs.sh 
    Starting namenodes on [hadoop102]
    Starting datanodes
    hadoop103: WARNING: /opt/module/hadoop-3.2.1/logs does not exist. Creating.
    hadoop104: WARNING: /opt/module/hadoop-3.2.1/logs does not exist. Creating.
    Starting secondary namenodes [hadoop104]

    可以直接使用 start-dfs.sh (脚本存放的位置配置在了环境变量里,因此可以在任何路径使用)启动 HDFS。

    • 在 hadoop102 上查看集群进程启动情况:

      1
      2
      3
      4
      [xisun@hadoop102 ~]$ jps
      29008 DataNode
      28885 NameNode
      29365 Jps
    • 在 hadoop103 上查看集群进程启动情况:

      1
      2
      3
      [xisun@hadoop103 ~]$ jps
      23137 DataNode
      23283 Jps
    • 在 hadoop104 上查看集群进程启动情况:

      1
      2
      3
      4
      [xisun@hadoop104 ~]$ jps
      23146 SecondaryNameNode
      23259 Jps
      23023 DataNode
    • Web 端查看 HDFS 的 NameNode,浏览器输入 http://192.168.10.102:9870/ 或者 http://hadoop102:9870/(要求 Windows 电脑上配置了 hadoop102 的主机映射)。

      image-20210901231013153

      image-20210901231122710

  • 第三步:在配置了 ResourceManager 的节点(hadoop103)上启动 YARN。

    1
    2
    3
    [xisun@hadoop103 ~]$ /opt/module/hadoop-3.2.1/sbin/start-yarn.sh 
    Starting resourcemanager
    Starting nodemanagers

    在 hadoop102 上也可以启动 YARN。

    可以直接使用 start-yarn.sh (脚本存放的位置配置在了环境变量里,因此可以在任何路径使用)启动 YARN。

    • 在 hadoop102 上查看集群进程启动情况:

      1
      2
      3
      4
      5
      [xisun@hadoop102 ~]$ jps
      29008 DataNode
      28885 NameNode
      29671 Jps
      29563 NodeManager

      hadoop102 是 NameNode 所在的节点。

    • 在 hadoop103 上查看集群进程启动情况:

      1
      2
      3
      4
      5
      [xisun@hadoop103 ~]$ jps
      23137 DataNode
      23523 ResourceManager
      23646 NodeManager
      23998 Jps

      hadoop103 是 ResourceManager 所在的节点。

    • 在 hadoop104 上查看集群进程启动情况:

      1
      2
      3
      4
      5
      [xisun@hadoop104 ~]$ jps
      23602 Jps
      23480 NodeManager
      23146 SecondaryNameNode
      23023 DataNode

      hadoop104 是 SecondaryNameNode 所在的节点。

    • Web 端查看 YARN 的 ResourceManager,浏览器输入 http://192.168.10.103:8088/ 或者 http://hadoop103:8088/(要求 Windows 电脑上配置了 hadoop103 的主机映射)。

      image-20210901232124548

集群基本测试
  • 上传文件到集群

    • 上传小文件

      1
      2
      3
      [xisun@hadoop102 ~]$ hdfs dfs -mkdir /wcinput
      [xisun@hadoop102 ~]$ hdfs dfs -put /opt/module/hadoop-3.2.1/wcinput/word.txt /wcinput
      2021-09-02 10:14:15,604 INFO sasl.SaslDataTransferClient: SASL encryption trust check: localHostTrusted = false, remoteHostTrusted = false
      • 在 Web 端查看 HDFS,根目录下新建了一个 wcinput 目录,wcinput 目录下也上传了一个 word.txt 文件:

        image-20210902101737216

        image-20210902101938588

        image-20210902102355046

      • 说明:如果需要在 Web 页面上删除 HDFS 上的文件,需要配置 core-site.xml,添加如下配置,然后集群分发 core-site.xml 文件,并重新启动集群。否则没有权限删除。

        image-20210903145651737

        1
        2
        3
        4
        5
        <!-- 配置HDFS网页登录使用的静态用户为atguigu -->
        <property>
        <name>hadoop.http.staticuser.user</name>
        <value>xisun</value>
        </property>
    • 上传大文件

      1
      2
      3
      4
      [xisun@hadoop102 ~]$ hdfs dfs -put /opt/software/hadoop-3.2.1.tar.gz /
      2021-09-02 10:41:41,346 INFO sasl.SaslDataTransferClient: SASL encryption trust check: localHostTrusted = false, remoteHostTrusted = false
      2021-09-02 10:43:40,782 INFO sasl.SaslDataTransferClient: SASL encryption trust check: localHostTrusted = false, remoteHostTrusted = false
      2021-09-02 10:44:58,477 INFO sasl.SaslDataTransferClient: SASL encryption trust check: localHostTrusted = false, remoteHostTrusted = false

      image-20210902104359318

  • 集群上文件的存储位置

    • 查看 HDFS 文件存储路径

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      [xisun@hadoop102 ~]$ cd /opt/module/hadoop-3.2.1/data/
      [xisun@hadoop102 data]$ pwd
      /opt/module/hadoop-3.2.1/data
      [xisun@hadoop102 data]$ ll
      总用量 0
      drwxrwxr-x. 4 xisun xisun 30 9月 1 22:58 dfs
      drwxr-xr-x. 5 xisun xisun 57 9月 1 23:15 nm-local-dir
      [xisun@hadoop102 data]$ cd dfs/
      [xisun@hadoop102 dfs]$ ll
      总用量 0
      drwx------. 3 xisun xisun 40 9月 1 22:58 data
      drwxrwxr-x. 3 xisun xisun 40 9月 1 22:58 name
      [xisun@hadoop102 dfs]$ cd data/
      [xisun@hadoop102 data]$ ll
      总用量 4
      drwxrwxr-x. 3 xisun xisun 70 9月 1 22:58 current
      -rw-rw-r--. 1 xisun xisun 15 9月 1 22:58 in_use.lock
      [xisun@hadoop102 data]$ cd current/BP-288566776-192.168.10.102-1630507194979/
      current/ tmp/
      [xisun@hadoop102 data]$ cd current/BP-288566776-192.168.10.102-1630507194979/current/
      finalized/ rbw/
      [xisun@hadoop102 data]$ cd current/BP-288566776-192.168.10.102-1630507194979/current/finalized/subdir0/subdir0/
      [xisun@hadoop102 subdir0]$ pwd
      /opt/module/hadoop-3.2.1/data/dfs/data/current/BP-288566776-192.168.10.102-1630507194979/current/finalized/subdir0/subdir0
      [xisun@hadoop102 subdir0]$ ll
      总用量 353540
      -rw-rw-r--. 1 xisun xisun 41 9月 2 10:14 blk_1073741825
      -rw-rw-r--. 1 xisun xisun 11 9月 2 10:14 blk_1073741825_1001.meta
      -rw-rw-r--. 1 xisun xisun 134217728 9月 2 10:43 blk_1073741826
      -rw-rw-r--. 1 xisun xisun 1048583 9月 2 10:43 blk_1073741826_1002.meta
      -rw-rw-r--. 1 xisun xisun 134217728 9月 2 10:44 blk_1073741827
      -rw-rw-r--. 1 xisun xisun 1048583 9月 2 10:44 blk_1073741827_1003.meta
      -rw-rw-r--. 1 xisun xisun 90761455 9月 2 10:45 blk_1073741828
      -rw-rw-r--. 1 xisun xisun 709083 9月 2 10:45 blk_1073741828_1004.meta
    • 查看 HDFS 在磁盘存储的 word.txt 文件的内容,可以看出,blk_1073741825 就是之前上传的 word.txt 文件。

      1
      2
      3
      4
      5
      [xisun@hadoop102 subdir0]$ cat blk_1073741825
      hadoop yarn
      hadoop mapreduce
      xisun
      xisun
    • 拼接 HDFS 在磁盘存储的 hadoop-3.2.1.tar.gz 文件的内容,追加到临时的压缩文件中,解压之后可以看出,blk_1073741826,blk_1073741827 和 blk_1073741828 就是之前上传的 hadoop-3.2.1.tar.gz 压缩文件。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      [xisun@hadoop102 subdir0]$ cat blk_1073741826 >> ~/tmp.tar.gz
      [xisun@hadoop102 subdir0]$ cat blk_1073741827 >> ~/tmp.tar.gz
      [xisun@hadoop102 subdir0]$ cat blk_1073741828 >> ~/tmp.tar.gz
      [xisun@hadoop102 subdir0]$ cd ~
      [xisun@hadoop102 ~]$ ll
      总用量 393216
      drwxrwxr-x. 2 xisun xisun 19 9月 1 13:33 bin
      -rw-rw-r--. 1 xisun xisun 359196911 9月 2 11:00 tmp.tar.gz
      drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 公共
      drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 模板
      drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 视频
      drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 图片
      drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 文档
      drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 下载
      drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 音乐
      drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 桌面
      [xisun@hadoop102 ~]$ tar -zxf tmp.tar.gz
      [xisun@hadoop102 ~]$ ll
      总用量 393216
      drwxrwxr-x. 2 xisun xisun 19 9月 1 13:33 bin
      drwxr-xr-x. 9 xisun xisun 149 9月 11 2019 hadoop-3.2.1
      -rw-rw-r--. 1 xisun xisun 359196911 9月 2 11:00 tmp.tar.gz
      drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 公共
      drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 模板
      drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 视频
      drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 图片
      drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 文档
      drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 下载
      drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 音乐
      drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 桌面
      • 说明:HDFS 在磁盘上存储的文件,可能是分散的,需要了解分散到哪些文件了,才能追加拼接。

        image-20210903150350257

        image-20210903150602428

    • HDFS 上的文件是备份在集群的每一台服务器上的(也就是集群的每一台服务器,都是 DataNode),在 hadoop102,hadoop103 和 hadoop104 上相同的路径下,都有相同的数据备份。

      image-20210902111343188

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      [xisun@hadoop102 subdir0]$ pwd
      /opt/module/hadoop-3.2.1/data/dfs/data/current/BP-288566776-192.168.10.102-1630507194979/current/finalized/subdir0/subdir0
      [xisun@hadoop102 subdir0]$ ll
      总用量 353540
      -rw-rw-r--. 1 xisun xisun 41 9月 2 10:14 blk_1073741825
      -rw-rw-r--. 1 xisun xisun 11 9月 2 10:14 blk_1073741825_1001.meta
      -rw-rw-r--. 1 xisun xisun 134217728 9月 2 10:43 blk_1073741826
      -rw-rw-r--. 1 xisun xisun 1048583 9月 2 10:43 blk_1073741826_1002.meta
      -rw-rw-r--. 1 xisun xisun 134217728 9月 2 10:44 blk_1073741827
      -rw-rw-r--. 1 xisun xisun 1048583 9月 2 10:44 blk_1073741827_1003.meta
      -rw-rw-r--. 1 xisun xisun 90761455 9月 2 10:45 blk_1073741828
      -rw-rw-r--. 1 xisun xisun 709083 9月 2 10:45 blk_1073741828_1004.meta
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      [xisun@hadoop103 subdir0]$ pwd
      /opt/module/hadoop-3.2.1/data/dfs/data/current/BP-288566776-192.168.10.102-1630507194979/current/finalized/subdir0/subdir0
      [xisun@hadoop103 subdir0]$ ll
      总用量 353540
      -rw-rw-r--. 1 xisun xisun 41 9月 2 10:14 blk_1073741825
      -rw-rw-r--. 1 xisun xisun 11 9月 2 10:14 blk_1073741825_1001.meta
      -rw-rw-r--. 1 xisun xisun 134217728 9月 2 10:43 blk_1073741826
      -rw-rw-r--. 1 xisun xisun 1048583 9月 2 10:43 blk_1073741826_1002.meta
      -rw-rw-r--. 1 xisun xisun 134217728 9月 2 10:44 blk_1073741827
      -rw-rw-r--. 1 xisun xisun 1048583 9月 2 10:44 blk_1073741827_1003.meta
      -rw-rw-r--. 1 xisun xisun 90761455 9月 2 10:45 blk_1073741828
      -rw-rw-r--. 1 xisun xisun 709083 9月 2 10:45 blk_1073741828_1004.meta
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      [xisun@hadoop104 subdir0]$ pwd
      /opt/module/hadoop-3.2.1/data/dfs/data/current/BP-288566776-192.168.10.102-1630507194979/current/finalized/subdir0/subdir0
      [xisun@hadoop104 subdir0]$ ll
      总用量 353540
      -rw-rw-r--. 1 xisun xisun 41 9月 2 10:14 blk_1073741825
      -rw-rw-r--. 1 xisun xisun 11 9月 2 10:14 blk_1073741825_1001.meta
      -rw-rw-r--. 1 xisun xisun 134217728 9月 2 10:43 blk_1073741826
      -rw-rw-r--. 1 xisun xisun 1048583 9月 2 10:43 blk_1073741826_1002.meta
      -rw-rw-r--. 1 xisun xisun 134217728 9月 2 10:44 blk_1073741827
      -rw-rw-r--. 1 xisun xisun 1048583 9月 2 10:44 blk_1073741827_1003.meta
      -rw-rw-r--. 1 xisun xisun 90761455 9月 2 10:45 blk_1073741828
      -rw-rw-r--. 1 xisun xisun 709083 9月 2 10:45 blk_1073741828_1004.meta
  • 从集群下载文件到本地

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    [xisun@hadoop102 ~]$ pwd
    /home/xisun
    [xisun@hadoop102 ~]$ ll
    总用量 0
    drwxrwxr-x. 2 xisun xisun 19 9月 1 13:33 bin
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 公共
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 模板
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 视频
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 图片
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 文档
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 下载
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 音乐
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 桌面
    [xisun@hadoop102 ~]$ hadoop fs -get /wcinput/word.txt ./
    2021-09-02 11:24:37,690 INFO sasl.SaslDataTransferClient: SASL encryption trust check: localHostTrusted = false, remoteHostTrusted = false
    [xisun@hadoop102 ~]$ ll
    总用量 4
    drwxrwxr-x. 2 xisun xisun 19 9月 1 13:33 bin
    -rw-r--r--. 1 xisun xisun 41 9月 2 11:24 word.txt
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 公共
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 模板
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 视频
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 图片
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 文档
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 下载
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 音乐
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 桌面
    [xisun@hadoop102 ~]$ cat word.txt
    hadoop yarn
    hadoop mapreduce
    xisun
  • 执行 wordcount 程序,查看 YARN 的执行情况。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    [xisun@hadoop102 ~]$ hadoop jar /opt/module/hadoop-3.2.1/share/hadoop/mapreduce/hadoop-mapreduce-examples-3.2.1.jar wordcount /wcinput /wcoutput
    2021-09-02 13:15:36,538 INFO client.RMProxy: Connecting to ResourceManager at hadoop103/192.168.10.103:8032
    2021-09-02 13:15:36,985 INFO mapreduce.JobResourceUploader: Disabling Erasure Coding for path: /tmp/hadoop-yarn/staging/xisun/.staging/job_1630509320297_0004
    2021-09-02 13:15:37,189 INFO sasl.SaslDataTransferClient: SASL encryption trust check: localHostTrusted = false, remoteHostTrusted = false
    2021-09-02 13:15:38,237 INFO input.FileInputFormat: Total input files to process : 1
    2021-09-02 13:15:38,317 INFO sasl.SaslDataTransferClient: SASL encryption trust check: localHostTrusted = false, remoteHostTrusted = false
    2021-09-02 13:15:38,407 INFO sasl.SaslDataTransferClient: SASL encryption trust check: localHostTrusted = false, remoteHostTrusted = false
    2021-09-02 13:15:38,456 INFO mapreduce.JobSubmitter: number of splits:1
    2021-09-02 13:15:38,608 INFO sasl.SaslDataTransferClient: SASL encryption trust check: localHostTrusted = false, remoteHostTrusted = false
    2021-09-02 13:15:38,673 INFO mapreduce.JobSubmitter: Submitting tokens for job: job_1630509320297_0004
    2021-09-02 13:15:38,673 INFO mapreduce.JobSubmitter: Executing with tokens: []
    2021-09-02 13:15:38,887 INFO conf.Configuration: resource-types.xml not found
    2021-09-02 13:15:38,887 INFO resource.ResourceUtils: Unable to find 'resource-types.xml'.
    2021-09-02 13:15:38,964 INFO impl.YarnClientImpl: Submitted application application_1630509320297_0004
    2021-09-02 13:15:39,063 INFO mapreduce.Job: The url to track the job: http://hadoop103:8088/proxy/application_1630509320297_0004/
    2021-09-02 13:15:39,063 INFO mapreduce.Job: Running job: job_1630509320297_0004
    2021-09-02 13:15:48,877 INFO mapreduce.Job: Job job_1630509320297_0004 running in uber mode : false
    2021-09-02 13:15:48,879 INFO mapreduce.Job: map 0% reduce 0%
    2021-09-02 13:17:39,986 INFO mapreduce.Job: map 100% reduce 0%
    2021-09-02 13:18:46,452 INFO mapreduce.Job: map 100% reduce 100%
    2021-09-02 13:18:48,469 INFO mapreduce.Job: Job job_1630509320297_0004 completed successfully
    2021-09-02 13:18:48,743 INFO mapreduce.Job: Counters: 54
    File System Counters
    FILE: Number of bytes read=58
    FILE: Number of bytes written=452423
    FILE: Number of read operations=0
    FILE: Number of large read operations=0
    FILE: Number of write operations=0
    HDFS: Number of bytes read=144
    HDFS: Number of bytes written=36
    HDFS: Number of read operations=8
    HDFS: Number of large read operations=0
    HDFS: Number of write operations=2
    HDFS: Number of bytes read erasure-coded=0
    Job Counters
    Launched map tasks=1
    Launched reduce tasks=1
    Data-local map tasks=1
    Total time spent by all maps in occupied slots (ms)=108569
    Total time spent by all reduces in occupied slots (ms)=63584
    Total time spent by all map tasks (ms)=108569
    Total time spent by all reduce tasks (ms)=63584
    Total vcore-milliseconds taken by all map tasks=108569
    Total vcore-milliseconds taken by all reduce tasks=63584
    Total megabyte-milliseconds taken by all map tasks=111174656
    Total megabyte-milliseconds taken by all reduce tasks=65110016
    Map-Reduce Framework
    Map input records=4
    Map output records=6
    Map output bytes=65
    Map output materialized bytes=58
    Input split bytes=103
    Combine input records=6
    Combine output records=4
    Reduce input groups=4
    Reduce shuffle bytes=58
    Reduce input records=4
    Reduce output records=4
    Spilled Records=8
    Shuffled Maps =1
    Failed Shuffles=0
    Merged Map outputs=1
    GC time elapsed (ms)=11835
    CPU time spent (ms)=68260
    Physical memory (bytes) snapshot=507523072
    Virtual memory (bytes) snapshot=5576531968
    Total committed heap usage (bytes)=404226048
    Peak Map Physical memory (bytes)=297627648
    Peak Map Virtual memory (bytes)=2785103872
    Peak Reduce Physical memory (bytes)=209895424
    Peak Reduce Virtual memory (bytes)=2791428096
    Shuffle Errors
    BAD_ID=0
    CONNECTION=0
    IO_ERROR=0
    WRONG_LENGTH=0
    WRONG_MAP=0
    WRONG_REDUCE=0
    File Input Format Counters
    Bytes Read=41
    File Output Format Counters
    Bytes Written=36
    • 查看执行结果:

      image-20210902132243410

    • 执行时异常的排除:在初次执行时,报异常 错误: 找不到或无法加载主类 org.apache.hadoop.mapreduce.v2.app.MRAppMaster,解决方法是停止集群,然后向 yarn-site.xml 配置文件中,添加一个属性值。然后,重新运行 wordcount 程序,即能正常执行。

      • 停止集群:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        [xisun@hadoop102 ~]$ stop-yarn.sh 
        Stopping nodemanagers
        hadoop103: WARNING: nodemanager did not stop gracefully after 5 seconds: Trying to kill with kill -9
        hadoop104: WARNING: nodemanager did not stop gracefully after 5 seconds: Trying to kill with kill -9
        hadoop102: WARNING: nodemanager did not stop gracefully after 5 seconds: Trying to kill with kill -9
        Stopping resourcemanager
        [xisun@hadoop102 ~]$ stop-dfs.sh
        Stopping namenodes on [hadoop102]
        Stopping datanodes
        Stopping secondary namenodes [hadoop104]
        [xisun@hadoop102 ~]$ jps
        42220 Jps
      • 配置 yarn-site.xml,添加 yarn.application.classpath 属性值:

        1
        2
        3
        [xisun@hadoop102 hadoop]$ hadoop classpath
        /opt/module/hadoop-3.2.1/etc/hadoop:/opt/module/hadoop-3.2.1/share/hadoop/common/lib/*:/opt/module/hadoop-3.2.1/share/hadoop/common/*:/opt/module/hadoop-3.2.1/share/hadoop/hdfs:/opt/module/hadoop-3.2.1/share/hadoop/hdfs/lib/*:/opt/module/hadoop-3.2.1/share/hadoop/hdfs/*:/opt/module/hadoop-3.2.1/share/hadoop/mapreduce/lib/*:/opt/module/hadoop-3.2.1/share/hadoop/mapreduce/*:/opt/module/hadoop-3.2.1/share/hadoop/yarn:/opt/module/hadoop-3.2.1/share/hadoop/yarn/lib/*:/opt/module/hadoop-3.2.1/share/hadoop/yarn/*
        [xisun@hadoop102 hadoop]$ vim yarn-site.xml
        1
        2
        3
        4
        <property>
        <name>yarn.application.classpath</name>
        <value>/opt/module/hadoop-3.2.1/etc/hadoop:/opt/module/hadoop-3.2.1/share/hadoop/common/lib/*:/opt/module/hadoop-3.2.1/share/hadoop/common/*:/opt/module/hadoop-3.2.1/share/hadoop/hdfs:/opt/module/hadoop-3.2.1/share/hadoop/hdfs/lib/*:/opt/module/hadoop-3.2.1/share/hadoop/hdfs/*:/opt/module/hadoop-3.2.1/share/hadoop/mapreduce/lib/*:/opt/module/hadoop-3.2.1/share/hadoop/mapreduce/*:/opt/module/hadoop-3.2.1/share/hadoop/yarn:/opt/module/hadoop-3.2.1/share/hadoop/yarn/lib/*:/opt/module/hadoop-3.2.1/share/hadoop/yarn/*</value>
        </property>
      • 分发 yarn-site.xml 到集群所有主机上:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        17
        18
        [xisun@hadoop102 ~]$ xsync /opt/module/hadoop-3.2.1/etc/hadoop/yarn-site.xml 
        ==================== hadoop102 ====================
        sending incremental file list

        sent 66 bytes received 12 bytes 156.00 bytes/sec
        total size is 1,621 speedup is 20.78
        ==================== hadoop103 ====================
        sending incremental file list
        yarn-site.xml

        sent 1,038 bytes received 47 bytes 434.00 bytes/sec
        total size is 1,621 speedup is 1.49
        ==================== hadoop104 ====================
        sending incremental file list
        yarn-site.xml

        sent 1,038 bytes received 47 bytes 2,170.00 bytes/sec
        total size is 1,621 speedup is 1.49
      • 启动集群:

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        [xisun@hadoop102 hadoop]$ start-dfs.sh 
        Starting namenodes on [hadoop102]
        Starting datanodes
        Starting secondary namenodes [hadoop104]
        [xisun@hadoop102 hadoop]$ start-yarn.sh
        Starting resourcemanager
        Starting nodemanagers
        [xisun@hadoop102 hadoop]$ jps
        42544 NameNode
        43346 Jps
        42680 DataNode
        43177 NodeManager
    • 与本地模式执行 wordcount 一样,HDFS 上不能已经存在 /wcoutput 目录,否则报错。如果已经存在,则需要删除:

      1
      2
      [xisun@hadoop102 ~]$ hdfs dfs -rm -r /wcoutput
      Deleted /wcoutput

配置历史服务器

  • 为了查看程序的历史运行情况,需要配置一下历史服务器。

  • 第一步:编辑 mapred-site.xml,增加历史服务器的配置。

    1
    [xisun@hadoop102 ~]$ vim /opt/module/hadoop-3.2.1/etc/hadoop/mapred-site.xml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    <!-- 历史服务器端地址 -->
    <property>
    <name>mapreduce.jobhistory.address</name>
    <value>hadoop102:10020</value>
    </property>

    <!-- 历史服务器Web端地址 -->
    <property>
    <name>mapreduce.jobhistory.webapp.address</name>
    <value>hadoop102:19888</value>
    </property>
  • 第二步:集群分发 mapred-site.xml。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    [xisun@hadoop102 ~]$ xsync /opt/module/hadoop-3.2.1/etc/hadoop/mapred-site.xml 
    ==================== hadoop102 ====================
    sending incremental file list

    sent 67 bytes received 12 bytes 158.00 bytes/sec
    total size is 1,229 speedup is 15.56
    ==================== hadoop103 ====================
    sending incremental file list
    mapred-site.xml

    sent 647 bytes received 47 bytes 462.67 bytes/sec
    total size is 1,229 speedup is 1.77
    ==================== hadoop104 ====================
    sending incremental file list
    mapred-site.xml

    sent 647 bytes received 47 bytes 1,388.00 bytes/sec
    total size is 1,229 speedup is 1.77
  • 第三步:在 hadoop102 上启动历史服务器。

    1
    2
    3
    4
    5
    6
    7
    [xisun@hadoop102 ~]$ mapred --daemon start historyserver
    [xisun@hadoop102 ~]$ jps
    47605 Jps
    46106 NodeManager
    45612 DataNode
    47564 JobHistoryServer
    45485 NameNode
  • 第四步:重新运行一次 wordcount(需要先删除 HDFS 上的 /wcoutput),查看任务的历史日志。

    image-20210902152328283

    image-20210902152507027

配置日志的聚集

  • 日志聚集概念:应用运行完成以后,将程序运行日志信息上传到 HDFS 系统上。

    image-20210902153939242

  • 如果不配置日志聚集,在 Web 端查看历史日志时,点击 logs 会无法查看(程序的运行日志,可能会分布在集群的各个机器上)。

    image-20210902153854565

  • 日志聚集功能好处:可以方便的查看到程序运行详情,方便开发调试。

  • 第一步:编辑 yarn-site.xml,添加日志聚集的配置。

    1
    [xisun@hadoop102 ~]$ vim /opt/module/hadoop-3.2.1/etc/hadoop/yarn-site.xml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    <!-- 开启日志聚集功能,默认不开启 -->
    <property>
    <name>yarn.log-aggregation-enable</name>
    <value>true</value>
    </property>

    <!-- 设置日志聚集服务器地址 -->
    <property>
    <name>yarn.log.server.url</name>
    <value>http://hadoop102:19888/jobhistory/logs</value>
    </property>

    <!-- 设置日志保留时间为7天 -->
    <property>
    <name>yarn.log-aggregation.retain-seconds</name>
    <value>604800</value>
    </property>
  • 第二步:集群分发 yarn-site.xml 文件。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    [xisun@hadoop102 ~]$ xsync /opt/module/hadoop-3.2.1/etc/hadoop/yarn-site.xml 
    ==================== hadoop102 ====================
    sending incremental file list

    sent 66 bytes received 12 bytes 156.00 bytes/sec
    total size is 2,115 speedup is 27.12
    ==================== hadoop103 ====================
    sending incremental file list
    yarn-site.xml

    sent 836 bytes received 53 bytes 1,778.00 bytes/sec
    total size is 2,115 speedup is 2.38
    ==================== hadoop104 ====================
    sending incremental file list
    yarn-site.xml

    sent 836 bytes received 53 bytes 1,778.00 bytes/sec
    total size is 2,115 speedup is 2.38
  • 第三步:重新启动 NodeManager 、ResourceManager 和 HistoryServer。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    [xisun@hadoop102 ~]$ mapred --daemon stop historyserver
    [xisun@hadoop102 ~]$ stop-yarn.sh
    Stopping nodemanagers
    hadoop102: WARNING: nodemanager did not stop gracefully after 5 seconds: Trying to kill with kill -9
    hadoop104: WARNING: nodemanager did not stop gracefully after 5 seconds: Trying to kill with kill -9
    hadoop103: WARNING: nodemanager did not stop gracefully after 5 seconds: Trying to kill with kill -9
    Stopping resourcemanager
    [xisun@hadoop102 ~]$ jps
    48872 Jps
    45612 DataNode
    45485 NameNode
    [xisun@hadoop102 ~]$ start-yarn.sh
    Starting resourcemanager
    Starting nodemanagers
    [xisun@hadoop102 ~]$ mapred --daemon start historyserver
    [xisun@hadoop102 ~]$ jps
    49696 Jps
    49636 JobHistoryServer
    45612 DataNode
    45485 NameNode
    49134 NodeManager
  • 第四步:重新运行一次 wordcount(需要先删除 HDFS 上的 /wcoutput),查看任务的历史日志。

    image-20210902165115208

集群启动/停止方式总结

  • 各个模块分开启动/停止(配置 ssh 是前提)— 常用

    • 整体启动/停止 HDFS

      1
      [xisun@hadoop102 ~]$ start-dfs.sh
      1
      [xisun@hadoop102 ~]$ stop-dfs.sh
    • 整体启动/停止 YARN

      1
      [xisun@hadoop102 ~]$ start-yarn.sh 
      1
      [xisun@hadoop102 ~]$ stop-yarn.sh 
  • 各个服务组件逐一启动/停止

    • 分别启动/停止 HDFS 组件

      1
      [xisun@hadoop102 ~]$ hdfs --daemon start namenode/datanode/secondarynamenode
      1
      [xisun@hadoop102 ~]$ hdfs --daemon stop namenode/datanode/secondarynamenode
    • 启动/停止 YARN

      1
      [xisun@hadoop102 ~]$ yarn --daemon start  resourcemanager/nodemanager
      1
      [xisun@hadoop102 ~]$ yarn --daemon stop  resourcemanager/nodemanager

编写 Hadoop 集群常用脚本

  • Hadoop 集群启停脚本(包含 HDFS,Yarn 和 Historyserver):myhadoop.sh

    • 编写脚本:

      1
      2
      3
      [xisun@hadoop102 bin]$ pwd
      /home/xisun/bin
      [xisun@hadoop102 bin]$ vim myhadoop.sh
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      #!/bin/bash

      if [ $# -lt 1 ]
      then
      echo "No Args Input..."
      exit ;
      fi

      case $1 in
      "start")
      echo " =================== 启动 hadoop集群 ==================="

      echo " ------------------- 启动 hdfs ---------------"
      ssh hadoop102 "/opt/module/hadoop-3.2.1/sbin/start-dfs.sh"
      echo " --------------- 启动 yarn ---------------"
      ssh hadoop103 "/opt/module/hadoop-3.2.1/sbin/start-yarn.sh"
      echo " --------------- 启动 historyserver ---------------"
      ssh hadoop102 "/opt/module/hadoop-3.2.1/bin/mapred --daemon start historyserver"
      ;;
      "stop")
      echo " =================== 关闭 hadoop集群 ==================="

      echo " --------------- 关闭 historyserver ---------------"
      ssh hadoop102 "/opt/module/hadoop-3.2.1/bin/mapred --daemon stop historyserver"
      echo " --------------- 关闭 yarn ---------------"
      ssh hadoop103 "/opt/module/hadoop-3.2.1/sbin/stop-yarn.sh"
      echo " --------------- 关闭 hdfs ---------------"
      ssh hadoop102 "/opt/module/hadoop-3.2.1/sbin/stop-dfs.sh"
      ;;
      *)
      echo "Input Args Error..."
      ;;
      esac

      在脚本中,使用全路径,如:/opt/module/hadoop-3.2.1/sbin/start-dfs.sh,不要使用 start-dfs.sh

    • 赋予脚本执行权限:

      1
      [xisun@hadoop102 bin]$ chmod 777 myhadoop.sh
    • 测试脚本停止集群:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      [xisun@hadoop102 ~]$ myhadoop.sh stop
      =================== 关闭 hadoop集群 ===================
      --------------- 关闭 historyserver ---------------
      --------------- 关闭 yarn ---------------
      Stopping nodemanagers
      Stopping resourcemanager
      --------------- 关闭 hdfs ---------------
      Stopping namenodes on [hadoop102]
      Stopping datanodes
      Stopping secondary namenodes [hadoop104]
      [xisun@hadoop102 ~]$ jps
      51019 Jps
    • 测试脚本启动集群:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      [xisun@hadoop102 ~]$ myhadoop.sh start
      =================== 启动 hadoop集群 ===================
      --------------- 启动 hdfs ---------------
      Starting namenodes on [hadoop102]
      Starting datanodes
      Starting secondary namenodes [hadoop104]
      --------------- 启动 yarn ---------------
      Starting resourcemanager
      Starting nodemanagers
      --------------- 启动 historyserver ---------------
      [xisun@hadoop102 ~]$ jps
      51666 NodeManager
      51209 NameNode
      51339 DataNode
      51917 Jps
      51839 JobHistoryServer
  • 查看三台服务器 Java 进程脚本:jpsall

    • 编写脚本:

      1
      2
      3
      4
      5
      6
      7
      #!/bin/bash

      for host in hadoop102 hadoop103 hadoop104
      do
      echo =============== $host ===============
      ssh $host jps
      done
      1
      2
      3
      4
      5
      6
      7
      #!/bin/bash

      for host in hadoop102 hadoop103 hadoop104
      do
      echo =============== $host ===============
      ssh $host jps
      done
    • 赋予脚本执行权限:

      1
      [xisun@hadoop102 bin]$ chmod 777 jpsall
    • 测试脚本:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      [xisun@hadoop102 ~]$ jpsall 
      =============== hadoop102 ===============
      51666 NodeManager
      51209 NameNode
      51339 DataNode
      51979 Jps
      51839 JobHistoryServer
      =============== hadoop103 ===============
      40195 Jps
      39492 DataNode
      39800 NodeManager
      39677 ResourceManager
      =============== hadoop104 ===============
      40920 NodeManager
      40809 SecondaryNameNode
      41081 Jps
      40699 DataNode
  • 分发 hadoop102 上的 /home/xisun/bin 目录,保证自定义脚本在集群的所有机器上都可以使用。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    [xisun@hadoop102 ~]$ xsync /home/xisun/bin/
    ==================== hadoop102 ====================
    sending incremental file list

    sent 139 bytes received 17 bytes 312.00 bytes/sec
    total size is 2,175 speedup is 13.94
    ==================== hadoop103 ====================
    sending incremental file list
    bin/
    bin/jpsall
    bin/myhadoop.sh

    sent 1,499 bytes received 58 bytes 3,114.00 bytes/sec
    total size is 2,175 speedup is 1.40
    ==================== hadoop104 ====================
    sending incremental file list
    bin/
    bin/jpsall
    bin/myhadoop.sh

    sent 1,499 bytes received 58 bytes 3,114.00 bytes/sec
    total size is 2,175 speedup is 1.40

常用端口号和配置文件说明

  • 常用端口号

    端口名称 Hadoop 2.x Hadoop 3.x
    HDFS NameNode 内部通信端口 8020 / 9000 8020 / 9000 / 9820
    HDFS NameNode HTTP UI
    (对用户的查询端口)
    50070 9870
    YARN MapReduce 查看执行任务端口 8088 8088
    历史服务器通信端口 19888 19888
  • 常用配置文件

    • Hadoop 2.x:core-site.xml,hdfs-site.xml,yarn-site.xml,mapred-site.xml,slaves。
    • Hadoop 3.x:core-site.xml,hdfs-site.xml,yarn-site.xml,mapred-site.xml,workers。

集群时间同步

  • 如果服务器在公网环境(能连接外网),可以不采用集群时间同步,因为服务器会定期和公网时间进行校准。
  • 如果服务器在内网环境,必须要配置集群时间同步,否则时间久了,会产生时间偏差,导致集群执行任务时间不同步。
  • 配置过程略。

HDFS 概述

HDFS 产生背景及定义

HDFS 产生背景

  • 随着数据量越来越大,在一个操作系统存不下所有的数据,那么就分配到更多的操作系统管理的磁盘中,但是不方便管理和维护,迫切需要一种系统来管理多台机器上的文件,这就是分布式文件管理系统。HDFS 只是分布式文件管理系统中的一种。

    • 个人电脑上的磁盘,是 NTFS 文件管理系统。

      image-20210903163243434

HDFS 定义

  • HDFS(Hadoop Distributed File System),它是一个文件系统,用于存储文件,通过目录树来定位文件;其次,它是分布式的,由很多服务器联合起来实现其功能,集群中的服务器有各自的角色。
  • HDFS 的使用场景:适合一次写入,多次读出的场景。一个文件经过创建、写入和关闭之后就不需要改变。

HDFS 优缺点

HDFS 优点

  • 高容错性

    • 数据自动保存多个副本。它通过增加副本的形式,提高容错性。

      image-20210903165715516

    • 某一个副本丢失以后,它可以自动恢复。

      image-20210903165748149

  • 适合处理大数据

    • 数据规模:能够处理数据规模达到 GB、TB、甚至 PB 级别的数据。
    • 文件规模:能够处理百万规模以上的文件数量,数量相当之大。
  • 可构建在廉价机器上,通过多副本机制,提高可靠性。

HDFS 缺点

  • 不适合低延时数据访问,比如毫秒级的存储数据,是做不到的。

  • 无法高效的对大量小文件进行存储。

    • 存储大量小文件的话,它会占用 NameNode 大量的内存来存储文件目录和块信息。这样是不可取的,因为 NameNode 的内存总是有限的。
    • 小文件存储的寻址时间会超过读取时间,它违反了 HDFS 的设计目标。
  • 不支持并发写入、文件随机修改。

    • 一个文件只能有一个写,不允许多个线程同时写。

      image-20210903170115237

    • 仅支持数据 append(追加),不支持文件的随机修改。

HDFS 组成架构

  • 官方文档:https://hadoop.apache.org/docs/

  • hadoop-3.2.1 HDFS 文档:https://hadoop.apache.org/docs/r3.2.1/hadoop-project-dist/hadoop-hdfs/HdfsDesign.html

  • HDFS 组成架构:

    image-20210903170728742

    • NameNode:nn,就是 Master,它是一个主管、管理者。
      • 管理 HDFS 的名称空间;
      • 配置副本策略;
      • 管理数据块(Block)映射信息;
      • 处理客户端读写请求。
    • DataNode:就是 Slave。NameNode下达命令,DataNode 执行实际的操作。
      • 存储实际的数据块;
      • 执行数据块的读/写操作。
  • Client:就是客户端。比如,Web 打开的 Browse Directory 页面就是一个客户端,能够对 HDFS 进行操作。

    • 文件切分。文件上传到 HDFS 的时候,Client 将文件切分成一个一个的 Block,然后进行上传;
    • 与 NameNode 交互,获取文件的位置信息;
    • 与 DataNode 交互,读取或者写入数据;
    • Client 提供一些命令来管理 HDFS,比如 NameNode 格式化;
    • Client 可以通过一些命令来访问 HDFS,比如对 HDFS 增删查改操作。
  • Secondary NameNode:2nn,并非 NameNode 的热备。当 NameNode 挂掉的时候,它并不能马上替换 NameNode 并提供服务。

    • 辅助 NameNode,分担其工作量,比如定期合并 Fsimage 和 Edits,并推送给 NameNode;
    • 在紧急情况下,可辅助恢复 NameNode(只能恢复一部分数据,无法恢复全部数据)。

HDFS 文件块大小

  • HDFS 中的文件在物理上是分块存储(Block),块的大小可以通过配置参数 dfs.blocksize 来规定,默认大小在 Hadoop 2.x/3.x 版本中是 128 MB,Hadoop 1.x 版本中是 64 MB。
    • 如果寻址时间约为 10 ms,即查找到集群中的目标 Block 的时间为 10 ms。当寻址时间为传输时间的 1% 时(专家研究),则为最佳状态。因此,传输时间 = 10 ms / 0.01 = 1000 ms = 1 s。而目前磁盘的传输速率普遍为 100 MB/s,因此,Block 大小 = 1 s * 100 MB/s = 100 MB。在计算机系统中,取 1024 的整数倍,即取 Block 大小为 128 MB。如果是固态硬盘,传输速率可以达到 200 ~ 300 MB/s,此时,一般取 Block 大小为 256 MB。
  • HDFS 的 Block 块的大小设置主要取决于磁盘传输速率。
    • 如果 HDFS 的 Block 块设置的太小,会增加寻址时间,程序一直在找块的开始位置。
    • 如果 HDFS 的 Block 块设置的太大,从磁盘传输数据的时间会明显大于定位这个块开始位置所需的时间,导致程序在处理这块数据时,会非常慢。

HDFS 的 Shell 操作

基本语法

  • 方式一:hadoop fs 具体命令
  • 方式二:hdfs dfs 具体命令

命令大全

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
[xisun@hadoop102 ~]$ hadoop fs
Usage: hadoop fs [generic options]
[-appendToFile <localsrc> ... <dst>]
[-cat [-ignoreCrc] <src> ...]
[-checksum <src> ...]
[-chgrp [-R] GROUP PATH...]
[-chmod [-R] <MODE[,MODE]... | OCTALMODE> PATH...]
[-chown [-R] [OWNER][:[GROUP]] PATH...]
[-copyFromLocal [-f] [-p] [-l] [-d] [-t <thread count>] <localsrc> ... <dst>]
[-copyToLocal [-f] [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
[-count [-q] [-h] [-v] [-t [<storage type>]] [-u] [-x] [-e] <path> ...]
[-cp [-f] [-p | -p[topax]] [-d] <src> ... <dst>]
[-createSnapshot <snapshotDir> [<snapshotName>]]
[-deleteSnapshot <snapshotDir> <snapshotName>]
[-df [-h] [<path> ...]]
[-du [-s] [-h] [-v] [-x] <path> ...]
[-expunge [-immediate]]
[-find <path> ... <expression> ...]
[-get [-f] [-p] [-ignoreCrc] [-crc] <src> ... <localdst>]
[-getfacl [-R] <path>]
[-getfattr [-R] {-n name | -d} [-e en] <path>]
[-getmerge [-nl] [-skip-empty-file] <src> <localdst>]
[-head <file>]
[-help [cmd ...]]
[-ls [-C] [-d] [-h] [-q] [-R] [-t] [-S] [-r] [-u] [-e] [<path> ...]]
[-mkdir [-p] <path> ...]
[-moveFromLocal <localsrc> ... <dst>]
[-moveToLocal <src> <localdst>]
[-mv <src> ... <dst>]
[-put [-f] [-p] [-l] [-d] <localsrc> ... <dst>]
[-renameSnapshot <snapshotDir> <oldName> <newName>]
[-rm [-f] [-r|-R] [-skipTrash] [-safely] <src> ...]
[-rmdir [--ignore-fail-on-non-empty] <dir> ...]
[-setfacl [-R] [{-b|-k} {-m|-x <acl_spec>} <path>]|[--set <acl_spec> <path>]]
[-setfattr {-n name [-v value] | -x name} <path>]
[-setrep [-R] [-w] <rep> <path> ...]
[-stat [format] <path> ...]
[-tail [-f] [-s <sleep interval>] <file>]
[-test -[defswrz] <path>]
[-text [-ignoreCrc] <src> ...]
[-touch [-a] [-m] [-t TIMESTAMP ] [-c] <path> ...]
[-touchz <path> ...]
[-truncate [-w] <length> <path> ...]
[-usage [cmd ...]]

Generic options supported are:
-conf <configuration file> specify an application configuration file
-D <property=value> define a value for a given property
-fs <file:///|hdfs://namenode:port> specify default filesystem URL to use, overrides 'fs.defaultFS' property from configurations.
-jt <local|resourcemanager:port> specify a ResourceManager
-files <file1,...> specify a comma-separated list of files to be copied to the map reduce cluster
-libjars <jar1,...> specify a comma-separated list of jar files to be included in the classpath
-archives <archive1,...> specify a comma-separated list of archives to be unarchived on the compute machines

The general command line syntax is:
command [genericOptions] [commandOptions]

常用命令

查看帮助

  • -help:查看命令的使用说明

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    [xisun@hadoop102 ~]$ hadoop fs -help rm
    -rm [-f] [-r|-R] [-skipTrash] [-safely] <src> ... :
    Delete all files that match the specified file pattern. Equivalent to the Unix
    command "rm <src>"

    -f If the file does not exist, do not display a diagnostic message or
    modify the exit status to reflect an error.
    -[rR] Recursively deletes directories.
    -skipTrash option bypasses trash, if enabled, and immediately deletes <src>.
    -safely option requires safety confirmation, if enabled, requires
    confirmation before deleting large directory with more than
    <hadoop.shell.delete.limit.num.files> files. Delay is expected when
    walking over large directory recursively to count the number of
    files to be deleted before the confirmation.

直接操作 HDFS

  • -ls:显示目录信息。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    [xisun@hadoop102 ~]$ hadoop fs -ls /
    Found 5 items
    -rw-r--r-- 3 xisun supergroup 359196911 2021-09-02 10:45 /hadoop-3.2.1.tar.gz
    drwx------ - xisun supergroup 0 2021-09-02 16:35 /tmp
    drwxr-xr-x - xisun supergroup 0 2021-09-02 10:14 /wcinput
    drwxr-xr-x - xisun supergroup 0 2021-09-02 16:36 /wcoutput
    [xisun@hadoop102 ~]$ hadoop fs -ls /wcinput
    Found 1 items
    -rw-r--r-- 3 xisun supergroup 41 2021-09-02 10:14 /wcinput/word.txt
  • -cat:显示文件内容。

    1
    2
    3
    4
    5
    6
    [xisun@hadoop102 ~]$ hadoop fs -cat /wcinput/word.txt
    2021-09-06 14:07:12,091 INFO sasl.SaslDataTransferClient: SASL encryption trust check: localHostTrusted = false, remoteHostTrusted = false
    hadoop yarn
    hadoop mapreduce
    xisun
    xisun
  • -mkdir:创建路径。

    1
    2
    3
    4
    5
    6
    7
    8
    [xisun@hadoop102 ~]$ hadoop fs -mkdir /sanguo
    [xisun@hadoop102 ~]$ hadoop fs -ls /
    Found 5 items
    -rw-r--r-- 3 xisun supergroup 359196911 2021-09-02 10:45 /hadoop-3.2.1.tar.gz
    drwxr-xr-x - xisun supergroup 0 2021-09-06 13:35 /sanguo
    drwx------ - xisun supergroup 0 2021-09-02 16:35 /tmp
    drwxr-xr-x - xisun supergroup 0 2021-09-02 10:14 /wcinput
    drwxr-xr-x - xisun supergroup 0 2021-09-02 16:36 /wcoutput
  • -cp:从 HDFS 的一个路径拷贝到 HDFS 的另一个路径。

    1
    2
    3
    4
    5
    6
    [xisun@hadoop102 ~]$ hadoop fs -cp /wcinput/word.txt /sanguo
    2021-09-06 16:16:26,225 INFO sasl.SaslDataTransferClient: SASL encryption trust check: localHostTrusted = false, remoteHostTrusted = false
    2021-09-06 16:16:27,148 INFO sasl.SaslDataTransferClient: SASL encryption trust check: localHostTrusted = false, remoteHostTrusted = false
    [xisun@hadoop102 ~]$ hadoop fs -ls /sanguo
    Found 1 items
    -rw-r--r-- 3 xisun supergroup 41 2021-09-06 16:16 /sanguo/word.txt
  • -mv:在 HDFS 目录中移动文件或重命名文件。

    1
    2
    3
    4
    [xisun@hadoop102 ~]$ hadoop fs -mv /sanguo/word.txt /sanguo/sanguo.txt
    [xisun@hadoop102 ~]$ hadoop fs -ls /sanguo
    Found 1 items
    -rw-r--r-- 3 xisun supergroup 41 2021-09-06 16:16 /sanguo/sanguo.txt
  • -tail:显示一个文件的末尾 1 kb 的数据。

    1
    2
    3
    4
    5
    6
    [xisun@hadoop102 ~]$ hadoop fs -tail /sanguo/sanguo.txt
    2021-09-06 16:19:45,518 INFO sasl.SaslDataTransferClient: SASL encryption trust check: localHostTrusted = false, remoteHostTrusted = false
    hadoop yarn
    hadoop mapreduce
    xisun
    xisun
  • -rm:删除文件。

    1
    2
    [xisun@hadoop102 ~]$ hadoop fs -rm /sanguo/sanguo.txt
    Deleted /sanguo/sanguo.txt
  • -rm -r:递归删除目录及目录里面内容。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    [xisun@hadoop102 ~]$ hadoop fs -rm /sanguo
    rm: `/sanguo': Is a directory
    [xisun@hadoop102 ~]$ hadoop fs -rm -r /sanguo
    Deleted /sanguo
    [xisun@hadoop102 ~]$ hadoop fs -ls /
    Found 4 items
    -rw-r--r-- 3 xisun supergroup 359196911 2021-09-02 10:45 /hadoop-3.2.1.tar.gz
    drwx------ - xisun supergroup 0 2021-09-02 16:35 /tmp
    drwxr-xr-x - xisun supergroup 0 2021-09-02 10:14 /wcinput
    drwxr-xr-x - xisun supergroup 0 2021-09-02 16:36 /wcoutput
  • -du:统计文件夹的大小信息。

    1
    2
    3
    4
    [xisun@hadoop102 ~]$ hadoop fs -du -s -h /wcinput
    41 123 /wcinput
    [xisun@hadoop102 ~]$ hadoop fs -du -h /wcinput
    41 123 /wcinput/word.txt
    • 41 表示文件大小;123 表示 41 * 3 个副本;/wcinput 表示查看的目录。
  • -chgrp、-chmod、-chown:与 Linux 文件系统中的用法一样,修改文件所属权限。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    [xisun@hadoop102 ~]$ hadoop fs -ls /wcinput
    Found 1 items
    -rw-r--r-- 3 xisun supergroup 41 2021-09-02 10:14 /wcinput/word.txt
    [xisun@hadoop102 ~]$ hadoop fs -chmod 666 /wcinput/word.txt
    [xisun@hadoop102 ~]$ hadoop fs -ls /wcinput
    Found 1 items
    -rw-rw-rw- 3 xisun supergroup 41 2021-09-02 10:14 /wcinput/word.txt
    [xisun@hadoop102 ~]$ hadoop fs -chown xisun:xisun /wcinput/word.txt
    [xisun@hadoop102 ~]$ hadoop fs -ls /wcinput
    Found 1 items
    -rw-rw-rw- 3 xisun xisun 41 2021-09-02 10:14 /wcinput/word.txt
  • -setrep:设置 HDFS 中文件的副本数量。

    1
    2
    [xisun@hadoop102 ~]$ hadoop fs -setrep 10 /wcinput/word.txt
    Replication 10 set: /wcinput/word.txt

    image-20210906163539785

    image-20210906163702812

    • 这里设置的副本数只是记录在 NameNode 的元数据中,是否真的会有这么多副本,取决于 DataNode 的数量。因为目前只有 3 台设备,最多也就 3 个副本,只有节点数的增加到 10 台时,副本数才能达到 10。

上传到 HDFS

  • -moveFromLocal:从本地文件系统剪切文件粘贴到 HDFS 路径。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    [xisun@hadoop102 ~]$ vim shuguo.txt
    [xisun@hadoop102 ~]$ ll
    总用量 4
    drwxrwxr-x. 2 xisun xisun 52 9月 2 23:15 bin
    -rw-rw-r--. 1 xisun xisun 7 9月 6 16:39 shuguo.txt
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 公共
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 模板
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 视频
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 图片
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 文档
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 下载
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 音乐
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 桌面
    [xisun@hadoop102 ~]$ hadoop fs -mkdir /sanguo
    [xisun@hadoop102 ~]$ hadoop fs -ls /sanguo
    [xisun@hadoop102 ~]$ hadoop fs -moveFromLocal ./shuguo.txt /sanguo
    2021-09-06 16:40:09,950 INFO sasl.SaslDataTransferClient: SASL encryption trust check: localHostTrusted = false, remoteHostTrusted = false
    [xisun@hadoop102 ~]$ hadoop fs -ls /sanguo
    Found 1 items
    -rw-r--r-- 3 xisun supergroup 7 2021-09-06 16:40 /sanguo/shuguo.txt
    [xisun@hadoop102 ~]$ ll
    总用量 0
    drwxrwxr-x. 2 xisun xisun 52 9月 2 23:15 bin
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 公共
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 模板
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 视频
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 图片
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 文档
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 下载
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 音乐
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 桌面
  • -copyFromLocal:从本地文件系统中拷贝文件到 HDFS 路径。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    [xisun@hadoop102 ~]$ vim weiguo.txt
    [xisun@hadoop102 ~]$ ll
    总用量 4
    drwxrwxr-x. 2 xisun xisun 52 9月 2 23:15 bin
    -rw-rw-r--. 1 xisun xisun 7 9月 6 16:43 weiguo.txt
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 公共
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 模板
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 视频
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 图片
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 文档
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 下载
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 音乐
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 桌面
    [xisun@hadoop102 ~]$ hadoop fs -copyFromLocal weiguo.txt /sanguo
    2021-09-06 16:43:50,298 INFO sasl.SaslDataTransferClient: SASL encryption trust check: localHostTrusted = false, remoteHostTrusted = false
    [xisun@hadoop102 ~]$ hadoop fs -ls /sanguo
    Found 2 items
    -rw-r--r-- 3 xisun supergroup 7 2021-09-06 16:40 /sanguo/shuguo.txt
    -rw-r--r-- 3 xisun supergroup 7 2021-09-06 16:43 /sanguo/weiguo.txt
    [xisun@hadoop102 ~]$ ll
    总用量 4
    drwxrwxr-x. 2 xisun xisun 52 9月 2 23:15 bin
    -rw-rw-r--. 1 xisun xisun 7 9月 6 16:43 weiguo.txt
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 公共
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 模板
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 视频
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 图片
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 文档
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 下载
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 音乐
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 桌面
  • -put:等同于 -copyFromLocal,生产环境更习惯用 -put。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    [xisun@hadoop102 ~]$ vim wuguo.txt
    [xisun@hadoop102 ~]$ ll
    总用量 8
    drwxrwxr-x. 2 xisun xisun 52 9月 2 23:15 bin
    -rw-rw-r--. 1 xisun xisun 7 9月 6 16:43 weiguo.txt
    -rw-rw-r--. 1 xisun xisun 6 9月 6 16:45 wuguo.txt
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 公共
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 模板
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 视频
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 图片
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 文档
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 下载
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 音乐
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 桌面
    [xisun@hadoop102 ~]$ hadoop fs -put wuguo.txt /sanguo
    2021-09-06 16:46:14,881 INFO sasl.SaslDataTransferClient: SASL encryption trust check: localHostTrusted = false, remoteHostTrusted = false
    [xisun@hadoop102 ~]$ hadoop fs -ls /sanguo
    Found 3 items
    -rw-r--r-- 3 xisun supergroup 7 2021-09-06 16:40 /sanguo/shuguo.txt
    -rw-r--r-- 3 xisun supergroup 7 2021-09-06 16:43 /sanguo/weiguo.txt
    -rw-r--r-- 3 xisun supergroup 6 2021-09-06 16:46 /sanguo/wuguo.txt
    [xisun@hadoop102 ~]$ ll
    总用量 8
    drwxrwxr-x. 2 xisun xisun 52 9月 2 23:15 bin
    -rw-rw-r--. 1 xisun xisun 7 9月 6 16:43 weiguo.txt
    -rw-rw-r--. 1 xisun xisun 6 9月 6 16:45 wuguo.txt
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 公共
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 模板
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 视频
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 图片
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 文档
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 下载
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 音乐
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 桌面
  • -appendToFile:追加一个文件到已经存在的文件末尾。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    [xisun@hadoop102 ~]$ hadoop fs -cat /sanguo/shuguo.txt
    2021-09-06 16:47:33,926 INFO sasl.SaslDataTransferClient: SASL encryption trust check: localHostTrusted = false, remoteHostTrusted = false
    shuguo
    [xisun@hadoop102 ~]$ vim liubei.txt
    [xisun@hadoop102 ~]$ cat liubei.txt
    liubei
    [xisun@hadoop102 ~]$ hadoop fs -appendToFile liubei.txt /sanguo/shuguo.txt
    2021-09-06 16:48:18,942 INFO sasl.SaslDataTransferClient: SASL encryption trust check: localHostTrusted = false, remoteHostTrusted = false
    [xisun@hadoop102 hadoop fs -cat /sanguo/shuguo.txt
    2021-09-06 16:48:32,423 INFO sasl.SaslDataTransferClient: SASL encryption trust check: localHostTrusted = false, remoteHostTrusted = false
    shuguo
    liubei

下载至 HDFS

  • -copyToLocal:从 HDFS 路径拷贝文件到本地文件系统。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    [xisun@hadoop102 ~]$ rm liubei.txt weiguo.txt wuguo.txt 
    [xisun@hadoop102 ~]$ ll
    总用量 0
    drwxrwxr-x. 2 xisun xisun 52 9月 2 23:15 bin
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 公共
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 模板
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 视频
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 图片
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 文档
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 下载
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 音乐
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 桌面
    [xisun@hadoop102 ~]$ hadoop fs -copyToLocal /sanguo/shuguo.txt ./
    2021-09-06 16:49:58,344 INFO sasl.SaslDataTransferClient: SASL encryption trust check: localHostTrusted = false, remoteHostTrusted = false
    [xisun@hadoop102 ~]$ ll
    总用量 4
    drwxrwxr-x. 2 xisun xisun 52 9月 2 23:15 bin
    -rw-r--r--. 1 xisun xisun 14 9月 6 16:49 shuguo.txt
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 公共
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 模板
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 视频
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 图片
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 文档
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 下载
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 音乐
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 桌面
  • -get:等同于 -copyToLocal,生产环境更习惯用 -get。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    [xisun@hadoop102 ~]$ hadoop fs -get /sanguo/weiguo.txt ./
    2021-09-06 16:50:23,583 INFO sasl.SaslDataTransferClient: SASL encryption trust check: localHostTrusted = false, remoteHostTrusted = false
    [xisun@hadoop102 ~]$ ll
    总用量 8
    drwxrwxr-x. 2 xisun xisun 52 9月 2 23:15 bin
    -rw-r--r--. 1 xisun xisun 14 9月 6 16:49 shuguo.txt
    -rw-r--r--. 1 xisun xisun 7 9月 6 16:50 weiguo.txt
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 公共
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 模板
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 视频
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 图片
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 文档
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 下载
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 音乐
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 桌面

HDFS 的 API 操作

客户端环境准备

  • Windows 系统开发 Hadoop 时,如果是远程连接 Linux 上的 Hadoop 集群,则不需要再下载安装 Windows 版本的 Hadoop。但是,需要在本地配置相关的 Hadoop 变量,主要包括 hadoop.dll 与 winutils.exe 等。

    • 由于 Hadoop 主要基于 Linux 编写,winutil.exe 主要用于模拟 Linux 下的目录环境。当 Hadoop 在 Windows 下运行或调用远程 Hadoop 集群的时候,需要该辅助程序才能运行。winutils.exe 是 Windows 中的二进制文件,适用于不同版本的 Hadoop 系统并构建在 Windows VM 上,该 VM 用以在 Windows 系统中测试 Hadoop/YARN 相关的应用程序。参考:https://blog.csdn.net/HeyShHeyou/article/details/103441110。

    • 相关异常信息:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      java.io.FileNotFoundException: java.io.FileNotFoundException: HADOOP_HOME and hadoop.home.dir are unset. -see https://wiki.apache.org/hadoop/WindowsProblems
      at org.apache.hadoop.util.Shell.fileNotFoundException(Shell.java:528) ~[hadoop-common-2.8.4.jar:na]
      at org.apache.hadoop.util.Shell.getHadoopHomeDir(Shell.java:549) ~[hadoop-common-2.8.4.jar:na]
      at org.apache.hadoop.util.Shell.getQualifiedBin(Shell.java:572) ~[hadoop-common-2.8.4.jar:na]
      at org.apache.hadoop.util.Shell.<clinit>(Shell.java:669) ~[hadoop-common-2.8.4.jar:na]
      at org.apache.hadoop.util.StringUtils.<clinit>(StringUtils.java:79) [hadoop-common-2.8.4.jar:na]
      at org.apache.hadoop.conf.Configuration.getBoolean(Configuration.java:1555) [hadoop-common-2.8.4.jar:na]
      at org.apache.hadoop.hbase.HBaseConfiguration.checkDefaultsVersion(HBaseConfiguration.java:66) [hbase-common-2.0.0.jar:2.0.0]
      at org.apache.hadoop.hbase.HBaseConfiguration.addHbaseResources(HBaseConfiguration.java:80) [hbase-common-2.0.0.jar:2.0.0]
      at org.apache.hadoop.hbase.HBaseConfiguration.create(HBaseConfiguration.java:94) [hbase-common-2.0.0.jar:2.0.0]
      at org.apache.phoenix.query.ConfigurationFactory$ConfigurationFactoryImpl$1.call(ConfigurationFactory.java:49) [phoenix-core-5.0.0-HBase-2.0.jar:5.0.0-HBase-2.0]
      at org.apache.phoenix.query.ConfigurationFactory$ConfigurationFactoryImpl$1.call(ConfigurationFactory.java:46) [phoenix-core-5.0.0-HBase-2.0.jar:5.0.0-HBase-2.0]
      at org.apache.phoenix.util.PhoenixContextExecutor.call(PhoenixContextExecutor.java:76) [phoenix-core-5.0.0-HBase-2.0.jar:5.0.0-HBase-2.0]
      at org.apache.phoenix.util.PhoenixContextExecutor.callWithoutPropagation(PhoenixContextExecutor.java:91) [phoenix-core-5.0.0-HBase-2.0.jar:5.0.0-HBase-2.0]
      at org.apache.phoenix.query.ConfigurationFactory$ConfigurationFactoryImpl.getConfiguration(ConfigurationFactory.java:46) [phoenix-core-5.0.0-HBase-2.0.jar:5.0.0-HBase-2.0]
      at org.apache.phoenix.jdbc.PhoenixDriver.initializeConnectionCache(PhoenixDriver.java:151) [phoenix-core-5.0.0-HBase-2.0.jar:5.0.0-HBase-2.0]
      at org.apache.phoenix.jdbc.PhoenixDriver.<init>(PhoenixDriver.java:143) [phoenix-core-5.0.0-HBase-2.0.jar:5.0.0-HBase-2.0]
  • 根据 Linux 上 Hadoop 版本,下载对应的 winutils.exe 版本:https://github.com/cdarlint/winutils,https://github.com/steveloughran/winutils。

    image-20210906233413928

  • 配置 HADOOP_HOME 环境变量:

    image-20210906232417504

  • 配置 Path 环境变量:

    image-20210906232525065

  • 验证 Hadoop 环境变量是否正常。双击 winutils.exe,如果一闪而过,说明正常;如果报如下错误,说明缺少微软运行库(正版系统往往有这个问题)。

    image-20210906232834423

    image-20210906233140290

  • Hadoop 环境变量配置好后,可能需要重启 IDEA 或者重启电脑。

项目创建

  • 添加依赖:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>cn.xisun.hadoop</groupId>
    <artifactId>xisun-hadoop</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
    <maven.compiler.version>3.6.1</maven.compiler.version>
    <maven.compiler.source>${java.version}</maven.compiler.source>
    <maven.compiler.target>${java.version}</maven.compiler.target>
    <hadoop.version>3.2.1</hadoop.version>
    </properties>

    <dependencies>
    <!-- 日志相关 -->
    <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.18.10</version>
    </dependency>
    <dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.3</version>
    </dependency>

    <!-- Hadoop客户端 -->
    <dependency>
    <groupId>org.apache.hadoop</groupId>
    <artifactId>hadoop-client</artifactId>
    <version>${hadoop.version}</version>
    </dependency>
    </dependencies>

    <build>
    <plugins>
    <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>${maven.compiler.version}</version>
    <configuration>
    <source>${maven.compiler.source}</source>
    <target>${maven.compiler.target}</target>
    </configuration>
    </plugin>
    </plugins>
    </build>
    </project>
  • 日志配置:

    • log4j.properties:

      1
      2
      3
      4
      5
      6
      7
      8
      log4j.rootLogger=INFO, stdout
      log4j.appender.stdout=org.apache.log4j.ConsoleAppender
      log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
      log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
      log4j.appender.logfile=org.apache.log4j.FileAppender
      log4j.appender.logfile.File=target/spring.log
      log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
      log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
    • logback.xml:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      <configuration
      debug="false"
      xmlns="http://ch.qos.logback/xml/ns/logback"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://ch.qos.logback/xml/ns/logback
      https://raw.githubusercontent.com/enricopulatzo/logback-XSD/master/src/main/xsd/logback.xsd"
      >
      <!-- 定义日志文件的存储地址 -->
      <property name="logging.path" value="./"/>
      <property name="logging.level" value="DEBUG"/>
      <property name="message.format"
      value="%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n%ex{full, DISPLAY_EX_EVAL}"/>

      <!-- 控制台输出日志 -->
      <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
      <encoder>
      <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
      <charset>UTF-8</charset>
      </encoder>
      </appender>

      <!-- 自定义滚动日志 -->
      <appender name="RollingAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
      <append>true</append>
      <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
      <level>${logging.level}</level>
      </filter>
      <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <FileNamePattern>${logging.path}/reaction-extractor-%d{yyyy-MM-dd}.log</FileNamePattern>
      <MaxHistory>30</MaxHistory>
      </rollingPolicy>
      <encoder>
      <pattern>${message.format}</pattern>
      <charset>UTF-8</charset>
      </encoder>
      </appender>

      <!-- 异步输出日志 -->
      <appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
      <discardingThreshold>0</discardingThreshold>
      <queueSize>100</queueSize>
      <appender-ref ref="RollingAppender"/>
      </appender>

      <root level="${logging.level}">
      <appender-ref ref="STDOUT"/>
      <appender-ref ref="ASYNC"/>
      </root>
      </configuration>
  • 项目结构:

    image-20210907150906533

案例实操

创建目录

  • 代码实现:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    /**
    * @Author XiSun
    * @Date 2021/9/6 22:46
    */
    @Slf4j
    public class HdfsClient {
    private static FileSystem fileSystem;

    static {
    try {
    init();
    } catch (URISyntaxException | IOException | InterruptedException e) {
    e.printStackTrace();
    }
    }

    /**
    * 获取文件系统
    *
    * @throws URISyntaxException
    * @throws IOException
    * @throws InterruptedException
    */
    public static void init() throws URISyntaxException, IOException, InterruptedException {
    // 集群nn的连接地址
    URI uri = new URI("hdfs://hadoop102:8020");
    // 创建一个配置文件,按需求自定义配置条件
    Configuration configuration = new Configuration();
    // 用户
    String user = "xisun";

    // 获取客户端对象
    fileSystem = FileSystem.get(uri, configuration, user);
    }

    /**
    * 关闭资源
    */
    public static void close() {
    if (fileSystem != null) {
    try {
    fileSystem.close();
    } catch (IOException exception) {
    exception.printStackTrace();
    }
    }
    }

    /**
    * 创建目录
    */
    public static void mkdirs() {
    try {
    fileSystem.mkdirs(new Path("/xiyou/huaguoshan/"));
    } catch (IOException exception) {
    exception.printStackTrace();
    } finally {
    close();
    }
    }

    public static void main(String[] args) {
    mkdirs();
    }
    }
    • 客户端去操作 HDFS 时,是有一个用户身份的。默认情况下,HDFS 客户端 API 会从采用 Windows 默认用户访问 HDFS,这通常会报权限异常错误。因此,在创建文件系统对象时,一定要配置用户。
  • 控制台输出:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    2021-09-07 15:35:02.744 [main] DEBUG o.apache.hadoop.metrics2.lib.MutableMetricsFactory - field org.apache.hadoop.metrics2.lib.MutableRate org.apache.hadoop.security.UserGroupInformation$UgiMetrics.loginSuccess with annotation @org.apache.hadoop.metrics2.annotation.Metric(sampleName=Ops, always=false, valueName=Time, about=, interval=10, type=DEFAULT, value=[Rate of successful kerberos logins and latency (milliseconds)])
    2021-09-07 15:35:02.750 [main] DEBUG o.apache.hadoop.metrics2.lib.MutableMetricsFactory - field org.apache.hadoop.metrics2.lib.MutableRate org.apache.hadoop.security.UserGroupInformation$UgiMetrics.loginFailure with annotation @org.apache.hadoop.metrics2.annotation.Metric(sampleName=Ops, always=false, valueName=Time, about=, interval=10, type=DEFAULT, value=[Rate of failed kerberos logins and latency (milliseconds)])
    2021-09-07 15:35:02.750 [main] DEBUG o.apache.hadoop.metrics2.lib.MutableMetricsFactory - field org.apache.hadoop.metrics2.lib.MutableRate org.apache.hadoop.security.UserGroupInformation$UgiMetrics.getGroups with annotation @org.apache.hadoop.metrics2.annotation.Metric(sampleName=Ops, always=false, valueName=Time, about=, interval=10, type=DEFAULT, value=[GetGroups])
    2021-09-07 15:35:02.751 [main] DEBUG o.apache.hadoop.metrics2.lib.MutableMetricsFactory - field private org.apache.hadoop.metrics2.lib.MutableGaugeLong org.apache.hadoop.security.UserGroupInformation$UgiMetrics.renewalFailuresTotal with annotation @org.apache.hadoop.metrics2.annotation.Metric(sampleName=Ops, always=false, valueName=Time, about=, interval=10, type=DEFAULT, value=[Renewal failures since startup])
    2021-09-07 15:35:02.751 [main] DEBUG o.apache.hadoop.metrics2.lib.MutableMetricsFactory - field private org.apache.hadoop.metrics2.lib.MutableGaugeInt org.apache.hadoop.security.UserGroupInformation$UgiMetrics.renewalFailures with annotation @org.apache.hadoop.metrics2.annotation.Metric(sampleName=Ops, always=false, valueName=Time, about=, interval=10, type=DEFAULT, value=[Renewal failures since last successful login])
    2021-09-07 15:35:02.752 [main] DEBUG org.apache.hadoop.metrics2.impl.MetricsSystemImpl - UgiMetrics, User and group related metrics
    2021-09-07 15:35:02.761 [main] DEBUG org.apache.hadoop.security.UserGroupInformation - PrivilegedAction as:xisun (auth:SIMPLE) from:org.apache.hadoop.fs.FileSystem.get(FileSystem.java:214)
    2021-09-07 15:35:03.049 [main] DEBUG org.apache.hadoop.fs.FileSystem - Loading filesystems
    2021-09-07 15:35:03.065 [main] DEBUG org.apache.hadoop.fs.FileSystem - file:// = class org.apache.hadoop.fs.LocalFileSystem from /D:/java/maven-repo/org/apache/hadoop/hadoop-common/3.2.1/hadoop-common-3.2.1.jar
    2021-09-07 15:35:03.073 [main] DEBUG org.apache.hadoop.fs.FileSystem - viewfs:// = class org.apache.hadoop.fs.viewfs.ViewFileSystem from /D:/java/maven-repo/org/apache/hadoop/hadoop-common/3.2.1/hadoop-common-3.2.1.jar
    2021-09-07 15:35:03.076 [main] DEBUG org.apache.hadoop.fs.FileSystem - har:// = class org.apache.hadoop.fs.HarFileSystem from /D:/java/maven-repo/org/apache/hadoop/hadoop-common/3.2.1/hadoop-common-3.2.1.jar
    2021-09-07 15:35:03.077 [main] DEBUG org.apache.hadoop.fs.FileSystem - http:// = class org.apache.hadoop.fs.http.HttpFileSystem from /D:/java/maven-repo/org/apache/hadoop/hadoop-common/3.2.1/hadoop-common-3.2.1.jar
    2021-09-07 15:35:03.078 [main] DEBUG org.apache.hadoop.fs.FileSystem - https:// = class org.apache.hadoop.fs.http.HttpsFileSystem from /D:/java/maven-repo/org/apache/hadoop/hadoop-common/3.2.1/hadoop-common-3.2.1.jar
    2021-09-07 15:35:03.090 [main] DEBUG org.apache.hadoop.fs.FileSystem - hdfs:// = class org.apache.hadoop.hdfs.DistributedFileSystem from /D:/java/maven-repo/org/apache/hadoop/hadoop-hdfs-client/3.2.1/hadoop-hdfs-client-3.2.1.jar
    2021-09-07 15:35:03.102 [main] DEBUG org.apache.hadoop.fs.FileSystem - webhdfs:// = class org.apache.hadoop.hdfs.web.WebHdfsFileSystem from /D:/java/maven-repo/org/apache/hadoop/hadoop-hdfs-client/3.2.1/hadoop-hdfs-client-3.2.1.jar
    2021-09-07 15:35:03.104 [main] DEBUG org.apache.hadoop.fs.FileSystem - swebhdfs:// = class org.apache.hadoop.hdfs.web.SWebHdfsFileSystem from /D:/java/maven-repo/org/apache/hadoop/hadoop-hdfs-client/3.2.1/hadoop-hdfs-client-3.2.1.jar
    2021-09-07 15:35:03.104 [main] DEBUG org.apache.hadoop.fs.FileSystem - Looking for FS supporting hdfs
    2021-09-07 15:35:03.104 [main] DEBUG org.apache.hadoop.fs.FileSystem - looking for configuration option fs.hdfs.impl
    2021-09-07 15:35:03.120 [main] DEBUG org.apache.hadoop.fs.FileSystem - Looking in service filesystems for implementation class
    2021-09-07 15:35:03.121 [main] DEBUG org.apache.hadoop.fs.FileSystem - FS for hdfs is class org.apache.hadoop.hdfs.DistributedFileSystem
    2021-09-07 15:35:03.204 [main] DEBUG org.apache.hadoop.hdfs.client.impl.DfsClientConf - dfs.client.use.legacy.blockreader.local = false
    2021-09-07 15:35:03.205 [main] DEBUG org.apache.hadoop.hdfs.client.impl.DfsClientConf - dfs.client.read.shortcircuit = false
    2021-09-07 15:35:03.205 [main] DEBUG org.apache.hadoop.hdfs.client.impl.DfsClientConf - dfs.client.domain.socket.data.traffic = false
    2021-09-07 15:35:03.205 [main] DEBUG org.apache.hadoop.hdfs.client.impl.DfsClientConf - dfs.domain.socket.path =
    2021-09-07 15:35:03.219 [main] DEBUG org.apache.hadoop.hdfs.DFSClient - Sets dfs.client.block.write.replace-datanode-on-failure.min-replication to 0
    2021-09-07 15:35:03.240 [main] DEBUG org.apache.hadoop.security.SecurityUtil - Setting hadoop.security.token.service.use_ip to true
    2021-09-07 15:35:03.254 [main] DEBUG org.apache.hadoop.io.retry.RetryUtils - multipleLinearRandomRetry = null
    2021-09-07 15:35:03.291 [main] DEBUG org.apache.hadoop.security.Groups - Creating new Groups object
    2021-09-07 15:35:03.293 [main] DEBUG org.apache.hadoop.util.NativeCodeLoader - Trying to load the custom-built native-hadoop library...
    2021-09-07 15:35:03.297 [main] DEBUG org.apache.hadoop.util.NativeCodeLoader - Loaded the native-hadoop library
    2021-09-07 15:35:03.298 [main] DEBUG o.apache.hadoop.security.JniBasedUnixGroupsMapping - Using JniBasedUnixGroupsMapping for Group resolution
    2021-09-07 15:35:03.298 [main] DEBUG o.a.h.s.JniBasedUnixGroupsMappingWithFallback - Group mapping impl=org.apache.hadoop.security.JniBasedUnixGroupsMapping
    2021-09-07 15:35:03.335 [main] DEBUG org.apache.hadoop.security.Groups - Group mapping impl=org.apache.hadoop.security.JniBasedUnixGroupsMappingWithFallback; cacheTimeout=300000; warningDeltaMs=5000
    2021-09-07 15:35:03.347 [main] DEBUG org.apache.hadoop.ipc.Server - rpcKind=RPC_PROTOCOL_BUFFER, rpcRequestWrapperClass=class org.apache.hadoop.ipc.ProtobufRpcEngine$RpcProtobufRequest, rpcInvoker=org.apache.hadoop.ipc.ProtobufRpcEngine$Server$ProtoBufRpcInvoker@3ce1e309
    2021-09-07 15:35:03.672 [main] DEBUG org.apache.hadoop.ipc.Client - getting client out of cache: org.apache.hadoop.ipc.Client@52bf72b5
    2021-09-07 15:35:04.085 [main] DEBUG org.apache.hadoop.util.PerformanceAdvisory - Both short-circuit local reads and UNIX domain socket are disabled.
    2021-09-07 15:35:04.092 [main] DEBUG o.a.h.h.p.datatransfer.sasl.DataTransferSaslUtil - DataTransferProtocol not using SaslPropertiesResolver, no QOP found in configuration for dfs.data.transfer.protection
    2021-09-07 15:35:04.112 [main] DEBUG org.apache.hadoop.hdfs.DFSClient - /xiyou/huaguoshan: masked={ masked: rwxr-xr-x, unmasked: rwxrwxrwx }
    2021-09-07 15:35:04.151 [main] DEBUG org.apache.hadoop.ipc.Client - The ping interval is 60000 ms.
    2021-09-07 15:35:04.153 [main] DEBUG org.apache.hadoop.ipc.Client - Connecting to hadoop102/192.168.10.102:8020
    2021-09-07 15:35:04.227 [IPC Client (956420404) connection to hadoop102/192.168.10.102:8020 from xisun] DEBUG org.apache.hadoop.ipc.Client - IPC Client (956420404) connection to hadoop102/192.168.10.102:8020 from xisun: starting, having connections 1
    2021-09-07 15:35:04.230 [IPC Parameter Sending Thread #0] DEBUG org.apache.hadoop.ipc.Client - IPC Client (956420404) connection to hadoop102/192.168.10.102:8020 from xisun sending #0 org.apache.hadoop.hdfs.protocol.ClientProtocol.mkdirs
    2021-09-07 15:35:04.244 [IPC Client (956420404) connection to hadoop102/192.168.10.102:8020 from xisun] DEBUG org.apache.hadoop.ipc.Client - IPC Client (956420404) connection to hadoop102/192.168.10.102:8020 from xisun got value #0
    2021-09-07 15:35:04.245 [main] DEBUG org.apache.hadoop.ipc.ProtobufRpcEngine - Call: mkdirs took 118ms
    2021-09-07 15:35:04.248 [main] DEBUG org.apache.hadoop.ipc.Client - stopping client from cache: org.apache.hadoop.ipc.Client@52bf72b5
    2021-09-07 15:35:04.248 [main] DEBUG org.apache.hadoop.ipc.Client - removing client from cache: org.apache.hadoop.ipc.Client@52bf72b5
    2021-09-07 15:35:04.248 [main] DEBUG org.apache.hadoop.ipc.Client - stopping actual client because no more references remain: org.apache.hadoop.ipc.Client@52bf72b5
    2021-09-07 15:35:04.248 [main] DEBUG org.apache.hadoop.ipc.Client - Stopping client
    2021-09-07 15:35:04.248 [IPC Client (956420404) connection to hadoop102/192.168.10.102:8020 from xisun] DEBUG org.apache.hadoop.ipc.Client - IPC Client (956420404) connection to hadoop102/192.168.10.102:8020 from xisun: closed
    2021-09-07 15:35:04.248 [IPC Client (956420404) connection to hadoop102/192.168.10.102:8020 from xisun] DEBUG org.apache.hadoop.ipc.Client - IPC Client (956420404) connection to hadoop102/192.168.10.102:8020 from xisun: stopped, remaining connections 0
    2021-09-07 15:35:04.354 [Thread-4] DEBUG org.apache.hadoop.util.ShutdownHookManager - Completed shutdown in 0.001 seconds; Timeouts: 0
    2021-09-07 15:35:04.363 [Thread-4] DEBUG org.apache.hadoop.util.ShutdownHookManager - ShutdownHookManger completed shutdown.

    Process finished with exit code 0
  • 创建结果:

    image-20210907153615806

文件上传

  • 代码实现:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    /**
    * 上传文件
    */
    public static void copyFromLocalFile() {
    try {
    // 参数一:Windows原文件是否删除;参数二:若HDFS目的地文件已存在,是否允许覆盖;参数三:Windows原文件路径;参数四:HDFS目的地路径
    fileSystem.copyFromLocalFile(false, true, new Path("E:\\sunwukong.txt"),
    new Path("hdfs://hadoop102/xiyou/huaguoshan"));
    } catch (IOException exception) {
    exception.printStackTrace();
    } finally {
    close();
    }
    }
  • 控制台输出:

    1
    2
    3
    2021-09-07 15:46:03.654 [Thread-6] INFO  o.a.h.h.p.datatransfer.sasl.SaslDataTransferClient - SASL encryption trust check: localHostTrusted = false, remoteHostTrusted = false

    Process finished with exit code 0
  • 上传结果:

    image-20210907154935556

    • 可以看出,上传文件,默认备份数是 3,参数的优先级顺序:hdfs-default.xml < hdfs-site.xml < 在项目资源目录下的配置文件 < 代码里面的配置。

      image-20210907155850375
      • 项目资源目录下的配置文件:

        image-20210907155455332

      • 代码里面的配置:

        image-20210907155532293

文件下载

  • 代码实现:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    /**
    * 下载文件
    */
    public static void copyToLocalFile() {
    try {
    // 参数一:HDFS原文件是否删除;参数二:HDFS原文件路径;参数三:Windows目标地址路径;参数四:是否开启本地文件校验,false表示开启
    fileSystem.copyToLocalFile(false, new Path("hdfs://hadoop102/wcinput/word.txt"),
    new Path("E:\\11\\"), false);
    } catch (IOException exception) {
    exception.printStackTrace();
    } finally {
    close();
    }
    }

    也可以直接下载 HDFS 上的文件路径。

  • 控制台输出:

    1
    2
    3
    2021-09-07 16:06:31.318 [main] INFO  o.a.h.h.p.datatransfer.sasl.SaslDataTransferClient - SASL encryption trust check: localHostTrusted = false, remoteHostTrusted = false

    Process finished with exit code 0
  • 下载结果:

    image-20210907161117479

文件删除

  • 代码实现:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    /**
    * 删除文件
    */
    public static void rm() {
    try {
    // 参数1:HDFS要删除的路径;参数2:是否递归删除

    // 删除文件
    fileSystem.delete(new Path("/hadoop-3.2.1.tar.gz"), false);

    // 删除空目录
    fileSystem.delete(new Path("/honglou"), false);

    // 删除非空目录
    fileSystem.delete(new Path("/xiyou"), true);
    } catch (IOException exception) {
    exception.printStackTrace();
    } finally {
    close();
    }
    }

文件的更名和移动

  • 代码实现:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    /**
    * 文件的更名和移动
    */
    public static void mv() {
    try {
    // 参数1:HDFS原文件路径;参数2:HDFS目标文件路径

    // 对文件名称的修改
    // fileSystem.rename(new Path("/wcinput/word.txt"), new Path("/wcinput/words.txt"));

    // 文件的移动和更名
    // fileSystem.rename(new Path("/wcinput/words.txt"), new Path("/wordout.txt"));

    // 目录更名
    fileSystem.rename(new Path("/honglou"), new Path("/hongloumeng"));
    } catch (IOException exception) {
    exception.printStackTrace();
    } finally {
    close();
    }
    }

文件详情查看

  • 代码实现:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    /**
    * 获取文件详细信息
    */
    public static void listFiles() {
    try {
    // 获取所有文件信息,第二个参数表示是否递归
    RemoteIterator<LocatedFileStatus> listFiles = fileSystem.listFiles(new Path("/"), true);
    // 遍历文件
    while (listFiles.hasNext()) {
    LocatedFileStatus fileStatus = listFiles.next();

    System.out.println("==========" + fileStatus.getPath() + "=========");
    System.out.println(fileStatus.getPermission());
    System.out.println(fileStatus.getOwner());
    System.out.println(fileStatus.getGroup());
    System.out.println(fileStatus.getLen());
    System.out.println(fileStatus.getModificationTime());
    System.out.println(fileStatus.getReplication());
    System.out.println(fileStatus.getBlockSize());
    System.out.println(fileStatus.getPath().getName());

    // 获取块信息
    BlockLocation[] blockLocations = fileStatus.getBlockLocations();
    System.out.println(Arrays.toString(blockLocations));
    }
    } catch (IOException exception) {
    exception.printStackTrace();
    } finally {
    close();
    }
    }
  • 控制台输出:

    image-20210907171215574

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    ==========hdfs://hadoop102:8020/sanguoyanyi/shuguo.txt=========
    rw-r--r--
    xisun
    supergroup
    14
    1630918100557
    3
    134217728
    shuguo.txt
    [0,14,hadoop102,hadoop103,hadoop104]
    ==========hdfs://hadoop102:8020/sanguoyanyi/weiguo.txt=========
    rw-r--r--
    xisun
    supergroup
    7
    1630917830657
    3
    134217728
    weiguo.txt
    [0,7,hadoop102,hadoop103,hadoop104]
    ==========hdfs://hadoop102:8020/sanguoyanyi/wuguo.txt=========
    rw-r--r--
    xisun
    supergroup
    6
    1630917975305
    3
    134217728
    wuguo.txt
    [0,6,hadoop102,hadoop103,hadoop104]

    Process finished with exit code 0

文件和文件夹类型判断

  • 代码实现:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    /**
    * 判断是文件夹还是文件
    */
    public static void fileType() {
    try {
    FileStatus[] listStatus = fileSystem.listStatus(new Path("/"));

    for (FileStatus status : listStatus) {
    if (status.isFile()) {
    System.out.println("文件:" + status.getPath().getName());
    } else {
    System.out.println("目录:" + status.getPath().getName());
    }
    }
    } catch (IOException exception) {
    exception.printStackTrace();
    } finally {
    close();
    }
    }
  • 控制台输出:

    image-20210907171344066

    1
    2
    3
    4
    5
    6
    7
    目录:sanguoyanyi
    目录:tmp
    目录:wcinput
    目录:wcoutput
    文件:wordout.txt

    Process finished with exit code 0

HDFS 的读写流程

HDFS 写数据流程

image-20210908104338787

  1. 客户端通过 Distributed FileSystem 模块向 NameNode 请求上传文件,NameNode 检查目标文件是否已存在,父目录是否存在。
  2. NameNode 返回是否可以上传。
  3. 客户端请求第一个 Block 上传到哪几个 DataNode 服务器上。
  4. NameNode 返回 3 个 DataNode 节点,分别为 dn1、dn2、dn3。
  5. 客户端通过 FSDataOutputStream 模块请求向 dn1 上传数据,dn1 收到请求会继续调用 dn2,然后 dn2 调用 dn3,将这个通信管道建立完成。
  6. dn1、dn2、dn3 逐级应答客户端。
  7. 客户端开始往 dn1 上传第一个 Block(先从磁盘读取数据放到一个本地内存缓存),以 Packet 为单位,dn1 收到一个 Packet 就会传给 dn2,dn2 再传给 dn3;dn1 每传一个 Packet 会放入一个应答队列等待应答。
  8. 当一个 Block 传输完成之后,客户端再次请求 NameNode 上传第二个 Block 的服务器。(重复执行 3 - 7 步)

网络拓扑 - 节点距离计算

  • 在 HDFS 写数据的过程中,NameNode 会选择距离待上传数据最近距离的 DataNode 接收数据。

  • 节点距离:两个节点到达最近的共同祖先的距离总和。

  • 假设有集群 d1 机架 r1 中的节点 n1,则该节点可以表示为 /d1/r1/n1。利用这种标记,这里给出四种距离描述,如下图所示:

    image-20210908104610376

    • 节点到其自身的距离为 0,到其所属机架的距离为 1,到其所属集群的距离为 2,到其所属机房的距离为 3。
    • Distance(/d1/r1/n0, /d1/r1/n0) = 0:同一节点上的进程。/d1/r1/n0 与 /d1/r1/n0 的共同祖先是 n0,因此,距离为 0 + 0 = 0。
    • Distance(/d1/r1/n1, /d1/r1/n2) = 2:同一机架上的不同节点。/d1/r1/n1 与 /d1/r1/n2 的共同祖先是机架 r1,因此,距离为 1 + 1 = 2。
    • Distance(/d1/r2/n0, /d1/r3/n2) = 4:同一数据中心不同机架上的节点。/d1/r2/n0 与 /d1/r3/n2 的共同祖先是集群 d1,因此,距离为 2 + 2 = 4。
    • Distance(/d1/r2/n1, /d2/r4/n1) = 6:不同数据中心的节点。/d1/r2/n1 与 /d2/r4/n1 的共同祖先是机房,因此,距离为 3 + 3 = 6。
  • 再比如下图互联网上的一个计算机群,5 号机和 9 号机的节点距离为 3,2 号机和 10 号机的节点距离也为 3。

    image-20210908091317080

机架感知 - 副本存储节点选择

  • 机架感知说明

    1
    For the common case, when the replication factor is three, HDFS’s placement policy is to put one replica on the local machine if the writer is on a datanode, otherwise on a random datanode in the same rack as that of the writer, another replica on a node in a different (remote) rack, and the last on a different node in the same remote rack. This policy cuts the inter-rack write traffic which generally improves write performance. The chance of rack failure is far less than that of node failure; this policy does not impact data reliability and availability guarantees. However, it does reduce the aggregate network bandwidth used when reading data since a block is placed in only two unique racks rather than three. With this policy, the replicas of a file do not evenly distribute across the racks. One third of replicas are on one node, two thirds of replicas are on one rack, and the other third are evenly distributed across the remaining racks. This policy improves write performance without compromising data reliability or read performance.
  • 副本存储节点选择

    image-20210908102248682

    • 第一个副本,在 Client 所处的节点上,节点距离最近,上传速度最快。如果客户端在集群外,则随机选一个。比如:/d1/r1/n0。
    • 第二个副本,在另一个机架的随机一个节点,以保证数据的可靠性。比如:/d1/r2/n0。
    • 第三个副本,在第二个副本所在机架的随机节点,考虑的是传输效率。比如:/d1/r2/n1。

HDFS 读数据流程

image-20210908105937977

  1. 客户端通过 DistributedFileSystem 向 NameNode 请求下载文件,NameNode 通过检查权限和查询元数据,找到文件块所在的 DataNode 地址。
  2. 挑选一台 DataNode(就近原则,然后随机)服务器,请求读取数据。
  3. DataNode 开始传输数据给客户端(从磁盘里面读取数据输入流,以 Packet 为单位来做校验)。
  4. 客户端以 Packet 为单位接收,先在本地缓存,然后写入目标文件。

NameNode 和 SecondaryNameNode

NN 和 2NN 工作机制

image-20210908114133555

  • NameNode 中的元数据如何存储的?
    • 首先,我们做个假设,如果存储在 NameNode 节点的磁盘中,因为经常需要进行随机访问,还有响应客户请求,必然是效率过低。因此,元数据需要存放在内存中。但如果只存在内存中,一旦断电,元数据丢失,整个集群就无法工作了。因此,需要一个在磁盘中备份元数据的 FsImage。
    • 其次,这样又会带来新的问题,当在内存中的元数据更新时,如果同时更新 FsImage,就会导致效率过低,但如果不更新,就会发生一致性问题,一旦 NameNode 节点断电,就会产生数据丢失。因此,引入 Edits 文件(此文件只进行追加操作,即只记录每一个请求的过程,不计算结果,效率很高)。每当元数据有更新或者添加元数据时,修改内存中的元数据并将请求操作追加到 Edits 中。这样,一旦 NameNode 节点断电,可以通过 FsImage 和 Edits 的合并,合成元数据。
    • 但是,如果长时间添加数据到 Edits 中,会导致该文件数据过大,效率降低,而且一旦断电,恢复元数据需要的时间过长。因此,需要定期进行 FsImage 和 Edits 的合并,如果这个操作由 NameNode 节点完成,又会效率过低。因此,引入一个新的节点 SecondaryNamenode,专门用于 FsImage 和 Edits 的合并。
  • 第一阶段:NameNode 启动。
    1. 第一次启动 NameNode 格式化后,创建 Fsimage(镜像文件)和 Edits(编辑日志)文件。如果不是第一次启动,直接加载 Fsimage 和 Edits 到内存。
    2. 客户端发送对元数据进行增删改的请求。
    3. NameNode 记录操作日志,更新滚动日志。
    4. NameNode 在内存中对元数据进行增删改。
  • 第二阶段:Secondary NameNode 工作。
    1. Secondary NameNode 询问 NameNode 是否需要 CheckPoint,并直接带回 NameNode 是否检查的结果。
    2. Secondary NameNode 请求执行 CheckPoint。
    3. NameNode 滚动正在写的 Edits 日志。
    4. NameNode 将滚动前的镜像文件和编辑日志拷贝到 Secondary NameNode。
    5. Secondary NameNode 加载镜像文件和编辑日志到内存,并合并。
    6. Secondary NameNode 生成新的镜像文件 fsimage.chkpoint。
    7. Secondary NameNode 拷贝 fsimage.chkpoint 到 NameNode。
    8. NameNode 将 fsimage.chkpoint 重新命名成 fsimage。

Fsimage 和 Edits 解析

Fsimage 和 Edits 的概念

  • NameNode 被格式化之后,将在 /opt/module/hadoop-3.1.3/data/tmp/dfs/name/current 路径中产生如下文件:

    1
    2
    3
    4
    5
    6
    7
    8
    [xisun@hadoop102 current]$ pwd
    /opt/module/hadoop-3.2.1/data/dfs/name/current
    [xisun@hadoop102 current]$ ll
    总用量 701
    -rw-rw-r--. 1 xisun xisun 418 9月 8 13:43 fsimage_0000000000000000000
    -rw-rw-r--. 1 xisun xisun 62 9月 8 13:43 fsimage_0000000000000000000.md5
    -rw-rw-r--. 1 xisun xisun 4 9月 8 13:43 seen_txid
    -rw-rw-r--. 1 xisun xisun 217 9月 7 11:44 VERSION
  • Fsimage 文件:HDFS 文件系统元数据的一个永久性的检查点,其中包含 HDFS 文件系统的所有目录和文件 inode 的序列化信息。

  • Edits 文件:存放 HDFS 文件系统的所有更新操作的路径,文件系统客户端执行的所有写操作首先会被记录到 Edits 文件中。

  • seen_txid 文件:保存的是一个数字,就是最后一个 edits_ 的数字。

    image-20210908162349654

  • 每次 NameNode 启动的时候都会将 Fsimage 文件读入内存,加载 Edits 里面的更新操作,保证内存中的元数据信息是最新的、同步的,可以看成当 NameNode 启动的时候就将 Fsimage 和 Edits 文件进行了合并。

oiv 查看 Fsimage 文件

  • 查看 oiv 和 oev 命令

    1
    2
    3
    4
    5
    6
    [xisun@hadoop102 current]$ hdfs
    Usage: hdfs [OPTIONS] SUBCOMMAND [SUBCOMMAND OPTIONS]
    ...
    oev apply the offline edits viewer to an edits file
    oiv apply the offline fsimage viewer to an fsimage
    ...
  • 基本语法

    1
    hdfs oiv -p 文件类型 -i 镜像文件名称 -o 转换后文件的输出路径

    -o 参数需要制定转换后文件的具体名称,不能只是一个目录。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    [xisun@hadoop102 current]$ hdfs oiv -p XML -i fsimage_0000000000000000931 -o ~
    Encountered exception. Exiting: /home/xisun (是一个目录)
    java.io.FileNotFoundException: /home/xisun (是一个目录)
    at java.io.FileOutputStream.open0(Native Method)
    at java.io.FileOutputStream.open(FileOutputStream.java:270)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:213)
    at java.io.FileOutputStream.<init>(FileOutputStream.java:101)
    at java.io.PrintStream.<init>(PrintStream.java:248)
    at org.apache.hadoop.hdfs.tools.offlineImageViewer.OfflineImageViewerPB.run(OfflineImageViewerPB.java:178)
    at org.apache.hadoop.hdfs.tools.offlineImageViewer.OfflineImageViewerPB.main(OfflineImageViewerPB.java:137)
  • 实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    [xisun@hadoop102 current]$ pwd
    /opt/module/hadoop-3.2.1/data/dfs/name/current
    [xisun@hadoop102 current]$ hdfs oiv -p XML -i fsimage_0000000000000000931 -o ~/fsimage.XML
    2021-09-08 16:35:27,445 INFO offlineImageViewer.FSImageHandler: Loading 6 strings
    2021-09-08 16:35:29,097 INFO namenode.FSDirectory: GLOBAL serial map: bits=29 maxEntries=536870911
    2021-09-08 16:35:29,097 INFO namenode.FSDirectory: USER serial map: bits=24 maxEntries=16777215
    2021-09-08 16:35:29,097 INFO namenode.FSDirectory: GROUP serial map: bits=24 maxEntries=16777215
    2021-09-08 16:35:29,097 INFO namenode.FSDirectory: XATTR serial map: bits=24 maxEntries=16777215
    [xisun@hadoop102 current]$ cd ~
    [xisun@hadoop102 ~]$ ll
    总用量 28
    drwxrwxr-x. 2 xisun xisun 52 9月 2 23:15 bin
    -rw-rw-r--. 1 xisun xisun 19241 9月 8 16:35 fsimage.XML
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 公共
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 模板
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 视频
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 图片
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 文档
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 下载
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 音乐
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 桌面
  • 下载文件并查看

    1
    [xisun@hadoop102 ~]$ sz fsimage.XML
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    <?xml version="1.0"?>
    <fsimage><version><layoutVersion>-65</layoutVersion><onDiskVersion>1</onDiskVersion><oivRevision>b3cbbb467e22ea829b3808f4b7b01d07e0bf3842</oivRevision></version>
    <NameSection><namespaceId>817173371</namespaceId><genstampV1>1000</genstampV1><genstampV2>1068</genstampV2><genstampV1Limit>0</genstampV1Limit><lastAllocatedBlockId>1073741891</lastAllocatedBlockId><txid>931</txid></NameSection>
    <ErasureCodingSection>
    <erasureCodingPolicy>
    <policyId>1</policyId><policyName>RS-6-3-1024k</policyName><cellSize>1048576</cellSize><policyState>DISABLED</policyState><ecSchema>
    <codecName>rs</codecName><dataUnits>6</dataUnits><parityUnits>3</parityUnits></ecSchema>
    </erasureCodingPolicy>

    <erasureCodingPolicy>
    <policyId>2</policyId><policyName>RS-3-2-1024k</policyName><cellSize>1048576</cellSize><policyState>DISABLED</policyState><ecSchema>
    <codecName>rs</codecName><dataUnits>3</dataUnits><parityUnits>2</parityUnits></ecSchema>
    </erasureCodingPolicy>

    <erasureCodingPolicy>
    <policyId>3</policyId><policyName>RS-LEGACY-6-3-1024k</policyName><cellSize>1048576</cellSize><policyState>DISABLED</policyState><ecSchema>
    <codecName>rs-legacy</codecName><dataUnits>6</dataUnits><parityUnits>3</parityUnits></ecSchema>
    </erasureCodingPolicy>

    <erasureCodingPolicy>
    <policyId>4</policyId><policyName>XOR-2-1-1024k</policyName><cellSize>1048576</cellSize><policyState>DISABLED</policyState><ecSchema>
    <codecName>xor</codecName><dataUnits>2</dataUnits><parityUnits>1</parityUnits></ecSchema>
    </erasureCodingPolicy>

    <erasureCodingPolicy>
    <policyId>5</policyId><policyName>RS-10-4-1024k</policyName><cellSize>1048576</cellSize><policyState>DISABLED</policyState><ecSchema>
    <codecName>rs</codecName><dataUnits>10</dataUnits><parityUnits>4</parityUnits></ecSchema>
    </erasureCodingPolicy>

    </ErasureCodingSection>

    <INodeSection><lastInodeId>16535</lastInodeId><numInodes>48</numInodes><inode><id>16385</id><type>DIRECTORY</type><name></name><mtime>1631005240758</mtime><permission>xisun:supergroup:0755</permission><nsquota>9223372036854775807</nsquota><dsquota>-1</dsquota></inode>
    <inode><id>16386</id><type>DIRECTORY</type><name>wcinput</name><mtime>1631005111883</mtime><permission>xisun:supergroup:0755</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
    <inode><id>16387</id><type>FILE</type><name>wordout.txt</name><replication>10</replication><mtime>1630548862351</mtime><atime>1631005650890</atime><preferredBlockSize>134217728</preferredBlockSize><permission>xisun:xisun:0666</permission><blocks><block><id>1073741825</id><genstamp>1001</genstamp><numBytes>41</numBytes></block>
    </blocks>
    <storagePolicyId>0</storagePolicyId></inode>
    <inode><id>16389</id><type>DIRECTORY</type><name>tmp</name><mtime>1630571709992</mtime><permission>xisun:supergroup:0700</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
    <inode><id>16390</id><type>DIRECTORY</type><name>hadoop-yarn</name><mtime>1630553418947</mtime><permission>xisun:supergroup:0700</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
    <inode><id>16391</id><type>DIRECTORY</type><name>staging</name><mtime>1630554923848</mtime><permission>xisun:supergroup:0700</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
    <inode><id>16392</id><type>DIRECTORY</type><name>xisun</name><mtime>1630553418948</mtime><permission>xisun:supergroup:0700</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
    <inode><id>16393</id><type>DIRECTORY</type><name>.staging</name><mtime>1630571777142</mtime><permission>xisun:supergroup:0700</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
    <inode><id>16394</id><type>DIRECTORY</type><name>job_1630509320297_0001</name><mtime>1630553421706</mtime><permission>xisun:supergroup:0700</permission><xattrs><xattr><ns>SYSTEM</ns><name>hdfs.erasurecoding.policy</name><val>\0000;\0000;\0000;\000b;replication</val></xattr></xattrs><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
    <inode><id>16395</id><type>FILE</type><name>job.jar</name><replication>10</replication><mtime>1630553421192</mtime><atime>1630553420729</atime><preferredBlockSize>134217728</preferredBlockSize><permission>xisun:supergroup:0644</permission><blocks><block><id>1073741829</id><genstamp>1005</genstamp><numBytes>316534</numBytes></block>
    </blocks>
    <storagePolicyId>0</storagePolicyId></inode>
    <inode><id>16396</id><type>FILE</type><name>job.split</name><replication>10</replication><mtime>1630553421574</mtime><atime>1630553421453</atime><preferredBlockSize>134217728</preferredBlockSize><permission>xisun:supergroup:0644</permission><blocks><block><id>1073741830</id><genstamp>1006</genstamp><numBytes>110</numBytes></block>
    </blocks>
    <storagePolicyId>0</storagePolicyId></inode>
    <inode><id>16397</id><type>FILE</type><name>job.splitmetainfo</name><replication>3</replication><mtime>1630553421698</mtime><atime>1630553421586</atime><preferredBlockSize>134217728</preferredBlockSize><permission>xisun:supergroup:0644</permission><blocks><block><id>1073741831</id><genstamp>1007</genstamp><numBytes>43</numBytes></block>
    </blocks>
    <storagePolicyId>0</storagePolicyId></inode>
    <inode><id>16398</id><type>FILE</type><name>job.xml</name><replication>3</replication><mtime>1630553422297</mtime><atime>1630553421706</atime><preferredBlockSize>134217728</preferredBlockSize><permission>xisun:supergroup:0644</permission><blocks><block><id>1073741832</id><genstamp>1008</genstamp><numBytes>192215</numBytes></block>
    </blocks>
    <storagePolicyId>0</storagePolicyId></inode>
    <inode><id>16399</id><type>DIRECTORY</type><name>job_1630509320297_0002</name><mtime>1630553679452</mtime><permission>xisun:supergroup:0700</permission><xattrs><xattr><ns>SYSTEM</ns><name>hdfs.erasurecoding.policy</name><val>\0000;\0000;\0000;\000b;replication</val></xattr></xattrs><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
    <inode><id>16400</id><type>FILE</type><name>job.jar</name><replication>10</replication><mtime>1630553679124</mtime><atime>1630553678890</atime><preferredBlockSize>134217728</preferredBlockSize><permission>xisun:supergroup:0644</permission><blocks><block><id>1073741833</id><genstamp>1009</genstamp><numBytes>316534</numBytes></block>
    </blocks>
    <storagePolicyId>0</storagePolicyId></inode>
    <inode><id>16401</id><type>FILE</type><name>job.split</name><replication>10</replication><mtime>1630553679334</mtime><atime>1630553679221</atime><preferredBlockSize>134217728</preferredBlockSize><permission>xisun:supergroup:0644</permission><blocks><block><id>1073741834</id><genstamp>1010</genstamp><numBytes>110</numBytes></block>
    </blocks>
    <storagePolicyId>0</storagePolicyId></inode>
    <inode><id>16402</id><type>FILE</type><name>job.splitmetainfo</name><replication>3</replication><mtime>1630553679443</mtime><atime>1630553679339</atime><preferredBlockSize>134217728</preferredBlockSize><permission>xisun:supergroup:0644</permission><blocks><block><id>1073741835</id><genstamp>1011</genstamp><numBytes>43</numBytes></block>
    </blocks>
    <storagePolicyId>0</storagePolicyId></inode>
    <inode><id>16403</id><type>FILE</type><name>job.xml</name><replication>3</replication><mtime>1630553679670</mtime><atime>1630553679452</atime><preferredBlockSize>134217728</preferredBlockSize><permission>xisun:supergroup:0644</permission><blocks><block><id>1073741836</id><genstamp>1012</genstamp><numBytes>192215</numBytes></block>
    </blocks>
    <storagePolicyId>0</storagePolicyId></inode>
    <inode><id>16409</id><type>DIRECTORY</type><name>history</name><mtime>1630567073024</mtime><permission>xisun:supergroup:0755</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
    <inode><id>16410</id><type>DIRECTORY</type><name>done_intermediate</name><mtime>1630554923873</mtime><permission>xisun:supergroup:1777</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
    <inode><id>16411</id><type>DIRECTORY</type><name>xisun</name><mtime>1630571854446</mtime><permission>xisun:supergroup:0770</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
    <inode><id>16418</id><type>FILE</type><name>job_1630509320297_0003-1630554915644-xisun-word+count-1630554943250-0-0-FAILED-default-1630554928660.jhist</name><replication>3</replication><mtime>1630554943458</mtime><atime>1630554943411</atime><preferredBlockSize>134217728</preferredBlockSize><permission>xisun:supergroup:0770</permission><blocks><block><id>1073741844</id><genstamp>1020</genstamp><numBytes>14969</numBytes></block>
    </blocks>
    <storagePolicyId>0</storagePolicyId></inode>
    <inode><id>16419</id><type>FILE</type><name>job_1630509320297_0003_conf.xml</name><replication>3</replication><mtime>1630554943540</mtime><atime>1630554943476</atime><preferredBlockSize>134217728</preferredBlockSize><permission>xisun:supergroup:0770</permission><blocks><block><id>1073741845</id><genstamp>1021</genstamp><numBytes>222769</numBytes></block>
    </blocks>
    <storagePolicyId>0</storagePolicyId></inode>
    <inode><id>16437</id><type>FILE</type><name>job_1630509320297_0004-1630559739775-xisun-word+count-1630559924980-1-1-SUCCEEDED-default-1630559746457.jhist</name><replication>3</replication><mtime>1630559927155</mtime><atime>1630559927104</atime><preferredBlockSize>134217728</preferredBlockSize><permission>xisun:supergroup:0770</permission><blocks><block><id>1073741854</id><genstamp>1030</genstamp><numBytes>22803</numBytes></block>
    </blocks>
    <storagePolicyId>0</storagePolicyId></inode>
    <inode><id>16438</id><type>FILE</type><name>job_1630509320297_0004_conf.xml</name><replication>3</replication><mtime>1630559927279</mtime><atime>1630559927177</atime><preferredBlockSize>134217728</preferredBlockSize><permission>xisun:supergroup:0770</permission><blocks><block><id>1073741855</id><genstamp>1031</genstamp><numBytes>223439</numBytes></block>
    </blocks>
    <storagePolicyId>0</storagePolicyId></inode>
    <inode><id>16456</id><type>FILE</type><name>job_1630509320297_0005-1630562908651-xisun-word+count-1630563047214-1-1-SUCCEEDED-default-1630562921426.jhist</name><replication>3</replication><mtime>1630563046601</mtime><atime>1630563046543</atime><preferredBlockSize>134217728</preferredBlockSize><permission>xisun:supergroup:0770</permission><blocks><block><id>1073741864</id><genstamp>1040</genstamp><numBytes>22770</numBytes></block>
    </blocks>
    <storagePolicyId>0</storagePolicyId></inode>
    <inode><id>16457</id><type>FILE</type><name>job_1630509320297_0005_conf.xml</name><replication>3</replication><mtime>1630563046693</mtime><atime>1630563046621</atime><preferredBlockSize>134217728</preferredBlockSize><permission>xisun:supergroup:0770</permission><blocks><block><id>1073741865</id><genstamp>1041</genstamp><numBytes>223439</numBytes></block>
    </blocks>
    <storagePolicyId>0</storagePolicyId></inode>
    <inode><id>16458</id><type>DIRECTORY</type><name>done</name><mtime>1630567231439</mtime><permission>xisun:supergroup:0770</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
    <inode><id>16476</id><type>FILE</type><name>job_1630509320297_0006-1630567142285-xisun-word+count-1630567220324-1-1-SUCCEEDED-default-1630567156915.jhist</name><replication>3</replication><mtime>1630567219772</mtime><atime>1630567219669</atime><preferredBlockSize>134217728</preferredBlockSize><permission>xisun:supergroup:0770</permission><blocks><block><id>1073741874</id><genstamp>1050</genstamp><numBytes>22792</numBytes></block>
    </blocks>
    <storagePolicyId>0</storagePolicyId></inode>
    <inode><id>16477</id><type>FILE</type><name>job_1630509320297_0006_conf.xml</name><replication>3</replication><mtime>1630567219913</mtime><atime>1630567219802</atime><preferredBlockSize>134217728</preferredBlockSize><permission>xisun:supergroup:0770</permission><blocks><block><id>1073741875</id><genstamp>1051</genstamp><numBytes>223437</numBytes></block>
    </blocks>
    <storagePolicyId>0</storagePolicyId></inode>
    <inode><id>16478</id><type>DIRECTORY</type><name>2021</name><mtime>1630567231440</mtime><permission>xisun:supergroup:0770</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
    <inode><id>16479</id><type>DIRECTORY</type><name>09</name><mtime>1630567231440</mtime><permission>xisun:supergroup:0770</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
    <inode><id>16480</id><type>DIRECTORY</type><name>02</name><mtime>1630567231441</mtime><permission>xisun:supergroup:0770</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
    <inode><id>16481</id><type>DIRECTORY</type><name>000000</name><mtime>1630571854446</mtime><permission>xisun:supergroup:0770</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
    <inode><id>16487</id><type>DIRECTORY</type><name>logs</name><mtime>1630571710042</mtime><permission>xisun:xisun:1777</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
    <inode><id>16488</id><type>DIRECTORY</type><name>xisun</name><mtime>1630571710049</mtime><permission>xisun:xisun:0770</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
    <inode><id>16489</id><type>DIRECTORY</type><name>logs-tfile</name><mtime>1630571710069</mtime><permission>xisun:xisun:0770</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
    <inode><id>16490</id><type>DIRECTORY</type><name>application_1630509320297_0007</name><mtime>1630571783775</mtime><permission>xisun:xisun:0770</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
    <inode><id>16492</id><type>DIRECTORY</type><name>wcoutput</name><mtime>1630571775649</mtime><permission>xisun:supergroup:0755</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
    <inode><id>16498</id><type>FILE</type><name>part-r-00000</name><replication>3</replication><mtime>1630571775482</mtime><atime>1630571775197</atime><preferredBlockSize>134217728</preferredBlockSize><permission>xisun:supergroup:0644</permission><blocks><block><id>1073741882</id><genstamp>1058</genstamp><numBytes>36</numBytes></block>
    </blocks>
    <storagePolicyId>0</storagePolicyId></inode>
    <inode><id>16500</id><type>FILE</type><name>_SUCCESS</name><replication>3</replication><mtime>1630571775653</mtime><atime>1630571775649</atime><preferredBlockSize>134217728</preferredBlockSize><permission>xisun:supergroup:0644</permission><storagePolicyId>0</storagePolicyId></inode>
    <inode><id>16503</id><type>FILE</type><name>job_1630509320297_0007-1630571709613-xisun-word+count-1630571776516-1-1-SUCCEEDED-default-1630571719711.jhist</name><replication>3</replication><mtime>1630571775936</mtime><atime>1630656192752</atime><preferredBlockSize>134217728</preferredBlockSize><permission>xisun:supergroup:0770</permission><blocks><block><id>1073741884</id><genstamp>1060</genstamp><numBytes>22765</numBytes></block>
    </blocks>
    <storagePolicyId>0</storagePolicyId></inode>
    <inode><id>16504</id><type>FILE</type><name>job_1630509320297_0007_conf.xml</name><replication>3</replication><mtime>1630571776037</mtime><atime>1630571775955</atime><preferredBlockSize>134217728</preferredBlockSize><permission>xisun:supergroup:0770</permission><blocks><block><id>1073741885</id><genstamp>1061</genstamp><numBytes>223615</numBytes></block>
    </blocks>
    <storagePolicyId>0</storagePolicyId></inode>
    <inode><id>16505</id><type>FILE</type><name>hadoop103_43362</name><replication>3</replication><mtime>1630571783767</mtime><atime>1630571783609</atime><preferredBlockSize>134217728</preferredBlockSize><permission>xisun:xisun:0640</permission><blocks><block><id>1073741886</id><genstamp>1062</genstamp><numBytes>136973</numBytes></block>
    </blocks>
    <storagePolicyId>0</storagePolicyId></inode>
    <inode><id>16508</id><type>DIRECTORY</type><name>sanguoyanyi</name><mtime>1630917975333</mtime><permission>xisun:supergroup:0755</permission><nsquota>-1</nsquota><dsquota>-1</dsquota></inode>
    <inode><id>16509</id><type>FILE</type><name>shuguo.txt</name><replication>3</replication><mtime>1630918100557</mtime><atime>1630917608900</atime><preferredBlockSize>134217728</preferredBlockSize><permission>xisun:supergroup:0644</permission><blocks><block><id>1073741888</id><genstamp>1067</genstamp><numBytes>14</numBytes></block>
    </blocks>
    <storagePolicyId>0</storagePolicyId></inode>
    <inode><id>16510</id><type>FILE</type><name>weiguo.txt</name><replication>3</replication><mtime>1630917830657</mtime><atime>1630917830222</atime><preferredBlockSize>134217728</preferredBlockSize><permission>xisun:supergroup:0644</permission><blocks><block><id>1073741889</id><genstamp>1065</genstamp><numBytes>7</numBytes></block>
    </blocks>
    <storagePolicyId>0</storagePolicyId></inode>
    <inode><id>16511</id><type>FILE</type><name>wuguo.txt</name><replication>3</replication><mtime>1630917975305</mtime><atime>1630917974782</atime><preferredBlockSize>134217728</preferredBlockSize><permission>xisun:supergroup:0644</permission><blocks><block><id>1073741890</id><genstamp>1066</genstamp><numBytes>6</numBytes></block>
    </blocks>
    <storagePolicyId>0</storagePolicyId></inode>
    </INodeSection>
    <INodeReferenceSection></INodeReferenceSection><SnapshotSection><snapshotCounter>0</snapshotCounter><numSnapshots>0</numSnapshots></SnapshotSection>
    <INodeDirectorySection><directory><parent>16385</parent><child>16508</child><child>16389</child><child>16386</child><child>16492</child><child>16387</child></directory>
    <directory><parent>16389</parent><child>16390</child><child>16487</child></directory>
    <directory><parent>16390</parent><child>16391</child></directory>
    <directory><parent>16391</parent><child>16409</child><child>16392</child></directory>
    <directory><parent>16392</parent><child>16393</child></directory>
    <directory><parent>16393</parent><child>16394</child><child>16399</child></directory>
    <directory><parent>16394</parent><child>16395</child><child>16396</child><child>16397</child><child>16398</child></directory>
    <directory><parent>16399</parent><child>16400</child><child>16401</child><child>16402</child><child>16403</child></directory>
    <directory><parent>16409</parent><child>16458</child><child>16410</child></directory>
    <directory><parent>16410</parent><child>16411</child></directory>
    <directory><parent>16458</parent><child>16478</child></directory>
    <directory><parent>16478</parent><child>16479</child></directory>
    <directory><parent>16479</parent><child>16480</child></directory>
    <directory><parent>16480</parent><child>16481</child></directory>
    <directory><parent>16481</parent><child>16418</child><child>16419</child><child>16437</child><child>16438</child><child>16456</child><child>16457</child><child>16476</child><child>16477</child><child>16503</child><child>16504</child></directory>
    <directory><parent>16487</parent><child>16488</child></directory>
    <directory><parent>16488</parent><child>16489</child></directory>
    <directory><parent>16489</parent><child>16490</child></directory>
    <directory><parent>16490</parent><child>16505</child></directory>
    <directory><parent>16492</parent><child>16500</child><child>16498</child></directory>
    <directory><parent>16508</parent><child>16509</child><child>16510</child><child>16511</child></directory>
    </INodeDirectorySection>
    <FileUnderConstructionSection></FileUnderConstructionSection>
    <SecretManagerSection><currentId>0</currentId><tokenSequenceNumber>0</tokenSequenceNumber><numDelegationKeys>0</numDelegationKeys><numTokens>0</numTokens></SecretManagerSection><CacheManagerSection><nextDirectiveId>1</nextDirectiveId><numDirectives>0</numDirectives><numPools>0</numPools></CacheManagerSection>
    </fsimage>
    • Fsimage 文件中保存了 HDFS 上存储的文件的信息,包括父节点和子节点的关系。
    • Fsimage 文件中没有记录 Block 块所对应的 DataNode 信息,这是因为,在集群启动后,会要求 DataNode 上报数据块信息,并间隔一段时间后再次上报。

oev 查看 Edits 文件

  • 基本语法

    1
    hdfs oev -p 文件类型 -i 编辑日志名称 -o 转换后文件的输出路径
  • 实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    [xisun@hadoop102 ~]$ cd /opt/module/hadoop-3.2.1/data/dfs/name/current
    [xisun@hadoop102 current]$ hdfs oev -p XML -i edits_inprogress_0000000000000000936 -o ~/edits.XML
    [xisun@hadoop102 current]$ cd ~
    [xisun@hadoop102 ~]$ ll
    总用量 24
    drwxrwxr-x. 2 xisun xisun 52 9月 2 23:15 bin
    -rw-rw-r--. 1 xisun xisun 221 9月 8 16:46 edits.XML
    -rw-rw-r--. 1 xisun xisun 19241 9月 8 16:35 fsimage.XML
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 公共
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 模板
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 视频
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 图片
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 文档
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 下载
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 音乐
    drwxr-xr-x. 2 xisun xisun 6 8月 28 23:56 桌面
  • 下载文件并查看

    1
    [xisun@hadoop102 current]$ sz ~/edits.xml
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <EDITS>
    <EDITS_VERSION>-65</EDITS_VERSION>
    <RECORD>
    <OPCODE>OP_START_LOG_SEGMENT</OPCODE>
    <DATA>
    <TXID>936</TXID>
    </DATA>
    </RECORD>
    <RECORD>
    <OPCODE>OP_DELETE</OPCODE>
    <DATA>
    <TXID>937</TXID>
    <LENGTH>0</LENGTH>
    <PATH>/sanguoyanyi</PATH>
    <TIMESTAMP>1631092478280</TIMESTAMP>
    <RPC_CLIENTID>db87d83d-dba1-4362-add1-ff9cbdbceea0</RPC_CLIENTID>
    <RPC_CALLID>3</RPC_CALLID>
    </DATA>
    </RECORD>
    </EDITS>
    • NameNode 如何确定下次开机启动的时候合并哪些 Edits:假设当前 fsimage 最大编号为 935,则会将所有编号大于 935 的 Edits 合并。

CheckPoint 时间设置

  • CheckPoint 是指 SecondaryNameNode 向 nn 执行的操作。

  • 通常情况下,SecondaryNameNode 每隔一小时执行一次。间隔时间在 hdfs-default.xml 文件中进行配置:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <property>
    <name>dfs.namenode.checkpoint.period</name>
    <value>3600s</value>
    <description>
    The number of seconds between two periodic checkpoints.
    Support multiple time unit suffix(case insensitive), as described
    in dfs.heartbeat.interval.
    </description>
    </property>
  • 另外,SecondaryNameNode 每隔一分钟检查一次 NameNode 的操作次数,当操作次数达到 1 百万时,SecondaryNameNode 执行一次 CheckPoint。间隔时间和操作次数在 hdfs-default.xml 文件中进行配置:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <property>
    <name>dfs.namenode.checkpoint.txns</name>
    <value>1000000</value>
    <description>The Secondary NameNode or CheckpointNode will create a checkpoint
    of the namespace every 'dfs.namenode.checkpoint.txns' transactions, regardless
    of whether 'dfs.namenode.checkpoint.period' has expired.
    </description>
    </property>

    <property>
    <name>dfs.namenode.checkpoint.check.period</name>
    <value>60s</value>
    <description>The SecondaryNameNode and CheckpointNode will poll the NameNode
    every 'dfs.namenode.checkpoint.check.period' seconds to query the number
    of uncheckpointed transactions. Support multiple time unit suffix(case insensitive),
    as described in dfs.heartbeat.interval.
    </description>
    </property>

DataNode

DataNode 工作机制

image-20210908232731057

  • 一个数据块在 DataNode 上以文件形式存储在磁盘上,包括两个文件,一个是数据本身,一个是元数据,包括数据块的长度,块数据的校验和,以及时间戳。

    1
    2
    3
    4
    5
    [xisun@hadoop102 ~]$ cd /opt/module/hadoop-3.2.1/data/dfs/data/current/BP-288566776-192.168.10.102-1630507194979/current/finalized/subdir0/subdir0
    [xisun@hadoop102 subdir0]$ ll
    总用量 52
    -rw-rw-r--. 1 xisun xisun 41 9月 2 10:14 blk_1073741825
    -rw-rw-r--. 1 xisun xisun 11 9月 2 10:14 blk_1073741825_1001.meta

    .meta 文件存储的是元数据,另一个文件存储的是数据本身。

  • DataNode 启动后向 NameNode 注册,通过后,再周期性(6 小时)的向 NameNode 上报所有的块信息。

    • DataNode 扫描自己节点块信息列表的时间,默认 6 小时。在 hdfs-default.xml 文件中配置:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      <property>
      <name>dfs.datanode.directoryscan.interval</name>
      <value>21600s</value>
      <description>Interval in seconds for Datanode to scan data directories and
      reconcile the difference between blocks in memory and on the disk.
      Support multiple time unit suffix(case insensitive), as described
      in dfs.heartbeat.interval.
      </description>
      </property>
    • DataNode 向 NameNode 汇报当前节点块信息的时间间隔,默认 6 小时。在 hdfs-default.xml 文件中配置:

      1
      2
      3
      4
      5
      <property>
      <name>dfs.blockreport.intervalMsec</name>
      <value>21600000</value>
      <description>Determines block reporting interval in milliseconds.</description>
      </property>
    • 可以看出,DataNode 每隔 6 小时自查一次,自查完成后,立即向 NameNode 上报一次当前节点的信息。如果服务器中存在某些服务器性能差,可以设置自查和上报的时间间隔短一点。

  • 心跳是每 3 秒一次,心跳返回结果带有 NameNode 给该 DataNode 的命令,比如复制块数据到另一台机器,或删除某个数据块。如果超过 10 分钟没有收到某个 DataNode 的心跳,则认为该节点不可用,NameNode 也就不会再和该 DataNode 有数据交互。

  • 集群运行中可以安全加入和退出一些机器。

数据完整性

  • 思考:如果电脑磁盘里面存储的数据是控制高铁信号灯的红灯信号(1)和绿灯信号(0),但是存储该数据的磁盘坏了,一直显示是绿灯,是否很危险?同理,如果 DataNode 节点上的数据损坏了,却没有发现,也很危险,那么如何解决呢?

  • 如下是 DataNode 节点保证数据完整性的方法:

    1. 当 DataNode 读取 Block 的时候,它会计算 CheckSum。

    2. 如果计算后的 CheckSum,与 Block 创建时的值不一样,说明 Block 已经损坏。

    3. 然后,Client 读取其他 DataNode 上的 Block。

    4. DataNode 会在其文件创建后周期验证 CheckSum。

    5. 常见的校验算法有: crc(32),md5(128),sha1(160)。

      image-20210909092530067

      • 奇偶校验位方法,是检验算法中极其简单的一种。原始数据封装时,查看待传输数据中 1 的个数,如果为偶数,则在数据后添加一个校验位,值为 0,如果为奇数,则校验位值为 1。当接收到数据后,对数据进行重新计算,查看数据中 1 的个数,验证其是否与传输前的校验位相同。如果在数据传输过程中,导致数据发生了错误,接收到的数据校验位与原始数据的不同,则认为数据损坏,不再使用。
      • 奇偶校验法,并不能保证一定检验出数据传输过程中可能出现的错误。crc 校验算法会更复杂,也更可靠,但原理上是相同的。

掉线时限参数设置

  • 如果 DataNode 进程死亡或者网络故障,造成 DataNode 无法与 NameNode 通信;

  • 此时,NameNode 不会立即把该 DataNode 节点判定为死亡,要经过一段时间,这段时间暂称作超时时长。

  • HDFS 默认的超时时长为 10 分钟 + 30 秒。(实际上,这就是 DataNode 工作机制中,DataNode 向 NameNode 发送心跳的超时时间)

  • 如果定义超时时间为 TimeOut,则超时时长的计算公式为:

    1
    TimeOut = 2 * dfs.namenode.heartbeat.recheck-interval + 10 * dfs.heartbeat.interval
  • 在 hdfs-default.xml 文件中,dfs.namenode.heartbeat.recheck-interval 默认为 300000 毫秒(5 分钟),dfs.heartbeat.interval 默认为 3 秒。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    <property>
    <name>dfs.namenode.heartbeat.recheck-interval</name>
    <value>300000</value>
    <description>
    This time decides the interval to check for expired datanodes.
    With this value and dfs.heartbeat.interval, the interval of
    deciding the datanode is stale or not is also calculated.
    The unit of this configuration is millisecond.
    </description>
    </property>

    <property>
    <name>dfs.heartbeat.interval</name>
    <value>3s</value>
    <description>
    Determines datanode heartbeat interval in seconds.
    Can use the following suffix (case insensitive):
    ms(millis), s(sec), m(min), h(hour), d(day)
    to specify the time (such as 2s, 2m, 1h, etc.).
    Or provide complete number in seconds (such as 30 for 30 seconds).
    </description>
    </property>

YARN 资源调度器

  • YARN 是一个资源调度平台,负责为运算程序提供服务器运算资源,相当于一个分布式的操作系统平台,而 MapReduce 等运算程序则相当于运行于操作系统之上的应用程序。

YARN 基础架构

image-20210909113318240

  • YARN 主要由 ResourceManager、NodeManager、ApplicationMaster 和 Container 等组件构成。
  • ResourceManager(RM)的主要作用如下:
    • 处理客户端请求。
    • 监控 NodeManager。
    • 启动或监控 ApplicationMaster。
    • 资源的分配与调度。
  • NodeManager(NM)的主要作用如下:
    • 管理单个节点上的资源。
    • 处理来自 ResourceManager 的命令。
    • 处理来自 ApplicationMaster 的命令。
  • ApplicationMaster(AM)的主要作用如下:
    • 为应用程序申请资源并分配给内部的任务。
    • 任务的监控与容错。
  • Container 的主要作用如下:
    • Container 是 YARN 中的资源抽象,它封装了某个节点上的多维度资源,如内存、CPU、磁盘、网络等。

YARN 工作机制

image-20210909132534626

  • MapReduce 程序(任务分为 MapTask 和 ReduceTask)提交到客户端所在的节点,程序执行后创建一个 YarnRunner。
  • YarnRunner 向 ResourceManager 申请一个 Application。
  • ResourceManager 将该应用程序的资源提交路径返回给 YarnRunner。
  • 该程序将运行所需资源(split 切片信息,xml 配置文件,JAR 包等)提交到 HDFS 上。
  • 程序运行所需的资源提交到 HDFS 完毕后,再向 ResourceManager 申请运行 ApplicationMaster。
  • ResourceManager 将客户端(用户)的请求初始化成一个 Task。并将 Task 以及其他客户端的请求所初始化的 Task,都放到一个任务调度队列中(Apache Hadoop 默认使用容量调度器)。
  • 集群中的一个空闲的 NodeManager,从任务调度队列中领取到 Task 任务。
  • 然后,该 NodeManager 创建一个容器 Container,并启动一个 ApplicationMaster 进程。
  • Container 从 HDFS 上拷贝程序运行所需的资源到本地。
  • ApplicationMaster 进程拿到 Job 的切片信息之后,再向 ResourceManager 申请运行 MapTask 的资源(假设 MapTask 有两个任务)。
  • ResourceManager 将运行 MapTask 的任务分配给集群另外两个 NodeManager(也有可能是同一个 NodeManager 的两个 Container 上),这两个 NodeManager 分别领取任务并创建容器,并拷贝任务运行所需的 JAR 包等资源。
  • MapReduce 向两个接收到任务的 NodeManager 发送程序启动脚本,然后这两个 NodeManager 分别启动 MapTask,各自开启一个 YarnChild 子进程,之后,MapTask 开始执行,对数据分区排序。
  • ApplicationMaster 进程等待所有的 MapTask 运行完毕后,再向 ResourceManager 申请容器,运行 ReduceTask。这一步与运行 MapTask 的操作相同。
  • ReduceTask 启动时,向 MapTask 获取相应分区的数据,然后执行任务。
  • 当程序运行完毕后,MapReduce 会向 ResourceManager 申请注销任务执行过程中所使用的资源。

作业提交全过程

  • HDFS、YARN、MapReduce 三者关系

    image-20210909152245552

  • 作业提交过程之 YARN

    image-20210909132534626

  • 作业提交过程之 HDFS & MapReduce

    image-20210909153850477

  • 作业提交全过程详解

    • 作业提交:
      • 第 1 步:Client 调用 job.waitForCompletion 方法,向整个集群提交 MR 作业。
      • 第 2 步:Client 向 RM 申请一个作业 id。
      • 第 3 步:RM 给 Client 返回该 Job 资源的 HDFS 提交路径和作业 id。
      • 第 4 步:Client 提交 JAR 包、切片信息和配置文件到指定的 HDFS 资源提交路径。
      • 第 5 步:Client 提交完资源后,向 RM 申请运行 AM。
    • 作业初始化:
      • 第 6 步:当 RM 收到 Client 的请求后,将该 Job 添加到容量调度器中。
      • 第 7 步:某一个空闲的 NM 领取到该 Job。
      • 第 8 步:该 NM 创建 Container,并启动 AM 进程。
      • 第 9 步:该 Container 下载 Client 提交到 HDFS 的资源到本地。
    • 任务分配:
      • 第 10 步:AM 向 RM 申请执行多个 MapTask 任务的资源。
      • 第 11 步:RM 将运行 MapTask 的任务分配给相应的 NM,这些 NM 分别领取任务并创建 Container。
    • 任务运行:
      • 第 12 步:MR 向接收到任务的 NM 发送程序启动脚本,这些 NM 分别启动 MapTask,MapTask 对数据分区排序。
      • 第 13 步:AM 等待所有 MapTask 运行完毕后,再向 RM 申请容器,运行 ReduceTask。
      • 第 14 步:ReduceTask 向 MapTask 获取相应分区的数据。
      • 第 15 步:程序运行完毕后,MR 向 RM 申请注销自己。
    • 进度和状态更新:
      • YARN 中的任务将其进度和状态(包括 counter)返回给应用管理器, 客户端每秒(通过 mapreduce.client.progressmonitor.pollinterval 设置)向应用管理器请求进度更新,展示给用户。
    • 作业完成:
      • 除了向应用管理器请求作业进度外,客户端每 5 秒都会通过调用 waitForCompletion() 来检查作业是否完成。时间间隔可以通过 mapreduce.client.completion.pollinterval 来设置。作业完成之后,应用管理器和 Container 会清理工作状态。作业的信息会被作业历史服务器存储以备之后用户核查。

YARN 调度器和调度算法

  • 目前,Hadoop 提供的任务队列调度器主要有三种:先进先出调度器(FIFO)、容量调度器(Capacity Scheduler)和公平调度器(Fair Scheduler)。

  • Apache Hadoop-3.2.1 默认的资源调度器是 Capacity Scheduler,在 yarn-default.xml 文件中,有具体的配置:

    1
    2
    3
    4
    5
    <property>
    <description>The class to use as the resource scheduler.</description>
    <name>yarn.resourcemanager.scheduler.class</name>
    <value>org.apache.hadoop.yarn.server.resourcemanager.scheduler.capacity.CapacityScheduler</value>
    </property>

    Cloudera Hadoop 默认使用的调度器是 Fair Scheduler。

先进先出调度器(FIFO)

image-20210909164336456

  • FIFO 调度器(First In First Out):单队列,根据提交作业的先后顺序,先来的先服务。
  • 优点:简单易懂。
  • 缺点:不支持多队列,生产环境很少使用。

容量调度器(Capacity Scheduler)

  • Capacity Scheduler 是 Yahoo 开发的多用户调度器。

  • 容量调度器的特点

    image-20210909170809620

    • 多队列:每个队列可配置一定的资源量,每个队列采用 FIFO 调度策略。
    • 容量保证:管理员可为每个队列设置资源最低保证和资源使用上限。
    • 灵活性:如果一个队列中的资源有剩余,可以暂时共享给那些需要资源的队列,而一旦该队列有新的应用程序提交,则其他队列借调的资源会归还给该队列(非强制回收)。
    • 多租户:支持多用户共享集群和多应用程序同时运行。为了防止同一个用户的作业独占队列中的资源,该调度器会对同一用户提交的作业所占资源量进行限定。比如,queueC 队列中,有 ss 和 cls 两个用户提交的作业,调度器可以限制每一个用户所占的资源量为自身资源的 50%。
  • 容量调度器的队列的资源分配方式

    • FIFO 策略,默认。
      • 具体的资源分配过程:
        • 第一步:队列资源分配。
          • 从 root 开始,使用深度优先算法,优先选择资源利用率最低(已使用的资源量/队列分配的资源容量)的队列分配资源。
        • 第二步:作业资源分配。
          • 默认按照提交作业的优先级和提交时间顺序分配资源。
        • 第三步:容器资源分配。
          • 按照容器的优先级分配资源。
          • 如果容器的优先级相同,按照数据本地性原则(节点距离最小的):
            • 任务和数据在同一节点。
            • 任务和数据在同一机架。
            • 任务和数据不在同一节点也不在同一机架。
    • DRF 策略
  • 容量调度器的资源分配算法实例

    image-20210909171256904

公平调度器(Fair Scheduler )

  • Fair Schedulere 是 Facebook 开发的多用户调度器。

  • 公平调度器的特点

    image-20210909173251464

    • 与容量调度器的相同点
      • 多队列:支持多队列多作业。
      • 容量保证:管理员可为每个队列设置资源最低保证和资源使用上限。
      • 灵活性:如果一个队列中的资源有剩余,可以暂时共享给那些需要资源的队列,而一旦该队列有新的应用程序提交,则其他队列借调的资源会归还给该队列。
      • 多租户:支持多用户共享集群和多应用程序同时运行。为了防止同一个用户的作业独占队列中的资源,该调度器会对同一用户提交的作业所占资源量进行限定。
    • 与容量调度器的不同点
      • 核心调度策略不同:
        • 容量调度器:优先选择资源利用率低的队列。
        • 公平调度器:优先选择对资源的缺额比例大的。
      • 每个队列可以单独设置资源的分配方式不同:
        • 容量调度器:FIFO、DRF。
        • 公平调度器:FIFO、FAIR、DRF。
  • 公平调度器的缺额概念

    image-20210909234011348

    • 公平调度器设计目标是:在时间尺度上,所有作业获得公平的资源。在某一时刻,一个作业应获取的资源和它实际获取的资源的差距叫“缺额”。
    • 公平调度器会优先为缺额大的作业分配资源。
  • 公平调度器的队列的资源分配方式

    • FIFO 策略

      • 公平调度器每个队列资源分配策略如果选择 FIFO 的话,此时公平调度器相当于上面讲过的容量调度器。
    • Fair 策略,默认。

      • Fair 策略是一种基于最大最小公平算法实现的资源多路复用方式,默认情况下,每个队列内部采用该方式分配资源。这意味着,如果一个队列中有两个应用程序同时运行,则每个应用程序可得到 1/2 的资源;如果三个应用程序同时运行,则每个应用程序可得到 1/3 的资源。

      • 具体的资源分配过程和容量调度器一致:

        • 选择队列

        • 选择作业

        • 选择容器

        • 注意:以上三步,每一步都是按照公平策略来分配资源。

          image-20210910171552241

          • 实际最小资源份额:mindshare = Min(资源需求量, 配置的最小资源)
          • 是否饥饿:isNeedy = 资源使用量 < mindshare
          • 资源分配比:minShareRatio = 资源使用量 / Max(mindshare, 1)
          • 资源使用权重比:useToWeightRatio = 资源使用量 / 权重
          • 假设一个任务,其资源需求量为 4,配置的最小资源为 2,现在的资源使用量为 1,权重为 8。则 mindshare 为 2,因为资源使用量小于 mindshare,所以该任务处于饥饿状态。另外,其 minShareRatio 的值为 1/2,useToWeightRatio 值为 1/6。同理,计算出其他任务的这些状态值,按上图流程,决定资源优先分配到哪个任务。
    • DRF 策略

      • DRF(Dominant Resource Fairness),前面说的资源,都是单一标准,例如只考虑内存(也是 YARN 默认的情况)。但是很多时候资源有很多种,例如内存,CPU,网络带宽等,这样就很难衡量两个应用应该分配的资源比例。
      • 在 YARN 中,用 DRF 来决定如何调度:
        • 假设集群一共有 100 CPU 和 10 T 内存,而应用 A 需要(2 CPU,300 GB 内存),应用 B 需要(6 CPU,100 GB 内存)。则两个应用分别需要 A(2% CPU,3% 内存)和 B(6% CPU,1% 内存)的资源,这就意味着 A 是内存主导的,B 是 CPU 主导的,针对这种情况,我们可以选择 DRF 策略对不同应用进行不同资源(CPU 和内存)的一个不同比例的限制。
  • 公平调度器的资源分配算法实例

    image-20210910230253307

    • 队列资源分配
      • 需求:集群总资源 100,有三个队列,对资源的需求分别是:queueA —> 20,queueB —> 50,queueC —> 30。
      • 第一次算:100 / 3 = 33.33,即每个队列应得资源 33.33。
        • queueA:分 33.33 —> 多 13.33。
        • queueB:分 33.33 —> 少 16.67。
        • queueC:分 33.33 —> 多 3.33。
      • 第二次算:(13.33 + 3.33) / 1 = 16.66,各队列空闲资源的总和,与需要资源的队列数的比值。
        • queueA:分 20。
        • queueB:分 33.33 + 16.66 = 50。
        • queueC:分 30。
    • 作业资源分配
      • 不加权(关注点是 job 的个数)
        • 需求:有一条队列总资源 12 个,有 4 个 job,对资源的需求分别是:job1 —> 1,job2 —> 2,job3 —> 6,job4 —> 5。
        • 第一次算:12 / 4 = 3。
          • job1:分 3 —> 多 2 个。
          • job2:分 3 —> 多 1 个。
          • job3:分 3 —> 少 3 个。
          • job4:分 3 —> 少 2 个。
        • 第二次算:3 / 2 = 1.5
          • job1:分 1 —> 最终:1。
          • job2:分 2 —> 最终:2。
          • job3:分 3 —> 少 3 个 —> 分 1.5 —> 最终:4.5。
          • job4:分 3 —> 少 2 个 —> 分 1.5 —> 最终:4.5。
        • job3 和 job4 的资源都不够,继续等待,运行过程中,有资源释放出来时,继续按平均计算。
        • 第 n 次算:一直算到没有空闲资源。
      • 加权( 关注点是 job 的权重)
        • 需求:有一条队列总资源 16 个,有 4 个 job,对资源的需求分别是:job1 —> 4,job2 —> 2,job3 —>10,job4 —> 4,每个 job 的权重为:job1 —> 5,job2 —> 8,job3 —> 1,job4 —> 2。
        • 第一次算:16 / (5 + 8 + 1 + 2) = 1。
          • job1:分 5 * 1 —> 多 1 个。
          • job2:分 8 * 1 —> 多 6 个。
          • job3:分 1 * 1 —> 少 9 个。
          • job4:分 2 * 1 —> 少 2 个。
        • 第二次算:7 / (1 + 2) = 7/3。
          • job1:分 4。
          • job2:分 2。
          • job3:分 1 —> 少 9 个 —> 分 1 * 7/3 ≈ 2.33 —> 少 6.67 个。
          • job4:分 2 —> 少 2 个 —> 分 2 * 7/3 ≈ 4.66 —> 多 2.66 个。
        • 第三次算:2.66 / 1 = 2.66。
          • job1:分 4 —> 最终:4。
          • job2:分 2 —> 最终:2。
          • job3:分 1 —> 少 9 个 —> 分 1 * 7/3 ≈ 2.33 —> 少 6.67 个 —> 分 1 * 2.66 —> 最终:6。
          • job4:分 4 —> 最终:4。
        • job3 资源不够,继续等待,运行过程中,有资源释放出来时,继续按平均计算。
        • 第 n 次算:一直算到没有空闲资源。

YARN 常用命令

  • YARN 状态的查询,除了可以在 http://hadoop103:8088/ 页面查看外,还可以通过命令操作。

yarn node 查看节点

  • 列出所有节点

    1
    [xisun@hadoop102 hadoop]$ yarn node -list -all

yarn queue 查看队列

  • 查询队列信息

    1
    [xisun@hadoop102 hadoop]$ yarn queue -status <QueueName>

yarn application 查看任务

  • 列出所有 Application

    1
    [xisun@hadoop102 hadoop]$ yarn application -list
  • 根据 Application 的状态查询

    1
    [xisun@hadoop102 hadoop]$ yarn application -list -appStates [option]

    状态参数可选项有:ALL、NEW、NEW_SAVING、SUBMITTED、ACCEPTED、RUNNING、FINISHED、FAILED、KILLED。

  • Kill Application

    1
    [xisun@hadoop102 hadoop]$ yarn application -kill [ApplicationId]

yarn container 查看容器

  • 列出所有 Container

    1
    [xisun@hadoop102 hadoop]$ yarn container -list <ApplicationId>
  • 打印 Container 状态

    1
    [xisun@hadoop102 hadoop]$ yarn container -status <ContainerId>

    只有在任务运行的过程中,才能看到 Container 的状态。如果任务运行结束了,Container 也就被回收了。

yarn logs 查看日志

  • 查询 Application 日志

    1
    [xisun@hadoop102 hadoop]$ yarn logs -applicationId <ApplicationId>
  • 查询 Container 日志

    1
    [xisun@hadoop102 hadoop]$ yarn logs -applicationId <ApplicationId> -containerId <ContainerId>

yarn applicationattempt 查看尝试运行的任务

  • 列出所有 Application 尝试的列表

    1
    [xisun@hadoop102 hadoop]$ yarn applicationattempt -list <ApplicationId>
  • 打印 ApplicationAttemp 状态

    1
    [xisun@hadoop102 hadoop]$ yarn applicationattempt -status <ApplicationAttemptId>

yarn rmadmin 更新配置

  • 更新队列配置

    1
    [xisun@hadoop102 hadoop]$ yarn rmadmin -refreshQueues

    如果修改了队列的相关信息,不需要重启 YARN,执行此命令即可生效。

YARN 生产环境核心参数

  • ResourceManager 相关
    • yarn.resourcemanager.scheduler.class:配置调度器,Apache Hadoop 默认使用容量调度器。
    • yarn.resourcemanager.scheduler.client.thread-count:ResourceManager 处理调度器请求的线程数量,默认 50。
  • NodeManager 相关
    • yarn.nodemanager.resource.detect-hardware-capabilities:是否让 YARN 自己检测硬件进行配置,默认 false。
    • yarn.nodemanager.resource.count-logical-processors-as-cores:是否将虚拟核数当作 CPU 核数,默认 false。
      • 虚拟 CPU 和物理 CPU。如果集群中的多台服务器,CPU 性能差距较大,可以考虑设置此参数为 true。
    • yarn.nodemanager.resource.pcores-vcores-multiplier:虚拟核数和物理核数乘数,例如:4 核 8 线程,该参数就应设为 2。默认为 1.0。如果上一个参数设置为 true,此参数按实际配置。
    • yarn.nodemanager.resource.memory-mb:NodeManager 使用的内存,默认 8 G。
    • yarn.nodemanager.resource.system-reserved-memory-mb:NodeManager 为系统保留多少内存(系统内存与使用内存的差值)。与上一个参数,二者配置一个即可。
    • yarn.nodemanager.resource.cpu-vcores:NodeManager 使用的 CPU 核数,默认 8 个。
    • yarn.nodemanager.pmem-check-enabled:是否开启物理内存检查限制 Container,默认打开。
      • 一种安全机制:如果 NodeManager 使用的内存,即将超过其可以使用的内存量时,触发报警机制,防止 NodeManager 占用虚拟机正常运行时的内存,导致系统崩溃。
    • yarn.nodemanager.vmem-check-enabled:是否开启虚拟内存检查限制 Container,默认打开。
    • yarn.nodemanager.vmem-pmem-ratio:虚拟内存与物理内存的比例,默认 2.1。
  • Container 相关
    • yarn.scheduler.minimum-allocation-mb:容器最小内存,默认 1 G。
    • yarn.scheduler.maximum-allocation-mb:容器最大内存,默认 8 G。不能超过 NodeManager 能使用的内存。
    • yarn.scheduler.minimum-allocation-vcores:容器最小 CPU 核数,默认 1 个。
    • yarn.scheduler.maximum-allocation-vcores:容器最大 CPU 核数,默认 4 个。

YARN 案例实操

  • 调整下列参数之前尽量拍摄 Linux 快照,否则后续的案例,还需要重新准备集群。

    image-20210912181004046

    image-20210912180732521

    image-20210912180838645

YARN 生产环境核心参数配置案例

  • 需求:从 1 G 数据中,统计每个单词出现的次数。服务器 3 台,每台配置 4 G 内存,4 核 CPU,4 线程。

本文参考

https://www.bilibili.com/video/BV1Qp4y1n7EN

声明:写作本文初衷是个人学习记录,鉴于本人学识有限,如有侵权或不当之处,请联系 wdshfut@163.com

a

那山那人那狗 岁月无声 夜莺

项目主体结构

  • 代码实现:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    public class FlinkKafkaJob3 {
    public static void main(String[] args) throws Exception {
    // 获取参数
    ParameterTool parameterTool = ParameterTool.fromArgs(args);
    String consumerTopic = parameterTool.get("consumerTopic");
    String producerTopic = parameterTool.get("producerTopic");
    String specialTopic = parameterTool.get("specialTopic");
    String ifEarliestOffset = parameterTool.get("ifEarliestOffset");
    String ifSpecialOffset = parameterTool.get("ifSpecialOffset");
    System.out.println("consumerTopic: " + consumerTopic + ", producerTopic: " + producerTopic +
    ", specialTopic: " + specialTopic + ", ifEarliestOffset: " + ifEarliestOffset + ", ifSpecialOffset: " + ifSpecialOffset);

    // 创建流环境
    StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();

    /*env.enableCheckpointing(30 * 1000);
    env.getCheckpointConfig().setCheckpointingMode(CheckpointingMode.EXACTLY_ONCE);
    env.getCheckpointConfig().setCheckpointTimeout(60000L);
    env.getCheckpointConfig().setMinPauseBetweenCheckpoints(60000L);
    env.setRestartStrategy(RestartStrategies.fixedDelayRestart(1, Time.minutes(1)));*/

    // 定义kafka消费者
    Properties consumerProp = ConsumerProperties.getProps();
    FlinkKafkaConsumer<ConsumerRecord<String, String>> consumer = new FlinkKafkaConsumer<>(
    consumerTopic,
    new ConsumerStringDeserializationSchema(),
    consumerProp);
    if ("yes".equals(ifEarliestOffset)) {
    consumer.setStartFromEarliest();
    } else if ("yes".equals(ifSpecialOffset)) {
    String partitions = parameterTool.get("partition");
    String offsets = parameterTool.get("offset");
    if (partitions != null && offsets != null) {
    Map<KafkaTopicPartition, Long> specificOffsets = new HashMap<>(16);
    String[] split = partitions.split(",");
    String[] split1 = offsets.split(",");
    for (int i = 0; i < split.length; i++) {
    KafkaTopicPartition kafkaTopicPartition = new KafkaTopicPartition(consumerTopic, Integer.parseInt(split[i]));
    specificOffsets.put(kafkaTopicPartition, Long.parseLong(split1[i]));
    }
    consumer.setStartFromSpecificOffsets(specificOffsets);
    }
    }

    // 定义kafka生产者
    Properties producerProp = ProducerProperties.getProps();
    FlinkKafkaProducer<String> producer = new FlinkKafkaProducer<>(
    producerTopic,
    new ProducerStringSerializationSchema(producerTopic),
    producerProp,
    FlinkKafkaProducer.Semantic.EXACTLY_ONCE);
    producer.setWriteTimestampToKafka(true);

    // Flink任务链
    env.addSource(consumer)
    .map((MapFunction<ConsumerRecord<String, String>, PatentMessage>) consumerRecord -> {
    String topic = consumerRecord.topic();
    int partition = consumerRecord.partition();
    long offset = consumerRecord.offset();
    String key = consumerRecord.key();
    String value = consumerRecord.value();
    JSONObject kafkaMessage = new JSONObject();
    kafkaMessage.put("topic", topic);
    kafkaMessage.put("partition", partition);
    kafkaMessage.put("offset", offset);
    kafkaMessage.put("key", key);
    return new PatentMessage(topic, partition, offset, key, value, null, kafkaMessage);
    })
    .filter(new FilterLargerOperator(specialTopic))
    .map((MapFunction<PatentMessage, PatentMessage>) patentMessage -> {
    String value = patentMessage.getValue();
    if (patentMessage.getKey().endsWith(PatentXmlTags.SGM)) {
    value = PatentContentUtil.transferSgmPatentContent(value);
    }
    Document document = Utils.buildXmlFromString(value);
    patentMessage.setDocument(document);
    return patentMessage;
    })
    .filter(new FilterBadOperator(specialTopic))
    .flatMap(new RichFlatMapOperator(specialTopic))
    // 有的时候,lambda表达式无法获悉返回值参数类型,需要指定,could not be determined automatically
    .returns(Types.STRING)
    .addSink(producer);

    // 执行任务
    env.execute("patent reaction extractor loader");
    }
    }
  • 打包命令:mvn clean package -DskipTests

集群配置

  • 主机地址:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    (base) [hadoop@client ~]$ ip addr
    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
    valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
    valid_lft forever preferred_lft forever
    2: ens192: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 00:0c:29:14:8b:4e brd ff:ff:ff:ff:ff:ff
    inet 192.168.2.106/24 brd 192.168.2.255 scope global noprefixroute dynamic ens192
    valid_lft 40466sec preferred_lft 40466sec
    inet6 fe80::fda6:9e98:3fce:8b74/64 scope link noprefixroute
    valid_lft forever preferred_lft forever
    (base) [hadoop@client ~]$ ifconfig
    ens192: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
    inet 192.168.2.106 netmask 255.255.255.0 broadcast 192.168.2.255
    inet6 fe80::fda6:9e98:3fce:8b74 prefixlen 64 scopeid 0x20<link>
    ether 00:0c:29:14:8b:4e txqueuelen 1000 (Ethernet)
    RX packets 2326369660 bytes 961932882940 (895.8 GiB)
    RX errors 0 dropped 0 overruns 0 frame 0
    TX packets 1614468546 bytes 1124856260518 (1.0 TiB)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

    lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
    inet 127.0.0.1 netmask 255.0.0.0
    inet6 ::1 prefixlen 128 scopeid 0x10<host>
    loop txqueuelen 1000 (Local Loopback)
    RX packets 34513 bytes 3083025 (2.9 MiB)
    RX errors 0 dropped 0 overruns 0 frame 0
    TX packets 34513 bytes 3083025 (2.9 MiB)
    TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

    主机名:hadoopclient。

  • Flink 版本:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    (base) [hadoop@client flink-1.11.1]$ pwd
    /opt/flink-1.11.1
    (base) [hadoop@client flink-1.11.1]$ flink -v
    SLF4J: Class path contains multiple SLF4J bindings.
    SLF4J: Found binding in [jar:file:/opt/flink-1.11.1/lib/logback-classic-1.2.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
    SLF4J: Found binding in [jar:file:/opt/hadoop-3.2.1/share/hadoop/common/lib/slf4j-log4j12-1.7.25.jar!/org/slf4j/impl/StaticLoggerBinder.class]
    SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
    SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]
    Version: 1.11.1, Commit ID: 7eb514a
  • Hadoop 版本:

    1
    2
    (base) [hadoop@client hadoop-3.2.1]$ pwd
    /opt/hadoop-3.2.1
  • Hadoop 节点:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    (base) [hadoop@client ~]$ cd .ssh/
    (base) [hadoop@client .ssh]$ pwd
    /home/hadoop/.ssh
    (base) [hadoop@client .ssh]$ ll
    total 24
    -rw-------. 1 hadoop hadoop 5921 Sep 3 2020 authorized_keys
    -rw-------. 1 hadoop hadoop 1675 Sep 3 2020 id_rsa
    -rw-r--r--. 1 hadoop hadoop 395 Sep 3 2020 id_rsa.pub
    -rw-r--r--. 1 hadoop hadoop 7446 Sep 9 2020 known_hosts
    (base) [hadoop@client .ssh]$ cat known_hosts
    datanode1,192.168.2.188
    datanode3,192.168.2.143
    datanode2,192.168.2.199
    node1,192.168.1.61
    node2,192.168.1.62
    node3,192.168.1.63
    node4,192.168.1.64
    node5,192.168.1.65
    node6,192.168.1.66
    node7,192.168.1.67
    node8,192.168.1.68

    known_hosts 文件内容有删改。

    datanode1 ~ 3 主要为存储节点,node1 ~ 8 主要为计算节点。

  • 主机与节点间的切换:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    (base) [hadoop@client ~]$ ssh node1
    Last login: Mon Aug 23 15:58:50 2021 from node2
    [hadoop@node1 ~]$ ll /opt/
    total 0
    drwxrwxr-x. 6 hadoop hadoop 99 Feb 28 2020 apache-maven-3.6.3
    drwxr-xr-x. 10 hadoop hadoop 156 Sep 3 2020 flink-1.11.1
    drwxr-xr-x. 12 hadoop hadoop 185 Sep 23 2020 hadoop-3.2.1
    drwxrwxr-x. 7 hadoop hadoop 146 Feb 13 2020 zookeeper-3.5.6
    [hadoop@node1 ~]$ ssh node6
    Last login: Mon Oct 19 14:19:59 2020 from node5
    [hadoop@node6 ~]$ ll /opt/
    total 0
    drwxrwxr-x. 6 hadoop hadoop 99 Aug 30 2020 apache-maven-3.6.3
    drwxr-xr-x. 10 hadoop hadoop 156 Sep 3 2020 flink-1.11.1
    drwxr-xr-x. 12 hadoop hadoop 185 Sep 23 2020 hadoop-3.2.1
    drwxrwxr-x. 7 hadoop hadoop 146 Aug 30 2020 zookeeper-3.5.6
    [hadoop@node6 ~]$ ssh hadoopclient
    Last login: Mon Aug 23 16:06:40 2021 from 192.168.1.1
    (base) [hadoop@client ~]$ ll /opt/
    total 0
    drwxrwxr-x. 6 hadoop hadoop 99 Aug 30 2020 apache-maven-3.6.3
    drwxr-xr-x. 10 hadoop hadoop 186 Aug 23 15:37 flink-1.11.1
    drwxr-xr-x. 12 hadoop hadoop 185 Sep 23 2020 hadoop-3.2.1
    drwxrwxr-x. 7 hadoop hadoop 146 Aug 30 2020 zookeeper-3.5.6

Kafka 操作命令

  • 查看 Kafka topic 列表命令,返回 topic 名字列表:

    1
    2
    3
    4
    5
    6
    7
    (base) [hadoop@client patent-extractor]$ ~/kafka_2.12-2.6.0/bin/kafka-topics.sh --zookeeper hadoopdatanode1:2181 --list
    __consumer_offsets
    __transaction_state
    extractor-log
    extractor-patent
    extractor-patent-exception
    extractor-result
  • 创建 Kafka topic 命令:

    1
    2
    (base) [hadoop@client patent-extractor]$ ~/kafka_2.12-2.6.0/bin/kafka-topics.sh --zookeeper hadoopdatanode1:2181,hadoopdatanode2:2181,hadoopdatanode3:2181 --create --partitions 12 --replication-factor 2 --topic extractor-patent
    Created topic extractor-patent.
  • 查看 Kafka 指定 topic 的详情命令,返回该 topic 的 partition 数量、replica 因子以及每个 partition 的 leader、replica 信息:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    (base) [hadoop@client patent-extractor]$ ~/kafka_2.12-2.6.0/bin/kafka-topics.sh --zookeeper hadoopdatanode1:2181 --describe --topic extractor-patent
    Topic: extractor-patent PartitionCount: 12 ReplicationFactor: 2 Configs:
    Topic: extractor-patent Partition: 0 Leader: 1 Replicas: 1,2 Isr: 1,2
    Topic: extractor-patent Partition: 1 Leader: 2 Replicas: 2,0 Isr: 2,0
    Topic: extractor-patent Partition: 2 Leader: 0 Replicas: 0,1 Isr: 0,1
    Topic: extractor-patent Partition: 3 Leader: 1 Replicas: 1,0 Isr: 1,0
    Topic: extractor-patent Partition: 4 Leader: 2 Replicas: 2,1 Isr: 2,1
    Topic: extractor-patent Partition: 5 Leader: 0 Replicas: 0,2 Isr: 0,2
    Topic: extractor-patent Partition: 6 Leader: 1 Replicas: 1,2 Isr: 1,2
    Topic: extractor-patent Partition: 7 Leader: 2 Replicas: 2,0 Isr: 2,0
    Topic: extractor-patent Partition: 8 Leader: 0 Replicas: 0,1 Isr: 0,1
    Topic: extractor-patent Partition: 9 Leader: 1 Replicas: 1,0 Isr: 1,0
    Topic: extractor-patent Partition: 10 Leader: 2 Replicas: 2,1 Isr: 2,1
    Topic: extractor-patent Partition: 11 Leader: 0 Replicas: 0,2 Isr: 0,2
  • 查看 Kafka 指定 topic 各 partition 的 offset 信息命令,–time 参数为 -1 时,表示各分区最大的 offset,为 -2 时,表示各分区最小的 offset:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    (base) [hadoop@client patent-extractor]$ ~/kafka_2.12-2.6.0/bin/kafka-run-class.sh kafka.tools.GetOffsetShell --broker-list hadoopdatanode1:9092 --time -1 --topic extractor-patent
    extractor-patent:0:364004
    extractor-patent:1:364109
    extractor-patent:2:363695
    extractor-patent:3:364158
    extractor-patent:4:363723
    extractor-patent:5:363860
    extractor-patent:6:363821
    extractor-patent:7:365197
    extractor-patent:8:364364
    extractor-patent:9:364092
    extractor-patent:10:365772
    extractor-patent:11:364990
  • 删除 Kafka topic 命令:

    1
    2
    3
    (base) [hadoop@client patent-extractor]$ ~/kafka_2.12-2.6.0/bin/kafka-topics.sh --zookeeper hadoopdatanode1:2181 --delete -topic extractor-patents
    Topic extractor-patents is marked for deletion.
    Note: This will have no impact if delete.topic.enable is not set to true.
  • 查看 Kafka consumer group 命令,返回 consumer group 名字列表 (新版信息保存在 broker 中,老版信息保存在 zookeeper 中,二者命令不同):

    1
    2
    3
    4
    5
    (base) [hadoop@client patent-extractor]$ ~/kafka_2.12-2.6.0/bin/kafka-consumer-groups.sh --bootstrap-server hadoopdatanode1:9092 --list
    extractor-patent-consumer
    result-consumer
    log-consumer
    timeout-consumer

    老版命令:~/kafka_2.12-2.6.0/bin/kafka-consumer-groups.sh --zookeeper hadoopdatanode1:2181 --list

  • 查看 Kafka 指定 consumer group 的详情命令,返回 consumer group 对应的 topic 信息、当前消费的 offset、总 offset、剩余待消费 offset 等信息:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    (base) [hadoop@client patent-extractor]$ ~/kafka_2.12-2.6.0/bin/kafka-consumer-groups.sh --bootstrap-server hadoopdatanode1:9092 --describe --group extractor-patent-consumer

    Consumer group 'extractor-patent-consumer' has no active members.

    GROUP TOPIC PARTITION CURRENT-OFFSET LOG-END-OFFSET LAG CONSUMER-ID HOST CLIENT-ID
    extractor-patent-consumer extractor-patent 5 262567 363860 101293 - - -
    extractor-patent-consumer extractor-patent 6 267012 363821 96809 - - -
    extractor-patent-consumer extractor-patent 3 262809 364158 101349 - - -
    extractor-patent-consumer extractor-patent 4 262506 363723 101217 - - -
    extractor-patent-consumer extractor-patent 9 266548 364092 97544 - - -
    extractor-patent-consumer extractor-patent 10 266975 365772 98797 - - -
    extractor-patent-consumer extractor-patent 7 264665 365197 100532 - - -
    extractor-patent-consumer extractor-patent 8 270991 364364 93373 - - -
    extractor-patent-consumer extractor-patent 11 256111 364990 108879 - - -
    extractor-patent-consumer extractor-patent 1 267012 364109 97097 - - -
    extractor-patent-consumer extractor-patent 2 264837 363695 98858 - - -
    extractor-patent-consumer extractor-patent 0 262513 364004 101491 - - -

    image-20210823171956927

  • 重置 Kafka 指定 consumer group 消费的 topic 的 offset 命令:

    1
    (base) [hadoop@client patent-extractor]$ ~/kafka_2.12-2.6.0/bin/kafka-consumer-groups.sh --bootstrap-server hadoopdatanode1:9092 --reset-offsets -to-offset 0 --execute --topic patent-app --group extractor-patent-consumer
  • 删除 Kafka 指定 consumer group 命令:

    1
    (base) [hadoop@client patent-extractor]$ ~/kafka_2.12-2.6.0/bin/kafka-consumer-groups.sh --bootstrap-server hadoopdatanode1:9092 --delete --group extractor-patent-consumer
  • 命令行消费 Kafka 指定 topic 的内容命令:

    1
    2
    # 从头开始消费
    (base) [hadoop@client patent-extractor]$ ~/kafka_2.12-2.6.0/bin/kafka-console-consumer.sh --bootstrap-server hadoopdatanode1:9092 --from-beginning --topic extractor-log > extractor.log
    1
    2
    # 从头开始消费前10条消息,并显示key
    (base) [hadoop@client patent-extractor]$ ~/kafka_2.12-2.6.0/bin/kafka-console-consumer.sh --bootstrap-server hadoopdatanode1:9092 --from-beginning --max-messages 10 --property print.key=true --topic extractor-log
    1
    2
    # 从指定分区、指定offset开始消费
    (base) [hadoop@client patent-extractor]$ ~/kafka_2.12-2.6.0/bin/kafka-console-consumer.sh --bootstrap-server hadoopdatanode1:9092 --partition 0 --offset 219000 --topic extractor-log
    1
    2
    # 从尾开始消费,必须指定分区
    (base) [hadoop@client patent-extractor]$ ~/kafka_2.12-2.6.0/bin/kafka-console-consumer.sh --bootstrap-server hadoopdatanode1:9092 --partition 0 --offset latest --topic extractor-log
  • 更多命令参数查看 help:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    (base) [hadoop@client patent-extractor]$ ~/kafka_2.12-2.6.0/bin/kafka-topics.sh --help
    This tool helps to create, delete, describe, or change a topic.
    Option Description
    ------ -----------
    --alter Alter the number of partitions,
    replica assignment, and/or
    configuration for the topic.
    --at-min-isr-partitions if set when describing topics, only
    show partitions whose isr count is
    equal to the configured minimum. Not
    supported with the --zookeeper
    option.
    --bootstrap-server <String: server to REQUIRED: The Kafka server to connect
    connect to> to. In case of providing this, a
    direct Zookeeper connection won't be
    required.
    --command-config <String: command Property file containing configs to be
    config property file> passed to Admin Client. This is used
    only with --bootstrap-server option
    for describing and altering broker
    configs.
    --config <String: name=value> A topic configuration override for the
    topic being created or altered.The
    following is a list of valid
    configurations:
    cleanup.policy
    compression.type
    delete.retention.ms
    file.delete.delay.ms
    flush.messages
    flush.ms
    follower.replication.throttled.
    replicas
    index.interval.bytes
    leader.replication.throttled.replicas
    max.compaction.lag.ms
    max.message.bytes
    message.downconversion.enable
    message.format.version
    message.timestamp.difference.max.ms
    message.timestamp.type
    min.cleanable.dirty.ratio
    min.compaction.lag.ms
    min.insync.replicas
    preallocate
    retention.bytes
    retention.ms
    segment.bytes
    segment.index.bytes
    segment.jitter.ms
    segment.ms
    unclean.leader.election.enable
    See the Kafka documentation for full
    details on the topic configs.It is
    supported only in combination with --
    create if --bootstrap-server option
    is used.
    --create Create a new topic.
    --delete Delete a topic
    --delete-config <String: name> A topic configuration override to be
    removed for an existing topic (see
    the list of configurations under the
    --config option). Not supported with
    the --bootstrap-server option.
    --describe List details for the given topics.
    --disable-rack-aware Disable rack aware replica assignment
    --exclude-internal exclude internal topics when running
    list or describe command. The
    internal topics will be listed by
    default
    --force Suppress console prompts
    --help Print usage information.
    --if-exists if set when altering or deleting or
    describing topics, the action will
    only execute if the topic exists.
    --if-not-exists if set when creating topics, the
    action will only execute if the
    topic does not already exist.
    --list List all available topics.
    --partitions <Integer: # of partitions> The number of partitions for the topic
    being created or altered (WARNING:
    If partitions are increased for a
    topic that has a key, the partition
    logic or ordering of the messages
    will be affected). If not supplied
    for create, defaults to the cluster
    default.
    --replica-assignment <String: A list of manual partition-to-broker
    broker_id_for_part1_replica1 : assignments for the topic being
    broker_id_for_part1_replica2 , created or altered.
    broker_id_for_part2_replica1 :
    broker_id_for_part2_replica2 , ...>
    --replication-factor <Integer: The replication factor for each
    replication factor> partition in the topic being
    created. If not supplied, defaults
    to the cluster default.
    --topic <String: topic> The topic to create, alter, describe
    or delete. It also accepts a regular
    expression, except for --create
    option. Put topic name in double
    quotes and use the '\' prefix to
    escape regular expression symbols; e.
    g. "test\.topic".
    --topics-with-overrides if set when describing topics, only
    show topics that have overridden
    configs
    --unavailable-partitions if set when describing topics, only
    show partitions whose leader is not
    available
    --under-min-isr-partitions if set when describing topics, only
    show partitions whose isr count is
    less than the configured minimum.
    Not supported with the --zookeeper
    option.
    --under-replicated-partitions if set when describing topics, only
    show under replicated partitions
    --version Display Kafka version.
    --zookeeper <String: hosts> DEPRECATED, The connection string for
    the zookeeper connection in the form
    host:port. Multiple hosts can be
    given to allow fail-over.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    (base) [hadoop@client patent-extractor]$ ~/kafka_2.12-2.6.0/bin/kafka-consumer-groups.sh --help
    Missing required argument "[bootstrap-server]"
    Option Description
    ------ -----------
    --all-groups Apply to all consumer groups.
    --all-topics Consider all topics assigned to a
    group in the `reset-offsets` process.
    --bootstrap-server <String: server to REQUIRED: The server(s) to connect to.
    connect to>
    --by-duration <String: duration> Reset offsets to offset by duration
    from current timestamp. Format:
    'PnDTnHnMnS'
    --command-config <String: command Property file containing configs to be
    config property file> passed to Admin Client and Consumer.
    --delete Pass in groups to delete topic
    partition offsets and ownership
    information over the entire consumer
    group. For instance --group g1 --
    group g2
    --delete-offsets Delete offsets of consumer group.
    Supports one consumer group at the
    time, and multiple topics.
    --describe Describe consumer group and list
    offset lag (number of messages not
    yet processed) related to given
    group.
    --dry-run Only show results without executing
    changes on Consumer Groups.
    Supported operations: reset-offsets.
    --execute Execute operation. Supported
    operations: reset-offsets.
    --export Export operation execution to a CSV
    file. Supported operations: reset-
    offsets.
    --from-file <String: path to CSV file> Reset offsets to values defined in CSV
    file.
    --group <String: consumer group> The consumer group we wish to act on.
    --help Print usage information.
    --list List all consumer groups.
    --members Describe members of the group. This
    option may be used with '--describe'
    and '--bootstrap-server' options
    only.
    Example: --bootstrap-server localhost:
    9092 --describe --group group1 --
    members
    --offsets Describe the group and list all topic
    partitions in the group along with
    their offset lag. This is the
    default sub-action of and may be
    used with '--describe' and '--
    bootstrap-server' options only.
    Example: --bootstrap-server localhost:
    9092 --describe --group group1 --
    offsets
    --reset-offsets Reset offsets of consumer group.
    Supports one consumer group at the
    time, and instances should be
    inactive
    Has 2 execution options: --dry-run
    (the default) to plan which offsets
    to reset, and --execute to update
    the offsets. Additionally, the --
    export option is used to export the
    results to a CSV format.
    You must choose one of the following
    reset specifications: --to-datetime,
    --by-period, --to-earliest, --to-
    latest, --shift-by, --from-file, --
    to-current.
    To define the scope use --all-topics
    or --topic. One scope must be
    specified unless you use '--from-
    file'.
    --shift-by <Long: number-of-offsets> Reset offsets shifting current offset
    by 'n', where 'n' can be positive or
    negative.
    --state [String] When specified with '--describe',
    includes the state of the group.
    Example: --bootstrap-server localhost:
    9092 --describe --group group1 --
    state
    When specified with '--list', it
    displays the state of all groups. It
    can also be used to list groups with
    specific states.
    Example: --bootstrap-server localhost:
    9092 --list --state stable,empty
    This option may be used with '--
    describe', '--list' and '--bootstrap-
    server' options only.
    --timeout <Long: timeout (ms)> The timeout that can be set for some
    use cases. For example, it can be
    used when describing the group to
    specify the maximum amount of time
    in milliseconds to wait before the
    group stabilizes (when the group is
    just created, or is going through
    some changes). (default: 5000)
    --to-current Reset offsets to current offset.
    --to-datetime <String: datetime> Reset offsets to offset from datetime.
    Format: 'YYYY-MM-DDTHH:mm:SS.sss'
    --to-earliest Reset offsets to earliest offset.
    --to-latest Reset offsets to latest offset.
    --to-offset <Long: offset> Reset offsets to a specific offset.
    --topic <String: topic> The topic whose consumer group
    information should be deleted or
    topic whose should be included in
    the reset offset process. In `reset-
    offsets` case, partitions can be
    specified using this format: `topic1:
    0,1,2`, where 0,1,2 are the
    partition to be included in the
    process. Reset-offsets also supports
    multiple topic inputs.
    --verbose Provide additional information, if
    any, when describing the group. This
    option may be used with '--
    offsets'/'--members'/'--state' and
    '--bootstrap-server' options only.
    Example: --bootstrap-server localhost:
    9092 --describe --group group1 --
    members --verbose
    --version Display Kafka version.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    (base) [hadoop@client patent-extractor]$ ~/kafka_2.12-2.6.0/bin/kafka-console-consumer.sh --help
    This tool helps to read data from Kafka topics and outputs it to standard output.
    Option Description
    ------ -----------
    --bootstrap-server <String: server to REQUIRED: The server(s) to connect to.
    connect to>
    --consumer-property <String: A mechanism to pass user-defined
    consumer_prop> properties in the form key=value to
    the consumer.
    --consumer.config <String: config file> Consumer config properties file. Note
    that [consumer-property] takes
    precedence over this config.
    --enable-systest-events Log lifecycle events of the consumer
    in addition to logging consumed
    messages. (This is specific for
    system tests.)
    --formatter <String: class> The name of a class to use for
    formatting kafka messages for
    display. (default: kafka.tools.
    DefaultMessageFormatter)
    --from-beginning If the consumer does not already have
    an established offset to consume
    from, start with the earliest
    message present in the log rather
    than the latest message.
    --group <String: consumer group id> The consumer group id of the consumer.
    --help Print usage information.
    --isolation-level <String> Set to read_committed in order to
    filter out transactional messages
    which are not committed. Set to
    read_uncommitted to read all
    messages. (default: read_uncommitted)
    --key-deserializer <String:
    deserializer for key>
    --max-messages <Integer: num_messages> The maximum number of messages to
    consume before exiting. If not set,
    consumption is continual.
    --offset <String: consume offset> The offset id to consume from (a non-
    negative number), or 'earliest'
    which means from beginning, or
    'latest' which means from end
    (default: latest)
    --partition <Integer: partition> The partition to consume from.
    Consumption starts from the end of
    the partition unless '--offset' is
    specified.
    --property <String: prop> The properties to initialize the
    message formatter. Default
    properties include:
    print.timestamp=true|false
    print.key=true|false
    print.value=true|false
    key.separator=<key.separator>
    line.separator=<line.separator>
    key.deserializer=<key.deserializer>
    value.deserializer=<value.
    deserializer>
    Users can also pass in customized
    properties for their formatter; more
    specifically, users can pass in
    properties keyed with 'key.
    deserializer.' and 'value.
    deserializer.' prefixes to configure
    their deserializers.
    --skip-message-on-error If there is an error when processing a
    message, skip it instead of halt.
    --timeout-ms <Integer: timeout_ms> If specified, exit if no message is
    available for consumption for the
    specified interval.
    --topic <String: topic> The topic id to consume on.
    --value-deserializer <String:
    deserializer for values>
    --version Display Kafka version.
    --whitelist <String: whitelist> Regular expression specifying
    whitelist of topics to include for
    consumption.
  • 提交任务所需的 jar 包,放置于主机上:

    1
    2
    3
    4
    5
    (base) [hadoop@client patent-extractor]$ pwd
    /data/patent/official/patent-extractor
    (base) [hadoop@client patent-extractor]$ ll
    total 349140
    -rw-rw-r-- 1 hadoop hadoop 357510953 Aug 20 12:01 reaction-extractor-1.0-SNAPSHOT.jar
  • 提交任务的模式:yarn-cluster。

  • 提交任务的命令:

    1
    flink run -m yarn-cluster -p 12 -d reaction-extractor-1.0-SNAPSHOT.jar --consumerTopic extractor-patent --producerTopic extractor-result --specialTopic extractor-patent-exception
    1
    flink run -m yarn-cluster -p 12 -d reaction-extractor-1.0-SNAPSHOT.jar --consumerTopic extractor-patent --producerTopic extractor-result --specialTopic extractor-patent-timeout --ifEarliestOffset yes
    1
    2
    flink run -m yarn-cluster -p 12 -d reaction-extractor-1.0-SNAPSHOT.jar --consumerTopic extractor-patent --producerTopic extractor-result --specialTopic extractor-patent-timeout --ifSpecialOffset yes 
    --partition 0,1,2,3,4,5,6,7,8,9,10,11 --offset 273413,277780,268447,274226,273855,273795,278069,275783,284768,277734,281195,265928

YARN 查询命令

  • 查看yarn上面的资源使用情况命令,ctrl+c退出:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    (base) [hadoop@client official]$ yarn top
    YARN top - 22:52:46, up 266d, 4:43, 0 active users, queue(s): root
    NodeManager(s): 11 total, 11 active, 0 unhealthy, 0 decommissioned, 0 lost, 0 rebooted
    Queue(s) Applications: 1 running, 167 submitted, 0 pending, 39 completed, 127 killed, 0 failed
    Queue(s) Mem(GB): 382 available, 146 allocated, 0 pending, 0 reserved
    Queue(s) VCores: 163 available, 13 allocated, 0 pending, 0 reserved
    Queue(s) Containers: 13 allocated, 0 pending, 0 reserved

    APPLICATIONID USER TYPE QUEUE PRIOR #CONT #RCONT VCORES RVCORES MEM RMEM VCORESECS MEMSECS %PROGR TIME NAME
    application_1606730935892_0168 hadoop apache flink default 0 13 0 13 0 146G 0G 68363 767752 100.00 00:01:27 Flink per-job cluster
  • 查看 YARN 上运行的任务列表命令,如果集群有 krb 认证的话,需要先 kinit,认证后可以看到所有正在运行的任务:

    1
    2
    3
    4
    (base) [hadoop@client official]$ yarn application -list
    Total number of applications (application-types: [], states: [SUBMITTED, ACCEPTED, RUNNING] and tags: []):1
    Application-Id Application-Name Application-Type User Queue State Final-State Progress Tracking-URL
    application_1606730935892_0168 Flink per-job cluster Apache Flink hadoop default RUNNING UNDEFINED 100% http://node3:36312
  • 查看 YARN 上运行的指定状态的任务列表命令:

    1
    2
    3
    4
    (base) [hadoop@client official]$ yarn application -list -appStates RUNNING
    Total number of applications (application-types: [], states: [RUNNING] and tags: []):1
    Application-Id Application-Name Application-Type User Queue State Final-State Progress Tracking-URL
    application_1606730935892_0168 Flink per-job cluster Apache Flink hadoop default RUNNING UNDEFINED 100% http://node3:36312
  • 查看 YARN 指定任务的状态信息命令:

    1
    yarn application -status <applicationId> 
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    (base) [hadoop@client official]$ yarn application -status application_1606730935892_0168
    Application Report :
    Application-Id : application_1606730935892_0168
    Application-Name : Flink per-job cluster
    Application-Type : Apache Flink
    User : hadoop
    Queue : default
    Application Priority : 0
    Start-Time : 1629725098333
    Finish-Time : 0
    Progress : 100%
    State : RUNNING
    Final-State : UNDEFINED
    Tracking-URL : http://node3:36312
    RPC Port : 36312
    AM Host : node3
    Aggregate Resource Allocation : 829449970 MB-seconds, 72126 vcore-seconds
    Aggregate Resource Preempted : 0 MB-seconds, 0 vcore-seconds
    Log Aggregation Status : NOT_START
    Diagnostics :
    Unmanaged Application : false
    Application Node Label Expression : <Not set>
    AM container Node Label Expression : <DEFAULT_PARTITION>
    TimeoutType : LIFETIME ExpiryTime : UNLIMITED RemainingTime : -1seconds
  • 查看 YARN 指定 application 任务日志命令,可以选择输出到本地文件:

    1
    yarn logs -applicationId <applicationId> > yarn.log
  • kill yarn application 命令:

    1
    yarn application -kill <applicationId>
  • kill yarn job 命令:

    1
    yarn job -kill <jobId>

MySQL 安装

Windows 上安装 MySQL

  • 下载:

  • 安装:

    • 产品选择:

      image-20210628105225639

      • Developer Default:开发者默认,安装 MySQL 开发所需的所有产品。
      • Server only:服务器,只安装 MySQL 服务器产品。
      • Client only:客户端,只安装没有服务器的 MySQL 客户端产品。
      • Full:完全,安装所有包含的 MySQL 产品和功能。
      • Custom:手动,手动选择系统上应安装的产品。
    • 跳过 Check Requirements:

      image-20210628105821442

    • 进度,安装需要一段时间:

      image-20210628110013750

    • 待配置项,接下来会一项接一项的进行配置。当一项配置完后,会回到此页面,并显示该项 Configuration Complete,然后进行下一项:

      image-20210628110646919

    • 端口:

      image-20210628111323014

    • root 用户密码 (此密码不能忘):

      image-20210628111107793

      可以在本页面添加其他用户,并赋予权限和登录密码。

    • 配置 MySQL 在 Windows 系统中的名字,以及是否选择开机启动 MySQL 服务:

      image-20210628111545278

    • 应用配置:

      image-20210628111742778

    • 安装日志,可以查看端口和安装位置等信息:

      image-20210628111936212

    • 安装完成:

      image-20210628112810961

    • 双击运行之前下载的安装包,能看到所安装的产品。

      image-20210628113107855

  • 添加环境变量:

    • 新建 MASQL_HOME:

    image-20210628113444200

    • 添加 path:

      image-20210628113538999

    • 测试:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      C:\Users\XiSun>mysql -u root -p
      Enter password: ***************
      Welcome to the MySQL monitor. Commands end with ; or \g.
      Your MySQL connection id is 30
      Server version: 8.0.25 MySQL Community Server - GPL

      Copyright (c) 2000, 2021, Oracle and/or its affiliates.

      Oracle is a registered trademark of Oracle Corporation and/or its
      affiliates. Other names may be trademarks of their respective
      owners.

      Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

      mysql>

本文参考

https://www.runoob.com/mysql/mysql-install.html

https://www.runoob.com/w3cnote/windows10-mysql-installer.html

声明:写作本文初衷是个人学习记录,鉴于本人学识有限,如有侵权或不当之处,请联系 wdshfut@163.com