yanpenggong 大数据实验室

一个专注于科研前线的大数据团队,致力于打造更好更牛的大数据平台

0%

Author: yanpengGong         Email:yanpenggong@163.com

目录


[TOC]

前言

Docker 是个伟大的项目,它彻底释放了虚拟化的威力,极大降低了云计算资源供应的成本,同时让应用的分发、测试、部署和分发都变得前所未有的高效和轻松!

本书既适用于具备基础 Linux 知识的 Docker 初学者,也希望可供理解原理和实现的高级用户参考。同时,书中给出的实践案例,可供在进行实际部署时借鉴。前六章为基础内容,供用户理解 Docker 的基本概念和操作;7 ~ 9 章介绍一些高级操作;第 10 章给出典型的应用场景和实践案例;11 ~ 13 章介绍关于 Docker 实现的相关技术。14 ~ 17章介绍相关的一些开源项目。

一、 Docker 简介

1. Docker是什么

Docker 是一个开源项目,诞生于 2013 年初,最初是 dotCloud 公司内部的一个业余项目。它基于 Google 公司推出的 Go 语言实现。 项目后来加入了 Linux 基金会,遵从了 Apache 2.0 协议,项目代码在 GitHub 上进行维护。

Docker 自开源后受到广泛的关注和讨论,以至于 dotCloud 公司后来都改名为 Docker Inc。Redhat 已经在其 RHEL6.5 中集中支持 Docker;Google 也在其 PaaS 产品中广泛应用。

Docker 项目的目标是实现轻量级的操作系统虚拟化解决方案。 Docker 的基础是 Linux 容器(LXC)等技术。

在 LXC 的基础上 Docker 进行了进一步的封装,让用户不需要去关心容器的管理,使得操作更为简便。用户操作 Docker 的容器就像操作一个快速轻量级的虚拟机一样简单。

容器是在操作系统层面上实现虚拟化,直接复用本地主机的操作系统,而传统方式则是在硬件层面实现。

2. 使用Docker的理由

作为一种虚拟化方式,Docker 跟传统的虚拟化方式相比具有众多的优势。

首先,Docker 容器的启动可以在秒级实现,这相比传统的虚拟机方式要快得多。 其次,Docker 对系统资源的利用率很高,一台主机上可以同时运行数千个 Docker 容器。

容器除了运行其中应用外,基本不消耗额外的系统资源,使得应用的性能很高,同时系统的开销尽量小。传统虚拟机方式运行 10 个不同的应用就要起 10 个虚拟机,而Docker 只需要启动 10 个隔离的应用即可。

具体说来,Docker 在如下几个方面具有较大的优势。

  1. 更快速的交付和部署

    对开发和运维(devop)人员来说,最希望的就是一次创建或配置,可以在任意地方正常运行。

    开发者可以使用一个标准的镜像来构建一套开发容器,开发完成之后,运维人员可以直接使用这个容器来部署代码。 Docker 可以快速创建容器,快速迭代应用程序,并让整个过程全程可见,使团队中的其他成员更容易理解应用程序是如何创建和工作的。 Docker 容器很轻很快!容器的启动时间是秒级的,大量地节约开发、测试、部署的时间。

  2. 更高效的虚拟化

    Docker 容器的运行不需要额外的 hypervisor 支持,它是内核级的虚拟化,因此可以实现更高的性能和效率。

  3. 更轻松的迁移和扩展

    Docker 容器几乎可以在任意的平台上运行,包括物理机、虚拟机、公有云、私有云、个人电脑、服务器等。 这种兼容性可以让用户把一个应用程序从一个平台直接迁移到另外一个。

  4. 更简单的管理

    使用 Docker,只需要小小的修改,就可以替代以往大量的更新工作。所有的修改都以增量的方式被分发和更新,从而实现自动化并且高效的管理。

  5. 对比传统虚拟机总结

    | 特性 | 容器 | 虚拟机 |
    | :————- | :————————- | :————- |
    | 启动 | 秒级 | 分钟级 |
    | 硬盘使用 | 一般为 MB | 一般为 GB |
    | 性能 | 接近原生 | 弱于 |
    | 系统支持量 | 单机支持上千个容器 | 一般几十个 |

二、Docker 基本概念

1. Docker 镜像

Docker 镜像就是一个只读的模板。

例如:一个镜像可以包含一个完整的 ubuntu 操作系统环境,里面仅安装了 Apache 或用户需要的其它应用程序。

镜像可以用来创建 Docker 容器。

Docker 提供了一个很简单的机制来创建镜像或者更新现有的镜像,用户甚至可以直接从其他人那里下载一个已经做好的镜像来直接使用。

2. Docker容器的运用

2018-08-04 17:51 更新

Docker 利用容器来运行应用。

容器是从镜像创建的运行实例。它可以被启动、开始、停止、删除。每个容器都是相互隔离的、保证安全的平台。

可以把容器看做是一个简易版的 Linux 环境(包括root用户权限、进程空间、用户空间和网络空间等)和运行在其中的应用程序。

注:镜像是只读的,容器在启动的时候创建一层可写层作为最上层。

3. Docker仓库

仓库是集中存放镜像文件的场所。有时候会把仓库和仓库注册服务器(Registry)混为一谈,并不严格区分。实际上,仓库注册服务器上往往存放着多个仓库,每个仓库中又包含了多个镜像,每个镜像有不同的标签(tag)。

仓库分为公开仓库(Public)和私有仓库(Private)两种形式。

最大的公开仓库是 Docker Hub,存放了数量庞大的镜像供用户下载。 国内的公开仓库包括 Docker Pool 等,可以提供大陆用户更稳定快速的访问。

当然,用户也可以在本地网络内创建一个私有仓库。

当用户创建了自己的镜像之后就可以使用 push 命令将它上传到公有或者私有仓库,这样下次在另外一台机器上使用这个镜像时候,只需要从仓库上 pull 下来就可以了。

注:Docker 仓库的概念跟 Git 类似,注册服务器可以理解为 GitHub 这样的托管服务。

三、Docker安装指南

官方网站上有各种环境下的 安装指南,这里主要介绍下CentOS系列的安装。

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
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
[root@localhost software]# curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
# Executing docker install script, commit: b2e29ef7a9a89840d2333637f7d1900a83e7153f
+ sh -c 'yum install -y -q yum-utils'
Package yum-utils-1.1.31-54.el7_8.noarch already installed and latest version
+ sh -c 'yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo'
Loaded plugins: fastestmirror, langpacks, product-id, subscription-manager

This system is not registered with an entitlement server. You can use subscription-manager to register.

adding repo from: https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
grabbing file https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo to /etc/yum.repos.d/docker-ce.repo
repo saved to /etc/yum.repos.d/docker-ce.repo
+ '[' stable '!=' stable ']'
+ sh -c 'yum makecache'
Loaded plugins: fastestmirror, langpacks, product-id, search-disabled-repos, subscription-manager

This system is not registered with an entitlement server. You can use subscription-manager to register.

Loading mirror speeds from cached hostfile
* base: ftp.sjtu.edu.cn
* extras: mirrors.bfsu.edu.cn
* updates: ftp.sjtu.edu.cn
base | 3.6 kB 00:00:00
docker-ce-stable | 3.5 kB 00:00:00
extras | 2.9 kB 00:00:00
updates | 2.9 kB 00:00:00
Metadata Cache Created
+ sh -c 'yum install -y -q docker-ce docker-ce-cli containerd.io docker-scan-plugin docker-compose-plugin docker-ce-rootless-extras'
warning: /var/cache/yum/x86_64/7/docker-ce-stable/packages/docker-ce-20.10.17-3.el7.x86_64.rpm: Header V4 RSA/SHA512 Signature, key ID 621e9f35: NOKEY
Public key for docker-ce-20.10.17-3.el7.x86_64.rpm is not installed

Importing GPG key 0x621E9F35:
Userid : "Docker Release (CE rpm) <docker@docker.com>"
Fingerprint: 060a 61c5 1b55 8a7f 742b 77aa c52f eb6b 621e 9f35
From : https://mirrors.aliyun.com/docker-ce/linux/centos/gpg

================================================================================

To run Docker as a non-privileged user, consider setting up the
Docker daemon in rootless mode for your user:

dockerd-rootless-setuptool.sh install

Visit https://docs.docker.com/go/rootless/ to learn about rootless mode.


To run the Docker daemon as a fully privileged service, but granting non-root
users access, refer to https://docs.docker.com/go/daemon-access/

WARNING: Access to the remote API on a privileged Docker daemon is equivalent
to root access on the host. Refer to the 'Docker daemon attack surface'
documentation for details: https://docs.docker.com/go/attack-surface/

================================================================================

[root@localhost software]#

也可以使用国内 daocloud 一键安装命令:

1
[root@localhost software]# curl -sSL https://get.daocloud.io/docker | sh

2. 手动安装

2.1 卸载旧版本

较旧的 Docker 版本称为 docker 或 docker-engine 。如果已安装这些程序,请卸载它们以及相关的依赖项。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
[root@localhost software]# yum remove docker \
> docker-client \
> docker-client-latest \
> docker-common \
> docker-latest \
> docker-latest-logrotate \
> docker-logrotate \
> docker-engine
Loaded plugins: fastestmirror, langpacks, product-id, search-disabled-repos, subscription-manager

This system is not registered with an entitlement server. You can use subscription-manager to register.

No Match for argument: docker
No Match for argument: docker-client
No Match for argument: docker-client-latest
No Match for argument: docker-common
No Match for argument: docker-latest
No Match for argument: docker-latest-logrotate
No Match for argument: docker-logrotate
No Match for argument: docker-engine
No Packages marked for removal
[root@localhost software]#

2.2 安装 Docker Engine-Community

在新主机上首次安装 Docker Engine-Community 之前,需要设置 Docker 仓库。之后,您可以从仓库安装和更新 Docker。

2.2.1 设置仓库

安装所需的软件包。yum-utils 提供了 yum-config-manager ,并且 device mapper 存储驱动程序需要 device-mapper-persistent-datalvm2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@localhost software]# yum install -y yum-utils device-mapper-persistent-data lvm2
Loaded plugins: fastestmirror, langpacks, product-id, search-disabled-repos, subscription-manager

This system is not registered with an entitlement server. You can use subscription-manager to register.

Loading mirror speeds from cached hostfile
* base: ftp.sjtu.edu.cn
* extras: mirrors.bfsu.edu.cn
* updates: ftp.sjtu.edu.cn
Package yum-utils-1.1.31-54.el7_8.noarch already installed and latest version
Package device-mapper-persistent-data-0.8.5-3.el7_9.2.x86_64 already installed and latest version
Package 7:lvm2-2.02.187-6.el7_9.5.x86_64 already installed and latest version
Nothing to do
[root@localhost software]#

设置稳定的仓库:

  • 使用官方源地址(比较慢)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    [root@localhost software]# yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
    Loaded plugins: fastestmirror, langpacks, product-id, subscription-manager

    This system is not registered with an entitlement server. You can use subscription-manager to register.

    adding repo from: https://download.docker.com/linux/centos/docker-ce.repo
    grabbing file https://download.docker.com/linux/centos/docker-ce.repo to /etc/yum.repos.d/docker-ce.repo
    repo saved to /etc/yum.repos.d/docker-ce.repo
    [root@localhost software]#

  • 选择国内的 阿里云 源地址:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    [root@localhost software]# yum-config-manager --add-repo http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
    Loaded plugins: fastestmirror, langpacks, product-id, subscription-manager

    This system is not registered with an entitlement server. You can use subscription-manager to register.

    adding repo from: http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo
    grabbing file http://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo to /etc/yum.repos.d/docker-ce.repo
    repo saved to /etc/yum.repos.d/docker-ce.repo
    [root@localhost software]#
  • 选择国内的 清华大学 源地址:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    [root@localhost software]# yum-config-manager --add-repo https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/docker-ce.repo
    Loaded plugins: fastestmirror, langpacks, product-id, subscription-manager

    This system is not registered with an entitlement server. You can use subscription-manager to register.

    adding repo from: https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/docker-ce.repo
    grabbing file https://mirrors.tuna.tsinghua.edu.cn/docker-ce/linux/centos/docker-ce.repo to /etc/yum.repos.d/docker-ce.repo
    repo saved to /etc/yum.repos.d/docker-ce.repo
    [root@localhost software]#

2.2.2 安装 Docker Engine-Community

  • 安装最新版本的 Docker Engine-Communitycontainerd

    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
    [root@localhost software]# yum install docker-ce docker-ce-cli containerd.io
    Loaded plugins: fastestmirror, langpacks, product-id, search-disabled-repos, subscription-manager

    This system is not registered with an entitlement server. You can use subscription-manager to register.

    Loading mirror speeds from cached hostfile
    * base: ftp.sjtu.edu.cn
    * extras: mirrors.bfsu.edu.cn
    * updates: ftp.sjtu.edu.cn
    docker-ce-stable | 3.5 kB 00:00:00
    Package 1:docker-ce-cli-20.10.17-3.el7.x86_64 already installed and latest version
    Package containerd.io-1.6.7-3.1.el7.x86_64 already installed and latest version
    Resolving Dependencies
    --> Running transaction check
    ---> Package docker-ce.x86_64 3:20.10.17-3.el7 will be installed
    --> Processing Dependency: docker-ce-rootless-extras for package: 3:docker-ce-20.10.17-3.el7.x86_64
    --> Running transaction check
    ---> Package docker-ce-rootless-extras.x86_64 0:20.10.17-3.el7 will be installed
    --> Finished Dependency Resolution

    Dependencies Resolved

    ========================================================================================================================
    Package Arch Version Repository Size
    ========================================================================================================================
    Installing:
    docker-ce x86_64 3:20.10.17-3.el7 docker-ce-stable 22 M
    Installing for dependencies:
    docker-ce-rootless-extras x86_64 20.10.17-3.el7 docker-ce-stable 8.2 M

    Transaction Summary
    ========================================================================================================================
    Install 1 Package (+1 Dependent package)

    Total download size: 31 M
    Installed size: 115 M
    Is this ok [y/d/N]: y
    Downloading packages:
    (1/2): docker-ce-rootless-extras-20.10.17-3.el7.x86_64.rpm | 8.2 MB 00:00:28
    (2/2): docker-ce-20.10.17-3.el7.x86_64.rpm | 22 MB 00:01:18
    ------------------------------------------------------------------------------------------------------------------------
    Total 400 kB/s | 31 MB 00:01:18
    Running transaction check
    Running transaction test
    Transaction test succeeded
    Running transaction
    Installing : 3:docker-ce-20.10.17-3.el7.x86_64 1/2
    Installing : docker-ce-rootless-extras-20.10.17-3.el7.x86_64 2/2
    Verifying : docker-ce-rootless-extras-20.10.17-3.el7.x86_64 1/2
    Verifying : 3:docker-ce-20.10.17-3.el7.x86_64 2/2

    Installed:
    docker-ce.x86_64 3:20.10.17-3.el7

    Dependency Installed:
    docker-ce-rootless-extras.x86_64 0:20.10.17-3.el7

    Complete!
    [root@localhost software]#

    如果提示您接受 GPG 密钥,请选是。

    有多个 Docker 仓库吗?

    如果启用了多个 Docker 仓库,则在 yum installyum update 命令中指定版本的情况下,进行的安装或更新将始终安装最高版本,这可能不适合您的稳定性需求。

    Docker 安装完默认未启动。并且已经创建好 docker 用户组,但该用户组下没有用户。

  • 安装特定版本:

    安装特定版本的 Docker Engine-Community,请在存储库中列出可用版本,然后选择并安装。

    • 列出并排序您存储库中可用的版本。此示例按版本号(从高到低)对结果进行排序。

      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
      [root@localhost software]# yum list docker-ce --showduplicates | sort -r
      * updates: ftp.sjtu.edu.cn
      This system is not registered with an entitlement server. You can use subscription-manager to register.
      : subscription-manager
      Loading mirror speeds from cached hostfile
      Loaded plugins: fastestmirror, langpacks, product-id, search-disabled-repos,
      Installed Packages
      * extras: mirrors.bfsu.edu.cn
      docker-ce.x86_64 3:20.10.9-3.el7 docker-ce-stable
      docker-ce.x86_64 3:20.10.8-3.el7 docker-ce-stable
      docker-ce.x86_64 3:20.10.7-3.el7 docker-ce-stable
      ...
      docker-ce.x86_64 3:18.09.2-3.el7 docker-ce-stable
      docker-ce.x86_64 3:18.09.1-3.el7 docker-ce-stable
      docker-ce.x86_64 3:18.09.0-3.el7 docker-ce-stable
      docker-ce.x86_64 18.06.3.ce-3.el7 docker-ce-stable
      docker-ce.x86_64 18.06.2.ce-3.el7 docker-ce-stable
      docker-ce.x86_64 18.06.1.ce-3.el7 docker-ce-stable
      docker-ce.x86_64 18.06.0.ce-3.el7 docker-ce-stable
      docker-ce.x86_64 18.03.1.ce-1.el7.centos docker-ce-stable
      ...
      * base: ftp.sjtu.edu.cn
      Available Packages


      [root@localhost software]#
  • 通过其完整的软件包名称安装特定版本,该软件包名称是软件包名称(docker-ce)加上版本字符串(第二列),从第一个冒号(:)一直到第一个连字符,并用连字符(-)分隔。例如:docker-ce-18.09.1

    1
    [root@localhost software]# yum install docker-ce-<VERSION_STRING> docker-ce-cli-<VERSION_STRING> containerd.io

3. Docker启动

启动 Docker:

1
2
[root@localhost software]# sudo systemctl start docker
[root@localhost software]#

通过运行 hello-world 镜像来验证是否正确安装了 Docker Engine-Community 。

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
[root@localhost software]# docker run hello-world
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
2db29710123e: Pull complete
Digest: sha256:7d246653d0511db2a6b2e0436cfd0e52ac8c066000264b3ce63331ac66dca625
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@localhost software]# chkconfig docker on
Note: Forwarding request to 'systemctl enable docker.service'.
Created symlink from /etc/systemd/system/multi-user.target.wants/docker.service to /usr/lib/systemd/system/docker.service.
[root@localhost software]#

4. Docker卸载

  1. 首先搜索已经安装的docker 安装包

    1
    2
    3
    4
    5
    6
    7
    8
    [root@localhost software]# yum list installed|grep docker
    containerd.io.x86_64 1.6.7-3.1.el7 @docker-ce-stable
    docker-ce.x86_64 3:20.10.17-3.el7 @docker-ce-stable
    docker-ce-cli.x86_64 1:20.10.17-3.el7 @docker-ce-stable
    docker-ce-rootless-extras.x86_64 20.10.17-3.el7 @docker-ce-stable
    docker-compose-plugin.x86_64 2.6.0-3.el7 @docker-ce-stable
    docker-scan-plugin.x86_64 0.17.0-3.el7 @docker-ce-stable
    [root@localhost software]#
  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
    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
    155
    156
    157
    158
    159
    160
    161
    162
    163
    [root@localhost software]# yum -y remove docker-ce.x86_64 
    Loaded plugins: fastestmirror, langpacks, product-id, search-disabled-repos, subscription-manager

    This system is not registered with an entitlement server. You can use subscription-manager to register.

    Resolving Dependencies
    --> Running transaction check
    ---> Package docker-ce.x86_64 3:20.10.17-3.el7 will be erased
    --> Processing Dependency: docker-ce for package: docker-ce-rootless-extras-20.10.17-3.el7.x86_64
    --> Running transaction check
    ---> Package docker-ce-rootless-extras.x86_64 0:20.10.17-3.el7 will be erased
    --> Finished Dependency Resolution

    Dependencies Resolved

    ========================================================================================================================
    Package Arch Version Repository Size
    ========================================================================================================================
    Removing:
    docker-ce x86_64 3:20.10.17-3.el7 @docker-ce-stable 96 M
    Removing for dependencies:
    docker-ce-rootless-extras x86_64 20.10.17-3.el7 @docker-ce-stable 19 M

    Transaction Summary
    ========================================================================================================================
    Remove 1 Package (+1 Dependent package)

    Installed size: 115 M
    Downloading packages:
    Running transaction check
    Running transaction test
    Transaction test succeeded
    Running transaction
    Erasing : 3:docker-ce-20.10.17-3.el7.x86_64 1/2
    Erasing : docker-ce-rootless-extras-20.10.17-3.el7.x86_64 2/2
    Verifying : docker-ce-rootless-extras-20.10.17-3.el7.x86_64 1/2
    Verifying : 3:docker-ce-20.10.17-3.el7.x86_64 2/2

    Removed:
    docker-ce.x86_64 3:20.10.17-3.el7

    Dependency Removed:
    docker-ce-rootless-extras.x86_64 0:20.10.17-3.el7

    Complete!
    [root@localhost software]# yum -y remove docker-ce-cli.x86_64
    Loaded plugins: fastestmirror, langpacks, product-id, search-disabled-repos, subscription-manager

    This system is not registered with an entitlement server. You can use subscription-manager to register.

    Resolving Dependencies
    --> Running transaction check
    ---> Package docker-ce-cli.x86_64 1:20.10.17-3.el7 will be erased
    --> Processing Dependency: docker-ce-cli for package: docker-scan-plugin-0.17.0-3.el7.x86_64
    --> Running transaction check
    ---> Package docker-scan-plugin.x86_64 0:0.17.0-3.el7 will be erased
    --> Finished Dependency Resolution

    Dependencies Resolved

    ========================================================================================================================
    Package Arch Version Repository Size
    ========================================================================================================================
    Removing:
    docker-ce-cli x86_64 1:20.10.17-3.el7 @docker-ce-stable 140 M
    Removing for dependencies:
    docker-scan-plugin x86_64 0.17.0-3.el7 @docker-ce-stable 13 M

    Transaction Summary
    ========================================================================================================================
    Remove 1 Package (+1 Dependent package)

    Installed size: 153 M
    Downloading packages:
    Running transaction check
    Running transaction test
    Transaction test succeeded
    Running transaction
    Erasing : 1:docker-ce-cli-20.10.17-3.el7.x86_64 1/2
    Erasing : docker-scan-plugin-0.17.0-3.el7.x86_64 2/2
    Verifying : docker-scan-plugin-0.17.0-3.el7.x86_64 1/2
    Verifying : 1:docker-ce-cli-20.10.17-3.el7.x86_64 2/2

    Removed:
    docker-ce-cli.x86_64 1:20.10.17-3.el7

    Dependency Removed:
    docker-scan-plugin.x86_64 0:0.17.0-3.el7

    Complete!

    [root@localhost software]# yum -y remove docker-compose-plugin.x86_64
    Loaded plugins: fastestmirror, langpacks, product-id, search-disabled-repos, subscription-manager

    This system is not registered with an entitlement server. You can use subscription-manager to register.

    Resolving Dependencies
    --> Running transaction check
    ---> Package docker-compose-plugin.x86_64 0:2.6.0-3.el7 will be erased
    --> Finished Dependency Resolution

    Dependencies Resolved

    ========================================================================================================================
    Package Arch Version Repository Size
    ========================================================================================================================
    Removing:
    docker-compose-plugin x86_64 2.6.0-3.el7 @docker-ce-stable 25 M

    Transaction Summary
    ========================================================================================================================
    Remove 1 Package

    Installed size: 25 M
    Downloading packages:
    Running transaction check
    Running transaction test
    Transaction test succeeded
    Running transaction
    Erasing : docker-compose-plugin-2.6.0-3.el7.x86_64 1/1
    Verifying : docker-compose-plugin-2.6.0-3.el7.x86_64 1/1

    Removed:
    docker-compose-plugin.x86_64 0:2.6.0-3.el7

    Complete!

    [root@localhost software]# yum -y remove containerd.io.x86_64
    Loaded plugins: fastestmirror, langpacks, product-id, search-disabled-repos, subscription-manager

    This system is not registered with an entitlement server. You can use subscription-manager to register.

    Resolving Dependencies
    --> Running transaction check
    ---> Package containerd.io.x86_64 0:1.6.7-3.1.el7 will be erased
    --> Finished Dependency Resolution

    Dependencies Resolved

    ========================================================================================================================
    Package Arch Version Repository Size
    ========================================================================================================================
    Removing:
    containerd.io x86_64 1.6.7-3.1.el7 @docker-ce-stable 125 M

    Transaction Summary
    ========================================================================================================================
    Remove 1 Package

    Installed size: 125 M
    Downloading packages:
    Running transaction check
    Running transaction test
    Transaction test succeeded
    Running transaction
    Erasing : containerd.io-1.6.7-3.1.el7.x86_64 1/1
    Verifying : containerd.io-1.6.7-3.1.el7.x86_64 1/1

    Removed:
    containerd.io.x86_64 0:1.6.7-3.1.el7

    Complete!
    [root@localhost software]#
  3. 删除docker 镜像

    1
    2
    [root@localhost software]# rm -rf /var/lib/docker
    [root@localhost software]#
  4. 再次check docker是否已经卸载成功

    1
    2
    [root@localhost software]# yum list installed|grep docker 
    [root@localhost software]#

    如果没有,就表示卸载成功。

四、Docker使用

1. Docker Hello World

Docker 允许你在容器内运行应用程序, 使用 docker run 命令来在容器内运行一个应用程序。输出Hello world

1
2
3
[root@localhost software]# docker run ubuntu:15.10 /bin/echo "Hello world"
Hello world
[root@localhost software]#

各个参数解析:

  • docker: Docker 的二进制执行文件。
  • run: 与前面的 docker 组合来运行一个容器。
  • ubuntu:15.10 指定要运行的镜像,Docker 首先从本地主机上查找镜像是否存在,如果不存在,Docker 就会从镜像仓库 Docker Hub 下载公共镜像。
  • /bin/echo “Hello world”: 在启动的容器里执行的命令

以上命令完整的意思可以解释为:Docker 以 ubuntu15.10 镜像创建一个新容器,然后在容器里执行 bin/echo “Hello world”,然后输出结果。

1.1 运行交互式的容器

通过 docker 的两个参数 -i -t,让 docker 运行的容器实现“对话”的能力:

1
2
[root@localhost software]# docker run -i -t ubuntu:15.10 /bin/bash
root@ed4a85705ff3:/#

各个参数解析:

  • -t: 在新容器内指定一个伪终端或终端。
  • -i: 允许你对容器内的标准输入 (STDIN) 进行交互。

注意第二行 root@ed4a85705ff3:/#,此时我们已进入一个 ubuntu15.10 系统的容器

我们尝试在容器中运行命令 cat /proc/versionls分别查看当前系统的版本信息和当前目录下的文件列表

1
2
3
4
5
root@ed4a85705ff3:/# cat /proc/version
Linux version 3.10.0-862.el7.x86_64 (builder@kbuilder.dev.centos.org) (gcc version 4.8.5 20150623 (Red Hat 4.8.5-28) (GCC) ) #1 SMP Fri Apr 20 16:44:24 UTC 2018
root@ed4a85705ff3:/# ls
bin boot dev etc home lib lib64 media mnt opt proc root run sbin srv sys tmp usr var
root@ed4a85705ff3:/#

可以通过运行 exit 命令或者使用 CTRL+D 来退出容器。

1
2
3
root@ed4a85705ff3:/# exit
exit
[root@localhost software]#

注意第三行中 [root@localhost software]# 表明我们已经退出了当前的容器,返回到当前的主机中。

1.2 启动容器(后台模式)

创建一个以进程方式运行的容器:

1
2
3
[root@localhost software]# docker run -d ubuntu:15.10 /bin/sh -c "while true; do echo hello world; sleep 1; done"
f8f69699ea5ee423c804656040a2512541dc1503320a19c573c5bf9a29bfb0a0
[root@localhost software]#

在输出中,我们没有看到期望的 hello world,而是一串长字符

f8f69699ea5ee423c804656040a2512541dc1503320a19c573c5bf9a29bfb0a0

这个长字符串叫做容器 ID,对每个容器来说都是唯一的,我们可以通过容器 ID 来查看对应的容器发生了什么。

首先,我们需要确认容器有在运行,可以通过 docker ps 来查看:

1
2
3
4
[root@localhost software]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f8f69699ea5e ubuntu:15.10 "/bin/sh -c 'while t…" 59 seconds ago Up 58 seconds reverent_rubin
[root@localhost software]#

输出详情介绍:

  • CONTAINER ID: 容器 ID。

  • IMAGE: 使用的镜像。

  • COMMAND: 启动容器时运行的命令。

  • CREATED: 容器的创建时间。

  • STATUS: 容器状态。状态有7种:

    • created(已创建)

    • restarting(重启中)

    • running 或 Up(运行中)

    • removing(迁移中)

    • paused(暂停)

    • exited(停止)

    • dead(死亡)

  • PORTS: 容器的端口信息和使用的连接类型(tcp\udp)。

  • NAMES: 自动分配的容器名称。

在宿主主机内使用 docker logs 命令,查看容器内的标准输出:

1
2
3
4
5
6
7
8
9
10
11
[root@localhost software]# docker logs f8f69699ea5e
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
hello world
...

1.3 停止容器

使用 docker stop 命令来停止容器:

1
2
3
[root@localhost software]# docker stop f8f69699ea5e
f8f69699ea5e
[root@localhost software]#

通过 docker ps 查看,容器已经停止工作:

1
2
3
[root@localhost software]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
[root@localhost software]#

可以看到容器已经不在了。

也可以用下面的命令来停止:

1
2
3
[root@localhost software]# docker stop reverent_rubin
reverent_rubin
[root@localhost software]#

2. Docker容器使用

2.1 Docker 客户端

docker 客户端非常简单 ,我们可以直接输入 docker 命令来查看到 Docker 客户端的所有命令选项。

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
[root@localhost software]# docker

Usage: docker [OPTIONS] COMMAND

A self-sufficient runtime for containers

Options:
--config string Location of client config files (default "/root/.docker")
-c, --context string Name of the context to use to connect to the daemon (overrides DOCKER_HOST env var and
default context set with "docker context use")
-D, --debug Enable debug mode
-H, --host list Daemon socket(s) to connect to
-l, --log-level string Set the logging level ("debug"|"info"|"warn"|"error"|"fatal") (default "info")
--tls Use TLS; implied by --tlsverify
--tlscacert string Trust certs signed only by this CA (default "/root/.docker/ca.pem")
--tlscert string Path to TLS certificate file (default "/root/.docker/cert.pem")
--tlskey string Path to TLS key file (default "/root/.docker/key.pem")
--tlsverify Use TLS and verify the remote
-v, --version Print version information and quit

Management Commands:
app* Docker App (Docker Inc., v0.9.1-beta3)
builder Manage builds
buildx* Docker Buildx (Docker Inc., v0.8.2-docker)
config Manage Docker configs
container Manage containers
context Manage contexts
image Manage images
manifest Manage Docker image manifests and manifest lists
network Manage networks
node Manage Swarm nodes
plugin Manage plugins
scan* Docker Scan (Docker Inc., v0.17.0)
secret Manage Docker secrets
service Manage services
stack Manage Docker stacks
swarm Manage Swarm
system Manage Docker
trust Manage trust on Docker images
volume Manage volumes

Commands:
attach Attach local standard input, output, and error streams to a running container
build Build an image from a Dockerfile
commit Create a new image from a container's changes
cp Copy files/folders between a container and the local filesystem
create Create a new container
diff Inspect changes to files or directories on a container's filesystem
events Get real time events from the server
exec Run a command in a running container
export Export a container's filesystem as a tar archive
history Show the history of an image
images List images
import Import the contents from a tarball to create a filesystem image
info Display system-wide information
inspect Return low-level information on Docker objects
kill Kill one or more running containers
load Load an image from a tar archive or STDIN
login Log in to a Docker registry
logout Log out from a Docker registry
logs Fetch the logs of a container
pause Pause all processes within one or more containers
port List port mappings or a specific mapping for the container
ps List containers
pull Pull an image or a repository from a registry
push Push an image or a repository to a registry
rename Rename a container
restart Restart one or more containers
rm Remove one or more containers
rmi Remove one or more images
run Run a command in a new container
save Save one or more images to a tar archive (streamed to STDOUT by default)
search Search the Docker Hub for images
start Start one or more stopped containers
stats Display a live stream of container(s) resource usage statistics
stop Stop one or more running containers
tag Create a tag TARGET_IMAGE that refers to SOURCE_IMAGE
top Display the running processes of a container
unpause Unpause all processes within one or more containers
update Update configuration of one or more containers
version Show the Docker version information
wait Block until one or more containers stop, then print their exit codes

Run 'docker COMMAND --help' for more information on a command.

To get more help with docker, check out our guides at https://docs.docker.com/go/guides/
[root@localhost software]#

可以通过命令docker command --help 更深入的了解指定的 Docker 命令使用方法。

例如我们要查看 docker stats 指令的具体使用方法:

1
2
3
4
5
6
7
8
9
10
11
12
[root@localhost software]# docker stats --help

Usage: docker stats [OPTIONS] [CONTAINER...]

Display a live stream of container(s) resource usage statistics

Options:
-a, --all Show all containers (default shows just running)
--format string Pretty-print images using a Go template
--no-stream Disable streaming stats and only pull the first result
--no-trunc Do not truncate output
[root@localhost software]#

2.2 容器使用

2.2.1 获取镜像

如果本地没有 ubuntu 镜像,可以使用 docker pull 命令来载入 ubuntu 镜像:

1
2
3
4
5
6
7
8
[root@localhost software]# docker pull ubuntu
Using default tag: latest
latest: Pulling from library/ubuntu
d19f32bd9e41: Pull complete
Digest: sha256:34fea4f31bf187bc915536831fd0afc9d214755bf700b5cdb1336c82516d154e
Status: Downloaded newer image for ubuntu:latest
docker.io/library/ubuntu:latest
[root@localhost software]#

2.2.2 启动容器

以下命令使用 ubuntu 镜像启动一个容器,参数为以命令行模式进入该容器:

1
2
[root@localhost software]# docker run -it ubuntu /bin/bash
root@5358c9601c75:/#

参数说明:

  • -i: 交互式操作。
  • -t: 终端。
  • ubuntu: ubuntu 镜像。
  • /bin/bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 /bin/bash。

要退出终端,直接输入 exit:

1
2
3
root@5358c9601c75:/# exit
exit
[root@localhost software]#

2.2.3 启动已停止运行的容器

查看所有的容器命令如下:

1
2
3
4
[root@localhost software]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5358c9601c75 ubuntu "/bin/bash" About a minute ago Exited (0) About a minute ago
[root@localhost software]#

使用 docker start 启动一个已停止的容器:

1
2
3
[root@localhost software]# docker start 5358c9601c75
5358c9601c75
[root@localhost software]#

2.2.4 后台运行

在大部分的场景下,希望 docker 的服务是在后台运行的,可以过 -d 指定容器的运行模式。

1
2
3
4
5
6
7
[root@localhost software]# docker run -itd --name ubuntu-test ubuntu /bin/bash
c293ba3fecac5d8f833bec90aca18670ba253fa0af7f7697990c9b8933902c23
[root@localhost software]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c293ba3fecac ubuntu "/bin/bash" 23 seconds ago Up 22 seconds ubuntu-test
5358c9601c75 ubuntu "/bin/bash" 4 minutes ago Up About a minute lucid_austin
[root@localhost software]#

注:加了 -d 参数默认不会进入容器,想要进入容器需要使用指令 docker exec(下面会介绍到)。

2.2.5 停止一个容器

停止容器的命令如下:

1
2
3
[root@localhost software]# docker stop c293ba3fecac
c293ba3fecac
[root@localhost software]#

停止的容器可以通过 docker restart 重启:

1
2
3
[root@localhost software]# docker restart c293ba3fecac
c293ba3fecac
[root@localhost software]#

2.2.6 进入容器

在使用 -d 参数时,容器启动后会进入后台。此时想要进入容器,可以通过以下指令进入:

  • docker attach

    1
    2
    3
    4
    5
    6
    7
    8
    9
    [root@localhost software]# docker ps
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    c293ba3fecac ubuntu "/bin/bash" 5 minutes ago Up 1 second ubuntu-test
    [root@localhost software]# docker attach c293ba3fecac
    root@c293ba3fecac:/# exit
    exit
    [root@localhost software]# docker ps
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    [root@localhost software]#

    注意: 如果从这个容器退出,会导致容器的停止。

  • docker exec:推荐大家使用 docker exec 命令,因为此命令会退出容器终端,但不会导致容器的停止。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    [root@localhost software]# docker ps
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    c293ba3fecac ubuntu "/bin/bash" 6 minutes ago Up 3 seconds ubuntu-test
    [root@localhost software]# docker exec -it c293ba3fecac /bin/bash
    root@c293ba3fecac:/# exit
    exit
    [root@localhost software]# docker ps
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    c293ba3fecac ubuntu "/bin/bash" 6 minutes ago Up 18 seconds ubuntu-test
    [root@localhost software]#

    注意: 如果从这个容器退出,容器不会停止,这就是为什么推荐大家使用 docker exec 的原因。

    更多参数说明请使用 docker exec —help 命令查看。

2.2.7 导出、导入容器和删除容器

  1. 导出容器

    如果要导出本地某个容器,可以使用 docker export 命令。

    1
    2
    3
    [root@localhost software]# cd DDocker/
    [root@localhost DDocker]# docker export c293ba3fecac > ./ubuntu.tar
    [root@localhost DDocker]#

    导出容器 c293ba3fecac 快照到本地文件 ubuntu.tar。

    1
    2
    3
    4
    [root@localhost DDocker]# ll ./
    total 78476
    -rw-r--r--. 1 root root 80356864 Aug 15 03:15 ubuntu.tar
    [root@localhost DDocker]#

    这样将导出容器快照到本地文件。

  2. 导入容器快照

    可以使用 docker import 从容器快照文件中再导入为镜像,以下实例将快照文件 ubuntu.tar 导入到镜像 test/ubuntu:v1:

    1
    2
    3
    4
    5
    6
    7
    8
    [root@localhost DDocker]# cat ./ubuntu.tar | docker import - test/ubuntu:v1
    sha256:c46e9fe3434edee953f9dd9fe8d1a2351dba59c0abd6e4510055e3b39995b9aa
    [root@localhost DDocker]# docker images
    REPOSITORY TAG IMAGE ID CREATED SIZE
    test/ubuntu v1 c46e9fe3434e 5 seconds ago 77.8MB
    ubuntu latest df5de72bdb3b 2 weeks ago 77.8MB
    ubuntu 15.10 9b9cb95443b5 6 years ago 137MB
    [root@localhost DDocker]#

    此外,也可以通过指定 URL 或者某个目录来导入,例如:

    1
    docker import 链接地址 example/imagerepo
  3. 删除容器

    删除容器使用 docker rm 命令:

    1
    2
    3
    4
    5
    6
    7
    8
    [root@localhost DDocker]# docker ps
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    c293ba3fecac ubuntu "/bin/bash" 3 days ago Up 3 days ubuntu-test
    [root@localhost DDocker]# docker rm -f c293ba3fecac
    c293ba3fecac
    [root@localhost DDocker]# docker ps
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    [root@localhost DDocker]#
  4. 清理掉所有处于终止状态的容器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    [root@localhost DDocker]# docker container prune
    WARNING! This will remove all stopped containers.
    Are you sure you want to continue? [y/N] y
    Deleted Containers:
    5358c9601c75ab8b25844441696287320cad518773d558e5ba506274e8e933c0
    f8f69699ea5ee423c804656040a2512541dc1503320a19c573c5bf9a29bfb0a0
    ed4a85705ff3bdc89fae2c8464033dcc3e6d712a3bcdeec9a206a934f7b9e566
    c19a6c0f44d983b5fc42999acc8e344669e4e5cd5a3e95a288a76f2a9c3e716f
    09a8c4e0a0ee2301d3b783fd326a9819ca39b94c6d891738ce1a760d4a1ca3fc
    ef0d5fdfe2791b92c8352e46d7e4c3bf226c555b097abc9f6ccdeec56bc59cbb

    Total reclaimed space: 31B
    [root@localhost DDocker]#

2.3 Docker 简单Web实例

2.3.1 运行一个 web 应用

前面运行的容器并没有一些什么特别的用处。

接下来让尝试使用 docker 构建一个 web 应用程序。在docker容器中运行一个 Python Flask 应用来运行一个web应用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
[root@localhost DDocker]# docker pull training/webapp  # 载入镜像
Using default tag: latest
latest: Pulling from training/webapp
Image docker.io/training/webapp:latest uses outdated schema1 manifest format. Please upgrade to a schema2 image for better future compatibility. More information at https://docs.docker.com/registry/spec/deprecated-schema-v1/
e190868d63f8: Pull complete
909cd34c6fd7: Pull complete
0b9bfabab7c1: Pull complete
a3ed95caeb02: Pull complete
10bbbc0fc0ff: Pull complete
fca59b508e9f: Pull complete
e7ae2541b15b: Pull complete
9dd97ef58ce9: Pull complete
a4c1b0cb7af7: Pull complete
Digest: sha256:06e9c1983bd6d5db5fba376ccd63bfa529e8d02f23d5079b8f74a616308fb11d
Status: Downloaded newer image for training/webapp:latest
docker.io/training/webapp:latest
[root@localhost DDocker]# docker run -d -P training/webapp python app.py
5d69665d500ef470659f02a6fa4a5c36707b67ec552a6797b3efbf79d82797b3
[root@localhost DDocker]#

参数说明:

  • -d:让容器在后台运行。
  • -P:将容器内部使用的网络端口随机映射到我们使用的主机上。

2.3.2 查看 WEB 应用容器

1
2
3
4
[root@localhost DDocker]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
5d69665d500e training/webapp "python app.py" 2 minutes ago Up 2 minutes 0.0.0.0:49153->5000/tcp, :::49153->5000/tcp jovial_kilby
[root@localhost DDocker]#

这里多了端口信息 0.0.0.0:49153->5000/tcp, :::49153->5000/tcp

Docker 开放了 5000 端口(默认 Python Flask 端口)映射到主机端口 49153上。

这时我们可以通过浏览器访问WEB应用

也可以通过 -p 参数来设置不一样的端口:

1
2
3
4
5
6
7
[root@localhost DDocker]# docker run -d -p 5000:5000 training/webapp python app.py
0a217a11c448cbe6e2223ddbe6dd09aeb883ad9614ce8050f12cb040c1399e89
[root@localhost DDocker]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0a217a11c448 training/webapp "python app.py" 12 seconds ago Up 11 seconds 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp awesome_tharp
5d69665d500e training/webapp "python app.py" 23 hours ago Up 23 hours 0.0.0.0:49153->5000/tcp, :::49153->5000/tcp jovial_kilby
[root@localhost DDocker]#

2.3.3 网络端口的快捷方式

通过 docker ps 命令可以查看到容器的端口映射,docker 还提供了另一个快捷方式 docker port,使用 docker port 可以查看指定 (ID 或者名字)容器的某个确定端口映射到宿主机的端口号。

上面创建的 web 应用容器 ID 为 0a217a11c448 名字为 awesome_tharp

我可以使用 docker port 0a217a11c448docker port awesome_tharp 来查看容器端口的映射情况。

1
2
3
4
5
6
7
[root@localhost DDocker]# docker port 0a217a11c448
5000/tcp -> 0.0.0.0:5000
5000/tcp -> :::5000
[root@localhost DDocker]# docker port awesome_tharp
5000/tcp -> 0.0.0.0:5000
5000/tcp -> :::5000
[root@localhost DDocker]#

2.3.4 查看Web应用程序日志

docker logs [ID或者名字] 可以查看容器内部的标准输出。

1
2
3
4
5
[root@localhost DDocker]# docker logs -f 0a217a11c448
* Running on http://0.0.0.0:5000/ (Press CTRL+C to quit)
192.168.48.1 - - [19/Aug/2022 08:54:01] "GET / HTTP/1.1" 200 -
192.168.48.1 - - [19/Aug/2022 08:54:01] "GET /favicon.ico HTTP/1.1" 404 -
192.168.48.1 - - [19/Aug/2022 08:54:03] "GET / HTTP/1.1" 200 -

参数说明:

  • -f:docker logs 像使用 tail -f 一样来输出容器内部的标准输出。

从上面,可以看到应用程序使用的是 5000 端口并且能够查看到应用程序的访问日志。

2.3.5 查看Web应用程序容器的进程

使用 docker top 来查看容器内部运行的进程:

1
2
3
4
[root@localhost DDocker]# docker top awesome_tharp
UID PID PPID C STIME TTY TIME CMD
root 12634 12612 0 01:52 ? 00:00:00 python app.py
[root@localhost DDocker]#

2.3.6 检查Web应用程序

使用 docker inspect 来查看 Docker 的底层信息。它会返回一个 JSON 文件记录着 Docker 容器的配置和状态信息。

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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
[root@localhost DDocker]# docker inspect awesome_tharp 
[
{
"Id": "0a217a11c448cbe6e2223ddbe6dd09aeb883ad9614ce8050f12cb040c1399e89",
"Created": "2022-08-19T08:52:59.445311998Z",
"Path": "python",
"Args": [
"app.py"
],
"State": {
"Status": "running",
"Running": true,
"Paused": false,
"Restarting": false,
"OOMKilled": false,
"Dead": false,
"Pid": 12634,
"ExitCode": 0,
"Error": "",
"StartedAt": "2022-08-19T08:53:00.035220635Z",
"FinishedAt": "0001-01-01T00:00:00Z"
},
"Image": "sha256:6fae60ef344644649a39240b94d73b8ba9c67f898ede85cf8e947a887b3e6557",
"ResolvConfPath": "/var/lib/docker/containers/0a217a11c448cbe6e2223ddbe6dd09aeb883ad9614ce8050f12cb040c1399e89/resolv.conf",
"HostnamePath": "/var/lib/docker/containers/0a217a11c448cbe6e2223ddbe6dd09aeb883ad9614ce8050f12cb040c1399e89/hostname",
"HostsPath": "/var/lib/docker/containers/0a217a11c448cbe6e2223ddbe6dd09aeb883ad9614ce8050f12cb040c1399e89/hosts",
"LogPath": "/var/lib/docker/containers/0a217a11c448cbe6e2223ddbe6dd09aeb883ad9614ce8050f12cb040c1399e89/0a217a11c448cbe6e2223ddbe6dd09aeb883ad9614ce8050f12cb040c1399e89-json.log",
"Name": "/awesome_tharp",
"RestartCount": 0,
"Driver": "overlay2",
"Platform": "linux",
"MountLabel": "",
"ProcessLabel": "",
"AppArmorProfile": "",
"ExecIDs": null,
"HostConfig": {
"Binds": null,
"ContainerIDFile": "",
"LogConfig": {
"Type": "json-file",
"Config": {}
},
"NetworkMode": "default",
"PortBindings": {
"5000/tcp": [
{
"HostIp": "",
"HostPort": "5000"
}
]
},
"RestartPolicy": {
"Name": "no",
"MaximumRetryCount": 0
},
"AutoRemove": false,
"VolumeDriver": "",
"VolumesFrom": null,
"CapAdd": null,
"CapDrop": null,
"CgroupnsMode": "host",
"Dns": [],
"DnsOptions": [],
"DnsSearch": [],
"ExtraHosts": null,
"GroupAdd": null,
"IpcMode": "private",
"Cgroup": "",
"Links": null,
"OomScoreAdj": 0,
"PidMode": "",
"Privileged": false,
"PublishAllPorts": false,
"ReadonlyRootfs": false,
"SecurityOpt": null,
"UTSMode": "",
"UsernsMode": "",
"ShmSize": 67108864,
"Runtime": "runc",
"ConsoleSize": [
0,
0
],
"Isolation": "",
"CpuShares": 0,
"Memory": 0,
"NanoCpus": 0,
"CgroupParent": "",
"BlkioWeight": 0,
"BlkioWeightDevice": [],
"BlkioDeviceReadBps": null,
"BlkioDeviceWriteBps": null,
"BlkioDeviceReadIOps": null,
"BlkioDeviceWriteIOps": null,
"CpuPeriod": 0,
"CpuQuota": 0,
"CpuRealtimePeriod": 0,
"CpuRealtimeRuntime": 0,
"CpusetCpus": "",
"CpusetMems": "",
"Devices": [],
"DeviceCgroupRules": null,
"DeviceRequests": null,
"KernelMemory": 0,
"KernelMemoryTCP": 0,
"MemoryReservation": 0,
"MemorySwap": 0,
"MemorySwappiness": null,
"OomKillDisable": false,
"PidsLimit": null,
"Ulimits": null,
"CpuCount": 0,
"CpuPercent": 0,
"IOMaximumIOps": 0,
"IOMaximumBandwidth": 0,
"MaskedPaths": [
"/proc/asound",
"/proc/acpi",
"/proc/kcore",
"/proc/keys",
"/proc/latency_stats",
"/proc/timer_list",
"/proc/timer_stats",
"/proc/sched_debug",
"/proc/scsi",
"/sys/firmware"
],
"ReadonlyPaths": [
"/proc/bus",
"/proc/fs",
"/proc/irq",
"/proc/sys",
"/proc/sysrq-trigger"
]
},
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/b297f5b6a2089c75af5d4a466b7d28760a309fd8d8038868d1c37552acf62393-init/diff:/var/lib/docker/overlay2/7154389c17280fdf4962246ab3dd248579bb536c13b07fe327bd8ec65ff36add/diff:/var/lib/docker/overlay2/711961c1287a9e045b7caa18fa4cf6d21e186a0fa80126905d2e832f27573bf5/diff:/var/lib/docker/overlay2/a57c52470deecd88547bc5d03c7418e7b88add1a22c61e49c62595219d46e368/diff:/var/lib/docker/overlay2/e4a2c8c9702b9cd21534ee77f134332c54a575036e3f6eb7d7d12e38f211d4a5/diff:/var/lib/docker/overlay2/f5eeb64487fcce01056ae15c28c4e1637d12fb6b518bcfa8c3e87452ab746939/diff:/var/lib/docker/overlay2/1f4882c84fd6fceab9f1063362906839f858f5ed07237f34e2fde4dea7d3b9ed/diff:/var/lib/docker/overlay2/e8b89880d7223d3a9ba8a4cc46d4b887b6ec33f4653bd0472d69516c6fac471b/diff:/var/lib/docker/overlay2/6e1d3528d9bb72efa226ba8631eab7ff7405d92c5f8d13825aec7de0a9c4b7a4/diff:/var/lib/docker/overlay2/d9b6e6af59f120800c9f332210dfe279ceeeb66bb6056496538d8e269470ad3b/diff:/var/lib/docker/overlay2/5861193f780069a9c6f8230a7d667941e5721b07f2c5313e320766288367913d/diff:/var/lib/docker/overlay2/306fcd234e922e52fdd1ce6aa7afc5013d430041f60a9451c3982be7b3251018/diff:/var/lib/docker/overlay2/d7e5fb7ae7525868dca45d5b61405e2f4008d88979c70c8f59ce8c117d77e42d/diff:/var/lib/docker/overlay2/574a21f740852a28afd807db044d9049e524be22450475138cb598a720038cbb/diff",
"MergedDir": "/var/lib/docker/overlay2/b297f5b6a2089c75af5d4a466b7d28760a309fd8d8038868d1c37552acf62393/merged",
"UpperDir": "/var/lib/docker/overlay2/b297f5b6a2089c75af5d4a466b7d28760a309fd8d8038868d1c37552acf62393/diff",
"WorkDir": "/var/lib/docker/overlay2/b297f5b6a2089c75af5d4a466b7d28760a309fd8d8038868d1c37552acf62393/work"
},
"Name": "overlay2"
},
"Mounts": [],
"Config": {
"Hostname": "0a217a11c448",
"Domainname": "",
"User": "",
"AttachStdin": false,
"AttachStdout": false,
"AttachStderr": false,
"ExposedPorts": {
"5000/tcp": {}
},
"Tty": false,
"OpenStdin": false,
"StdinOnce": false,
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
],
"Cmd": [
"python",
"app.py"
],
"Image": "training/webapp",
"Volumes": null,
"WorkingDir": "/opt/webapp",
"Entrypoint": null,
"OnBuild": null,
"Labels": {}
},
"NetworkSettings": {
"Bridge": "",
"SandboxID": "6489190fa50b7e3fbe25a49a039250da0042155719bf3e455038399ab6e61f3a",
"HairpinMode": false,
"LinkLocalIPv6Address": "",
"LinkLocalIPv6PrefixLen": 0,
"Ports": {
"5000/tcp": [
{
"HostIp": "0.0.0.0",
"HostPort": "5000"
},
{
"HostIp": "::",
"HostPort": "5000"
}
]
},
"SandboxKey": "/var/run/docker/netns/6489190fa50b",
"SecondaryIPAddresses": null,
"SecondaryIPv6Addresses": null,
"EndpointID": "adbdf001a02ad9946a1b5df84a5e0d8bc2ec9e6dea316dc62ebaa714954bd423",
"Gateway": "172.17.0.1",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"IPAddress": "172.17.0.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"MacAddress": "02:42:ac:11:00:03",
"Networks": {
"bridge": {
"IPAMConfig": null,
"Links": null,
"Aliases": null,
"NetworkID": "1df9775fe6801665441fb8dcde4fe10916578f316c83e1d3fa234ac473a433a6",
"EndpointID": "adbdf001a02ad9946a1b5df84a5e0d8bc2ec9e6dea316dc62ebaa714954bd423",
"Gateway": "172.17.0.1",
"IPAddress": "172.17.0.3",
"IPPrefixLen": 16,
"IPv6Gateway": "",
"GlobalIPv6Address": "",
"GlobalIPv6PrefixLen": 0,
"MacAddress": "02:42:ac:11:00:03",
"DriverOpts": null
}
}
}
}
]
[root@localhost DDocker]#

2.3.7 停止Web应用程序

1
2
3
[root@localhost DDocker]# docker stop awesome_tharp 
awesome_tharp
[root@localhost DDocker]#

2.3.8 重启Web应用容器

已经停止的容器,可以使用命令 docker start 来启动。

1
2
3
[root@localhost DDocker]# docker start awesome_tharp 
awesome_tharp
[root@localhost DDocker]#

docker ps -l 查询最后一次创建的容器:

1
2
3
4
[root@localhost DDocker]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
0a217a11c448 training/webapp "python app.py" About an hour ago Up 45 seconds 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp awesome_tharp
[root@localhost DDocker]#

正在运行的容器,我们可以使用 docker restart 命令来重启。

1
2
3
[root@localhost DDocker]# docker restart awesome_tharp 
awesome_tharp
[root@localhost DDocker]#

2.3.9 移除Web应用容器

使用 docker rm 命令来删除不需要的容器:

1
2
3
4
5
[root@localhost DDocker]# docker stop awesome_tharp
awesome_tharp
[root@localhost DDocker]# docker rm awesome_tharp
awesome_tharp
[root@localhost DDocker]#

除容器时,容器必须是停止状态,否则会报如下错误:

1
2
3
[root@localhost DDocker]# docker rm awesome_tharp
Error response from daemon: You cannot remove a running container 0a217a11c448cbe6e2223ddbe6dd09aeb883ad9614ce8050f12cb040c1399e89. Stop the container before attempting removal or force remove
[root@localhost DDocker]#

3. Docker镜像使用

当运行容器时,使用的镜像如果在本地中不存在,docker 就会自动从 docker 镜像仓库中下载,默认是从 Docker Hub 公共镜像源下载。

3.1 列出镜像列表

使用 docker images 来列出本地主机上的镜像。

1
2
3
4
5
6
7
8
[root@localhost DDocker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
test/ubuntu v1 c46e9fe3434e 3 days ago 77.8MB
ubuntu latest df5de72bdb3b 2 weeks ago 77.8MB
ubuntu 18.04 8d5df41c547b 2 weeks ago 63.1MB
ubuntu 15.10 9b9cb95443b5 6 years ago 137MB
training/webapp latest 6fae60ef3446 7 years ago 349MB
[root@localhost DDocker]#

各个选项说明:

  • REPOSITORY:表示镜像的仓库源
  • TAG:镜像的标签
  • IMAGE ID:镜像ID
  • CREATED:镜像创建时间
  • SIZE:镜像大小

同一仓库源可以有多个 TAG,代表这个仓库源的不同个版本,如 ubuntu 仓库源里,有 15.1018.04 等多个不同的版本,我们使用 REPOSITORY:TAG 来定义不同的镜像。

所以,如果要使用版本为15.10ubuntu系统镜像来运行容器时,命令如下:

1
2
[root@localhost DDocker]# docker run -t -i ubuntu:15.10 /bin/bash
root@4494c4d76bef:/#

参数说明:

  • -i: 交互式操作。
  • -t: 终端。
  • ubuntu:15.10: 这是指用 ubuntu 15.10 版本镜像为基础来启动容器。
  • /bin/bash:放在镜像名后的是命令,这里我们希望有个交互式 Shell,因此用的是 /bin/bash。

如果要使用版本为 18.04 的 ubuntu 系统镜像来运行容器时,命令如下:

1
2
[root@localhost DDocker]# docker run -t -i ubuntu:18.04 /bin/bash
root@d25c29d78f45:/#

如果不指定一个镜像的版本标签,例如只使用 ubuntu,docker 将默认使用 ubuntu:latest 镜像。

3.2 获取一个新的镜像

当在本地主机上使用一个不存在的镜像时 Docker 就会自动下载这个镜像。如果想预先下载这个镜像,可以使用 docker pull 命令来下载它。

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@localhost DDocker]# docker pull ubuntu:13.10
13.10: Pulling from library/ubuntu
Image docker.io/library/ubuntu:13.10 uses outdated schema1 manifest format. Please upgrade to a schema2 image for better future compatibility. More information at https://docs.docker.com/registry/spec/deprecated-schema-v1/
a3ed95caeb02: Pull complete
0d8710fc57fd: Pull complete
5037c5cd623d: Pull complete
83b53423b49f: Pull complete
e9e8bd3b94ab: Pull complete
7db00e6b6e5e: Pull complete
Digest: sha256:403105e61e2d540187da20d837b6a6e92efc3eb4337da9c04c191fb5e28c44dc
Status: Downloaded newer image for ubuntu:13.10
docker.io/library/ubuntu:13.10
[root@localhost DDocker]#

下载完成后,可以直接使用这个镜像来运行容器。

3.3 查找镜像

可以从 Docker Hub 网站来搜索镜像,Docker Hub 网址为: https://hub.docker.com/

也可以使用 docker search 命令来搜索镜像。比如需要一个 httpd 的镜像来作为web 服务。可以通过 docker search 命令搜索 httpd 来寻找适合我们的镜像。

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
[root@localhost DDocker]# docker search httpd
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
httpd The Apache HTTP Server Project 4121 [OK]
centos/httpd-24-centos7 Platform for running Apache httpd 2.4 or bui… 44
centos/httpd 35 [OK]
hypoport/httpd-cgi httpd-cgi 2 [OK]
clearlinux/httpd httpd HyperText Transfer Protocol (HTTP) ser… 2
solsson/httpd-openidc mod_auth_openidc on official httpd image, ve… 2 [OK]
nnasaki/httpd-ssi SSI enabled Apache 2.4 on Alpine Linux 1
dockerpinata/httpd 1
centos/httpd-24-centos8 1
lead4good/httpd-fpm httpd server which connects via fcgi proxy h1 [OK]
inanimate/httpd-ssl A play container with httpd, ssl enabled, an… 1 [OK]
dariko/httpd-rproxy-ldap Apache httpd reverse proxy with LDAP authent… 1 [OK]
manageiq/httpd Container with httpd, built on CentOS for Ma… 1 [OK]
publici/httpd httpd:latest 1 [OK]
httpdocker/kubia 0
patrickha/httpd-err 0
manageiq/httpd_configmap_generator Httpd Configmap Generator 0 [OK]
amd64/httpd The Apache HTTP Server Project 0
manasip/httpd 0
httpdss/archerysec ArcherySec repository 0 [OK]
e2eteam/httpd 0
sandeep1988/httpd-new httpd-new 0
paketobuildpacks/httpd 0
19022021/httpd-connection_test This httpd image will test the connectivity … 0
sherazahmedvaival/httpd-php-fpm74 0
[root@localhost DDocker]#

参数说明:

  • NAME: 镜像仓库源的名称

  • DESCRIPTION: 镜像的描述

  • OFFICIAL: 是否 docker 官方发布

  • stars: 类似 Github 里面的 star,表示点赞、喜欢的意思。

  • AUTOMATED: 自动构建。

3.4 拖取镜像

决定使用上图中的httpd 官方版本的镜像,使用命令 docker pull 来下载镜像。

1
2
3
4
5
6
7
8
9
10
[root@localhost DDocker]# docker pull httpd
Using default tag: latest
latest: Pulling from library/httpd
1efc276f4ff9: Downloading [==================================================>] 31.37MB/31.37MB
aed046121ed8: Download complete
4340e7be3d7f: Download complete
80e368ef21fc: Download complete
80cb79a80bbe: Download complete
write /var/lib/docker/tmp/GetImageBlob1509640261: no space left on device
[root@localhost DDocker]#

下载完成后,就可以使用这个镜像了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@localhost docker]# docker run httpd
Unable to find image 'httpd:latest' locally
latest: Pulling from library/httpd
1efc276f4ff9: Pull complete
aed046121ed8: Pull complete
4340e7be3d7f: Pull complete
80e368ef21fc: Pull complete
80cb79a80bbe: Pull complete
Digest: sha256:343452ec820a5d59eb3ab9aaa6201d193f91c3354f8c4f29705796d9353d4cc6
Status: Downloaded newer image for httpd:latest
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message
[Mon Aug 22 06:29:11.880882 2022] [mpm_event:notice] [pid 1:tid 140442894695744] AH00489: Apache/2.4.54 (Unix) configured -- resuming normal operations
[Mon Aug 22 06:29:11.881094 2022] [core:notice] [pid 1:tid 140442894695744] AH00094: Command line: 'httpd -D FOREGROUND'

3.5 删除镜像

镜像删除使用docker rmi 命令,比如删除hello-world 镜像:

1
2
3
4
5
6
[root@localhost docker]# docker rmi hello-world
Untagged: hello-world:latest
Untagged: hello-world@sha256:7d246653d0511db2a6b2e0436cfd0e52ac8c066000264b3ce63331ac66dca625
Deleted: sha256:feb5d9fea6a5e9606aa995e879d862b825965ba48de054caab5ef356dc6b3412
Deleted: sha256:e07ee1baac5fae6a26f30cabfe54a36d3402f96afda318fe0a96cec4ca393359
[root@localhost docker]#

3.6 创建镜像

当从 docker 镜像仓库中下载的镜像不能满足需求时,可以通过以下方式对镜像进行更改。

3.6.1 更新镜像

从已经创建的容器中更新镜像,并且提交这个镜像。

更新镜像之前,需要使用镜像来创建一个容器。

1
2
[root@localhost software]# docker run -t -i ubuntu:18.04 /bin/bash
root@5a156e79af57:/#

在运行的容器内使用 apt-get update 命令进行更新。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
root@5a156e79af57:/# apt-get update
Ign:1 http://mirrors.163.com/debian jessie InRelease
Ign:2 http://mirrors.163.com/debian jessie-proposed-updates InRelease
Get:3 http://mirrors.163.com/debian jessie Release [77.3 kB]
Hit:4 http://archive.ubuntu.com/ubuntu bionic InRelease
Err:5 http://mirrors.163.com/debian jessie-proposed-updates Release
404 Not Found [IP: 60.191.80.11 80]
Get:6 http://mirrors.163.com/debian jessie Release.gpg [1652 B]
Hit:7 http://archive.ubuntu.com/ubuntu bionic-updates InRelease
Hit:8 http://security.ubuntu.com/ubuntu bionic-security InRelease
Ign:6 http://mirrors.163.com/debian jessie Release.gpg
Hit:9 http://archive.ubuntu.com/ubuntu bionic-backports InRelease
Reading package lists... Done
E: The repository 'http://mirrors.163.com/debian jessie-proposed-updates Release' does not have a Release file.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.
W: GPG error: http://mirrors.163.com/debian jessie Release: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 7638D0442B90D010 NO_PUBKEY CBF8D6FD518E17E1
E: The repository 'http://mirrors.163.com/debian jessie Release' is not signed.
N: Updating from such a repository can't be done securely, and is therefore disabled by default.
N: See apt-secure(8) manpage for repository creation and user configuration details.
root@5a156e79af57:/#
  1. 问题阐述:

    在运行的容器内使用 apt-get update 命令进行更新时,发下很多404错误。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    root@5a156e79af57:/# apt-get update 
    Ign http://archive.ubuntu.com wily InRelease
    Ign http://archive.ubuntu.com wily-updates InRelease
    Ign http://archive.ubuntu.com wily-security InRelease
    Ign http://archive.ubuntu.com wily Release.gpg
    Ign http://archive.ubuntu.com wily-updates Release.gpg
    Ign http://archive.ubuntu.com wily-security Release.gpg
    Ign http://archive.ubuntu.com wily Release
    Ign http://archive.ubuntu.com wily-updates Release
    Ign http://archive.ubuntu.com wily-security Release
    Err http://archive.ubuntu.com wily/main Sources
    404 Not Found [IP: 91.189.91.39 80]
    Err http://archive.ubuntu.com wily/restricted Sources
    404 Not Found [IP: 91.189.91.39 80]
    ...
    W: Failed to fetch http://archive.ubuntu.com/ubuntu/dists/wily-security/universe/binary-amd64/Packages 404 Not Found [IP: 91.189.91.39 80]

    E: Some index files failed to download. They have been ignored, or old ones used instead.
    root@5a156e79af57:/#
  2. 问题解决:

    经查,每一个Ubuntu发布版本都有它的结束时间,通常,Ubuntu发布版本支持18个月,而LTS (Long Term Support)(长期支持)版本分别支持3年(服务器版)和5年(桌面版)。

    当一个Ubuntu发布版本到达结束期后,它的库将不再能够访问,并且你也不会得到任何维护更新和安全补丁。当写这个的时候,我的15.10版本已经到了它的结束期了。
    对于那些使用旧版本的Ubuntu的用户,这是一个过期库的归档。因此,Ubuntu过期后,我们必须把源切换到 old-releases.ubuntu.com。

    下面的方法通过切换到旧版本的源来解决“404 Not Found”错误。

    首先,使用旧版本的源来替换当前主源

    1
    2
    3
    4
    5
    6
    7
    8
    root@5a156e79af57:/# cat <<eof> /etc/apt/sources.list
    > deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal main restricted universe multiverse
    > deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-updates main restricted universe multiverse
    > deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-backports main restricted universe multiverse
    > deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-security main restricted universe multiverse
    > deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-proposed main restricted universe multiverse
    > eof
    root@5a156e79af57:/#

    现在,应该能够在旧版本的Ubuntu镜像系统上进行安装或者更新了

    1
    2
    3
    root@5a156e79af57:/# apt-get update
    ......
    root@5a156e79af57:/# apt-get install vim
  3. 更换国内镜像

    打开网站https://mirrors.tuna.tsinghua.edu.cn/

    找到ubuntu后面的问号,点击跳转后,有对应的设置方法

    1
    2
    3
    4
    root@94a33576bd1b:/# sed -i "s@http://.*archive.ubuntu.com@https://mirrors.tuna.tsinghua.edu.cn@g" /etc/apt/sources.list

    root@94a33576bd1b:/# sed -i "s@http://.*security.ubuntu.com@https://mirrors.tuna.tsinghua.edu.cn@g" /etc/apt/sources.list
    root@94a33576bd1b:/#

在完成操作之后,输入 exit 命令来退出这个容器。

此时 ID 为 94a33576bd1b 的容器,是按需求更改的容器。可以通过命令 docker commit 来提交容器副本。

1
2
3
[root@localhost software]# docker commit -m "has update" -a="yanpenggong" 94a33576bd1b yanpenggong/ubuntu:v2
sha256:e0a0ea0b15174c6f322a806ca08f11c316b4f878c01689a807c950f3447b840b
[root@localhost software]#

各个参数说明:

  • -m: 提交的描述信息
  • -a: 指定镜像作者
  • e218edb10161:容器 ID
  • runoob/ubuntu:v2: 指定要创建的目标镜像名

我们可以使用 docker images 命令来查看我们的新镜像 yanpenggong/ubuntu:v2

1
2
3
4
5
6
[root@localhost software]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
yanpenggong/ubuntu v2 e0a0ea0b1517 46 seconds ago 99.3MB
httpd latest f2a976f932ec 2 weeks ago 145MB
ubuntu 18.04 8d5df41c547b 2 weeks ago 63.1MB
[root@localhost software]#

使用我们的新镜像 yanpenggong/ubuntu 来启动一个容器:

1
2
[root@localhost software]# docker run -t -i yanpenggong/ubuntu:v2 /bin/bash
root@4cd6ec171b77:/#

3.6.2 构建镜像

使用 Dockerfile 指令来创建一个新的镜像

使用命令 docker build, 从零开始来创建一个新的镜像。为此,我们需要创建一个 Dockerfile 文件,其中包含一组指令来告诉 Docker 如何构建镜像。

1
2
3
4
5
6
7
8
9
10
11
12
[root@localhost DDocker]# cat Dockerfile 
FROM centos:6.7
MAINTAINER yanpenggong "yanpenggong@163.com"

RUN /bin/echo "root:yanpenggong" | chpasswd
RUN useradd yanpenggong
RUN /bin/echo "yanpenggong:yanpenggong" | chpasswd
RUN /bin/echo -e "LANG=\"en_US.UTF-8\"" > /etc/default/local
EXPOSE 22
EXPOSE 80
CMD /usr/sbin/sshd -D
[root@localhost DDocker]#

每一个指令都会在镜像上创建一个新的层,每一个指令的前缀都必须是大写的。

第一条FROM,指定使用哪个镜像源,RUN 指令告诉docker 在镜像内执行命令,安装了什么。

参数说明:

  • FROM:构建镜像基于哪个镜像
  • MAINTAINER:镜像维护者姓名或邮箱地址
  • RUN:构建镜像时运行的指令
  • CMD:运行容器时执行的shell环境
  • VOLUME:指定容器挂载点到宿主机自动生成的目录或其他容器
  • USER:为RUN、CMD、和 ENTRYPOINT 执行命令指定运行用户
  • WORKDIR:为 RUN、CMD、ENTRYPOINT、COPY 和 ADD 设置工作目录,就是切换目录
  • HEALTHCHECH:健康检查
  • ARG:构建时指定的一些参数
  • EXPOSE:声明容器的服务端口(仅仅是声明)
  • ENV:设置容器环境变量
  • ADD:拷贝文件或目录到容器中,如果是URL或压缩包便会自动下载或自动解压
  • COPY:拷贝文件或目录到容器中,跟ADD类似,但不具备自动下载或解压的功能
  • ENTRYPOINT:运行容器时执行的shell命令

然后,使用 Dockerfile 文件,通过 docker build 命令来构建一个镜像。

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
[root@localhost DDocker]# docker build -t yanpenggong/centos:6.7 .
Sending build context to Docker daemon 80.36MB
Step 1/9 : FROM centos:6.7
6.7: Pulling from library/centos
cbddbc0189a0: Pull complete
Digest: sha256:4c952fc7d30ed134109c769387313ab864711d1bd8b4660017f9d27243622df1
Status: Downloaded newer image for centos:6.7
---> 9f1de3c6ad53
Step 2/9 : MAINTAINER yanpenggong "yanpenggong@163.com"
---> Running in f2ceecd3f084
Removing intermediate container f2ceecd3f084
---> 94858bb3d4ef
Step 3/9 : RUN /bin/echo "root:yanpenggong" | chpasswd
---> Running in 425b7bfbb037
Removing intermediate container 425b7bfbb037
---> 1c9059ca47f8
Step 4/9 : RUN useradd yanpenggong
---> Running in 03fc22eb515b
Removing intermediate container 03fc22eb515b
---> 27028b46ae31
Step 5/9 : RUN /bin/echo "yanpenggong:yanpenggong" | chpasswd
---> Running in e8ad081c0835
Removing intermediate container e8ad081c0835
---> 06533911be02
Step 6/9 : RUN /bin/echo -e "LANG=\"en_US.UTF-8\"" > /etc/default/local
---> Running in ea73216a2abc
Removing intermediate container ea73216a2abc
---> a09cf5c5f9a1
Step 7/9 : EXPOSE 22
---> Running in 2090bcdb357b
Removing intermediate container 2090bcdb357b
---> d7c5685a04ce
Step 8/9 : EXPOSE 80
---> Running in 09b19ed81af5
Removing intermediate container 09b19ed81af5
---> 5acf09136b6b
Step 9/9 : CMD /usr/sbin/sshd -D
---> Running in 514a034e0a13
Removing intermediate container 514a034e0a13
---> d791216a0356
Successfully built d791216a0356
Successfully tagged yanpenggong/centos:6.7
[root@localhost DDocker]#

参数说明:

  • -t :指定要创建的目标镜像名
  • . :Dockerfile 文件所在目录,可以指定Dockerfile 的绝对路径

使用docker images 查看创建的镜像已经在列表中存在,镜像ID为d791216a0356

1
2
3
4
5
6
7
8
[root@localhost DDocker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
yanpenggong/centos 6.7 d791216a0356 48 seconds ago 191MB
yanpenggong/ubuntu v2 e0a0ea0b1517 56 minutes ago 99.3MB
httpd latest f2a976f932ec 2 weeks ago 145MB
ubuntu 18.04 8d5df41c547b 2 weeks ago 63.1MB
centos 6.7 9f1de3c6ad53 3 years ago 191MB
[root@localhost DDocker]#

使用新的镜像来创建容器:

1
2
3
4
[root@localhost DDocker]# docker run -it yanpenggong/centos:6.7 /bin/bash
[root@666f0af44d9c /]# id yanpenggong
uid=500(yanpenggong) gid=500(yanpenggong) groups=500(yanpenggong)
[root@666f0af44d9c /]#

从上面看到新镜像已经包含我们创建的用户 yanpenggong

3.6.3 设置镜像标签

使用 docker tag 命令,为镜像添加一个新的标签。

1
2
[root@localhost DDocker]# docker tag d791216a0356 yanpenggong/centos:dev
[root@localhost DDocker]#

docker tag 镜像ID,这里是 d791216a0356 ,用户名称、镜像源名(repository name)和新的标签名(tag)。

使用 docker images 命令可以看到,ID为d791216a0356的镜像多一个标签。

1
2
3
4
5
6
7
8
9
[root@localhost DDocker]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
yanpenggong/centos 6.7 d791216a0356 6 minutes ago 191MB
yanpenggong/centos dev d791216a0356 6 minutes ago 191MB
yanpenggong/ubuntu v2 e0a0ea0b1517 About an hour ago 99.3MB
httpd latest f2a976f932ec 2 weeks ago 145MB
ubuntu 18.04 8d5df41c547b 2 weeks ago 63.1MB
centos 6.7 9f1de3c6ad53 3 years ago 191MB
[root@localhost DDocker]#

4. Docker容器连接

容器中可以运行一些网络应用,要让外部也可以访问这些应用,可以通过 -P-p 参数来指定端口映射。

下面我们来实现通过端口连接到一个 docker 容器。

4.1 网络端口映射

创建了一个 python 应用的容器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[root@localhost DDocker]# docker run -d -P training/webapp python app.py
Unable to find image 'training/webapp:latest' locally
latest: Pulling from training/webapp
Image docker.io/training/webapp:latest uses outdated schema1 manifest format. Please upgrade to a schema2 image for better future compatibility. More information at https://docs.docker.com/registry/spec/deprecated-schema-v1/
e190868d63f8: Pull complete
909cd34c6fd7: Pull complete
0b9bfabab7c1: Pull complete
a3ed95caeb02: Pull complete
10bbbc0fc0ff: Pull complete
fca59b508e9f: Pull complete
e7ae2541b15b: Pull complete
9dd97ef58ce9: Pull complete
a4c1b0cb7af7: Pull complete
Digest: sha256:06e9c1983bd6d5db5fba376ccd63bfa529e8d02f23d5079b8f74a616308fb11d
Status: Downloaded newer image for training/webapp:latest
949ba9ad02954210132ff41d52c4d402031a4b87647a62be458cec17ee2a1fc5
[root@localhost DDocker]#

另外,可以指定容器绑定的网络地址,比如绑定 127.0.0.1。

使用 -P 绑定端口号,使用 docker ps 可以看到容器端口 5000 绑定主机端口 49153。

1
2
3
4
[root@localhost DDocker]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
949ba9ad0295 training/webapp "python app.py" 9 seconds ago Up 8 seconds 0.0.0.0:49153->5000/tcp, :::49153->5000/tcp hopeful_darwin
[root@localhost DDocker]#

也可以使用 -p 标识来指定容器端口绑定到主机端口。

两种方式的区别是:

  • -P : [大写],是容器内部端口随机映射到主机的端口。
  • -p : [小写],是容器内部端口绑定到指定的主机端口。
1
2
3
4
5
6
7
[root@localhost DDocker]# docker run -d -p 5000:5000 training/webapp python app.py
fabc2132704350dfe29a1b899abef72926660a8ffb98f04f6a05d00db367e3f6
[root@localhost DDocker]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fabc21327043 training/webapp "python app.py" 28 seconds ago Up 27 seconds 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp competent_allen
949ba9ad0295 training/webapp "python app.py" 3 hours ago Up 3 hours 0.0.0.0:49153->5000/tcp, :::49153->5000/tcp hopeful_darwin
[root@localhost DDocker]#

另外,可以指定容器绑定的网络地址,比如绑定 127.0.0.1。

1
2
3
4
5
6
7
8
[root@localhost DDocker]# docker run -d -p 127.0.0.1:5001:5000 training/webapp python app.py
08da7892182cc14a717909593cfcd62862f6bcae9535aa8af88563b281b107e9
[root@localhost DDocker]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
08da7892182c training/webapp "python app.py" 2 seconds ago Up 1 second 127.0.0.1:5001->5000/tcp angry_beaver
fabc21327043 training/webapp "python app.py" 4 minutes ago Up 4 minutes 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp competent_allen
949ba9ad0295 training/webapp "python app.py" 3 hours ago Up 3 hours 0.0.0.0:49153->5000/tcp, :::49153->5000/tcp hopeful_darwin
[root@localhost DDocker]#

这样就可以通过访问 127.0.0.1:5001 来访问容器的 5000 端口。

上面的例子中,默认都是绑定 tcp 端口,如果要绑定 UDP 端口,可以在端口后面加上 /udp

1
2
3
4
5
6
7
8
9
[root@localhost DDocker]# docker run -d -p 127.0.0.1:5001:5000/udp training/webapp python app.py
452f6b05777215093e648b730693ca6f5f9c2b1c75909a92b13b87dd84eb549e
[root@localhost DDocker]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
452f6b057772 training/webapp "python app.py" 2 seconds ago Up 1 second 5000/tcp, 127.0.0.1:5001->5000/udp beautiful_rosalind
08da7892182c training/webapp "python app.py" About a minute ago Up About a minute 127.0.0.1:5001->5000/tcp angry_beaver
fabc21327043 training/webapp "python app.py" 6 minutes ago Up 5 minutes 0.0.0.0:5000->5000/tcp, :::5000->5000/tcp competent_allen
949ba9ad0295 training/webapp "python app.py" 3 hours ago Up 3 hours 0.0.0.0:49153->5000/tcp, :::49153->5000/tcp hopeful_darwin
[root@localhost DDocker]#

docker port 命令可以快捷地查看端口的绑定情况。

1
2
3
[root@localhost DDocker]# docker port angry_beaver 5000
127.0.0.1:5001
[root@localhost DDocker]#

4.2 Docker 容器互联

端口映射并不是唯一把 docker 连接到另一个容器的方法。

docker 有一个连接系统允许将多个容器连接在一起,共享连接信息。

docker 连接会创建一个父子关系,其中父容器可以看到子容器的信息。

4.2.1 容器命名

当创建一个容器的时候,docker 会自动对它进行命名。另外,也可以使用 —name 标识来命名容器,例如:

1
2
3
[root@localhost DDocker]# docker run -d -P --name gyp01 training/webapp python app.py
1b5960c5c67768da9bfa1e692bfb4e92ffb8bb7adf84e97673834897428305ad
[root@localhost DDocker]#

可以使用 docker ps 命令来查看容器名称。

1
2
3
4
[root@localhost DDocker]# docker ps -l
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
1b5960c5c677 training/webapp "python app.py" 9 seconds ago Up 8 seconds 0.0.0.0:49154->5000/tcp, :::49154->5000/tcp gyp01
[root@localhost DDocker]#

4.2.2 新建网络

创建一个新的 Docker 网络。

1
2
3
4
5
6
7
8
9
[root@localhost DDocker]# docker network create -d bridge test-net
9cd4cfe85b059e418a34d22ad67c93163fde29fd24c558b18ec8ffd2f67a32e8
[root@localhost DDocker]# docker network ls
NETWORK ID NAME DRIVER SCOPE
90318cd44c6e bridge bridge local
1a9a32f8cdda host host local
83e6b7fb39a6 none null local
9cd4cfe85b05 test-net bridge local
[root@localhost DDocker]#

参数说明:

-d:参数指定 Docker 网络类型,有 bridge、overlay。

其中 overlay 网络类型用于 Swarm mode。

4.2.3 连接容器

运行一个容器并连接到新建的 test-net 网络:

1
2
3
4
5
6
7
8
[root@localhost DDocker]# docker run -itd --name test1 --network test-net ubuntu /bin/bash
Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
d19f32bd9e41: Pull complete
Digest: sha256:34fea4f31bf187bc915536831fd0afc9d214755bf700b5cdb1336c82516d154e
Status: Downloaded newer image for ubuntu:latest
e6d15d1d5dc6f9698ab88a74c029d24e9b960a3ef45a946a476ffc0db6a3c64a
[root@localhost DDocker]#

打开新的终端,再运行一个容器并加入到 test-net 网络:

1
2
3
[root@localhost DDocker]# docker run -itd --name test2 --network test-net ubuntu /bin/bash
fa1f782105efcc19828d20e4391e91bb8d480621c3cab330be73820a58091a96
[root@localhost DDocker]#

下面通过 ping 来证明 test1 容器和 test2 容器建立了互联关系。

如果 test1、test2 容器内中无 ping 命令,则在容器内执行以下命令安装 ping(即学即用:可以在一个容器里安装好,提交容器到镜像,在以新的镜像重新运行以上俩个容器)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
root@e6d15d1d5dc6:/# apt-get update
Get:1 http://mirrors.tuna.tsinghua.edu.cn/ubuntu focal InRelease [265 kB]
...
Get:22 http://mirrors.tuna.tsinghua.edu.cn/ubuntu focal-proposed/restricted amd64 Packages [257 kB]
Fetched 24.2 MB in 1min 27s (279 kB/s)
Reading package lists... Done
root@e6d15d1d5dc6:/# apt-get install iputils-ping
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
...
debconf: unable to initialize frontend: Readline
debconf: (Can't locate Term/ReadLine.pm in @INC (you may need to install the Term::ReadLine module) (@INC contains: /etc/perl /usr/local/lib/x86_64-linux-gnu/perl/5.34.0 /usr/local/share/perl/5.34.0 /usr/lib/x86_64-linux-gnu/perl5/5.34 /usr/share/perl5 /usr/lib/x86_64-linux-gnu/perl-base /usr/lib/x86_64-linux-gnu/perl/5.34 /usr/share/perl/5.34 /usr/local/lib/site_perl) at /usr/share/perl5/Debconf/FrontEnd/Readline.pm line 7.)
debconf: falling back to frontend: Teletype
Setting up iputils-ping (3:20190709-3) ...
root@e6d15d1d5dc6:/#

在 test1 容器输入以下命令:

1
2
3
4
5
6
7
[root@localhost DDocker]# docker exec -it test1 /bin/bash
root@e6d15d1d5dc6:/# ping test2
PING test2 (172.18.0.3) 56(84) bytes of data.
64 bytes from test2.test-net (172.18.0.3): icmp_seq=1 ttl=64 time=0.134 ms
64 bytes from test2.test-net (172.18.0.3): icmp_seq=2 ttl=64 time=0.116 ms
64 bytes from test2.test-net (172.18.0.3): icmp_seq=3 ttl=64 time=0.065 ms

同理在 test2 容器也会成功连接到:

1
2
3
4
5
6
7
[root@localhost DDocker]# docker exec -it test2 /bin/bash
root@fa1f782105ef:/# ping test1
PING test1 (172.18.0.2) 56(84) bytes of data.
64 bytes from test1.test-net (172.18.0.2): icmp_seq=1 ttl=64 time=0.065 ms
64 bytes from test1.test-net (172.18.0.2): icmp_seq=2 ttl=64 time=0.084 ms
64 bytes from test1.test-net (172.18.0.2): icmp_seq=3 ttl=64 time=0.121 ms
64 bytes from test1.test-net (172.18.0.2): icmp_seq=4 ttl=64 time=0.070 ms

这样,test1 容器和 test2 容器建立了互联关系。

如果有多个容器之间需要互相连接,推荐使用 Docker Compose,后面会介绍。

4.3 配置 DNS

可以在宿主机的 /etc/docker/daemon.json 文件中增加以下内容来设置全部容器的 DNS:

1
2
3
4
5
6
{
"dns" : [
"114.114.114.114",
"8.8.8.8"
]
}

设置后,启动容器的 DNS 会自动配置为 114.114.114.114 和 8.8.8.8。

配置完,需要重启 docker 才能生效。

查看容器的 DNS 是否生效可以使用以下命令,它会输出容器的 DNS 信息:

1
2
3
4
[root@localhost DDocker]# docker run -it --rm  ubuntu  cat etc/resolv.conf
nameserver 8.8.8.8
nameserver 114.114.114.114
[root@localhost DDocker]#

手动指定容器的配置

如果只想在指定的容器设置 DNS,则可以使用以下命令:

1
2
[root@localhost DDocker]# docker run -it --rm -h host_ubuntu  --dns=114.114.114.114 --dns-search=test.com ubuntu
root@host_ubuntu:/#

参数说明:

  • --rm:容器退出时自动清理容器内部的文件系统。

  • -h HOSTNAME 或者 --hostname=HOSTNAME: 设定容器的主机名,它会被写到容器内的 /etc/hostname/etc/hosts

  • --dns=IP_ADDRESS: 添加 DNS 服务器到容器的 /etc/resolv.conf中,让容器用这个服务器来解析所有不在 /etc/hosts 中的主机名。

  • --dns-search=DOMAIN: 设定容器的搜索域,当设定搜索域为 .example.com 时,在搜索一个名为 host 的主机时,DNS 不仅搜索 host,还会搜索 host.example.com。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@localhost DDocker]# docker run -it --rm -h host_ubuntu  --dns=114.114.114.114 --dns-search=test.com ubuntu
root@host_ubuntu:/# cat /etc/hostname
host_ubuntu
root@host_ubuntu:/# cat /etc/hosts
127.0.0.1 localhost
::1 localhost ip6-localhost ip6-loopback
fe00::0 ip6-localnet
ff00::0 ip6-mcastprefix
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
172.17.0.7 host_ubuntu
root@host_ubuntu:/# cat /etc/resolv.conf
search test.com
nameserver 114.114.114.114
root@host_ubuntu:/#

如果在容器启动时没有指定 --dns--dns-search,Docker 会默认用宿主主机上的 /etc/resolv.conf 来配置容器的 DNS。

5. Docker仓库管理

仓库(Repository)是集中存放镜像的地方。以下介绍一下 Docker Hub。当然不止 docker hub,只是远程的服务商不一样,操作都是一样的。

5.1 Docker Hub

目前 Docker 官方维护了一个公共仓库 Docker Hub

大部分需求都可以通过在 Docker Hub 中直接下载镜像来实现。

5.2 注册

https://hub.docker.com 免费注册一个 Docker 账号。

5.3 登录和退出

登录需要输入用户名和密码,登录成功后,我们就可以从 docker hub 上拉取自己账号下的全部镜像。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@localhost DDocker]# docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: kungs
Password:
Error response from daemon: Get "https://registry-1.docker.io/v2/": unauthorized: incorrect username or password
[root@localhost DDocker]# docker login
Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
Username: kungs
Password:
WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
Configure a credential helper to remove this warning. See
https://docs.docker.com/engine/reference/commandline/login/#credentials-store

Login Succeeded
[root@localhost DDocker]#

退出 docker hub 可以使用以下命令:

1
2
3
[root@localhost DDocker]# docker logout
Removing login credentials for https://index.docker.io/v1/
[root@localhost DDocker]#

5.4 拉取镜像

可以通过 docker search 命令来查找官方仓库中的镜像,并利用 docker pull 命令来将它下载到本地。

以 ubuntu 为关键词进行搜索:

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
[root@localhost DDocker]# docker search ubuntu
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
ubuntu Ubuntu is a Debian-based Linux operating sys… 14855 [OK]
websphere-liberty WebSphere Liberty multi-architecture images … 288 [OK]
ubuntu-upstart DEPRECATED, as is Upstart (find other proces… 112 [OK]
neurodebian NeuroDebian provides neuroscience research s… 92 [OK]
ubuntu/nginx Nginx, a high-performance reverse proxy & we… 57
open-liberty Open Liberty multi-architecture images based… 54 [OK]
ubuntu-debootstrap DEPRECATED; use "ubuntu" instead 46 [OK]
ubuntu/apache2 Apache, a secure & extensible open-source HT… 40
ubuntu/mysql MySQL open source fast, stable, multi-thread36
kasmweb/ubuntu-bionic-desktop Ubuntu productivity desktop for Kasm Workspa… 31
ubuntu/squid Squid is a caching proxy for the Web. Long-t30
ubuntu/prometheus Prometheus is a systems and service monitori… 28
ubuntu/bind9 BIND 9 is a very flexible, full-featured DNS… 25
ubuntu/postgres PostgreSQL is an open source object-relation19
ubuntu/redis Redis, an open source key-value store. Long-… 11
ubuntu/kafka Apache Kafka, a distributed event streaming … 11
ubuntu/grafana Grafana, a feature rich metrics dashboard & … 6
ubuntu/prometheus-alertmanager Alertmanager handles client alerts from Prom… 6
ubuntu/memcached Memcached, in-memory keyvalue store for smal… 5
ubuntu/zookeeper ZooKeeper maintains configuration informatio… 5
ubuntu/telegraf Telegraf collects, processes, aggregates & w… 4
ubuntu/cortex Cortex provides storage for Prometheus. Long… 3
ubuntu/cassandra Cassandra, an open source NoSQL distributed … 2
ubuntu/dotnet-deps Chiselled Ubuntu for self-contained .NET & A… 2
ubuntu/loki Grafana Loki, a log aggregation system like … 0
[root@localhost DDocker]#

使用 docker pull 将官方 ubuntu 镜像下载到本地:

1
2
3
4
5
6
7
[root@localhost DDocker]# docker pull ubuntu
Using default tag: latest
latest: Pulling from library/ubuntu
Digest: sha256:34fea4f31bf187bc915536831fd0afc9d214755bf700b5cdb1336c82516d154e
Status: Image is up to date for ubuntu:latest
docker.io/library/ubuntu:latest
[root@localhost DDocker]#

5.5 推送镜像

用户登录后,可以通过 docker push 命令将自己的镜像推送到 Docker Hub。

以下命令中的 kungs 请替换为你的 Docker 账号用户名。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
[root@localhost DDocker]# docker tag ubuntu:18.04 kungs/ubuntu:18.04
[root@localhost DDocker]# docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest df5de72bdb3b 4 weeks ago 77.8MB
kungs/ubuntu 18.04 8d5df41c547b 4 weeks ago 63.1MB
ubuntu 18.04 8d5df41c547b 4 weeks ago 63.1MB
training/webapp latest 6fae60ef3446 7 years ago 349MB
[root@localhost DDocker]# docker push kungs/ubuntu:18.04
The push refers to repository [docker.io/kungs/ubuntu]
e722d396f503: Mounted from library/ubuntu
18.04: digest: sha256:e4771b7160543c6e43968b4e9795be9ddcad9d573edd7cd7aebd3ce61326fc7a size: 529
[root@localhost DDocker]# docker search kungs/ubuntu
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
kungs/ubuntu

6. Docker Dockerfile

6.1 什么是 Dockerfile?

Dockerfile 是一个用来构建镜像的文本文件,文本内容包含了一条条构建镜像所需的指令和说明。

6.2 使用 Dockerfile 定制镜像

这里仅讲解如何运行 Dockerfile 文件来定制一个镜像,具体 Dockerfile 文件内指令详解,将在下一节中介绍,这里你只要知道构建的流程即可。

  1. 下面以定制一个 nginx 镜像(构建好的镜像内会有一个 /usr/share/nginx/html/index.html 文件)

    在一个空目录下,新建一个名为 Dockerfile 文件,并在文件内添加以下内容:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    [root@localhost ~]# cd /root/yanpenggong/DEMO/DockerTest/docker/
    [root@localhost docker]# mkdir Dockerfile
    [root@localhost docker]# cd Dockerfile/
    [root@localhost Dockerfile]# pwd
    /root/yanpenggong/DEMO/DockerTest/docker/Dockerfile
    [root@localhost Dockerfile]# vi Dockerfile
    [root@localhost Dockerfile]# cat Dockerfile
    FROM nginx
    RUN echo "这是一个本地构建的nginx镜像" > /usr/share/nginx/html/index.html
    [root@localhost Dockerfile]#
  2. FROM 和 RUN 指令的作用

    • FROM:定制的镜像都是基于 FROM 的镜像,这里的 nginx 就是定制需要的基础镜像。后续的操作都是基于 nginx。

    • RUN:用于执行后面跟着的命令行命令。有以下俩种格式:

      • shell 格式:

        1
        2
        RUN <命令行命令>
        # <命令行命令> 等同于 在终端操作的 shell 命令.
      • exec 格式:

        1
        2
        3
        RUN ["可执行文件", "参数1", "参数2"]
        # 例如:
        # RUN ["./test.py", "dev", "offline"] 等价于 RUN ./test.py def offline

        注意:Dockerfile 的指令每执行一次都会在 docker 上新建一层。所以过多无意义的层,会造成镜像膨胀过大。例如:

        1
        2
        3
        4
        FROM centos
        RUN yum -y install wget
        RUN wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz"
        RUN tar -xvf redis.tar.gz

        以上执行会创建 3 层镜像。可简化为以下格式:

        1
        2
        3
        4
        FROM centos
        RUN yum -y install wget \
        && wget -O redis.tar.gz "http://download.redis.io/releases/redis-5.0.3.tar.gz" \
        && tar -xvf redis.tar.gz

        如上,以 && 符号连接命令,这样执行后,只会创建 1 层镜像。

6.3 开始构建镜像

在 Dockerfile 文件的存放目录下,执行构建动作。

以下示例,通过目录下的 Dockerfile 构建一个nginx:v3(镜像名称:镜像标签)。

:最后的 . 代表本次执行的上下文路径。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
[root@localhost Dockerfile]# docker build -t nginx:v1 .
Sending build context to Docker daemon 2.048kB
Step 1/2 : FROM nginx
---> 3964ce7b8458
Step 2/2 : RUN echo "这是一个本地构建的nginx镜像" > /usr/share/nginx/html/index.html
---> Running in 37afd3da723f
Removing intermediate container 37afd3da723f
---> bc6855014a02
Successfully built bc6855014a02
Successfully tagged nginx:v1
[root@localhost Dockerfile]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx v1 bc6855014a02 About a minute ago 142MB
kungs1 v2 5707f6758e8f 2 days ago 118MB
kungs1 v1 2d82fcabb70f 2 days ago 77.8MB
nginx latest 3964ce7b8458 5 days ago 142MB
ubuntu latest 6b7dfa7e8fdb 10 days ago 77.8MB
httpd latest 157dcdf23d6c 12 days ago 145MB
training/webapp latest 6fae60ef3446 7 years ago 349MB
[root@localhost Dockerfile]#

以上显示,说明已经构建成功。

6.4 上下文路径

上面有提到指令最后一个 . 是上下文路径,那么什么是上下文路径呢?

上下文路径,是指 docker 在构建镜像,有时候想要使用到本机的文件(比如复制),docker build 命令得知这个路径后,会将路径下的所有内容打包。

解析:由于 docker 的运行模式是 C/S。我们本机是 C,docker 引擎是 S。实际的构建过程是在 docker 引擎下完成的,所以这个时候无法用到我们本机的文件。这就需要把我们本机的指定目录下的文件一起打包提供给 docker 引擎使用。

如果未说明最后一个参数,那么默认上下文路径就是 Dockerfile 所在的位置。

注意:上下文路径下不要放无用的文件,因为会一起打包发送给 docker 引擎,如果文件过多会造成过程缓慢。

6.5 指令详解

命令 说明
FROM 建镜像基于哪个镜像
MAINTAINER 镜像维护者姓名或邮箱地址
RUN 构建镜像时运行的指令
CMD 运行容器时执行的shell环境
VOLUME 指定容器挂载点到宿主机自动生成的目录或其他容器
USER 为RUN、CMD、和 ENTRYPOINT 执行命令指定运行用户
WORKDIR 为 RUN、CMD、ENTRYPOINT、COPY 和 ADD 设置工作目录,就是切换目录
HEALTHCHECH 健康检查
ARG 构建时指定的一些参数
EXPOSE 声明容器的服务端口(仅仅是声明)
ENV 设置容器环境变量
ADD 拷贝文件或目录到容器中,如果是URL或压缩包便会自动下载或自动解压
COPY 拷贝文件或目录到容器中,跟ADD类似,但不具备自动下载或解压的功能
ENTRYPOINT 运行容器时执行的shell命令

6.5.1 COPY

复制指令,从上下文目录中复制文件或者目录到容器里指定路径。

格式:

1
2
COPY [--chown=<user>:<group>] <源路径1>...  <目标路径>
COPY [--chown=<user>:<group>] ["<源路径1>",... "<目标路径>"]

参数说明:

  • [--chown=:<group>]: 可选参数,用户改变复制到容器内文件的拥有者和属组。

  • <源路径1>: 源文件或者源目录,这里可以是通配符表达式,其通配符规则要满足 Go 的 filepath.Match 规则。例如:

    1
    2
    COPY hom* /mydir/
    COPY hom?.txt /mydir/
  • <目标路径>: 容器内的指定路径,该路径不用事先建好,路径不存在的话,会自动创建。

6.5.2 ADD

ADD 指令和 COPY 的使用格类似(同样需求下,官方推荐使用 COPY)。功能也类似,不同之处如下:

  • ADD 的优点:在执行 <源文件> 为 tar 压缩文件的话,压缩格式为 gzip, bzip2 以及 xz 的情况下,会自动复制并解压到 <目标路径>。
  • ADD 的缺点:在不解压的前提下,无法复制 tar 压缩文件。会令镜像构建缓存失效,从而可能会令镜像构建变得比较缓慢。具体是否使用,可以根据是否需要自动解压来决定。

6.5.3 CMD

类似于 RUN 指令,用于运行程序,但二者运行的时间点不同:

  • CMDdocker run 时运行。
  • RUN 是在 docker build

作用:为启动的容器指定默认要运行的程序,程序运行结束,容器也就结束。CMD 指令指定的程序可被 docker run 命令行参数中指定要运行的程序所覆盖。

注意:如果 Dockerfile 中如果存在多个 CMD 指令,仅最后一个生效。

格式:

1
2
3
CMD <shell 命令> 
CMD ["<可执行文件或命令>","<param1>","<param2>",...]
CMD ["<param1>","<param2>",...] # 该写法是为 ENTRYPOINT 指令指定的程序提供默认参数

推荐使用第二种格式,执行过程比较明确。第一种格式实际上在运行的过程中也会自动转换成第二种格式运行,并且默认可执行文件是 sh。

6.5.4 ENTRYPOINT

类似于 CMD 指令,但其不会被 docker run 的命令行参数指定的指令所覆盖,而且这些命令行参数会被当作参数送给 ENTRYPOINT 指令指定的程序。

但是, 如果运行 docker run 时使用了--entrypoint 选项,将覆盖 ENTRYPOINT 指令指定的程序。

优点:在执行 docker run 的时候可以指定 ENTRYPOINT 运行所需的参数。

注意:如果 Dockerfile 中如果存在多个 ENTRYPOINT 指令,仅最后一个生效。

格式:

1
ENTRYPOINT ["<executeable>","<param1>","<param2>",...]

可以搭配 CMD 命令使用:一般是变参才会使用 CMD ,这里的 CMD 等于是在给 ENTRYPOINT 传参,以下示例会提到。

示例:

假设已通过 Dockerfile 构建了 nginx:test 镜像:

1
2
3
FROM nginx
ENTRYPOINT ["nginx", "-c"] # 定参
CMD ["/etc/nginx/nginx.conf"] # 变参
  1. 不传参运行

    1
    [root@localhost Dockerfile]# docker run  nginx:test

    容器内会默认运行以下命令,启动主进程。

    1
    nginx -c /etc/nginx/nginx.conf
  2. 传参运行

    1
    [root@localhost Dockerfile]# docker run  nginx:test -c /etc/nginx/new.conf

    容器内会默认运行以下命令,启动主进程(/etc/nginx/new.conf:假设容器内已有此文件)

    1
    nginx -c /etc/nginx/new.conf

6.5.5 ENV

设置环境变量,定义了环境变量,那么在后续的指令中,就可以使用这个环境变量。

格式:

1
2
ENV <key> <value>
ENV <key1>=<value1> <key2>=<value2>...

以下示例设置 NODE_VERSION = 7.2.0 , 在后续的指令中可以通过 $NODE_VERSION 引用:

1
2
3
4
ENV NODE_VERSION 7.2.0

RUN curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" \
&& curl -SLO "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc"

6.5.6 ARG

构建参数,与 ENV 作用一致。不过作用域不一样。ARG 设置的环境变量仅对 Dockerfile 内有效,也就是说只有 docker build 的过程中有效,构建好的镜像内不存在此环境变量。

构建命令 docker build 中可以用 --build-arg <参数名>=<值> 来覆盖。

格式:

1
ARG <参数名>[=<默认值>]

6.5.7 VOLUME

定义匿名数据卷。在启动容器时忘记挂载数据卷,会自动挂载到匿名卷。

作用:

  • 避免重要的数据,因容器重启而丢失,这是非常致命的。
  • 避免容器不断变大。

格式:

1
2
VOLUME ["<路径1>", "<路径2>"...]
VOLUME <路径>

在启动容器 docker run 的时候,我们可以通过 -v 参数修改挂载点。

6.5.8 EXPOSE

仅仅只是声明端口。

作用:

  • 帮助镜像使用者理解这个镜像服务的守护端口,以方便配置映射。
  • 在运行时使用随机端口映射时,也就是 docker run -P 时,会自动随机映射 EXPOSE 的端口。

格式:

1
EXPOSE <端口1> [<端口2>...]

6.5.9 WORKDIR

指定工作目录。用 WORKDIR 指定的工作目录,会在构建镜像的每一层中都存在。(WORKDIR 指定的工作目录,必须是提前创建好的)。

docker build 构建镜像过程中的,每一个 RUN 命令都是新建的一层。只有通过 WORKDIR 创建的目录才会一直存在。

格式:

1
WORKDIR <工作目录路径>

6.5.10 USER

用于指定执行后续命令的用户和用户组,这边只是切换后续命令执行的用户(用户和用户组必须提前已经存在)。

格式:

1
USER <用户名>[:<用户组>]

6.5.11 HEALTHCHECK

用于指定某个程序或者指令来监控 docker 容器服务的运行状态。

格式:

1
2
3
4
HEALTHCHECK [选项] CMD <命令>:设置检查容器健康状况的命令
HEALTHCHECK NONE:如果基础镜像有健康检查指令,使用这行可以屏蔽掉其健康检查指令

HEALTHCHECK [选项] CMD <命令> : 这边 CMD 后面跟随的命令使用,可以参考 CMD 的用法。

6.5.12 ONBUILD

用于延迟构建命令的执行。简单的说,就是 Dockerfile 里用 ONBUILD 指定的命令,在本次构建镜像的过程中不会执行(假设镜像为 test-build)。当有新的 Dockerfile 使用了之前构建的镜像 FROM test-build ,这时执行新镜像的 Dockerfile 构建时候,会执行 test-build 的 Dockerfile 里的 ONBUILD 指定的命令。

格式:

1
ONBUILD <其它指令>

6.5.13 LABEL

LABEL 指令用来给镜像添加一些元数据(metadata),以键值对的形式,语法格式如下:

1
LABEL <key>=<value> <key>=<value> <key>=<value> ...

比如我们可以添加镜像的作者:

1
LABEL org.opencontainers.image.authors="yanpenggong"

7. Docker Compose

7.0 YAML 入门教程

YAML 是 “YAML Ain’t a Markup Language”(YAML 不是一种标记语言)的递归缩写。在开发的这种语言时,YAML 的意思其实是:”Yet Another Markup Language”(仍是一种标记语言)。

YAML 的语法和其他高级语言类似,并且可以简单表达清单、散列表,标量等数据形态。它使用空白符号缩进和大量依赖外观的特色,特别适合用来表达或编辑数据结构、各种配置文件、倾印调试内容、文件大纲(例如:许多电子邮件标题格式和YAML非常接近)。

YAML 的配置文件后缀为 .yml,如:yanpenggong.yml

7.0.1 基本语法

  • 大小写敏感
  • 使用缩进表示层级关系
  • 缩进不允许使用tab,只允许空格
  • 缩进的空格数不重要,只要相同层级的元素左对齐即可
  • #表示注释

7.0.2 数据类型

YAML 支持以下几种数据类型:

  • 对象:键值对的集合,又称为映射(mapping)/ 哈希(hashes) / 字典(dictionary)
  • 数组:一组按次序排列的值,又称为序列(sequence) / 列表(list)
  • 纯量(scalars):单个的、不可再分的值
7.0.2.1 YAML 对象

对象键值对使用冒号结构表示 key: value,冒号后面要加一个空格。

也可以使用 key:{key1: value1, key2: value2, …}

还可以使用缩进表示层级关系;

1
2
3
key: 
child-key: value
child-key2: value2

较为复杂的对象格式,可以使用问号加一个空格代表一个复杂的 key,配合一个冒号加一个空格代表一个 value:

1
2
3
4
5
6
?  
- complexkey1
- complexkey2
:
- complexvalue1
- complexvalue2

意思即对象的属性是一个数组 [complexkey1,complexkey2],对应的值也是一个数组 [complexvalue1,complexvalue2]

7.0.2.2 YAML 数组

- 开头的行表示构成一个数组:

1
2
3
- A
- B
- C

YAML 支持多维数组,可以使用行内表示:

1
key: [value1, value2, ...]

数据结构的子成员是一个数组,则可以在该项下面缩进一个空格。

1
2
3
4
-
- A
- B
- C

一个相对复杂的例子:

1
2
3
4
5
6
7
8
9
companies:
-
id: 1
name: company1
price: 200W
-
id: 2
name: company2
price: 500W

意思是 companies 属性是一个数组,每一个数组元素又是由 id、name、price 三个属性构成。

数组也可以使用流式(flow)的方式表示:

1
companies: [{id: 1,name: company1,price: 200W},{id: 2,name: company2,price: 500W}]
7.0.2.3 复合结构

数组和对象可以构成复合结构,例:

1
2
3
4
5
6
7
8
9
languages:
- Ruby
- Perl
- Python
websites:
YAML: yaml.org
Ruby: ruby-lang.org
Python: python.org
Perl: use.perl.org

转换为 json 为:

1
2
3
4
5
6
7
8
9
{ 
languages: [ 'Ruby', 'Perl', 'Python'],
websites: {
YAML: 'yaml.org',
Ruby: 'ruby-lang.org',
Python: 'python.org',
Perl: 'use.perl.org'
}
}
7.0.2.4 纯量

纯量是最基本的,不可再分的值,包括:

  • 字符串
  • 布尔值
  • 整数
  • 浮点数
  • Null
  • 时间
  • 日期

使用一个例子来快速了解纯量的基本使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
boolean: 
- TRUE #true,True都可以
- FALSE #false,False都可以
float:
- 3.14
- 6.8523015e+5 #可以使用科学计数法
int:
- 123
- 0b1010_0111_0100_1010_1110 #二进制表示
null:
nodeName: 'node'
parent: ~ #使用~表示null
string:
- 哈哈
- 'Hello world' #可以使用双引号或者单引号包裹特殊字符
- newline
newline2 #字符串可以拆成多行,每一行会被转化成一个空格
date:
- 2022-08-31 #日期必须使用ISO 8601格式,即yyyy-MM-dd
datetime:
- 2022-08-31T10:50:21+08:00 #时间使用ISO 8601格式,时间和日期之间使用T连接,最后使用+代表时区
7.0.2.5 引用
  • & 锚点和 * 别名,可以用来引用:
1
2
3
4
5
6
7
8
9
10
11
defaults: &defaults
adapter: postgres
host: localhost

development:
database: myapp_development
<<: *defaults

test:
database: myapp_test
<<: *defaults

相当于:

1
2
3
4
5
6
7
8
9
10
11
12
13
defaults:
adapter: postgres
host: localhost

development:
database: myapp_development
adapter: postgres
host: localhost

test:
database: myapp_test
adapter: postgres
host: localhost

& 用来建立锚点(defaults),<< 表示合并到当前数据,* 用来引用锚点。

下面是另一个例子:

1
2
3
4
5
- &showell Steve 
- Clark
- Brian
- Oren
- *showell

转为 JavaScript 代码如下:

1
[ 'Steve', 'Clark', 'Brian', 'Oren', 'Steve' ]

7.1 Compose 简介

Compose 是用于定义和运行多容器 Docker 应用程序的工具。通过 Compose,您可以使用 YML 文件来配置应用程序需要的所有服务。然后,使用一个命令,就可以从 YML 文件配置中创建并启动所有服务。

Compose 使用的三个步骤:

  • 使用 Dockerfile 定义应用程序的环境。
  • 使用 docker-compose.yml 定义构成应用程序的服务,这样它们可以在隔离环境中一起运行。
  • 最后,执行 docker-compose up 命令来启动并运行整个应用程序。

docker-compose.yml 的配置案例如下(配置参数参考下文):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# yml 配置实例
version: "1.0"
services:
web:
build: .
ports:
- "5000:5000"
volumes:
- .: /code
- logvolume01: /var/log
links:
- redis
redis:
image: redis
volumes:
logvolume01: {}

7.2 Compose 安装

Linux 上可以从 Github 上下载它的二进制包来使用,最新发行的版本地址:https://github.com/docker/compose/releases。

运行以下命令以下载 Docker Compose 的当前稳定版本:

1
2
3
4
5
6
[root@localhost DDocker]# sudo curl -SL "https://github.com/docker/compose/releases/download/v2.10.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 425 100 425 0 0 479 0 --:--:-- --:--:-- --:--:-- 479
100 24.5M 100 24.5M 0 0 7220k 0 0:00:03 0:00:03 --:--:-- 13.3M
[root@localhost DDocker]#

要安装其他版本的 Compose,请替换 v2.14.0。

Docker Compose 存放在 GitHub,不太稳定。

也可以通过执行下面的命令,高速安装 Docker Compose。

1
2
3
4
5
6
7
[root@localhost Dockerfile]# curl -SL https://github.com/docker/compose/releases/download/v2.14.0/docker-compose-linux-x86_64 -o /usr/local/bin/docker-compose
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
2 42.8M 2 944k 0 0 11860 0 1:03:07 0:01:21 1:01:46 8238
100 42.8M 100 42.8M 0 0 98k 0 0:07:27 0:07:27 --:--:-- 208k
[root@localhost Dockerfile]#

将可执行权限应用于二进制文件:

1
2
[root@localhost DDocker]# sudo chmod +x /usr/local/bin/docker-compose
[root@localhost DDocker]#

创建软链:

1
2
[root@localhost DDocker]# sudo ln -s /usr/local/bin/docker-compose /usr/bin/docker-compose
[root@localhost DDocker]#

测试是否安装成功:

1
2
3
[root@localhost Dockerfile]# docker-compose --version
Docker Compose version v2.14.0
[root@localhost Dockerfile]#

注意: 对于 alpine,需要以下依赖包: py-pippython-devlibffi-devopenssl-devgcclibc-dev,和 make

macOS 和 windows:

1
Docker 桌面版和 Docker Toolbox 已经包括 Compose 和其他 Docker 应用程序,故不需要单独安装 Compose。

7.3 使用

7.3.1 准备

创建一个测试目录:

1
2
3
4
5
[root@localhost DockerTest]# pwd
/root/yanpenggong/DEMO/DockerTest
[root@localhost DockerTest]# mkdir composeTest
[root@localhost DockerTest]# cd composeTest/
[root@localhost composeTest]#

在测试目录中创建一个名为 app.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
[root@localhost composetest]# cat app.py 
import time

import redis
from flask import Flask

app = Flask(__name__)
cache = redis.Redis(host='redis', port=6379)


def get_hit_count():
retries = 5
while True:
try:
return cache.incr('hits')
except redis.exceptions.ConnectionError as exc:
if retries == 0:
raise exc
retries -= 1
time.sleep(0.5)


@app.route('/')
def hello():
count = get_hit_count()
return 'Hello World! I have been seen {} times.\n'.format(count)
[root@localhost composetest]#

在此示例中,redis 是应用程序网络上的 redis 容器的主机名,该主机使用的端口为 6379。

在 composeTest 目录中创建另一个名为 requirements.txt 的文件,内容如下:

1
2
3
4
[root@localhost composetest]# cat requirements.txt 
flask
redis
[root@localhost composetest]#

7.3.2 创建 Dockerfile 文件

在 composeTest 目录中,创建一个名为 Dockerfile 的文件,内容如下:

1
2
3
4
5
6
7
8
9
10
11
[root@localhost composeTest]# cat Dockerfile 
FROM python:3.7-alpine3.10
WORKDIR /code
ENV FLASK_APP=app.py \
FLASK_RUN_HOST=0.0.0.0
RUN apk add --no-cache gcc musl-dev linux-headers
COPY requirements.txt requirements.txt
RUN pip3 install -r requirements.txt
COPY . .
CMD ["flask", "run"]
[root@localhost composeTest]#

Dockerfile 内容解释:

  • FROM python:3.7-alpine: 从 Python 3.7 映像开始构建镜像。

  • WORKDIR /code: 将工作目录设置为 /code。

  • ENV:设置 flask 命令使用的环境变量。

    1
    2
    ENV FLASK_APP app.py
    ENV FLASK_RUN_HOST 0.0.0.0

    1
    2
    ENV FLASK_APP=app.py \
    FLASK_RUN_HOST=0.0.0.0
  • RUN apk add —no-cache gcc musl-dev linux-headers: 安装 gcc,以便诸如 MarkupSafe 和 SQLAlchemy 之类的 Python 包可以编译加速。

  • ```
    COPY requirements.txt requirements.txt
    RUN pip install -r requirements.txt

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    复制 requirements.txt 并安装 Python 依赖项。

    - **COPY . .**: 将 . 项目中的当前目录复制到 `.` 镜像中的工作目录。

    - **CMD ["flask", "run"]**: 容器提供默认的执行命令为:`flask run`。

    #### 7.3.3 创建 docker-compose.yml

    > **端口永久开放(permanent)**
    >
    > ```shell
    > #开端口
    > firewall-cmd --get-active-zones
    > firewall-cmd --zone=public --add-port=端口号/tcp --permanent
    > #重启
    > firewall-cmd --reload
    > #检验端口是否开放
    > firewall-cmd --query-port=8000/tcp

在测试目录中创建一个名为 docker-compose.yml 的文件,内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
[root@localhost composeTest]# cat docker-compose.yml 
# yml 配置实例
version: '2.0'
services:
web:
build: .
ports:
- "8001:8001"
redis:
image: redis:alpine
ports:
- "6379:6379"
[root@localhost composeTest]#

7.3.4 使用 Compose 命令构建和运行您的应用

在测试目录中,执行 docker-compose up 命令来启动应用程序:

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@localhost composeTest]# docker-compose up
[+] Running 2/0
⠿ Container composetest-redis-1 Created 0.0s
⠿ Container composetest-app1-1 Created 0.0s
Attaching to composetest-app1-1, composetest-redis-1
composetest-redis-1 | 1:C 19 Dec 2022 09:07:46.874 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
composetest-redis-1 | 1:C 19 Dec 2022 09:07:46.874 # Redis version=7.0.7, bits=64, commit=00000000, modified=0, pid=1, just started
composetest-redis-1 | 1:C 19 Dec 2022 09:07:46.874 # Warning: no config file specified, using the default config. In order to specify a config file use redis-server /path/to/redis.conf
composetest-redis-1 | 1:M 19 Dec 2022 09:07:46.875 * monotonic clock: POSIX clock_gettime
composetest-redis-1 | 1:M 19 Dec 2022 09:07:46.876 * Running mode=standalone, port=6379.
composetest-redis-1 | 1:M 19 Dec 2022 09:07:46.876 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
composetest-redis-1 | 1:M 19 Dec 2022 09:07:46.876 # Server initialized
composetest-redis-1 | 1:M 19 Dec 2022 09:07:46.876 # WARNING Memory overcommit must be enabled! Without it, a background save or replication may fail under low memory condition. Being disabled, it can can also cause failures without low memory condition, see https://github.com/jemalloc/jemalloc/issues/1328. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
composetest-redis-1 | 1:M 19 Dec 2022 09:07:46.876 * Loading RDB produced by version 7.0.7
composetest-redis-1 | 1:M 19 Dec 2022 09:07:46.876 * RDB age 165 seconds
composetest-redis-1 | 1:M 19 Dec 2022 09:07:46.876 * RDB memory usage when created 0.85 Mb
composetest-redis-1 | 1:M 19 Dec 2022 09:07:46.876 * Done loading RDB, keys loaded: 1, keys expired: 0.
composetest-redis-1 | 1:M 19 Dec 2022 09:07:46.876 * DB loaded from disk: 0.000 seconds
composetest-redis-1 | 1:M 19 Dec 2022 09:07:46.876 * Ready to accept connections
composetest-app1-1 | * Serving Flask app 'app.py'
composetest-app1-1 | * Debug mode: off
composetest-app1-1 | WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
composetest-app1-1 | * Running on all addresses (0.0.0.0)
composetest-app1-1 | * Running on http://127.0.0.1:8001
composetest-app1-1 | * Running on http://172.26.0.3:8001
composetest-app1-1 | Press CTRL+C to quit
...

如果想在后台执行该服务可以加上 -d 参数:docker-compose up -d

1
2
3
4
5
6
[root@localhost composeTest]# docker-compose up -d
[+] Running 3/3
⠿ Network composetest_default Created 0.2s
⠿ Container composetest-redis-1 Started 0.4s
⠿ Container composetest-app1-1 Started 0.4s
[root@localhost composeTest]#

注意:

1
2
1. 修改dockerfile后,需要进行 `docker-compose up --build`
2. 修改docker-compose,仅仅需要 `docker-compose up`

7.4 yml配置指令参考

ID 指令 描述
1 version 指定本 yml 依从的 compose 哪个版本制定的
2 build 指定为构建镜像上下文路径
3 cap_add, cap_drop 添加或删除容器拥有的宿主机的内核功能
4 cgroup_parent 为容器指定父 cgroup 组,意味着将继承该组的资源限制
5 command 覆盖容器启动的默认命令
6 container_name 指定自定义容器名称,而不是生成的默认名称
7 depends_on 设置依赖关系
8 deploy 指定与服务的部署和运行有关的配置。只在 swarm 模式下才会有用
9 devices 指定设备映射列表
10 dns 自定义 DNS 服务器,可以是单个值或列表的多个值。
11 dns_search 自定义 DNS 搜索域。可以是单个值或列表。
12 entrypoint 覆盖容器默认的 entrypoint。
13 env_file 从文件添加环境变量。可以是单个值或列表的多个值。
14 environment 添加环境变量。您可以使用数组或字典、任何布尔值,布尔值需要用引号引起来,以确保 YML 解析器不会将其转换为 True 或 False。
15 expose 暴露端口,但不映射到宿主机,只被连接的服务访问。
16 extra_hosts 添加主机名映射。类似 docker client --add-host
17 healthcheck 用于检测 docker 服务是否健康运行。
18 image 指定容器运行的镜像。
19 logging 服务的日志记录配置。
20 network_mode 设置网络模式
21 restart 重启容器策略
22 secrets 存储敏感数据,例如密码
23 security_opt 修改容器默认的 schema 标签。
24 stop_grace_period 指定在容器无法处理 SIGTERM (或者任何 stop_signal 的信号),等待多久后发送 SIGKILL 信号关闭容器。
25 stop_signal 设置停止容器的替代信号。默认情况下使用 SIGTERM
26 sysctls 设置容器中的内核参数,可以使用数组或字典格式。
27 tmpfs 在容器内安装一个临时文件系统。可以是单个值或列表的多个值。
28 ulimits 覆盖容器默认的 ulimit。
29 volumes 将主机的数据卷或者文件挂载到容器里。

7.4.1 version

指定本 yml 依从的 compose 哪个版本制定的。

7.4.2 build

指定为构建镜像上下文路径:

例如 webapp 服务,指定为从上下文路径 ./dir/Dockerfile 所构建的镜像:

1
2
3
4
version: "2.0"
services:
webapp:
build: ./dir

或者,作为具有在上下文指定的路径的对象,以及可选的 Dockerfile 和 args:

1
2
3
4
5
6
7
8
9
10
11
12
13
version: "3.7"
services:
webapp:
build:
context: ./dir
dockerfile: Dockerfile-alternate
args:
buildno: 1
labels:
- "com.example.description=Accounting webapp"
- "com.example.department=Finance"
- "com.example.label-with-empty-value"
target: prod
  • context:上下文路径。
  • dockerfile:指定构建镜像的 Dockerfile 文件名。
  • args:添加构建参数,这是只能在构建过程中访问的环境变量。
  • labels:设置构建镜像的标签。
  • target:多层构建,可以指定构建哪一层。

7.4.3 cap_add,cap_drop

添加或删除容器拥有的宿主机的内核功能。

1
2
3
4
5
cap_add:
- ALL # 开启全部权限

cap_drop:
- SYS_PTRACE # 关闭 ptrace权限

7.4.4 cgroup_parent

为容器指定父 cgroup 组,意味着将继承该组的资源限制。

1
cgroup_parent: m-executor-abcd

7.4.5 command

覆盖容器启动的默认命令。

1
command: ["bundle", "exec", "thin", "-p", "3000"]

7.4.6 container_name

指定自定义容器名称,而不是生成的默认名称。

1
container_name: my-web-container

7.4.7 depends_on

设置依赖关系。

  • docker-compose up :以依赖性顺序启动服务。在以下示例中,先启动 db 和 redis ,才会启动 web。
  • docker-compose up SERVICE :自动包含 SERVICE 的依赖项。在以下示例中,docker-compose up web 还将创建并启动 db 和 redis。
  • docker-compose stop :按依赖关系顺序停止服务。在以下示例中,web 在 db 和 redis 之前停止。
1
2
3
4
5
6
7
8
9
10
11
version: "3.7"
services:
web:
build: .
depends_on:
- db
- redis
redis:
image: redis
db:
image: postgres

注意:web 服务不会等待 redis db 完全启动 之后才启动。

7.4.8 deploy

指定与服务的部署和运行有关的配置。==只在 swarm 模式下才会有用==。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
version: "3.8"
services:
redis:
image: redis.alpine
deploy:
mode: replicated
replicas: 6
endpoint_mode: dnsrr
labels:
description: "This redis service label"
resources:
limits:
cpus: "0.50"
memory: 50M
reservations:
cpus: "0.25"
memory: 20M
restart_policy:
condition: on-failure
delay: 5s
max_attempts: 3
window: 120s

可以选参数:

  • endpoint_mode:访问集群服务的方式。

    1
    2
    3
    4
    endpoint_mode: vip 
    # Docker 集群服务一个对外的虚拟 ip。所有的请求都会通过这个虚拟 ip 到达集群服务内部的机器。
    endpoint_mode: dnsrr
    # DNS 轮询(DNSRR)。所有的请求会自动轮询获取到集群 ip 列表中的一个 ip 地址。
  • labels:在服务上设置标签。可以用容器上的 labels(跟 deploy 同级的配置) 覆盖 deploy 下的 labels。

  • mode:指定服务提供的模式。

    • replicated:复制服务,复制指定服务到集群的机器上。

    • global:全局服务,服务将部署至集群的每个节点。

    • 图解:下图中黄色的方块是 replicated 模式的运行情况,灰色方块是 global 模式的运行情况。

  • replicasmode 为 replicated 时,需要使用此参数配置具体运行的节点数量。

  • resources:配置服务器资源使用的限制,例如上例子,配置 redis 集群运行需要的 cpu 的百分比 和 内存的占用。避免占用资源过高出现异常。

    • limits: 控制最大限制

      • cpus: “0.50”,表示可占处理周期百分之50的处理时间
      • memory: 50M,表示可用的内存为50M
    • reservations: 初始可使用资源,保留资源

      • cpus: “0.25”, 表示可占处理周期百分之25的处理时间
      • memory: 20M,表示可用的内存为20M
  • restart_policy:配置如何在退出容器时重新启动容器。

    • condition:可选 none,on-failure 或者 any(默认值:any)。
    • delay:设置多久之后重启(默认值:0)。
    • max_attempts:尝试重新启动容器的次数,超出次数,则不再尝试(默认值:一直重试)。
    • window:设置容器重启超时时间(默认值:0)。
  • rollback_config:配置在更新失败的情况下应如何回滚服务。

    • parallelism:一次要回滚的容器数。如果设置为0,则所有容器将同时回滚。
    • delay:每个容器组回滚之间等待的时间(默认为0s)。
    • failure_action:如果回滚失败,该怎么办。其中一个 continue 或者 pause(默认pause)。
    • monitor:每个容器更新后,持续观察是否失败了的时间 (ns|us|ms|s|m|h)(默认为0s)。
    • max_failure_ratio:在回滚期间可以容忍的故障率(默认为0)。
    • order:回滚期间的操作顺序。其中一个 stop-first(串行回滚),或者 start-first(并行回滚)(默认 stop-first )。
  • update_config:配置应如何更新服务,对于配置滚动更新很有用。

    • parallelism:一次更新的容器数。
    • delay:在更新一组容器之间等待的时间。
    • failure_action:如果更新失败,该怎么办。其中一个 continue,rollback 或者pause (默认:pause)。
    • monitor:每个容器更新后,持续观察是否失败了的时间 (ns|us|ms|s|m|h)(默认为0s)。
    • max_failure_ratio:在更新过程中可以容忍的故障率。
    • order:回滚期间的操作顺序。其中一个 stop-first(串行回滚),或者 start-first(并行回滚)(默认stop-first)。

    :仅支持 V3.4 及更高版本。

7.4.9 devices

指定设备映射列表。

1
2
devices:
- "/dev/ttyUSB0:/dev/ttyUSB0"

7.4.10 dns

自定义 DNS 服务器,可以是单个值或列表的多个值。

1
2
3
4
5
dns: 8.8.8.8

dns:
- 8.8.8.8
- 9.9.9.9

自定义 DNS 搜索域。可以是单个值或列表。

1
2
3
4
5
dns_search: example.com

dns_search:
- dc1.example.com
- dc2.example.com

7.4.12 entrypoint

覆盖容器默认的 entrypoint。

1
entrypoint: /code/entrypoint.sh

也可以是以下格式:

1
2
3
4
5
6
7
entrypoint:
- php
- -d
- zend_extension=/usr/local/lib/php/extensions/no-debug-non-zts-20100525/xdebug.so
- -d
- memory_limit=-1
- vendor/bin/phpunit

7.4.13 env_file

从文件添加环境变量。可以是单个值或列表的多个值。

1
env_file: .env

也可以是列表格式:

1
2
3
4
env_file:
- ./common.env
- ./apps/web.env
- /opt/secrets.env

7.4.14 environment

添加环境变量。您可以使用数组或字典、任何布尔值,布尔值需要用引号引起来,以确保 YML 解析器不会将其转换为 True 或 False。

1
2
3
environments:
RACK_ENV: development
SHOW: "true"

7.4.15 expose

暴露端口,但不映射到宿主机,只被连接的服务访问。

仅可以指定内部端口为参数:

1
2
3
expose:
- "8000"
- "8862"

7.4.16 extra_hosts

添加主机名映射。类似 docker client --add-host

1
2
3
extra_hosts:
- "onehost:192.168.58.101"
- "otherhost:192.168.58.102"

以上会在此服务的内部容器中 /etc/hosts 创建一个具有 ip 地址和主机名的映射关系:

1
2
192.168.58.101  onehost
192.168.58.102 otherhost

7.4.17 healthcheck

用于检测 docker 服务是否健康运行。

1
2
3
4
5
6
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"] # 设置监测程序
interval: 1m30s # 设置监测间隔
timeout: 10s # 设置检测超时时间
retries: 3 # 设置重试次数
start_period: 40s # 启动后,多少秒开始启动检测程序

7.4.18 image

指定容器运行的镜像。以下格式都可以:

1
2
3
4
image: redis
image: ubuntu:16.04
image: tutum/influxdb
image: 60ce5883af74

7.4.19 logging

服务的日志记录配置。

driver:指定服务容器的日志记录驱动程序,默认值为json-file。有以下三个选项

1
2
3
driver: "json-file"
driver: "syslog"
driver: "none"
  • driver: "json-file" 驱动程序下,可以使用以下参数,限制日志得数量和大小。

    1
    2
    3
    4
    5
    logging:
    driver: json-file
    options:
    max-size: "200k" # 单个文件大小为200k
    max-file: "10" # 最多10个文件

    当达到文件限制上限,会自动删除旧得文件。

  • driver: "syslog" 驱动程序下,可以使用 syslog-address 指定日志接收地址。

    1
    2
    3
    4
    logging:
    driver: syslog
    options:
    syslog-address: "tcp://192.168.58.101:8802"

7.4.20 network_mode

设置网络模式

1
2
3
4
5
network-mode: "bridge"
network-mode: "host"
network-mode: "none"
network-mode: "service:[service name]"
network-mode: "container:[container name/id]"

networks:配置容器连接的网络,引用顶级networks下的条目

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
services:
one-service:
networks:
one-network:
aliases:
- alias1
other-network:
aliases:
-alias2
networks:
one-network:
# Use a custom driver
driver: custom-driver-1
other-network:
# Use a custom driver which takes special options
driver: custom-driver-2

aliases: 同一网络上的其他容器阔以使用服务名称或此别名来连接到对应容器的服务。

7.4.21 restart

  • no: 默认的重启策略,在任何情况下都不会重启容器
  • always: 容器总是重新启动
  • on-failure: 在容器非正常退出时(退出状态非0),才会重启容器
  • unless-stopped: 在容器退出时总是重启容器,但是不考虑在Docker守护进程启动时就已经停止了的容器
1
2
3
4
restart: "no"
restart: "always"
restart: "on-failure"
retart: "unless-stopped"

注意:swarm集群模式,请改用restart_policy

7.4.22 secrets

存储敏感数据,例如密码:

1
2
3
4
5
6
7
8
9
10
11
version: "2.0"
services:
mysql:
image: mysql
environment:
MYSQL_ROOT_PASSWORD_FILE: /run/secrets/my_secret
secrets:
- my_secret
secrets:
my_secret:
file: ./my_secret.txt

7.4.23 security_opt

修改容器默认的 schema 标签。

1
2
3
4
5
security-opt:
- label: user:USER # 设置容器的用户标签
- label: role: ROLE # 设置容器的角色标签
- label: type: TYPE # 设置容器的安全策略标签
- label: level:LEVEL # 设置容器的安全等级标签

7.4.24 stop_grace_period

指定在容器无法处理 SIGTERM (或者任何 stop_signal 的信号),等待多久后发送 SIGKILL 信号关闭容器。

1
2
stop_grace_period: 1s  # 等待1秒
stop_grace_period: 1m30s # 等待1分30秒

默认的等待时间时10秒。

7.4.25 stop_signal

设置停止容器的替代信号。默认情况下使用 SIGTERM

以下示例,使用 SIGUSR1 替代信号 SIGTERM 来停止容器。

1
stop_signal: SIGUSR1

7.4.26 sysctls

设置容器中的内核参数,可以使用数组或字典格式。

1
2
3
4
5
6
sysctls:
net.core.somaxconn: 1024
net.ipv4.tcp_syncookies: 0
sysctls:
- net.core.somaxconn=1024
- net.ipv4.tcp_syncookies=0

7.4.27 tmpfs

在容器内安装一个临时文件系统。可以是单个值或列表的多个值。

1
2
3
4
tmpfs: /run
tmpfs:
- /run
- /tmp

7.4.28 ulimits

覆盖容器默认的 ulimit。

1
2
3
4
5
ulimits:
nproc: 65535
nofile:
soft: 20000
hard: 40000

7.4.29 volumes

将主机的数据卷或者文件挂载到容器里。

1
2
3
4
5
6
7
8
# yml 配置实例
version: '2.0'
services:
db:
image: postgres:latest
volumes:
- "/localhost/postgres.sock:/var/run/postgres/postgres.sock"
- "/localhost/data:/var/lib/postgres/data"

8. Docker Machine

8.1 简介

Docker Machine 是一种可以让您在虚拟主机上安装 Docker 的工具,并可以使用 docker-machine 命令来管理主机。

Docker Machine 也可以集中管理所有的 docker 主机,比如快速的给 100 台服务器安装上 docker。

Docker Machine 管理的虚拟主机可以是机上的,也可以是云供应商,如阿里云,腾讯云,AWS,或 DigitalOcean等等。

使用 docker-machine 命令,您可以启动,检查,停止和重新启动托管主机,也可以升级 Docker 客户端和守护程序,以及配置 Docker 客户端与您的主机进行通信。

8.2 安装

安装 Docker Machine 之前你需要先安装 Docker

Docker Machine 可以在多种平台上安装使用,包括 Linux 、MacOS 以及 windows。

8.2.1 macOS安装命令

1
2
3
4
5
6
(base) kungs@kungs-MacPro ~ % curl -L https://github.com/docker/machine/releases/download/v0.16.2/docker-machine-`uname -s`-`uname -m` >/usr/local/bin/docker-machine && \
> chmod +x /usr/local/bin/docker-machine
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
0 32.6M 0 97716 0 0 355 0 26:46:17 0:04:34 26:41:43 0

8.2.2 Linux 安装命令

1
2
3
4
5
[root@localhost composeTest]# curl -L https://github.com/docker/machine/releases/download/v0.16.2/docker-machine-`uname -s`-`uname -m` >/tmp/docker-machine &&     chmod +x /tmp/docker-machine &&     sudo cp /tmp/docker-machine /usr/local/bin/docker-machine
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
0 32.6M 0 97716 0 0 355 0 26:46:17 0:04:34 26:41:43 0

8.2.3 Windows with git bash

1
2
3
4
5
6
7
8
yanpenggong@kungs MINGW64 ~
$ if [[ ! -d "$HOME/bin" ]]; then mkdir -p "$HOME/bin"; fi && \
curl -L https://github.com/docker/machine/releases/download/v0.16.2/docker-machine-Windows-x86_64.exe > "$HOME/bin/docker-machine.exe" && \
chmod +x "$HOME/bin/docker-machine.exe"
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- --:--:-- --:--:-- 0
0 32.8M 0 111k 0 0 23166 0 0:24:47 0:00:04 0:24:43 34068

否则,直接从发布页面下载其中一个版本。

有关更多安装选项和说明,请参阅安装文档

8.2.4 查看是否安装成功:

1
2
3
[root@localhost composeTest]# docker-machine --version
docker-machine version 0.16.2, build bd45ab13
[root@localhost composeTest]#

注意:各版本更新日志里面也有安装说明:https://github.com/docker/machine/releases

8.3 使用

这里通过 vmware来介绍 docker-machine 的使用方法。其他云服务商操作与此基本一致。具体可以参考每家服务商的指导文档。

8.3.1列出可用的机器

可以看到目前只有这里默认的 default 虚拟机。

1
2
3
[root@localhost composeTest]# docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
[root@localhost composeTest]#

8.3.2 创建机器

创建一台名为 test 的机器。

  • —driver:指定用来创建机器的驱动类型,这里是 virtualbox

    1
    (base) kungs@kungs-MacPro DockerLearning % docker-machine create --driver virtualbox test

    ERROR:

    1
    2
    (base) kungs@kungs-MacPro DockerLearning % docker-machine create --driver virtualbox test
    (base) kungs@kungs-MacPro DockerLearning %

    解决办法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    (base) kungs@kungs-MacPro DockerLearning % brew install virtualbox
    Loaded plugins: fastestmirror
    Loading mirror speeds from cached hostfile
    * base: mirrors.ustc.edu.cn
    * extras: ftp.sjtu.edu.cn
    * updates: mirrors.ustc.edu.cn
    base | 3.6 kB 00:00:00
    docker-ce-stable | 3.5 kB 00:00:00
    extras | 2.9 kB 00:00:00
    updates | 2.9 kB 00:00:00
    (1/2): docker-ce-stable/7/x86_64/primary_db | 91 kB 00:00:00
    (2/2): updates/7/x86_64/primary_db | 19 MB 00:00:06
    (base) kungs@kungs-MacPro DockerLearning %
  • —driver:指定用来创建机器的驱动类型,这里是 vmware

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    (base) kungs@kungs-MacPro DockerLearning % docker-machine create --driver=vmware yanpenggong1
    Running pre-create checks...
    Creating machine...
    (yanpenggong1) Copying /Users/kungs/.docker/machine/cache/boot2docker.iso to /Users/kungs/.docker/machine/machines/yanpenggong1/boot2docker.iso...
    (yanpenggong1) Creating SSH key...
    (yanpenggong1) Creating VM...
    (yanpenggong1) Starting yanpenggong1...
    (yanpenggong1) Waiting for VM to come online...
    Waiting for machine to be running, this may take a few minutes...
    Detecting operating system of created instance...
    Waiting for SSH to be available...
    Detecting the provisioner...
    Provisioning with boot2docker...
    Copying certs to the local machine directory...
    Copying certs to the remote machine...
    Setting Docker configuration on the remote daemon...
    Checking connection to Docker...
    Docker is up and running!
    To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: docker-machine env yanpenggong1
    (base) kungs@kungs-MacPro DockerLearning % docker-machine ls
    NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
    yanpenggong1 - vmware Running tcp://172.16.247.6:2376 v19.03.12
    (base) kungs@kungs-MacPro DockerLearning %

    ERROR解决办法:

    包的路径:docker-machine-driver-vmware

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    (base) kungs@kungs-MacPro DockerLearning % brew install docker-machine-driver-vmware
    ==> Fetching docker-machine-driver-vmware
    ==> Downloading https://mirrors.aliyun.com/homebrew/homebrew-bottles/docker-machine-driver-vmware-0.1.5.monterey.bottle.1.tar.gz
    ######################################################################## 100.0%
    ==> Pouring docker-machine-driver-vmware-0.1.5.monterey.bottle.1.tar.gz
    /usr/local/Cellar/docker-machine-driver-vmware/0.1.5: 5 files, 10MB
    ==> Running `brew cleanup docker-machine-driver-vmware`...
    Disable this behaviour by setting HOMEBREW_NO_INSTALL_CLEANUP.
    Hide these hints with HOMEBREW_NO_ENV_HINTS (see `man brew`).
    (base) kungs@kungs-MacPro DockerLearning %

8.3.3 查看机器的 ip

1
2
3
(base) kungs@kungs-MacPro DockerLearning % docker-machine ip yanpenggong1
172.16.247.6
(base) kungs@kungs-MacPro DockerLearning %

8.3.4 停止机器

1
2
3
4
(base) kungs@kungs-MacPro DockerLearning % docker-machine stop yanpenggong1 
Stopping "yanpenggong1"...
Machine "yanpenggong1" was stopped.
(base) kungs@kungs-MacPro DockerLearning %

8.3.5 启动机器

1
2
3
4
5
6
7
8
9
(base) kungs@kungs-MacPro DockerLearning % docker-machine start yanpenggong1
Starting "yanpenggong1"...
(yanpenggong1) Starting yanpenggong1...
(yanpenggong1) Waiting for VM to come online...
Machine "yanpenggong1" was started.
Waiting for SSH to be available...
Detecting the provisioner...
Started machines may have new IP addresses. You may need to re-run the `docker-machine env` command.
(base) kungs@kungs-MacPro DockerLearning %

8.3.6 进入机器

1
2
3
4
5
6
7
8
9
10
11
12
(base) kungs@kungs-MacPro DockerLearning % docker-machine ssh yanpenggong1
( '>')
/) TC (\ Core is distributed with ABSOLUTELY NO WARRANTY.
(/-_--_-\) www.tinycorelinux.net

chmod: /mnt/hgfs/Users: Operation not permitted
fuse: mountpoint is not empty
fuse: if you are sure this is safe, use the 'nonempty' mount option
chmod: /mnt/hgfs/Users: Operation not permitted
fuse: mountpoint is not empty
fuse: if you are sure this is safe, use the 'nonempty' mount option
docker@yanpenggong1:~$

8.3.7 docker-machine 命令参数说明

激活docker的指定环境eval $(docker-machine env 创建的环境名),实例:

1
2
3
4
5
(base) kungs@kungs-MacPro DockerLearning %  eval $(docker-machine env yanpenggong1)
(base) kungs@kungs-MacPro DockerLearning % docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
yanpenggong1 * vmware Running tcp://172.16.247.6:2376 v19.03.12
(base) kungs@kungs-MacPro DockerLearning %

演示情况:

1
2
3
4
5
6
7
8
9
10
11
12
(base) kungs@kungs-MacPro DockerLearning % docker-machine ls                       
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
yanpenggong1 - vmware Running tcp://172.16.247.6:2376 v19.03.12
(base) kungs@kungs-MacPro DockerLearning % eval $(docker-machine env yanpenggong1)
(base) kungs@kungs-MacPro DockerLearning % docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
yanpenggong1 * vmware Running tcp://172.16.247.6:2376 v19.03.12
(base) kungs@kungs-MacPro DockerLearning % echo $DOCKER_HOST
tcp://172.16.247.6:2376
(base) kungs@kungs-MacPro DockerLearning % docker-machine active
yanpenggong1
(base) kungs@kungs-MacPro DockerLearning %
ID 参数 参数说明
1 active 查看当前激活状态的 Docker 主机。
2 config 查看当前激活状态 Docker 主机的连接信息。
3 create 创建 Docker 主机
4 env 显示连接到某个主机需要的环境变量
5 inspect 以 json 格式输出指定Docker的详细信息
6 ip 获取指定 Docker 主机的地址
7 kill 直接杀死指定的 Docker 主机
8 ls 列出所有的管理主机
9 provision 重新配置指定主机
10 regenerate-certs 某个主机重新生成 TLS 信息
11 restart 重启指定的主机
12 rm 删除某台 Docker 主机,对应的虚拟机也会被删除
13 ssh 通过 SSH 连接到主机上,执行命令
14 scp 在 Docker 主机之间以及 Docker 主机和本地主机之间通过 scp 远程复制数据
15 mount 使用 SSHFS 从计算机装载或卸载目录
16 start 启动一个指定的 Docker 主机,如果对象是个虚拟机,该虚拟机将被启动
17 status 获取指定 Docker 主机的状态(包括:Running、Paused、Saved、Stopped、Stopping、Starting、Error)等
18 stop 停止一个指定的 Docker 主机
19 upgrade 将一个指定主机的 Docker 版本更新为最新
20 url 获取指定 Docker 主机的监听 URL
21 version 显示 Docker Machine 的版本或者主机 Docker 版本
22 help 显示帮助信息

9. Swarm集群管理

==这块内容都是基于macbook下的Docker进行操作的。==

9.1 简介

Docker Swarm 是 Docker 的集群管理工具。它将 Docker 主机池转变为单个虚拟 Docker 主机。 Docker Swarm 提供了标准的 Docker API,所有任何已经与 Docker 守护程序通信的工具都可以使用 Swarm 轻松地扩展到多个主机。

支持的工具包括但不限于以下各项:

  • Dokku
  • Docker Compose
  • Docker Machine
  • Jenkins

9.2 原理

swarm 集群由管理节点(manager)工作节点(work node)构成。

  • swarm mananger:负责整个集群的管理工作包括集群配置、服务管理等所有跟集群有关的工作。
  • work node:即图中的 available node,主要负责运行相应的服务来执行任务(task)。

9.3 使用

以下示例,以 Docker Machinevmware 进行介绍,确保你的主机已安装 vmware

9.3.1 创建 swarm 集群管理节点(manager)

创建 docker 机器:

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) kungs@kungs-MacPro DockerLearning % docker-machine create -driver vmware swarm-manager
Running pre-create checks...
Creating machine...
(swarm-manager) Copying /Users/kungs/.docker/machine/cache/boot2docker.iso to /Users/kungs/.docker/machine/machines/swarm-manager/boot2docker.iso...
(swarm-manager) Creating SSH key...
(swarm-manager) Creating VM...
(swarm-manager) Starting swarm-manager...
(swarm-manager) Waiting for VM to come online...
Waiting for machine to be running, this may take a few minutes...
Detecting operating system of created instance...
Waiting for SSH to be available...
Detecting the provisioner...
Provisioning with boot2docker...
Copying certs to the local machine directory...
Copying certs to the remote machine...
Setting Docker configuration on the remote daemon...
Checking connection to Docker...
Docker is up and running!
To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: docker-machine env swarm-manager
(base) kungs@kungs-MacPro DockerLearning % docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
swarm-manager - vmware Running tcp://172.16.247.7:2376 v19.03.12
yanpenggong1 * vmware Running tcp://172.16.247.6:2376 v19.03.12
(base) kungs@kungs-MacPro DockerLearning %

初始化 swarm 集群,进行初始化的这台机器,就是集群的管理节点。其中docker swarm init --advertise-addr 172.16.247.7对应的ip是创建机器时分配的 ip。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
(base) kungs@kungs-MacPro DockerLearning % docker-machine ssh swarm-manager    
( '>')
/) TC (\ Core is distributed with ABSOLUTELY NO WARRANTY.
(/-_--_-\) www.tinycorelinux.net

docker@swarm-manager:~$ docker swarm init --advertise-addr 172.16.247.7
Swarm initialized: current node (qrywiizkesql8crxvyy9maafb) is now a manager.

To add a worker to this swarm, run the following command:

docker swarm join --token SWMTKN-1-0wstyhdwc045fcam3n3r6yocmrnlj3eyr0ywkjxni2jp4lk0z3-5jzty2vwepgh1vrnfxplfzq7a 172.16.247.7:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

docker@swarm-manager:~$

以上输出,证明已经初始化成功。需要把以下这行复制出来,在增加工作节点时会用到:

1
docker swarm join --token SWMTKN-1-0wstyhdwc045fcam3n3r6yocmrnlj3eyr0ywkjxni2jp4lk0z3-5jzty2vwepgh1vrnfxplfzq7a 172.16.247.7:2377

9.3.2 创建 swarm 集群工作节点(worker)

这里直接创建好俩台机器,swarm-worker1swarm-worker2

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
(base) kungs@kungs-MacPro DockerLearning % docker-machine create -driver vmware swarm-worker1
Running pre-create checks...
Creating machine...
(swarm-worker1) Copying /Users/kungs/.docker/machine/cache/boot2docker.iso to /Users/kungs/.docker/machine/machines/swarm-worker1/boot2docker.iso...
(swarm-worker1) Creating SSH key...
(swarm-worker1) Creating VM...
(swarm-worker1) Starting swarm-worker1...
(swarm-worker1) Waiting for VM to come online...
Waiting for machine to be running, this may take a few minutes...
Detecting operating system of created instance...
Waiting for SSH to be available...
Detecting the provisioner...
Provisioning with boot2docker...
Copying certs to the local machine directory...
Copying certs to the remote machine...
Setting Docker configuration on the remote daemon...
Checking connection to Docker...
Docker is up and running!
To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: docker-machine env swarm-worker1
(base) kungs@kungs-MacPro DockerLearning % docker-machine create -driver vmware swarm-worker2
Running pre-create checks...
Creating machine...
(swarm-worker2) Copying /Users/kungs/.docker/machine/cache/boot2docker.iso to /Users/kungs/.docker/machine/machines/swarm-worker2/boot2docker.iso...
(swarm-worker2) Creating SSH key...
(swarm-worker2) Creating VM...
(swarm-worker2) Starting swarm-worker2...
(swarm-worker2) Waiting for VM to come online...
Waiting for machine to be running, this may take a few minutes...
Detecting operating system of created instance...
Waiting for SSH to be available...
Detecting the provisioner...
Provisioning with boot2docker...
Copying certs to the local machine directory...
Copying certs to the remote machine...
Setting Docker configuration on the remote daemon...
Checking connection to Docker...
Docker is up and running!
To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: docker-machine env swarm-worker2
(base) kungs@kungs-MacPro DockerLearning % docker-machine ls
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
swarm-manager - vmware Running tcp://172.16.247.7:2376 v19.03.12
swarm-worker1 - vmware Running tcp://172.16.247.8:2376 v19.03.12
swarm-worker2 - vmware Running tcp://172.16.247.9:2376 v19.03.12
yanpenggong1 * vmware Running tcp://172.16.247.6:2376 v19.03.12
(base) kungs@kungs-MacPro DockerLearning %

分别进入两个机器里,指定添加至上一步中创建的集群,这里会用到上一步复制的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(base) kungs@kungs-MacPro DockerLearning % docker-machine ssh swarm-worker1
( '>')
/) TC (\ Core is distributed with ABSOLUTELY NO WARRANTY.
(/-_--_-\) www.tinycorelinux.net

<tyhdwc045fcam3n3r6yocmrnlj3eyr0ywkjxni2jp4lk0z3-5jzty2vwepgh1vrnfxplfzq7a 172.16.247.7:2377
This node joined a swarm as a worker.
docker@swarm-worker1:~$ exit
logout
(base) kungs@kungs-MacPro DockerLearning % docker-machine ssh swarm-worker2
( '>')
/) TC (\ Core is distributed with ABSOLUTELY NO WARRANTY.
(/-_--_-\) www.tinycorelinux.net

<tyhdwc045fcam3n3r6yocmrnlj3eyr0ywkjxni2jp4lk0z3-5jzty2vwepgh1vrnfxplfzq7a 172.16.247.7:2377
This node joined a swarm as a worker.
docker@swarm-worker2:~$ exit
logout
(base) kungs@kungs-MacPro DockerLearning %

以上数据输出说明已经添加成功。

上图中,由于上一步复制的内容比较长,会被自动截断,实际上在图运行的命令如下:

1
2
docker@swarm-worker2:~$ docker swarm join --token SWMTKN-1-0wstyhdwc045fcam3n3r6yocmrnlj3eyr0ywkjxni2jp4lk0z3-5jzty2vwepgh1vrnfxplfzq7a 172.16.247.7:2377
(base) kungs@kungs-MacPro DockerLearning %

9.3.3 查看集群信息

激活swarm模式

1
2
3
4
5
6
7
(base) kungs@kungs-MacPro DockerLearning % eval $(docker-machine env swarm-manager)
(base) kungs@kungs-MacPro DockerLearning % docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
qrywiizkesql8crxvyy9maafb * swarm-manager Ready Active Leader 19.03.12
rr74dtx0mq67hskuaxt6kgx0w swarm-worker1 Ready Active 19.03.12
am79rf9q1mo0tvu0otketbf4q swarm-worker2 Ready Active 19.03.12
(base) kungs@kungs-MacPro DockerLearning %

进入管理节点,执行:docker info 可以查看当前集群的信息。

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
(base) kungs@kungs-MacPro DockerLearning % docker info                     
Client:
Context: default
Debug Mode: false
Plugins:
buildx: Docker Buildx (Docker Inc., v0.8.2)
compose: Docker Compose (Docker Inc., v2.7.0)
extension: Manages Docker extensions (Docker Inc., v0.2.8)
sbom: View the packaged-based Software Bill Of Materials (SBOM) for an image (Anchore Inc., 0.6.0)
scan: Docker Scan (Docker Inc., v0.17.0)

Server:
Containers: 0
Running: 0
Paused: 0
Stopped: 0
Images: 0
Server Version: 19.03.12
Storage Driver: overlay2
Backing Filesystem: extfs
Supports d_type: true
Native Overlay Diff: true
Logging Driver: json-file
Cgroup Driver: cgroupfs
Plugins:
Volume: local
Network: bridge host ipvlan macvlan null overlay
Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
Swarm: active
NodeID: qrywiizkesql8crxvyy9maafb
Is Manager: true
ClusterID: xgdh712ll4k6nraf2heear3tm
Managers: 1
Nodes: 3
Default Address Pool: 10.0.0.0/8
SubnetSize: 24
Data Path Port: 4789
Orchestration:
Task History Retention Limit: 5
Raft:
Snapshot Interval: 10000
Number of Old Snapshots to Retain: 0
Heartbeat Tick: 1
Election Tick: 10
Dispatcher:
Heartbeat Period: 5 seconds
CA Configuration:
Expiry Duration: 3 months
Force Rotate: 0
Autolock Managers: false
Root Rotation In Progress: false
Node Address: 172.16.247.7
Manager Addresses:
172.16.247.7:2377
Runtimes: runc
Default Runtime: runc
Init Binary: docker-init
containerd version: 7ad184331fa3e55e52b890ea95e65ba581ae3429
runc version: dc9208a3303feef5b3839f4323d9beb36df0a9dd
init version: fec3683
Security Options:
seccomp
Profile: default
Kernel Version: 4.19.130-boot2docker
Operating System: Boot2Docker 19.03.12 (TCL 10.1)
OSType: linux
Architecture: x86_64
CPUs: 1
Total Memory: 984.3MiB
Name: swarm-manager
ID: XJDY:TYXT:LFCV:CYTK:IDRY:BVD2:AWQO:FYBY:RY6D:YI2D:YC4Z:6LJL
Docker Root Dir: /mnt/sda1/var/lib/docker
Debug Mode: false
Registry: https://index.docker.io/v1/
Labels:
provider=vmware
Experimental: false
Insecure Registries:
127.0.0.0/8
Live Restore Enabled: false
Product License: Community Engine

(base) kungs@kungs-MacPro DockerLearning %

其中

1
2
3
4
5
6
Swarm: active  # docker engine有没有激活swarm模式, 默认是没有(inactive)
NodeID: qrywiizkesql8crxvyy9maafb
Is Manager: true
ClusterID: xgdh712ll4k6nraf2heear3tm
Managers: 1 # 管理节点
Nodes: 3 # 三个节点

9.3.4 部署服务到集群中

注意:跟集群管理有关的任何操作,都是在管理节点上操作的。

以下例子,在一个工作节点上创建一个名为 helloworld 的服务,这里是随机指派给一个工作节点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
(base) kungs@kungs-MacPro DockerLearning % docker-machine ls                       
NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS
swarm-manager * vmware Running tcp://172.16.247.7:2376 v19.03.12
swarm-worker1 - vmware Running tcp://172.16.247.8:2376 v19.03.12
swarm-worker2 - vmware Running tcp://172.16.247.9:2376 v19.03.12
yanpenggong1 - vmware Running tcp://172.16.247.6:2376 v19.03.12
(base) kungs@kungs-MacPro DockerLearning %
(base) kungs@kungs-MacPro DockerLearning %
(base) kungs@kungs-MacPro DockerLearning % docker-machine ssh swarm-manager
( '>')
/) TC (\ Core is distributed with ABSOLUTELY NO WARRANTY.
(/-_--_-\) www.tinycorelinux.net

docker@swarm-manager:~$ docker service create --replicas 1 --name helloworld alpine ping docker.com
05o7ocmbmpm28xcfeu8ci4cml
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Service converged
docker@swarm-manager:~$

9.3.5 查看服务部署情况

查看 helloworld 服务运行在哪个节点上,可以看到目前是在 swarm-worker2 节点:

1
2
3
4
docker@swarm-manager:~$ docker service ps helloworld
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
bpopbylx99di helloworld.1 alpine:latest swarm-worker2 Running Running about a minute ago
docker@swarm-manager:~$

查看 helloworld 部署的具体信息:

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
docker@swarm-manager:~$ docker service inspect --pretty helloworld                                                                          

ID: 05o7ocmbmpm28xcfeu8ci4cml
Name: helloworld
Service Mode: Replicated
Replicas: 1
Placement:
UpdateConfig:
Parallelism: 1
On failure: pause
Monitoring Period: 5s
Max failure ratio: 0
Update order: stop-first
RollbackConfig:
Parallelism: 1
On failure: pause
Monitoring Period: 5s
Max failure ratio: 0
Rollback order: stop-first
ContainerSpec:
Image: alpine:latest@sha256:f271e74b17ced29b915d351685fd4644785c6d1559dd1f2d4189a5e851ef753a
Args: ping docker.com
Init: false
Resources:
Endpoint Mode: vip

docker@swarm-manager:~$

9.3.6 扩展集群服务

将上述的 helloworld 服务扩展到俩个节点。

1
2
3
4
5
6
7
8
9
10
docker@swarm-manager:~$ docker service ps helloworld 
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
bpopbylx99di helloworld.1 alpine:latest swarm-worker2 Running Running about an hour ago
docker@swarm-manager:~$ docker service scale helloworld=2
helloworld scaled to 2
overall progress: 2 out of 2 tasks
1/2: running [==================================================>]
2/2: running [==================================================>]
verify: Service converged
docker@swarm-manager:~$

可以看到已经从一个节点,扩展到两个节点。

1
2
3
4
5
docker@swarm-manager:~$ docker service ps helloworld     
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
bpopbylx99di helloworld.1 alpine:latest swarm-worker2 Running Running about an hour ago
vr81swcln6s9 helloworld.2 alpine:latest swarm-manager Running Running 45 seconds ago
docker@swarm-manager:~$

9.3.7 删除服务

1
2
3
4
5
docker@swarm-manager:~$ docker service rm helloworld 
helloworld
docker@swarm-manager:~$ docker service ps helloworld
no such service: helloworld
docker@swarm-manager:~$

命令 docker service ps helloworld 查看是否已删除

9.3.8 滚动升级服务

介绍 redis 版本如何滚动升级至更高版本。这里创建一个 3.0.5 版本的 redis。

1
2
3
4
5
6
7
8
9
10
11
12
docker@swarm-manager:~$ docker service create --replicas 1 --name redis --update-delay 10s redis:3.0.5 
image redis:3.0.5 could not be accessed on a registry to record
its digest. Each node will access redis:3.0.5 independently,
possibly leading to different nodes running different
versions of the image.

t25x2wtwzxlkaybsijmshdjel
overall progress: 1 out of 1 tasks
1/1: running [==================================================>]
verify: Service converged
docker@swarm-manager:~$

滚动升级 redis 。

1
2
3
4
5
docker@swarm-manager:~$ docker service ps redis                                                       
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
k9yx1lkg8mef redis.1 redis:3.0.7 swarm-manager Running Running 10 seconds ago
ouanlbtgnjo9 \_ redis.1 redis:3.0.5 swarm-manager Shutdown Shutdown 10 seconds ago
docker@swarm-manager:~$

看图可以知道 redis 的版本已经从 3.0.5 升级到了 3.0.8,说明服务已经升级成功。

9.3.9 停止某个节点接收新的任务

查看所有的节点:

1
2
3
4
5
6
docker@swarm-manager:~$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
qrywiizkesql8crxvyy9maafb * swarm-manager Ready Active Leader 19.03.12
rr74dtx0mq67hskuaxt6kgx0w swarm-worker1 Ready Active 19.03.12
am79rf9q1mo0tvu0otketbf4q swarm-worker2 Ready Active 19.03.12
docker@swarm-manager:~$

可以看到目前所有的节点都是 Active, 可以接收新的任务分配。

停止节点 swarm-worker2:

1
2
3
4
5
6
7
8
docker@swarm-manager:~$ docker node update --availability drain swarm-worker2
swarm-worker2
docker@swarm-manager:~$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
qrywiizkesql8crxvyy9maafb * swarm-manager Ready Active Leader 19.03.12
rr74dtx0mq67hskuaxt6kgx0w swarm-worker1 Ready Active 19.03.12
am79rf9q1mo0tvu0otketbf4q swarm-worker2 Ready Drain 19.03.12
docker@swarm-manager:~$

注意:swarm-worker2 状态变为 Drain。不会影响到集群的服务,只是 swarm-worker2 节点不再接收新的任务,集群的负载能力有所下降。

可以通过以下命令重新激活节点:

1
2
3
4
5
6
7
8
docker@swarm-manager:~$ docker node update --availability active swarm-worker2
swarm-worker2
docker@swarm-manager:~$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
qrywiizkesql8crxvyy9maafb * swarm-manager Ready Active Leader 19.03.12
rr74dtx0mq67hskuaxt6kgx0w swarm-worker1 Ready Active 19.03.12
am79rf9q1mo0tvu0otketbf4q swarm-worker2 Ready Active 19.03.12
docker@swarm-manager:~$

10. Docker 安装软件

10.1 Docker 安装 Centos

Ubuntu 是基于 Debian 的 Linux 操作系统。

10.1.1 查看可用的 Ubuntu 版本

访问 Ubuntu 镜像库地址: https://hub.docker.com/_/ubuntu?tab=tags&page=1。

也可以在下拉列表中找到其他想要的版本。

10.1.2 拉取最新版的 Ubuntu 镜像

docker pull ubuntudocker pull ubuntu:latest

1
2
3
4
5
6
7
8
[root@localhost DockerTest]# docker pull ubuntu
Using default tag: latest
latest: Pulling from library/ubuntu
6e3729cf69e0: Pull complete
Digest: sha256:27cb6e6ccef575a4698b66f5de06c7ecd61589132d5a91d098f7f3f9285415a9
Status: Downloaded newer image for ubuntu:latest
docker.io/library/ubuntu:latest
[root@localhost DockerTest]#

10.1.3 查看本地镜像

1
2
3
4
[root@localhost DockerTest]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest 6b7dfa7e8fdb 5 weeks ago 77.8MB
[root@localhost DockerTest]#

可以看到我们已经安装了最新版本的 ubuntu。

10.1.4 运行容器,并且可以通过 exec 命令进入 ubuntu 容器

1
2
3
[root@localhost DockerTest]# docker run -itd --name ubuntu-test1 ubuntu
c281416b5c63869c864b8521819bf4c25e8097eff3bf273bee752ae41f265301
[root@localhost DockerTest]#

10.1.5安装成功

通过 docker ps 命令查看容器的运行信息:

1
2
3
4
[root@localhost DockerTest]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
c281416b5c63 ubuntu "bash" About a minute ago Up About a minute ubuntu-test1
[root@localhost DockerTest]#

10.2 Docker 安装CentOS

CentOS(Community Enterprise Operating System)是 Linux 发行版之一,它是来自于 Red Hat Enterprise Linux(RHEL) 依照开放源代码规定发布的源代码所编译而成。由于出自同样的源代码,因此有些要求高度稳定性的服务器以 CentOS 替代商业版的 Red Hat Enterprise Linux 使用。

10.2.1 查看可用的 CentOS 版本

访问 CentOS 镜像库地址:https://hub.docker.com/_/centos?tab=tags&page=1。

10.2.2 拉取指定版本的 CentOS 镜像,这里我们安装指定版本为例(centos7):

1
2
3
4
5
6
7
[root@localhost DockerTest]# docker pull centos:centos7
centos7: Pulling from library/centos
2d473b07cdd5: Pull complete
Digest: sha256:be65f488b7764ad3638f236b7b515b3678369a5124c47b8d32916d6487418ea4
Status: Downloaded newer image for centos:centos7
docker.io/library/centos:centos7
[root@localhost DockerTest]#

10.2.3 查看本地镜像

1
2
3
4
5
[root@localhost DockerTest]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
ubuntu latest 6b7dfa7e8fdb 5 weeks ago 77.8MB
centos centos7 eeb6ee3f44bd 16 months ago 204MB
[root@localhost DockerTest]#

10.2.4 运行容器,并且可以通过 exec 命令进入 CentOS 容器。

1
2
3
[root@localhost DockerTest]# docker run -itd --name centos-test centos:centos7
81cbdd935383d55fd41a7947e580310920d0e948d1d8bea80a696b767f437a33
[root@localhost DockerTest]#

10.2.5 安装成功

通过 docker ps 命令查看容器的运行信息:

1
2
3
4
5
[root@localhost DockerTest]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
81cbdd935383 centos:centos7 "/bin/bash" 18 seconds ago Up 13 seconds centos-test
c281416b5c63 ubuntu "bash" 31 minutes ago Up 31 minutes ubuntu-test1
[root@localhost DockerTest]#

10.3 Docker 安装 Nginx

Nginx 是一个高性能的 HTTP 和反向代理 web 服务器,同时也提供了 IMAP/POP3/SMTP 服务 。

10.3.1 查看可用的 Nginx 版本

访问 Nginx 镜像库地址: https://hub.docker.com/_/nginx?tab=tags。

docker search nginx 命令来查看可用版本:

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
[root@localhost DockerTest]# docker search nginx
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
nginx Official build of Nginx. 17948 [OK]
linuxserver/nginx An Nginx container, brought to you by LinuxS… 183
bitnami/nginx Bitnami nginx Docker Image 150 [OK]
ubuntu/nginx Nginx, a high-performance reverse proxy & we… 75
bitnami/nginx-ingress-controller Bitnami Docker Image for NGINX Ingress Contr… 23 [OK]
rancher/nginx-ingress-controller 11
kasmweb/nginx An Nginx image based off nginx:alpine and in4
ibmcom/nginx-ingress-controller Docker Image for IBM Cloud Private-CE (Commu… 4
bitnami/nginx-exporter 3
bitnami/nginx-ldap-auth-daemon 3
rancher/nginx 2
circleci/nginx This image is for internal use 2
rancher/nginx-ingress-controller-defaultbackend 2
rapidfort/nginx RapidFort optimized, hardened image for NGINX 2
vmware/nginx 2
vmware/nginx-photon 1
bitnami/nginx-intel 1
wallarm/nginx-ingress-controller Kubernetes Ingress Controller with Wallarm e… 1
ibmcom/nginx-ingress-controller-ppc64le Docker Image for IBM Cloud Private-CE (Commu… 0
rancher/nginx-conf 0
rapidfort/nginx-official RapidFort optimized, hardened image for NGIN… 0
ibmcom/nginx-ppc64le Docker image for nginx-ppc64le 0
rancher/nginx-ssl 0
rapidfort/nginx-ib RapidFort optimized, hardened image for NGIN… 0
continuumio/nginx-ingress-ws 0
[root@localhost DockerTest]#

10.3.2 取最新版的 Nginx 镜像

1
2
3
4
5
6
7
8
9
10
11
12
[root@localhost DockerTest]# docker pull nginx:latest
latest: Pulling from library/nginx
8740c948ffd4: Pull complete
d2c0556a17c5: Pull complete
c8b9881f2c6a: Pull complete
693c3ffa8f43: Pull complete
8316c5e80e6d: Pull complete
b2fe3577faa4: Pull complete
Digest: sha256:b8f2383a95879e1ae064940d9a200f67a6c79e710ed82ac42263397367e7cc4e
Status: Downloaded newer image for nginx:latest
docker.io/library/nginx:latest
[root@localhost DockerTest]#

10.3.3 查看本地镜像是否已安装了 nginx:

1
2
3
4
5
6
[root@localhost DockerTest]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest a99a39d070bf 6 days ago 142MB
ubuntu latest 6b7dfa7e8fdb 5 weeks ago 77.8MB
centos centos7 eeb6ee3f44bd 16 months ago 204MB
[root@localhost DockerTest]#

可以看到我们已经安装了最新版本(latest)的 nginx 镜像。

10.3.4 运行容器

1
2
3
[root@localhost DockerTest]# docker run --name nginx-test -p 8080:80 -d nginx
5f1b0abb64ab9704b2f6f175f1d6e5fd5e1c36b39740c3c4341743d821129a12
[root@localhost DockerTest]#

参数说明:

  • —name nginx-test:容器名称。
  • -p 8080:80: 端口进行映射,将本地 8080 端口映射到容器内部的 80 端口。
  • -d nginx: 设置容器在在后台一直运行。

10.3.5 安装成功

通过浏览器可以直接访问 8080 端口的 nginx 服务:

10.4 Docker 安装 Node.js

Node.js 是一个基于 Chrome V8 引擎的 JavaScript 运行环境,是一个让 JavaScript 运行在服务端的开发平台。

10.4.1 查看可用的 Node 版本

访问 Node 镜像库地址: https://hub.docker.com/_/node?tab=tags。

docker search node 命令来查看可用版本:

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
[root@localhost DockerTest]# docker search node
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
node Node.js is a JavaScript-based platform for s… 12278 [OK]
mongo-express Web-based MongoDB admin interface, written w… 1274 [OK]
nodered/node-red Low-code programming for event-driven applic… 545
nodered/node-red-docker Deprecated - older Node-RED Docker images. 357 [OK]
circleci/node Node.js is a JavaScript-based platform for s… 130
kindest/node sigs.k8s.io/kind node image 78
bitnami/node Bitnami Node.js Docker Image 69 [OK]
cimg/node The CircleCI Node.js Docker Convenience Imag… 14
opendronemap/nodeodm Automated build for NodeODM 10 [OK]
bitnami/node-exporter Bitnami Node Exporter Docker Image 9 [OK]
appdynamics/nodejs-agent Agent for monitoring Node.js applications 5
wallarm/node Wallarm: end-to-end API security solution 5 [OK]
nodered/node-red-dev Dev/Test builds for Node-RED project (NOT st… 4
sysdig/node-image-analyzer In cluster component that allows scanning im… 2
okteto/node 2
openwhisk/nodejs6action Apache OpenWhisk runtime for Node.js v6 Acti… 2 [OK]
bitnami/node-snapshot 1
ibmcom/node-exporter-ppc64le Docker Image for IBM Cloud Private-CE (Commu… 0
ibmcom/node-exporter Docker Image for IBM Cloud Private-CE (Commu… 0
docker/node-agent-k8s 0
ibmcom/nodejs-mobile-foundation 0
rancher/node-simulator 0
ibmcom/node-for-redis 0
purestorage/node-config image for configuring node to install tools … 0
vmware/node Node.js base built on top of Photon OS 0 [OK]
[root@localhost DockerTest]#

10.4.2 取最新版的 node 镜像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[root@localhost DockerTest]# docker pull node:latest
latest: Pulling from library/node
bbeef03cda1f: Pull complete
f049f75f014e: Pull complete
56261d0e6b05: Pull complete
9bd150679dbd: Pull complete
5b282ee9da04: Pull complete
8bc43c905b24: Pull complete
3ce9e21024ae: Pull complete
36d91be124f1: Pull complete
7d6b04e90455: Pull complete
Digest: sha256:c1d6d7364e956b061d62241c362b3cd0856beba066ec60e25523a169e2137623
Status: Downloaded newer image for node:latest
docker.io/library/node:latest
[root@localhost DockerTest]#

10.4.3查看本地镜像是否已安装了 node

1
2
3
4
5
6
7
[root@localhost DockerTest]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
node latest 51bd6c84a7f2 6 days ago 998MB
nginx latest a99a39d070bf 6 days ago 142MB
ubuntu latest 6b7dfa7e8fdb 5 weeks ago 77.8MB
centos centos7 eeb6ee3f44bd 16 months ago 204MB
[root@localhost DockerTest]#

可以看到我们已经安装了最新版本(latest)的 node 镜像。

10.4.4 运行容器

1
2
3
[root@localhost DockerTest]# docker run -itd --name node-test node
5c3af81aab8da4da7d4bed00142711c9f565557eae37b9ce2ca2799e35f6eed3
[root@localhost DockerTest]#

参数说明:

  • —name node-test:容器名称。

10.4.5 安装成功

1
2
3
4
[root@localhost DockerTest]# docker exec -it node-test /bin/bash
root@5c3af81aab8d:/# node -v
v19.4.0
root@5c3af81aab8d:/#

11. Docker命令大全

11.1 容器生命周期管理

11.1.1 run

创建一个新的容器并运行一个命令

  1. 语法

    1
    docker run [OPTIONS] IMAGE [COMMAND] [ARG...]

    OPTIONS说明:

    • -a stdin: 指定标准输入输出内容类型,可选 STDIN/STDOUT/STDERR 三项;
    • -d: 后台运行容器,并返回容器ID;
    • -i: 以交互模式运行容器,通常与 -t 同时使用;
    • -P: 随机端口映射,容器内部端口随机映射到主机的端口
    • -p: 指定端口映射,格式为:主机(宿主)端口:容器端口
    • -t: 为容器重新分配一个伪输入终端,通常与 -i 同时使用;
    • —name=”nginx-lb”: 为容器指定一个名称;
    • —dns 8.8.8.8: 指定容器使用的DNS服务器,默认和宿主一致;
    • —dns-search example.com: 指定容器DNS搜索域名,默认和宿主一致;
    • -h “mars”: 指定容器的hostname;
    • -e username=”ritchie”: 设置环境变量;
    • —env-file=[]: 从指定文件读入环境变量;
    • —cpuset=”0-2” or —cpuset=”0,1,2”: 绑定容器到指定CPU运行;
    • -m :设置容器使用内存最大值;
    • —net=”bridge”: 指定容器的网络连接类型,支持 bridge/host/none/container: 四种类型;
    • —link=[]: 添加链接到另一个容器;
    • —expose=[]: 开放一个端口或一组端口;
    • —volume , -v: 绑定一个卷
  2. 实例

    使用docker镜像nginx:latest以后台模式启动一个容器,并将容器命名为mynginx。

    1
    docker run --name mynginx -d nginx:latest

    使用镜像nginx:latest以后台模式启动一个容器,并将容器的80端口映射到主机随机端口。

    1
    docker run -P -d nginx:latest

    使用镜像 nginx:latest,以后台模式启动一个容器,将容器的 80 端口映射到主机的 80 端口,主机的目录 /data 映射到容器的 /data。

    1
    docker run -p 80:80 -v /data:/data -d nginx:latest

    绑定容器的 8080 端口,并将其映射到本地主机 127.0.0.1 的 80 端口上。

    1
    $ docker run -p 127.0.0.1:80:8080/tcp ubuntu bash

    使用镜像nginx:latest以交互模式启动一个容器,在容器内执行/bin/bash命令。

    1
    2
    [root@localhost DockerTest]# docker run -it nginx:latest /bin/bash
    root@9f7e293c70ab:/#

    在 Docker 容器退出时,默认容器内部的文件系统仍然被保留,以方便调试并保留用户数据。

    但是,对于 foreground 容器,由于其只是在开发调试过程中短期运行,其用户数据并无保留的必要,因而可以在容器启动时设置 —rm 选项,这样在容器退出时就能够自动清理容器内部的文件系统。

    1
    docker run --rm yanpenggong1

    1
    docker run --rm=true yanpenggong1

    ==注意==:—rm 选项不能与 -d 同时使用(或者说同时使用没有意义),即只能自动清理 foreground 容器,不能自动清理detached容器。

    ==注意==,—rm 选项也会清理容器的匿名data volumes。

    执行 docker run 命令带 —rm命令选项,等价于在容器退出后,执行 docker rm -v

11.1.2 start|stop|restart

  1. 语法

    • 启动一个或多个已经被停止的容器

      1
      docker start [OPTIONS] CONTAINER [CONTAINER...]
    • 停止一个运行中的容器

      1
      docker stop [OPTIONS] CONTAINER [CONTAINER...]
    • 重启容器

      1
      docker restart [OPTIONS] CONTAINER [CONTAINER...]
  2. 实例

    • 启动已被停止的容器 yanpenggong1

      1
      docker start yanpenggong1
    • 停止运行中的容器 yanpenggong1

      1
      docker stop yanpenggong1
    • 重启容器 yanpenggong1

      1
      docker restart yanpenggong1

11.1.3 kill

杀掉一个运行中的容器

  1. 语法

    1
    docker kill [OPTIONS] CONTAINER [CONTAINER...]

    OPTIONS说明:

    • -s : 向容器发送一个信号
  2. 实例

    杀掉运行中的容器mynginx

    1
    2
    [root@localhost DockerTest]# docker kill -s KILL mynginx
    mynginx

11.1.4 rm

删除一个或多个容器

  1. 语法

    1
    docker rm [OPTIONS] CONTAINER [CONTAINER...]

    OPTIONS说明:

    • -f : 通过 SIGKILL 信号强制删除一个运行中的容器。
    • -l : 移除容器间的网络连接,而非容器本身。
    • -v : 删除与容器关联的卷。
  2. 实例

    • 强制删除容器 db01、db02:

      1
      docker rm -f db01 db02
    • 移除容器 nginx01 对容器 db01 的连接,连接名 db:

      1
      docker rm -l db 
    • 删除容器 nginx01, 并删除容器挂载的数据卷:

      1
      docker rm -v nginx01
  • 删除所有已经停止的容器:

    1
    docker rm $(docker ps -a -q)

11.1.5 pause|unpause

  1. 语法

    • 暂停容器中所有的进程。

      1
      docker pause CONTAINER [CONTAINER...]
    • 恢复容器中所有的进程。

      1
      docker unpause CONTAINER [CONTAINER...]
  2. 实例

    • 暂停数据库容器db01提供服务。

      1
      docker pause db01
    • 恢复数据库容器 db01 提供服务。

      1
      docker unpause db01

11.1.6 create

创建一个新的容器但不启动它

用法同 docker run

  1. 语法

    1
    docker create [OPTIONS] IMAGE [COMMAND] [ARG...]
  2. 实例

    使用docker镜像 nginx:latest 创建一个容器,并将容器命名为yanpenggong1

    1
    2
    3
    [root@localhost DockerTest]# docker create  --name yanpenggong1  nginx:latest
    ab1aa65cb3d1d6180de62b890a9caddaada09e8edaf43f1facd3872eb1053784
    [root@localhost DockerTest]#

11.1.7 exec

在运行的容器中执行命令

  1. 语法

    1
    docker exec [OPTIONS] CONTAINER COMMAND [ARG...]

    OPTIONS说明:

    • -d :分离模式: 在后台运行
    • -i :即使没有附加也保持STDIN 打开
    • -t :分配一个伪终端
  2. 实例

    前期准备工作:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    [root@localhost DockerTest]# docker exec -it yanpenggong1 /bin/bash
    root@ab1aa65cb3d1:/# apt-get update
    ...
    root@ab1aa65cb3d1:/# apt-get upgrade
    Reading package lists... Done
    Building dependency tree... Done
    Reading state information... Done
    Calculating upgrade... Done
    0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
    root@ab1aa65cb3d1:/# apt-get install vim
    ...
    root@ab1aa65cb3d1:/# vim /root/yanpenggong.sh
    root@ab1aa65cb3d1:/# cat /root/yanpenggong.sh
    echo "Welcome yanpenggong, Come on!"

    在容器 mynginx 中以交互模式执行容器内 /root/yanpenggong1.sh 脚本:

    1
    2
    3
    [root@localhost DockerTest]# docker exec -it yanpenggong1 /bin/bash /root/yanpenggong.sh
    Welcome yanpenggong, Come on!
    [root@localhost DockerTest]#

    在容器 mynginx 中开启一个交互模式的终端:

    1
    2
    [root@localhost DockerTest]# docker exec -it yanpenggong1 /bin/bash
    root@ab1aa65cb3d1:/#

    也可以通过 docker ps -a 命令查看已经在运行的容器,然后使用容器 ID 进入容器。

    查看已经在运行的容器 ID:

    1
    2
    3
    4
    5
    6
    [root@localhost DockerTest]# docker ps -a 
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS
    ...
    ab1aa65cb3d1 nginx:latest "/docker-entrypoint.…" 2 hours ago Up 30 minutes 80/tcp yanpenggong1
    ...
    [root@localhost DockerTest]#

    第一列的 ab1aa65cb3d1 就是容器 ID。

    通过 exec 命令对指定的容器执行 bash:

    1
    2
    [root@localhost DockerTest]# docker exec -it ab1aa65cb3d1 /bin/bash
    root@ab1aa65cb3d1:/#

11.2 容器操作

11.2.1 ps

列出容器

  1. 语法

    1
    docker ps [OPTIONS]

    OPTIONS说明:

    • -a :显示所有的容器,包括未运行的。

    • -f :根据条件过滤显示的内容。

  • —format :指定返回值的模板文件。

  • -l :显示最近创建的容器。

  • -n :列出最近创建的n个容器。

  • —no-trunc :不截断输出。

  • -q :静默模式,只显示容器编号。

  • -s :显示总的文件大小。

  1. 实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    [root@localhost DockerTest]# docker ps
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    565fab9cc1d6 nginx "/docker-entrypoint.…" 2 hours ago Up 2 hours 80/tcp, 0.0.0.0:8000->8000/tcp, :::8000->8000/tcp nginx-yanpenggong
    ab1aa65cb3d1 nginx:latest "/docker-entrypoint.…" 2 hours ago Up 45 minutes 80/tcp yanpenggong1
    d4048088ff57 php:8.2.1-fpm "docker-php-entrypoi…" 19 hours ago Up 19 hours 9000/tcp myphp-fpm
    5c3af81aab8d node "docker-entrypoint.s…" 21 hours ago Up 21 hours node-test
    5f1b0abb64ab nginx "/docker-entrypoint.…" 22 hours ago Up 22 hours 0.0.0.0:8080->80/tcp, :::8080->80/tcp nginx-test
    81cbdd935383 centos:centos7 "/bin/bash" 22 hours ago Up 22 hours centos-test
    c281416b5c63 ubuntu "bash" 22 hours ago Up 22 hours ubuntu-test1
    [root@localhost DockerTest]#

    输出详情介绍:

    • CONTAINER ID: 容器 ID。

    • IMAGE: 使用的镜像。

    • COMMAND: 启动容器时运行的命令。

    • CREATED: 容器的创建时间。

    • STATUS: 容器状态。状态有7种:

      • created(已创建)

      • restarting(重启中)

      • running(运行中)

      • removing(迁移中)

      • paused(暂停)

      • exited(停止)

      • dead(死亡)

    • PORTS: 容器的端口信息和使用的连接类型(tcp\udp)。

    • NAMES: 自动分配的容器名称。

    列出最近创建的5个容器信息。

    1
    2
    3
    4
    5
    6
    7
    8
    [root@localhost DockerTest]# docker ps -n 5
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    565fab9cc1d6 nginx "/docker-entrypoint.…" 2 hours ago Up 2 hours 80/tcp, 0.0.0.0:8000->8000/tcp, :::8000->8000/tcp nginx-yanpenggong
    e7ed1ae97d71 nginx:latest "/docker-entrypoint.…" 2 hours ago Exited (0) 2 hours ago friendly_pascal
    ab1aa65cb3d1 nginx:latest "/docker-entrypoint.…" 2 hours ago Up 46 minutes 80/tcp yanpenggong1
    9ee8936ebfb4 nginx:latest "/docker-entrypoint.…" 2 hours ago Exited (0) 2 hours ago cool_herschel
    9f7e293c70ab nginx:latest "/docker-entrypoint.…" 2 hours ago Exited (127) 2 hours ago angry_liskov
    [root@localhost DockerTest]#

    列出所有创建的容器ID。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    [root@localhost DockerTest]# docker ps -a -q
    565fab9cc1d6
    e7ed1ae97d71
    ab1aa65cb3d1
    9ee8936ebfb4
    9f7e293c70ab
    e9ec935b0a03
    d4048088ff57
    5c3af81aab8d
    5f1b0abb64ab
    81cbdd935383
    c281416b5c63
    [root@localhost DockerTest]#

    根据条件过滤显示的内容:

    • 根据标签过滤

      1
      2
      3
      4
      5
      6
      7
      8
      9
      [root@localhost DockerTest]# docker run -d --name=nginx-labelset --label color=blue nginx
      76febf58a85a95ae00dc36ac7397fa4b95e666090686a02dc5e1e9d344b5da38
      [root@localhost DockerTest]# docker ps --filter "label=color"
      CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
      76febf58a85a nginx "/docker-entrypoint.…" 22 seconds ago Up 21 seconds 80/tcp nginx-labelset
      [root@localhost DockerTest]# docker ps --filter "label=color=blue"
      CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
      76febf58a85a nginx "/docker-entrypoint.…" 28 seconds ago Up 27 seconds 80/tcp nginx-labelset
      [root@localhost DockerTest]#
    • 根据名称过滤

      1
      2
      3
      4
      [root@localhost DockerTest]# docker ps --filter "name=nginx-labelset"
      CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
      76febf58a85a nginx "/docker-entrypoint.…" About a minute ago Up About a minute 80/tcp nginx-labelset
      [root@localhost DockerTest]#
    • 根据状态过滤

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      [root@localhost DockerTest]# docker ps -a --filter "exited=0"
      CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
      e7ed1ae97d71 nginx:latest "/docker-entrypoint.…" 2 hours ago Exited (0) 2 hours ago friendly_pascal
      9ee8936ebfb4 nginx:latest "/docker-entrypoint.…" 2 hours ago Exited (0) 2 hours ago cool_herschel
      [root@localhost DockerTest]# docker ps --filter status=running
      CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
      76febf58a85a nginx "/docker-entrypoint.…" 3 minutes ago Up 3 minutes 80/tcp nginx-labelset
      565fab9cc1d6 nginx "/docker-entrypoint.…" 2 hours ago Up 2 hours 80/tcp, 0.0.0.0:8000->8000/tcp, :::8000->8000/tcp nginx-yanpenggong
      ab1aa65cb3d1 nginx:latest "/docker-entrypoint.…" 2 hours ago Up 51 minutes 80/tcp yanpenggong1
      d4048088ff57 php:8.2.1-fpm "docker-php-entrypoi…" 19 hours ago Up 19 hours 9000/tcp myphp-fpm
      5c3af81aab8d node "docker-entrypoint.s…" 22 hours ago Up 22 hours node-test
      5f1b0abb64ab nginx "/docker-entrypoint.…" 22 hours ago Up 22 hours 0.0.0.0:8080->80/tcp, :::8080->80/tcp nginx-test
      81cbdd935383 centos:centos7 "/bin/bash" 22 hours ago Up 22 hours centos-test
      c281416b5c63 ubuntu "bash" 22 hours ago Up 22 hours ubuntu-test1
      [root@localhost DockerTest]# docker ps --filter status=paused
      CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
      [root@localhost DockerTest]#
    • 根据镜像过滤

      • 镜像名称

        1
        2
        3
        [root@localhost DockerTest]# docker ps --filter ancestor=yanpenggong1
        CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
        [root@localhost DockerTest]#
      • 镜像ID

        1
        2
        3
        [root@localhost DockerTest]# docker ps --filter ancestor=ab1aa65cb3d1
        CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
        [root@localhost DockerTest]#
    • 根据启动顺序过滤

      1
      2
      [root@localhost DockerTest]# docker ps --filter before=565fab9cc1d6
      [root@localhost DockerTest]# docker ps --filter since=565fab9cc1d6

11.2.2 inspect

获取容器/镜像的元数据。

  1. 语法

    1
    docker inspect [OPTIONS] NAME|ID [NAME|ID...]

    OPTIONS说明:

    • -f :指定返回值的模板文件。
    • -s :显示总的文件大小。
    • —type :为指定类型返回 JSON。
  2. 实例

    获取镜像 mysql:5.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
    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
    [root@localhost DockerTest]# docker inspect mysql:5.7
    [
    {
    "Id": "sha256:e982339a20a53052bd5f2b2e8438b3c95c91013f653ee781a67934cd1f9f9631",
    "RepoTags": [
    "mysql:5.7"
    ],
    "RepoDigests": [
    "mysql@sha256:f04fc2e2f01e65d6e2828b4cce2c4761d9258aee71d989e273b2ae309f44a945"
    ],
    "Parent": "",
    "Comment": "",
    "Created": "2023-01-17T21:08:43.190102558Z",
    "Container": "0986b6641b52d0f008c86df95549764df209daf54453c8ae1585823822ea24e7",
    "ContainerConfig": {
    "Hostname": "0986b6641b52",
    "Domainname": "",
    "User": "",
    "AttachStdin": false,
    "AttachStdout": false,
    "AttachStderr": false,
    "ExposedPorts": {
    "3306/tcp": {},
    "33060/tcp": {}
    },
    "Tty": false,
    "OpenStdin": false,
    "StdinOnce": false,
    "Env": [
    "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
    "GOSU_VERSION=1.14",
    "MYSQL_MAJOR=5.7",
    "MYSQL_VERSION=5.7.41-1.el7",
    "MYSQL_SHELL_VERSION=8.0.32-1.el7"
    ],
    "Cmd": [
    "/bin/sh",
    "-c",
    "#(nop) ",
    "CMD [\"mysqld\"]"
    ],
    "Image": "sha256:dbef667589a9b91b3a5c92717cd272365c6af916b218e357277837b0f447e3e3",
    "Volumes": {
    "/var/lib/mysql": {}
    },
    "WorkingDir": "",
    "Entrypoint": [
    "docker-entrypoint.sh"
    ],
    "OnBuild": null,
    "Labels": {}
    },
    "DockerVersion": "20.10.12",
    "Author": "",
    "Config": {
    "Hostname": "",
    "Domainname": "",
    "User": "",
    "AttachStdin": false,
    "AttachStdout": false,
    "AttachStderr": false,
    "ExposedPorts": {
    "3306/tcp": {},
    "33060/tcp": {}
    },
    "Tty": false,
    "OpenStdin": false,
    "StdinOnce": false,
    "Env": [
    "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
    "GOSU_VERSION=1.14",
    "MYSQL_MAJOR=5.7",
    "MYSQL_VERSION=5.7.41-1.el7",
    "MYSQL_SHELL_VERSION=8.0.32-1.el7"
    ],
    "Cmd": [
    "mysqld"
    ],
    "Image": "sha256:dbef667589a9b91b3a5c92717cd272365c6af916b218e357277837b0f447e3e3",
    "Volumes": {
    "/var/lib/mysql": {}
    },
    "WorkingDir": "",
    "Entrypoint": [
    "docker-entrypoint.sh"
    ],
    "OnBuild": null,
    "Labels": null
    },
    "Architecture": "amd64",
    "Os": "linux",
    "Size": 451547844,
    "VirtualSize": 451547844,
    "GraphDriver": {
    "Data": {
    "LowerDir": "/var/lib/docker/overlay2/ef0961e2e6aab1506df05b62e97e01d08e701b726b54537b24b9c4c16c024b2a/diff:/var/lib/docker/overlay2/614ebd76596a654735feb8e2f02179b830dc01e18fc73ff51ba369eb9d4305f1/diff:/var/lib/docker/overlay2/beff48d6417ae0ec536cf6885716e36cba4816b436419774c952e6c975d286a2/diff:/var/lib/docker/overlay2/c4877779ab5e00499e5a0cbf2e316c3ff3067a5355ee24d2b249564c15f5650e/diff:/var/lib/docker/overlay2/b1804f8b6eab76ec28f336e6deba72d9d6b081732f77774dd64ae60f6ccd6ca6/diff:/var/lib/docker/overlay2/fde9ec916ffc6d5a4eb7002f98541a1a5e1512e247ba1c6dcd0209cad5583957/diff:/var/lib/docker/overlay2/41e4c8924e80a6a72a376bc9a3be6ae1fde0874652918e5c5fd803e023c18845/diff:/var/lib/docker/overlay2/ad8ede93da1142c1dc043658204ab5fd2402b8fd2a24ce921406e3fa8e3a1987/diff:/var/lib/docker/overlay2/63d5fabc079fd5e454df0710c2dcbb2ee39d190c44f97a84016fc133ea9ac25f/diff:/var/lib/docker/overlay2/cc89d6ef19a9bbf01a30cc7b5eb97142cc9239359ceb99545c1a770360aea90a/diff",
    "MergedDir": "/var/lib/docker/overlay2/c310ac5e33624289534acb8d52701991e2342bad5a12698f493858d666aa3d6e/merged",
    "UpperDir": "/var/lib/docker/overlay2/c310ac5e33624289534acb8d52701991e2342bad5a12698f493858d666aa3d6e/diff",
    "WorkDir": "/var/lib/docker/overlay2/c310ac5e33624289534acb8d52701991e2342bad5a12698f493858d666aa3d6e/work"
    },
    "Name": "overlay2"
    },
    "RootFS": {
    "Type": "layers",
    "Layers": [
    "sha256:62d9c4cbe8f4b26952ebb533b5336bf7af791db2b4288df65c9a685e1f2530cd",
    "sha256:49769e21013b6fea06035a5dcdbed32ce7c17b66b8a19eab8ce626a492d4e045",
    "sha256:1a26f263a6af50cde950eb9059948fbc1ae332b27d4f248064838e8233d98781",
    "sha256:1ab9edd16f9eb635e5240ae4167f8556b742f3b95047c98d43893f2e2bffe064",
    "sha256:56a71f69f1a80e8e96b53f062f47abb507c71dd418a8cf9037dd141e45dd2b96",
    "sha256:45968403dd22f9dfd92bc4c0a3349a0919abe64a62ebf85ecd3dbc386e17b15d",
    "sha256:f4bb02745d0337d503a510f28b98ac101bb9916eff4bd51b6ea108fffc01b567",
    "sha256:c1f1b5039e40f8c152f16f83d2bd382aea116e5d26779096dfb87a612f4366c8",
    "sha256:e974776afbe2457e7c63f3d6b8c66aa4942414252d5af613904eacb11d0f4b44",
    "sha256:868b2e381adfd7f4f912f3add73f60e9ec7f3c18937d7f08ffec29d60a24b0e7",
    "sha256:5c542b9ec644bfc9eeace71cf555f9b7ca6ad7e657eb7863aebc1367e1b101d7"
    ]
    },
    "Metadata": {
    "LastTagTime": "0001-01-01T00:00:00Z"
    }
    }
    ]
    [root@localhost DockerTest]#

    获取正在运行的容器 mysql-test 的 IP,注意这里mysql-test是容器名称。

    1
    2
    3
    [root@localhost DockerTest]# docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' mysql-test
    172.17.0.10
    [root@localhost DockerTest]#

11.2.3 top

查看容器中运行的进程信息,支持 ps 命令参数。

  1. 语法

    1
    docker top [OPTIONS] CONTAINER [ps OPTIONS]

    容器运行时不一定有/bin/bash终端来交互执行top命令,而且容器还不一定有top命令,可以使用docker top来实现查看 container 中正在运行的进程。

  2. 实例

    查看容器mysql-test 的进程信息。

    1
    2
    3
    4
    [root@localhost DockerTest]# docker top mysql-test
    UID PID PPID C STIME TTY TIME CMD
    polkitd 42708 42687 0 00:43 pts/0 00:00:09 mysqld
    [root@localhost DockerTest]#

    查看所有运行容器的进程信息。

    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
    [root@localhost DockerTest]# for i in  `docker ps |grep Up|awk '{print $1}'`;do echo \ &&docker top $i; done

    UID PID PPID C STIME TTY TIME CMD
    polkitd 42708 42687 0 00:43 pts/0 00:00:09 mysqld

    UID PID PPID C STIME TTY TIME CMD
    root 39930 39910 0 Jan17 ? 00:00:00 nginx: master process nginx -g daemon off;
    101 39980 39930 0 Jan17 ? 00:00:00 nginx: worker process
    101 39981 39930 0 Jan17 ? 00:00:00 nginx: worker process

    UID PID PPID C STIME TTY TIME CMD
    root 34104 34083 0 Jan17 ? 00:00:00 nginx: master process nginx -g daemon off;
    101 34173 34104 0 Jan17 ? 00:00:00 nginx: worker process
    101 34174 34104 0 Jan17 ? 00:00:00 nginx: worker process

    UID PID PPID C STIME TTY TIME CMD
    root 36525 36505 0 Jan17 ? 00:00:00 nginx: master process nginx -g daemon off;
    101 36575 36525 0 Jan17 ? 00:00:00 nginx: worker process
    101 36576 36525 0 Jan17 ? 00:00:00 nginx: worker process

    UID PID PPID C STIME TTY TIME CMD
    root 31274 31254 0 Jan17 ? 00:00:08 php-fpm: master process (/usr/local/etc/php-fpm.conf)
    33 31320 31274 0 Jan17 ? 00:00:00 php-fpm: pool www
    33 31321 31274 0 Jan17 ? 00:00:00 php-fpm: pool www

    UID PID PPID C STIME TTY TIME CMD
    root 23383 23361 0 Jan17 pts/0 00:00:00 node

    UID PID PPID C STIME TTY TIME CMD
    root 22888 22868 0 Jan17 ? 00:00:00 nginx: master process nginx -g daemon off;
    101 22952 22888 0 Jan17 ? 00:00:00 nginx: worker process
    101 22953 22888 0 Jan17 ? 00:00:00 nginx: worker process

    UID PID PPID C STIME TTY TIME CMD
    root 22489 22469 0 Jan17 pts/0 00:00:00 /bin/bash

    UID PID PPID C STIME TTY TIME CMD
    root 22094 22073 0 Jan17 pts/0 00:00:00 bash
    [root@localhost DockerTest]#

11.2.4 attach/exec

连接到正在运行中的容器。

  1. 语法

    1
    docker attach [OPTIONS] CONTAINER

    attach 上去的容器必须正在运行,可以同时连接上同一个container来共享屏幕(与screen命令的attach类似)。

    官方文档中说attach后可以通过CTRL-C来detach,但实际上经过我的测试,如果container当前在运行bash,CTRL-C自然是当前行的输入,没有退出;如果container当前正在前台运行进程,如输出nginx的access.log日志,CTRL-C不仅会导致退出容器,而且还stop了。这不是我们想要的,detach的意思按理应该是脱离容器终端,但容器依然运行。好在attach是可以带上--sig-proxy=false来确保CTRL-DCTRL-C不会关闭容器。

  2. 实例

    容器mynginx将访问日志指到标准输出,连接到容器查看访问信息。

    当docker容器在 “-d”守护态运行的时候,比如通过supervisord控制两个程序非守护态运行:
    ssh -D
    tomcat
    那么这个时候,用户就无法直接进入到容器中去,docker attach 容器id 就会一直卡着。
    因为此时容器运行的进程是ssh,而不是/bin/bash 也没有虚拟终端(-it)参数,所以是进入不到的,
    那么这种情况下,该如何attach进去并进入到一个/bin/bash里呢?

    ==可以用docker exec -it containerID /bin/bash方式进入容器==

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    [root@localhost DockerTest]# docker ps
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    d5a81f38372c mysql:5.7 "docker-entrypoint.s…" 3 hours ago Up 16 seconds 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp mysql-test
    76febf58a85a nginx "/docker-entrypoint.…" 5 hours ago Up 5 hours 80/tcp nginx-labelset
    565fab9cc1d6 nginx "/docker-entrypoint.…" 7 hours ago Up 7 hours 80/tcp, 0.0.0.0:8000->8000/tcp, :::8000->8000/tcp nginx-yanpenggong
    ab1aa65cb3d1 nginx:latest "/docker-entrypoint.…" 7 hours ago Up 5 hours 80/tcp yanpenggong1
    d4048088ff57 php:8.2.1-fpm "docker-php-entrypoi…" 24 hours ago Up 24 hours 9000/tcp myphp-fpm
    5c3af81aab8d node "docker-entrypoint.s…" 26 hours ago Up 26 hours node-test
    5f1b0abb64ab nginx "/docker-entrypoint.…" 26 hours ago Up 26 hours 0.0.0.0:8080->80/tcp, :::8080->80/tcp nginx-test
    81cbdd935383 centos:centos7 "/bin/bash" 26 hours ago Up 26 hours centos-test
    c281416b5c63 ubuntu "bash" 27 hours ago Up 27 hours
    [root@localhost DockerTest]# docker exec -it d5a81f38372c /bin/bash
    bash-4.2# exit
    exit
    [root@localhost DockerTest]# docker exec -it mysql-test /bin/bash
    bash-4.2#

11.2.5 events

从服务器获取实时事件

  1. 语法

    1
    docker events [OPTIONS]

    OPTIONS说明:

    • -f :根据条件过滤事件;
    • —since :从指定的时间戳后显示所有事件;
    • —until :流水时间显示到指定的时间为止;
  2. 实例

    • 显示docker 2016年7月1日后的所有事件。

      1
      2
      3
      4
      5
      6
      [root@localhost DockerTest]# docker events  --since="1467302400"
      2023-01-17T00:36:22.632702912-05:00 image untag sha256:157dcdf23d6c0ebe14bedd910dfa29d224f75ed104757c7866fa708eaefd16de (name=sha256:157dcdf23d6c0ebe14bedd910dfa29d224f75ed104757c7866fa708eaefd16de)
      2023-01-17T00:36:22.725821259-05:00 image delete sha256:157dcdf23d6c0ebe14bedd910dfa29d224f75ed104757c7866fa708eaefd16de (name=sha256:157dcdf23d6c0ebe14bedd910dfa29d224f75ed104757c7866fa708eaefd16de)
      2023-01-17T00:36:53.327637992-05:00 image untag sha256:6fae60ef344644649a39240b94d73b8ba9c67f898ede85cf8e947a887b3e6557 (name=sha256:6fae60ef344644649a39240b94d73b8ba9c67f898ede85cf8e947a887b3e6557)
      2023-01-17T00:36:54.752238644-05:00 image delete sha256:6fae60ef344644649a39240b94d73b8ba9c67f898ede85cf8e947a887b3e6557 (name=sha256:6fae60ef344644649a39240b94d73b8ba9c67f898ede85cf8e947a887b3e6557)
      ...
    • 显示docker 镜像为mysql:5.6 2016年7月1日后的相关事件。

      1
      2
      3
      4
      5
      6
      7
      [root@localhost DockerTest]# docker events  --since="1467302400"
      2023-01-17T00:36:22.632702912-05:00 image untag sha256:157dcdf23d6c0ebe14bedd910dfa29d224f75ed104757c7866fa708eaefd16de (name=sha256:157dcdf23d6c0ebe14bedd910dfa29d224f75ed104757c7866fa708eaefd16de)
      2023-01-17T00:36:22.725821259-05:00 image delete sha256:157dcdf23d6c0ebe14bedd910dfa29d224f75ed104757c7866fa708eaefd16de (name=sha256:157dcdf23d6c0ebe14bedd910dfa29d224f75ed104757c7866fa708eaefd16de)
      2023-01-17T00:36:53.327637992-05:00 image untag sha256:6fae60ef344644649a39240b94d73b8ba9c67f898ede85cf8e947a887b3e6557 (name=sha256:6fae60ef344644649a39240b94d73b8ba9c67f898ede85cf8e947a887b3e6557)
      2023-01-17T00:36:54.752238644-05:00 image delete sha256:6fae60ef344644649a39240b94d73b8ba9c67f898ede85cf8e947a887b3e6557 (name=sha256:6fae60ef344644649a39240b94d73b8ba9c67f898ede85cf8e947a887b3e6557)
      2023-01-17T00:37:43.600321934-05:00 container destroy 795555d12b2a0c537b6d8a972241a1f24a27538b241b25afa13c4c45637389de (com.docker.compose.config-hash=ae53e06d500b53a458b03065a6c547dcb1f49fca00638ae785ee3a2f3bbb81eb, com.docker.compose.container-number=1, com.docker.compose.depends_on=, com.docker.compose.image=sha256:8ace02fae412cc7d1ac5b7a10f7f5b7b2a1e1ae6bdc31a92a190a1a8415d412b, com.docker.compose.oneoff=False, com.docker.compose.project=composetest, com.docker.compose.project.config_files=/root/yanpenggong/DEMO/DockerTest/composeTest/docker-compose.yml, com.docker.compose.project.working_dir=/root/yanpenggong/DEMO/DockerTest/composeTest, com.docker.compose.service=redis, com.docker.compose.version=2.14.0, image=redis:alpine, name=composetest-redis-1)
      ...

    如果指定的时间是到秒级的,需要将时间转成时间戳。如果时间为日期的话,可以直接使用,如—since=”2016-07-01”。

    1
    2
    3
    4
    5
    6
    7
    [root@localhost DockerTest]# docker events -f "image"="mysql:5.7" --since="2016-07-01" 
    2023-01-18T00:39:41.140668490-05:00 image pull mysql:5.7 (name=mysql)
    2023-01-18T00:39:41.682132231-05:00 container create f318356c965ba6403e095fe456b63f6172d475ba1097476d4e30beff7246e58d (image=mysql:5.7, name=stupefied_banach)
    2023-01-18T00:39:42.003726040-05:00 container start f318356c965ba6403e095fe456b63f6172d475ba1097476d4e30beff7246e58d (image=mysql:5.7, name=stupefied_banach)
    2023-01-18T00:39:42.439945201-05:00 container die f318356c965ba6403e095fe456b63f6172d475ba1097476d4e30beff7246e58d (exitCode=1, image=mysql:5.7, name=stupefied_banach)
    2023-01-18T00:40:37.076467617-05:00 container start f318356c965ba6403e095fe456b63f6172d475ba1097476d4e30beff7246e58d (image=mysql:5.7, name=stupefied_banach)
    ...

11.2.6 logs

获取容器的日志

  1. 语法

    1
    docker logs [OPTIONS] CONTAINER

    OPTIONS说明:

    • -f : 跟踪日志输出
    • —since :显示某个开始时间的所有日志
    • -t : 显示时间戳
    • —tail :仅列出最新N条容器日志
  2. 实例

    跟踪查看容器mysql-test 的日志输出。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    [root@localhost DockerTest]# docker logs -f mysql-test
    2023-01-18 05:43:33+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 5.7.41-1.el7 started.
    2023-01-18 05:43:34+00:00 [Note] [Entrypoint]: Switching to dedicated user 'mysql'
    2023-01-18 05:43:34+00:00 [Note] [Entrypoint]: Entrypoint script for MySQL Server 5.7.41-1.el7 started.
    2023-01-18 05:43:34+00:00 [Note] [Entrypoint]: Initializing database files
    2023-01-18T05:43:34.342035Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
    2023-01-18T05:43:34.580669Z 0 [Warning] InnoDB: New log files created, LSN=45790
    2023-01-18T05:43:34.613971Z 0 [Warning] InnoDB: Creating foreign key constraint system tables.
    2023-01-18T05:43:34.679346Z 0 [Warning] No existing UUID has been found, so we assume that this is the first time that this server has been started. Generating a new UUID: 0c59ef46-96f3-11ed-adba-0242ac11000a.
    2023-01-18T05:43:34.680219Z 0 [Warning] Gtid table is not ready to be used. Table 'mysql.gtid_executed' cannot be opened.
    2023-01-18T05:43:34.769058Z 0 [Warning] A deprecated TLS version TLSv1 is enabled. Please use TLSv1.2 or higher.
    2023-01-18T05:43:34.769079Z 0 [Warning] A deprecated TLS version TLSv1.1 is enabled. Please use TLSv1.2 or higher.
    2023-01-18T05:43:34.769519Z 0 [Warning] CA certificate ca.pem is self signed.
    2023-01-18T05:43:34.832020Z 1 [Warning] root@localhost is created with an empty password ! Please consider switching off the --initialize-insecure option.
    2023-01-18 05:43:36+00:00 [Note] [Entrypoint]: Database files initialized
    2023-01-18 05:43:36+00:00 [Note] [Entrypoint]: Starting temporary server
    2023-01-18 05:43:36+00:00 [Note] [Entrypoint]: Waiting for server startup
    2023-01-18T05:43:36.752707Z 0 [Warning] TIMESTAMP with implicit DEFAULT value is deprecated. Please use --explicit_defaults_for_timestamp server option (see documentation for more details).
    2023-01-18T05:43:36.754485Z 0 [Note] mysqld (mysqld 5.7.41) starting as process 124 ...
    2023-01-18T05:43:36.757512Z 0 [Note] InnoDB: PUNCH HOLE support available
    2023-01-18T05:43:36.757535Z 0 [Note] InnoDB: Mutexes and rw_locks use GCC atomic builtins
    2023-01-18T05:43:36.757538Z 0 [Note] InnoDB: Uses event mutexes
    ...

    查看容器mysql-test 从2016年7月1日后的最新10条日志。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    [root@localhost DockerTest]# docker logs --since="2022-12-30" --tail=10 mysql-test
    2023-01-18T08:42:41.892365Z 0 [Warning] CA certificate ca.pem is self signed.
    2023-01-18T08:42:41.892405Z 0 [Note] Skipping generation of RSA key pair as key files are present in data directory.
    2023-01-18T08:42:41.892692Z 0 [Note] Server hostname (bind-address): '*'; port: 3306
    2023-01-18T08:42:41.892740Z 0 [Note] IPv6 is available.
    2023-01-18T08:42:41.892749Z 0 [Note] - '::' resolves to '::';
    2023-01-18T08:42:41.892771Z 0 [Note] Server socket created on IP: '::'.
    2023-01-18T08:42:41.894066Z 0 [Warning] Insecure configuration for --pid-file: Location '/var/run/mysqld' in the path is accessible to all OS users. Consider choosing a different directory.
    2023-01-18T08:42:41.901316Z 0 [Note] Event Scheduler: Loaded 0 events
    2023-01-18T08:42:41.901805Z 0 [Note] mysqld: ready for connections.
    Version: '5.7.41' socket: '/var/run/mysqld/mysqld.sock' port: 3306 MySQL Community Server (GPL)
    [root@localhost DockerTest]#

11.2.7 wait

阻塞运行直到容器停止,然后打印出它的退出代码。

  1. 语法

    1
    docker wait [OPTIONS] CONTAINER [CONTAINER...]
  2. 实例

    1
    2
    3
    [root@localhost DockerTest]# docker wait mysql-test
    0
    [root@localhost DockerTest]#

    注意:这里在运行停止容器后才会出现返回的0

11.2.8 export

将文件系统作为一个tar归档文件导出到 STDOUT

  1. 语法

    1
    docker export [OPTIONS] CONTAINER

    OPTIONS说明:

    • -o :将输入内容写到文件。
  2. 实例

    将id为d5a81f38372c的容器按日期保存为tar文件。在本地会发现多了一个mysql-20230118.tar文件。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    [root@localhost DockerTest]# docker ps 
    CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
    d5a81f38372c mysql:5.7 "docker-entrypoint.s…" 4 hours ago Up 1 second 0.0.0.0:3306->3306/tcp, :::3306->3306/tcp, 33060/tcp mysql-test
    76febf58a85a nginx "/docker-entrypoint.…" 5 hours ago Up 5 hours 80/tcp nginx-labelset
    565fab9cc1d6 nginx "/docker-entrypoint.…" 7 hours ago Up 7 hours 80/tcp, 0.0.0.0:8000->8000/tcp, :::8000->8000/tcp nginx-yanpenggong
    ab1aa65cb3d1 nginx:latest "/docker-entrypoint.…" 7 hours ago Up 6 hours 80/tcp yanpenggong1
    d4048088ff57 php:8.2.1-fpm "docker-php-entrypoi…" 24 hours ago Up 24 hours 9000/tcp myphp-fpm
    5c3af81aab8d node "docker-entrypoint.s…" 27 hours ago Up 27 hours node-test
    5f1b0abb64ab nginx "/docker-entrypoint.…" 27 hours ago Up 27 hours 0.0.0.0:8080->80/tcp, :::8080->80/tcp nginx-test
    81cbdd935383 centos:centos7 "/bin/bash" 27 hours ago Up 27 hours centos-test
    c281416b5c63 ubuntu "bash" 28 hours ago Up 28 hours ubuntu-test1
    [root@localhost DockerTest]# docker export -o mysql-`date +%Y%m%d`.tar d5a81f38372c
    [root@localhost DockerTest]#

11.2.9 port

用于列出指定的容器的端口映射,或者查找将 PRIVATE_PORT NAT 到面向公众的端口。

  1. 语法

    1
    docker port [OPTIONS] CONTAINER [PRIVATE_PORT[/PROTO]]
  2. 实例

    查看容器 mysql-test 的端口映射情况:

    1
    2
    3
    4
    [root@localhost DockerTest]# docker port mysql-test
    3306/tcp -> 0.0.0.0:3306
    3306/tcp -> :::3306
    [root@localhost DockerTest]#

11.2.10 stats

显示容器资源的使用情况,包括:CPU、内存、网络 I/O 等。

  1. 语法

    1
    docker stats [OPTIONS] [CONTAINER...]

    OPTIONS 说明:

    • —all , -a :显示所有的容器,包括未运行的。
    • —format :指定返回值的模板文件。
    • —no-stream :展示当前状态就直接退出了,不再实时更新。
    • —no-trunc :不截断输出。
  2. 实例

    列出所有在运行的容器信息。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    [root@localhost DockerTest]# docker stats
    CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
    d5a81f38372c mysql-test 0.10% 175.8MiB / 1.777GiB 9.66% 656B / 0B 3.28MB / 25.4MB 27
    76febf58a85a nginx-labelset 0.00% 2.016MiB / 1.777GiB 0.11% 656B / 0B 139kB / 24.6kB 3
    565fab9cc1d6 nginx-yanpenggong 0.00% 3.027MiB / 1.777GiB 0.17% 8.84MB / 211kB 1.2MB / 22.5kB 3
    ab1aa65cb3d1 yanpenggong1 0.00% 3.398MiB / 1.777GiB 0.19% 20.2MB / 399kB 54.1MB / 84.2MB 3
    d4048088ff57 myphp-fpm 0.01% 4.734MiB / 1.777GiB 0.26% 740B / 0B 0B / 0B 3
    5c3af81aab8d node-test 0.00% 11.73MiB / 1.777GiB 0.64% 782B / 0B 12.7MB / 0B 11
    5f1b0abb64ab nginx-test 0.00% 1.996MiB / 1.777GiB 0.11% 3.45kB / 2.85kB 0B / 15.4kB 3
    81cbdd935383 centos-test 0.00% 392KiB / 1.777GiB 0.02% 824B / 0B 0B / 0B 1
    c281416b5c63 ubuntu-test1 0.00% 560KiB / 1.777GiB 0.03% 1.27kB / 0B 0B / 0B 1

    输出详情介绍:

    • CONTAINER ID 与 NAME: 容器 ID 与名称。

    • CPU % 与 MEM %: 容器使用的 CPU 和内存的百分比。

    • MEM USAGE / LIMIT: 容器正在使用的总内存,以及允许使用的内存总量。

    • NET I/O: 容器通过其网络接口发送和接收的数据量。

    • BLOCK I/O: 容器从主机上的块设备读取和写入的数据量。

    • PIDs: 容器创建的进程或线程数。

    根据容器等 ID 或名称现实信息:

    1
    2
    3
    4
    [root@localhost DockerTest]# docker stats mysql-test 76febf58a85a
    CONTAINER ID NAME CPU % MEM USAGE / LIMIT MEM % NET I/O BLOCK I/O PIDS
    d5a81f38372c mysql-test 0.11% 175.8MiB / 1.777GiB 9.66% 656B / 0B 3.28MB / 25.4MB 27
    76febf58a85a nginx-labelset 0.00% 2.016MiB / 1.777GiB 0.11% 656B / 0B 139kB / 24.6kB 3

    以 JSON 格式输出:

    1
    2
    3
    [root@localhost DockerTest]# docker stats mysql-test --no-stream --format "{{ json . }}"
    {"BlockIO":"3.28MB / 25.4MB","CPUPerc":"0.08%","Container":"mysql-test","ID":"d5a81f38372c","MemPerc":"9.66%","MemUsage":"175.8MiB / 1.777GiB","Name":"mysql-test","NetIO":"656B / 0B","PIDs":"27"}
    [root@localhost DockerTest]#

    输出指定的信息:

    1
    2
    3
    4
    5
    6
    [root@localhost DockerTest]# docker stats --all --format "table {{.Container}}\t{{.CPUPerc}}\t{{.MemUsage}}" d5a81f38372c nginx-labelset yanpenggong1 centos-test
    CONTAINER CPU % MEM USAGE / LIMIT
    d5a81f38372c 0.10% 175.8MiB / 1.777GiB
    nginx-labelset 0.00% 2.016MiB / 1.777GiB
    yanpenggong1 0.00% 3.398MiB / 1.777GiB
    centos-test 0.00% 392KiB / 1.777GiB

11.3 容器rootfs命令

11.3.1 commit

从容器创建一个新的镜像。

  1. 语法

    1
    docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]]

    OPTIONS说明:

    • -a :提交的镜像作者;
    • -c :使用Dockerfile指令来创建镜像;
    • -m :提交时的说明文字;
    • -p :在commit时,将容器暂停。
  2. 实例

    将容器a404c6c174a2 保存为新的镜像,并添加提交人信息和说明信息。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    [root@localhost DockerTest]# docker commit -a "yanpenggong" -m "my apache" mysql-test  mysql:v1
    sha256:aafc21722e07a2c532b197fc85860ad0416a741659d20bd62680e75cceffd5b7
    [root@localhost DockerTest]# docker images
    REPOSITORY TAG IMAGE ID CREATED SIZE
    mysql v1 aafc21722e07 25 seconds ago 452MB
    mysql 5.7 e982339a20a5 12 hours ago 452MB
    php 8.2.1-fpm 6c2e0d7fb356 7 days ago 450MB
    node latest 51bd6c84a7f2 7 days ago 998MB
    nginx latest a99a39d070bf 7 days ago 142MB
    ubuntu latest 6b7dfa7e8fdb 5 weeks ago 77.8MB
    centos centos7 eeb6ee3f44bd 16 months ago 204MB
    [root@localhost DockerTest]#

11.3.2 cp

用于容器与主机之间的数据拷贝。

  1. 语法

    • 将容器中的目录拷贝到主机中

      1
      docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-
    • 将主机中的目录拷贝到容器中

      1
      docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH

    OPTIONS说明:

    • -L :保持源目标中的链接
  2. 实例

    • 将主机./GGG/pythonFile目录拷贝到容器aafc21722e07/GGG目录下。

      1
      [root@localhost DockerTest]# docker cp ./GGG/pythonFile aafc21722e07:/GGG/
    • 将主机./GGG/pythonFile目录拷贝到容器aafc21722e07中,目录重命名为GGG

      1
      [root@localhost DockerTest]# docker cp ./GGG/pythonFile aafc21722e07:/GGG
    • 将容器aafc21722e07/GGG目录拷贝到主机的./tmp目录中。

      1
      [root@localhost DockerTest]# docker cp aafc21722e07:/GGG ./temp/

11.3.3 diff

检查容器里文件结构的更改。

  1. 语法

    1
    docker diff [OPTIONS] CONTAINER
  2. 实例

    查看容器mysql-test的文件结构更改。

    1
    2
    3
    4
    5
    6
    7
    8
    [root@localhost DockerTest]# docker diff mysql-test
    A /logs
    A /mysql_data
    C /run
    C /run/mysqld
    A /run/mysqld/mysqld.pid
    A /run/mysqld/mysqld.sock
    C /tmp

11.4 镜像仓库

11.4.1 login

  1. 语法

    • 登陆到一个Docker镜像仓库,如果未指定镜像仓库地址,默认为官方仓库 Docker Hub

      1
      docker login [OPTIONS] [SERVER]
  • 登出一个Docker镜像仓库,如果未指定镜像仓库地址,默认为官方仓库 Docker Hub

    1
    docker logout [OPTIONS] [SERVER]

    OPTIONS说明:

  • -u :登陆的用户名

  • -p :登陆的密码
  1. 实例

    • 登陆到Docker Hub

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      [root@localhost DockerTest]# docker login
      Login with your Docker ID to push and pull images from Docker Hub. If you don't have a Docker ID, head over to https://hub.docker.com to create one.
      Username: kungs
      Password:
      WARNING! Your password will be stored unencrypted in /root/.docker/config.json.
      Configure a credential helper to remove this warning. See
      https://docs.docker.com/engine/reference/commandline/login/#credentials-store

      Login Succeeded
      [root@localhost DockerTest]#
    • 登出Docker Hub

      1
      2
      3
      [root@localhost DockerTest]# docker logout
      Removing login credentials for https://index.docker.io/v1/
      [root@localhost DockerTest]#

11.4.2 pull

从镜像仓库中拉取或者更新指定镜像

  1. 语法

    1
    docker pull [OPTIONS] NAME[:TAG|@DIGEST]

    OPTIONS说明:

    • -a :拉取所有 tagged 镜像
    • —disable-content-trust :忽略镜像的校验,默认开启
  2. 实例

    从Docker Hub下载 python 最新版镜像。\

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    [root@localhost DockerTest]# docker pull python
    Using default tag: latest
    latest: Pulling from library/python
    bbeef03cda1f: Already exists
    f049f75f014e: Already exists
    56261d0e6b05: Already exists
    9bd150679dbd: Already exists
    5b282ee9da04: Already exists
    03f027d5e312: Pull complete
    db6ee1ace097: Pull complete
    0a86d528f1ea: Pull complete
    4cfb032ae58b: Pull complete
    Digest: sha256:a3c0c6766535f85f18e7304d3a0111de5208d73935bcf1b024217005ad5ce195
    Status: Downloaded newer image for python:latest
    docker.io/library/python:latest
    [root@localhost DockerTest]#

    从Docker Hub下载REPOSITORYpython 的所有镜像。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    [root@localhost DockerTest]# docker pull -a python
    2: Pulling from library/python
    7e2b2a5af8f6: Pull complete
    09b6f03ffac4: Pull complete
    dc3f0c679f0f: Pull complete
    fd4b47407fc3: Pull complete
    b32f6bf7d96d: Pull complete
    6f4489a7e4cf: Pull complete
    af4b99ad9ef0: Pull complete
    39db0bc48c26: Pull complete
    acb4a89489fc: Pull complete
    Digest: sha256:cfa62318c459b1fde9e0841c619906d15ada5910d625176e24bf692cf8a2601d
    2-alpine: Pulling from library/python
    aad63a933944: Pull complete
    259d822268fb: Pull complete
    10ba96d218d3: Pull complete
    44ba9f6a4209: Pull complete
    Digest: sha256:724d0540eb56ffaa6dd770aa13c3bc7dfc829dec561d87cb36b2f5b9ff8a760a
    ...
    [root@localhost DockerTest]#

    获取指定编译平台的镜像:

    1
    docker pull --platform=arm64|amd64... image_name

11.4.3 push

将本地的镜像上传到镜像仓库,要先登陆到镜像仓库

  1. 语法

    1
    docker push [OPTIONS] NAME[:TAG]

    OPTIONS说明:

    • —disable-content-trust :忽略镜像的校验,默认开启
  2. 实例

    上传本地镜像mysql:v1 到镜像仓库中。

    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@localhost DockerTest]# docker images
    REPOSITORY TAG IMAGE ID CREATED SIZE
    mysql v1 aafc21722e07 21 minutes ago 452MB
    python latest b44268c8cbc0 10 hours ago 932MB
    mysql 5.7 e982339a20a5 13 hours ago 452MB
    php 8.2.1-fpm 6c2e0d7fb356 7 days ago 450MB
    node latest 51bd6c84a7f2 7 days ago 998MB
    nginx latest a99a39d070bf 7 days ago 142MB
    ubuntu latest 6b7dfa7e8fdb 5 weeks ago 77.8MB
    centos centos7 eeb6ee3f44bd 16 months ago 204MB
    python 2-alpine3.10 dc740d648004 2 years ago 68.9MB
    python 2-alpine 8579e446340f 2 years ago 71.1MB
    python 2-alpine3.11 8579e446340f 2 years ago 71.1MB
    python 2 68e7be49c28c 2 years ago 902MB
    python 2-alpine3.8 fcbce699af86 3 years ago 58.4MB
    python 2-alpine3.6 dd4c05fcb8d5 3 years ago 56.5MB
    python 2-alpine3.7 ec0218200ad6 3 years ago 58.2MB
    python 2-alpine3.4 5fdd069daf25 4 years ago 73.5MB
    [root@localhost DockerTest]# docker push mysql:v1
    The push refers to repository [docker.io/library/mysql]
    d9cfab7e0ea4: Preparing
    5c542b9ec644: Preparing
    868b2e381adf: Preparing
    e974776afbe2: Preparing
    c1f1b5039e40: Preparing
    f4bb02745d03: Waiting
    45968403dd22: Waiting
    56a71f69f1a8: Waiting
    1ab9edd16f9e: Waiting
    1a26f263a6af: Waiting
    49769e21013b: Waiting
    62d9c4cbe8f4: Waiting
    denied: requested access to the resource is denied
    [root@localhost DockerTest]#

从Docker Hub查找镜像

  1. 语法

    1
    docker search [OPTIONS] TERM

    OPTIONS说明:

    • —automated :只列出 automated build类型的镜像;
    • —no-trunc :显示完整的镜像描述;
    • -f <过滤条件>:列出收藏数不小于指定值的镜像。
  2. 实例

    从 Docker Hub 查找所有镜像名包含 python,并且收藏数大于 10 的镜像

    1
    2
    3
    4
    5
    6
    7
    8
    [root@localhost DockerTest]# docker search -f stars=10 python
    NAME DESCRIPTION STARS OFFICIAL AUTOMATED
    python Python is an interpreted, interactive, objec… 8323 [OK]
    pypy PyPy is a fast, compliant alternative implem… 355 [OK]
    circleci/python Python is an interpreted, interactive, objec… 61
    hylang Hy is a Lisp dialect that translates express… 53 [OK]
    bitnami/python Bitnami Python Docker Image 25 [OK]
    [root@localhost DockerTest]#

    参数说明:

    • NAME: 镜像仓库源的名称

    • DESCRIPTION: 镜像的描述

    • OFFICIAL: 是否 docker 官方发布

    • stars: 类似 Github 里面的 star,表示点赞、喜欢的意思。

    • AUTOMATED: 自动构建。

11.5 本地镜像管理

11.5.1 images

列出本地镜像。

  1. 语法

    1
    docker images [OPTIONS] [REPOSITORY[:TAG]]

    OPTIONS说明:

    • -a :列出本地所有的镜像(含中间映像层,默认情况下,过滤掉中间映像层);
    • —digests :显示镜像的摘要信息;
    • -f :显示满足条件的镜像;
    • —format :指定返回值的模板文件;
    • —no-trunc :显示完整的镜像信息;
    • -q :只显示镜像ID。
  2. 实例

    • 查看本地镜像列表。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      [root@localhost DockerTest]# docker images
      REPOSITORY TAG IMAGE ID CREATED SIZE
      mysql v1 aafc21722e07 27 minutes ago 452MB
      python latest b44268c8cbc0 10 hours ago 932MB
      mysql 5.7 e982339a20a5 13 hours ago 452MB
      php 8.2.1-fpm 6c2e0d7fb356 7 days ago 450MB
      node latest 51bd6c84a7f2 7 days ago 998MB
      nginx latest a99a39d070bf 7 days ago 142MB
      ubuntu latest 6b7dfa7e8fdb 5 weeks ago 77.8MB
      centos centos7 eeb6ee3f44bd 16 months ago 204MB
      python 2-alpine3.10 dc740d648004 2 years ago 68.9MB
      python 2-alpine 8579e446340f 2 years ago 71.1MB
      python 2-alpine3.11 8579e446340f 2 years ago 71.1MB
      python 2 68e7be49c28c 2 years ago 902MB
      python 2-alpine3.8 fcbce699af86 3 years ago 58.4MB
      python 2-alpine3.6 dd4c05fcb8d5 3 years ago 56.5MB
      python 2-alpine3.7 ec0218200ad6 3 years ago 58.2MB
      python 2-alpine3.4 5fdd069daf25 4 years ago 73.5MB
      [root@localhost DockerTest]#
    • 列出本地镜像中 REPOSITORY 为centos的镜像列表。

      1
      2
      3
      4
      [root@localhost DockerTest]# docker images centos
      REPOSITORY TAG IMAGE ID CREATED SIZE
      centos centos7 eeb6ee3f44bd 16 months ago 204MB
      [root@localhost DockerTest]#

11.5.2 rmi

删除本地一个或多个镜像。

  1. 语法

    1
    docker rmi [OPTIONS] IMAGE [IMAGE...]

    OPTIONS说明:

    • -f :强制删除;
    • —no-prune :不移除该镜像的过程镜像,默认移除;
  2. 实例

    强制删除本地镜像mysql:v2

    1
       
  1. prune 命令用来删除不再使用的 docker 对象。

    删除所有未被 tag 标记和未被容器使用的镜像:

    1
    2
    3
    $ docker image prune
    WARNING! This will remove all dangling images.
    Are you sure you want to continue? [y/N] y

    删除所有未被容器使用的镜像:

    1
    $ docker image prune -a

    删除所有停止运行的容器:

    1
    $ docker container prune

    删除所有未被挂载的卷:

    1
    $ docker volume prune

    删除所有网络:

    1
    $ docker network prune

    删除 docker 所有资源:

    1
    $ docker system prune
  2. docker system prune 命令:

    1
    2
    3
    4
    5
    This will remove:
    - all stopped containers
    - all networks not used by at least one container
    - all dangling images
    - all dangling build cache

    删除停止的容器、删除所有未被容器使用的网络、删除所有none的镜像。

11.5.3 tag

标记本地镜像,将其归入某一仓库。

  1. 语法

    1
    docker tag [OPTIONS] IMAGE[:TAG] [REGISTRYHOST/][USERNAME/]NAME[:TAG]
  2. 实例

    将镜像centos:centos7标记为yanpenggong/centos:centos7 镜像。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    [root@localhost DockerTest]# docker tag centos:centos7 yanpenggong/centos:centos7
    [root@localhost DockerTest]# docker images
    REPOSITORY TAG IMAGE ID CREATED SIZE
    mysql v1 aafc21722e07 17 hours ago 452MB
    python latest b44268c8cbc0 27 hours ago 932MB
    mysql 5.7 e982339a20a5 29 hours ago 452MB
    php 8.2.1-fpm 6c2e0d7fb356 7 days ago 450MB
    node latest 51bd6c84a7f2 7 days ago 998MB
    nginx latest a99a39d070bf 7 days ago 142MB
    ubuntu latest 6b7dfa7e8fdb 5 weeks ago 77.8MB
    centos centos7 eeb6ee3f44bd 16 months ago 204MB
    yanpenggong/centos centos7 eeb6ee3f44bd 16 months ago 204MB
    python 2-alpine3.10 dc740d648004 2 years ago 68.9MB
    python 2-alpine 8579e446340f 2 years ago 71.1MB
    python 2-alpine3.11 8579e446340f 2 years ago 71.1MB
    python 2 68e7be49c28c 2 years ago 902MB
    python 2-alpine3.8 fcbce699af86 3 years ago 58.4MB
    python 2-alpine3.6 dd4c05fcb8d5 3 years ago 56.5MB
    python 2-alpine3.7 ec0218200ad6 3 years ago 58.2MB
    python 2-alpine3.4 5fdd069daf25 4 years ago 73.5MB
    [root@localhost DockerTest]#

11.5.4 build

用于使用 Dockerfile 创建镜像。

  1. 语法

    1
    docker build [OPTIONS] PATH | URL | -

    OPTIONS说明:

    • —build-arg=[] :设置镜像创建时的变量;
    • —cpu-shares :设置 cpu 使用权重;
    • —cpu-period :限制 CPU CFS周期;
    • —cpu-quota :限制 CPU CFS配额;
    • —cpuset-cpus :指定使用的CPU id;
    • —cpuset-mems :指定使用的内存 id;
    • —disable-content-trust :忽略校验,默认开启;
    • -f :指定要使用的Dockerfile路径;
    • —force-rm :设置镜像过程中删除中间容器;
    • —isolation :使用容器隔离技术;
    • —label=[] :设置镜像使用的元数据;
    • -m :设置内存最大值;
    • —memory-swap :设置Swap的最大值为内存+swap,”-1”表示不限swap;
    • —no-cache :创建镜像的过程不使用缓存;
    • —pull :尝试去更新镜像的新版本;
    • —quiet, -q :安静模式,成功后只输出镜像 ID;
    • —rm :设置镜像成功后删除中间容器;
    • —shm-size :设置/dev/shm的大小,默认值是64M;
    • —ulimit :Ulimit配置。
    • —squash :将 Dockerfile 中所有的操作压缩为一层。
    • —tag, -t: 镜像的名字及标签,通常 name:tag 或者 name 格式;可以在一次构建中为一个镜像设置多个标签。
    • —network: 默认 default。在构建期间设置RUN指令的网络模式
  2. 实例

    使用当前目录的 Dockerfile 创建镜像,标签为 yanpenggong/centos:centos7

    1
    [root@localhost DockerTest]# docker build -t yanpenggong/centos:centos7 . 

    使用URL github.com/creack/docker-firefox 的 Dockerfile 创建镜像。

    1
    [root@localhost DockerTest]# docker build github.com/creack/docker-firefox

    也可以通过 -f Dockerfile 文件的位置:

    1
    [root@localhost DockerTest]# docker build -f /path/to/a/Dockerfile .

    在 Docker 守护进程执行 Dockerfile 中的指令前,首先会对 Dockerfile 进行语法检查,有语法错误时会返回:

    1
    2
    3
    [root@localhost DockerTest]# docker build -t test/myapp .
    Sending build context to Docker daemon 2.048 kB
    Error response from daemon: Unknown instruction: RUNCMD

11.5.5 history

查看指定镜像的创建历史。

  1. 语法

    1
    docker history [OPTIONS] IMAGE

    OPTIONS说明:

    • -H :以可读的格式打印镜像大小和日期,默认为true;
    • —no-trunc :显示完整的提交记录;
    • -q :仅列出提交记录ID。
  2. 实例

    查看本地镜像yanpenggong/centos:centos7的创建历史。

    1
    2
    3
    4
    5
    6
    [root@localhost DockerTest]# docker history yanpenggong/centos:centos7
    IMAGE CREATED CREATED BY SIZE COMMENT
    eeb6ee3f44bd 16 months ago /bin/sh -c #(nop) CMD ["/bin/bash"] 0B
    <missing> 16 months ago /bin/sh -c #(nop) LABEL org.label-schema.sc… 0B
    <missing> 16 months ago /bin/sh -c #(nop) ADD file:b3ebbe8bd304723d4… 204MB
    [root@localhost DockerTest]#

11.5.6 save

将指定镜像保存成 tar 归档文件。

  1. 语法

    1
    docker save [OPTIONS] IMAGE [IMAGE...]

    OPTIONS 说明:

    • -o :输出到的文件。
  2. 实例

    将镜像 yanpenggong/centos:centos7 生成 my_centos_v1.tar 文档

    1
    2
    3
    4
    [root@localhost DockerTest]# docker save -o my_centos_v1.tar yanpenggong/centos:centos7
    [root@localhost DockerTest]# ll my_centos_v1.tar
    -rw-------. 1 root root 211696640 Jan 18 21:23 my_centos_v1.tar
    [root@localhost DockerTest]#

export 和 import 导出的是一个容器的快照, 不是镜像本身, 也就是说没有 layer。

dockerfile 里的 workdir, entrypoint 之类的所有东西都会丢失,commit 过的话也会丢失。

快照文件将丢弃所有的历史记录和元数据信息(即仅保存容器当时的快照状态),而镜像存储文件将保存完整记录,体积也更大。

  • docker save 保存的是镜像(image),docker export 保存的是容器(container);
  • docker load 用来载入镜像包,docker import 用来载入容器包,但两者都会恢复为镜像;
  • docker load 不能对载入的镜像重命名,而 docker import 可以为镜像指定新名称。

11.5.7 load

导入使用 docker save 命令导出的镜像。

  1. 语法

    1
    docker load [OPTIONS]

    OPTIONS 说明:

    • —input , -i : 指定导入的文件,代替 STDIN。
    • —quiet , -q : 精简输出信息。
  2. 实例

    导入镜像:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    [root@localhost DockerTest]# docker image ls
    REPOSITORY TAG IMAGE ID CREATED SIZE
    [root@localhost DockerTest]# docker load < busybox.tar.gz
    Loaded image: busybox:latest
    [root@localhost DockerTest]# docker images
    REPOSITORY TAG IMAGE ID CREATED SIZE
    busybox latest 769b9341d937 7 weeks ago 2.489 MB
    [root@localhost DockerTest]# docker load --input fedora.tar
    Loaded image: fedora:rawhide
    Loaded image: fedora:20
    [root@localhost DockerTest]# docker images
    REPOSITORY TAG IMAGE ID CREATED SIZE
    busybox latest 769b9341d937 7 weeks ago 2.489 MB
    fedora rawhide 0d20aec6529d 7 weeks ago 387 MB
    fedora 20 58394af37342 7 weeks ago 385.5 MB
    fedora heisenbug 58394af37342 7 weeks ago 385.5 MB
    fedora latest 58394af37342 7 weeks ago 385.5 MB
    [root@localhost DockerTest]#

11.5.8 import

从归档文件中创建镜像。

  1. 语法

    1
    docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]

    OPTIONS说明:

    • -c :应用docker 指令创建镜像;
    • -m :提交时的说明文字;
  2. 实例

    从镜像归档文件my_centos_v1.tar创建镜像,命名为yanpenggong/centos:v1

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    [root@localhost DockerTest]# docker import my_centos_v1.tar yanpenggong/centos:v1
    sha256:623ecbbf2e8d746fdfc3e62f8eb4e1268c9bd43e6f3e6ad5c08b52cc2c01e7ca
    [root@localhost DockerTest]# docker image ls
    REPOSITORY TAG IMAGE ID CREATED SIZE
    yanpenggong/centos v1 623ecbbf2e8d 3 seconds ago 212MB
    mysql v1 aafc21722e07 17 hours ago 452MB
    python latest b44268c8cbc0 27 hours ago 932MB
    mysql 5.7 e982339a20a5 29 hours ago 452MB
    php 8.2.1-fpm 6c2e0d7fb356 7 days ago 450MB
    node latest 51bd6c84a7f2 7 days ago 998MB
    nginx latest a99a39d070bf 7 days ago 142MB
    ubuntu latest 6b7dfa7e8fdb 5 weeks ago 77.8MB
    centos centos7 eeb6ee3f44bd 16 months ago 204MB
    yanpenggong/centos centos7 eeb6ee3f44bd 16 months ago 204MB
    [root@localhost DockerTest]#

11.6 info|version

11.6.1 info

显示 Docker 系统信息,包括镜像和容器数。

  1. 语法

    1
    docker info [OPTIONS]
  2. 实例

    查看docker系统信息。

    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
    [root@localhost DockerTest]# docker info
    Client:
    Context: default
    Debug Mode: false
    Plugins:
    app: Docker App (Docker Inc., v0.9.1-beta3)
    buildx: Docker Buildx (Docker Inc., v0.9.1-docker)
    scan: Docker Scan (Docker Inc., v0.23.0)

    Server:
    Containers: 13
    Running: 9
    Paused: 0
    Stopped: 4
    Images: 16
    Server Version: 20.10.22
    Storage Driver: overlay2
    Backing Filesystem: xfs
    Supports d_type: true
    Native Overlay Diff: true
    userxattr: false
    Logging Driver: json-file
    Cgroup Driver: cgroupfs
    Cgroup Version: 1
    Plugins:
    Volume: local
    Network: bridge host ipvlan macvlan null overlay
    Log: awslogs fluentd gcplogs gelf journald json-file local logentries splunk syslog
    Swarm: inactive
    Runtimes: io.containerd.runtime.v1.linux runc io.containerd.runc.v2
    Default Runtime: runc
    Init Binary: docker-init
    containerd version: 5b842e528e99d4d4c1686467debf2bd4b88ecd86
    runc version: v1.1.4-0-g5fd4c4d
    init version: de40ad0
    Security Options:
    seccomp
    Profile: default
    Kernel Version: 3.10.0-1160.81.1.el7.x86_64
    Operating System: CentOS Linux 7 (Core)
    OSType: linux
    Architecture: x86_64
    CPUs: 2
    Total Memory: 1.777GiB
    Name: localhost
    ID: V755:HONZ:LVHJ:WBDK:OTF4:B7TK:QTMF:RLPZ:Z55T:4PAM:EE6C:SQFK
    Docker Root Dir: /var/lib/docker
    Debug Mode: false
    Username: kungs
    Registry: https://index.docker.io/v1/
    Labels:
    Experimental: false
    Insecure Registries:
    127.0.0.0/8
    Live Restore Enabled: false

    [root@localhost DockerTest]#

11.6.2 version

显示 Docker 版本信息。

  1. 语法

    1
    docker version [OPTIONS]

    OPTIONS说明:

    • -f :指定返回值的模板文件。
  2. 实例

    显示 Docker 版本信息。

    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@localhost DockerTest]# docker version
    Client: Docker Engine - Community
    Version: 20.10.22
    API version: 1.41
    Go version: go1.18.9
    Git commit: 3a2c30b
    Built: Thu Dec 15 22:30:24 2022
    OS/Arch: linux/amd64
    Context: default
    Experimental: true

    Server: Docker Engine - Community
    Engine:
    Version: 20.10.22
    API version: 1.41 (minimum version 1.12)
    Go version: go1.18.9
    Git commit: 42c8b31
    Built: Thu Dec 15 22:28:33 2022
    OS/Arch: linux/amd64
    Experimental: false
    containerd:
    Version: 1.6.15
    GitCommit: 5b842e528e99d4d4c1686467debf2bd4b88ecd86
    runc:
    Version: 1.1.4
    GitCommit: v1.1.4-0-g5fd4c4d
    docker-init:
    Version: 0.19.0
    GitCommit: de40ad0
    [root@localhost DockerTest]#

12. Docker在线资源及国内镜像

12.1 Docker资源

12.2 Docker国内镜像

Redis教程
Author: yanpenggong       Email: yanpenggong@163.com
Github: kungs8      CSDN: https://blog.csdn.net/yanpenggong

[toc]

1. Linux 安装 Redis 并配置

1.1 下载,执行编译并安装

下载地址:http://redis.io/download,下载最新稳定版本。

本教程使用的最新文档版本为 6.2.6,下载并安装:

1
2
3
4
5
[root@localhost ~]# cd /opt/software/
[root@localhost software]# wget http://download.redis.io//releases/redis-6.2.6.tar.gz # 下载redis安装包
[root@localhost software]# tar -xzf redis-6.2.6.tar.gz # 下载redis安装包
[root@localhost software]# cd redis-6.2.6
[root@localhost redis-6.2.6]# make

注意

  1. 如果没有wget,则会报错,通过使用yum install wget 就行。

    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
    [root@localhost Redis_dir]# wget http://download.redis.io//releases/redis-6.2.6.tar.gz
    -bash: wget: 未找到命令
    [root@localhost Redis_dir]# yum install wget
    已加载插件:fastestmirror
    Loading mirror speeds from cached hostfile
    * base: mirror.lzu.edu.cn
    * extras: mirror.lzu.edu.cn
    * updates: mirrors.aliyun.com
    正在解决依赖关系
    --> 正在检查事务
    ---> 软件包 wget.x86_64.0.1.14-18.el7_6.1 将被 安装
    --> 解决依赖关系完成

    依赖关系解决

    =======================================================================================================================
    Package 架构 版本 源 大小
    ============================================================================```=====================================
    正在安装:
    wget x86_64 1.14-18.el7_6.1 base 547 k

    事务概要
    =======================================================================================================================
    安装 1 软件包

    总下载量:547 k
    安装大小:2.0 M
    Is this ok [y/d/N]: y
    Downloading packages:
    wget-1.14-18.el7_6.1.x86_64.rpm | 547 kB 00:00:00
    Running transaction check
    Running transaction test
    Transaction test succeeded
    Running transaction
    正在安装 : wget-1.14-18.el7_6.1.x86_64 1/1
    验证中 : wget-1.14-18.el7_6.1.x86_64 1/1

    已安装:
    wget.x86_64 0:1.14-18.el7_6.1

    完毕!
    [root@localhost Redis_dir]#
  2. 系统缺少gcc环境的报错(安装Redis执行make命令时遇到此错误)

    问题:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    make[3]: cc:命令未找到
    make[3]: *** [alloc.o] 错误 127
    make[3]: 离开目录"/opt/software/redis-6.2.6/deps/hiredis"
    make[2]: *** [hiredis] 错误 2
    make[2]: 离开目录"/opt/software/redis-6.2.6/deps"
    make[1]: [persist-settings] 错误 2 (忽略)
    CC adlist.o
    /bin/sh: cc: 未找到命令
    make[1]: *** [adlist.o] 错误 127
    make[1]: 离开目录"/opt/software/redis-6.2.6/src"
    make: *** [all] 错误 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
    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
    [root@localhost redis-6.2.6]# yum install gcc c++
    已加载插件:fastestmirror
    Loading mirror speeds from cached hostfile
    * base: mirror.lzu.edu.cn
    * extras: mirror.lzu.edu.cn
    * updates: mirrors.aliyun.com
    没有可用软件包 c++。
    正在解决依赖关系
    --> 正在检查事务
    ---> 软件包 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 需要
    --> 正在处理依赖关系 libmpfr.so.4()(64bit),它被软件包 gcc-4.8.5-44.el7.x86_64 需要
    --> 正在处理依赖关系 libmpc.so.3()(64bit),它被软件包 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 需要
    ---> 软件包 libmpc.x86_64.0.1.0.1-3.el7 将被 安装
    ---> 软件包 mpfr.x86_64.0.3.1.1-4.el7 将被 安装
    --> 正在检查事务
    ---> 软件包 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.62.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.62.1.el7 updates 9.1 M
    libmpc x86_64 1.0.1-3.el7 base 51 k
    mpfr x86_64 3.1.1-4.el7 base 203 k

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

    总下载量:33 M
    安装大小:60 M
    Is this ok [y/d/N]: r
    Is this ok [y/d/N]: y
    Downloading packages:
    (1/7): glibc-headers-2.17-325.el7_9.x86_64.rpm | 691 kB 00:00:00
    (2/7): glibc-devel-2.17-325.el7_9.x86_64.rpm | 1.1 MB 00:00:00
    (3/7): cpp-4.8.5-44.el7.x86_64.rpm | 5.9 MB 00:00:01
    (4/7): libmpc-1.0.1-3.el7.x86_64.rpm | 51 kB 00:00:00
    (5/7): mpfr-3.1.1-4.el7.x86_64.rpm | 203 kB 00:00:00
    (6/7): kernel-headers-3.10.0-1160.62.1.el7.x86_64.rpm | 9.1 MB 00:00:01
    (7/7): gcc-4.8.5-44.el7.x86_64.rpm | 16 MB 00:00:02
    -----------------------------------------------------------------------------------------------------------------------
    总计 11 MB/s | 33 MB 00:00:02
    Running transaction check
    Running transaction test
    Transaction test succeeded
    Running transaction
    正在安装 : mpfr-3.1.1-4.el7.x86_64 1/7
    正在安装 : libmpc-1.0.1-3.el7.x86_64 2/7
    正在安装 : cpp-4.8.5-44.el7.x86_64 3/7
    正在安装 : kernel-headers-3.10.0-1160.62.1.el7.x86_64 4/7
    正在安装 : glibc-headers-2.17-325.el7_9.x86_64 5/7
    正在安装 : glibc-devel-2.17-325.el7_9.x86_64 6/7
    正在安装 : gcc-4.8.5-44.el7.x86_64 7/7
    验证中 : kernel-headers-3.10.0-1160.62.1.el7.x86_64 1/7
    验证中 : mpfr-3.1.1-4.el7.x86_64 2/7
    验证中 : glibc-devel-2.17-325.el7_9.x86_64 3/7
    验证中 : gcc-4.8.5-44.el7.x86_64 4/7
    验证中 : glibc-headers-2.17-325.el7_9.x86_64 5/7
    验证中 : libmpc-1.0.1-3.el7.x86_64 6/7
    验证中 : cpp-4.8.5-44.el7.x86_64 7/7

    已安装:
    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.62.1.el7
    libmpc.x86_64 0:1.0.1-3.el7 mpfr.x86_64 0:3.1.1-4.el7

    完毕!
    [root@localhost redis-6.2.6]#
  3. 安装好gcc 和c++ 后,必须清空后再编译,否则会报如下错误

    问题:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    [root@localhost redis-6.2.6]# make
    cd src && make all
    make[1]: 进入目录"/opt/software/redis-6.2.6/src"
    CC Makefile.dep
    make[1]: 离开目录"/opt/software/redis-6.2.6/src"
    make[1]: 进入目录"/opt/software/redis-6.2.6/src"
    CC adlist.o
    In file included from adlist.c:34:0:
    zmalloc.h:50:31: 致命错误:jemalloc/jemalloc.h:没有那个文件或目录
    #include <jemalloc/jemalloc.h>
    ^
    编译中断。
    make[1]: *** [adlist.o] 错误 1
    make[1]: 离开目录"/opt/software/redis-6.2.6/src"
    make: *** [all] 错误 2
    [root@localhost redis-6.2.6]#

    解决办法:

    1
    2
    [root@localhost redis-6.2.6]# make distclean  # 清空上次编译失败残留文件
    [root@localhost redis-6.2.6]# make && make install # 执行编译及安装

执行完 make 命令后,redis-6.2.6 目录下会出现编译后的 redis 服务程序 redis-server,还有用于测试的客户端程序 redis-cli,两个程序位于安装目录 src 目录下。

1.2 启动Redis服务

下面启动 redis 服务:

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@localhost src]# cd src/
[root@localhost src]# ./redis-server ../redis.conf
7061:C 16 May 2022 12:09:22.469 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo
7061:C 16 May 2022 12:09:22.469 # Redis version=6.2.6, bits=64, commit=00000000, modified=0, pid=7061, just started
7061:C 16 May 2022 12:09:22.469 # Configuration loaded
7061:M 16 May 2022 12:09:22.470 * Increased maximum number of open files to 10032 (it was originally set to 1024).
7061:M 16 May 2022 12:09:22.470 * monotonic clock: POSIX clock_gettime
_._
_.-``__ ''-._
_.-`` `. `_. ''-._ Redis 6.2.6 (00000000/0) 64 bit
.-`` .-```. ```\/ _.,_ ''-._
( ' , .-` | `, ) Running in standalone mode
|`-._`-...-` __...-.``-._|'` _.-'| Port: 6379
| `-._ `._ / _.-' | PID: 7061
`-._ `-._ `-./ _.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' | https://redis.io
`-._ `-._`-.__.-'_.-' _.-'
|`-._`-._ `-.__.-' _.-'_.-'|
| `-._`-._ _.-'_.-' |
`-._ `-._`-.__.-'_.-' _.-'
`-._ `-.__.-' _.-'
`-._ _.-'
`-.__.-'

7061:M 16 May 2022 12:09:22.472 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128.
7061:M 16 May 2022 12:09:22.472 # Server initialized
7061:M 16 May 2022 12:09:22.472 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
7061:M 16 May 2022 12:09:22.472 * Ready to accept connections

redis.conf 是一个默认的配置文件。我们可以根据需要使用自己的配置文件。

启动 redis 服务进程后,就可以使用测试客户端程序( redis-cli )和 redis 服务交互了。 比如:

1
2
3
4
5
6
7
8
9
10
[root@localhost ~]# cd /opt/software/redis-6.2.6/src
[root@localhost src]# ./redis-cli -a yanpenggong
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> set foo bar
OK
127.0.0.1:6379> get foo
"bar"
127.0.0.1:6379>

1.3 Redis 配置后台服务和访问密码

配置 Redis 为后台服务 将配置文件中的 daemonize no 改成 daemonize yes,配置 redis 为后台启动。

Redis 设置访问密码 在配置文件中找到 requirepass,去掉前面的注释,并修改后面的密码。

常用配置文件例子 redis.conf 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#默认端口6379
port 6379
#绑定ip,如果是内网可以直接绑定 127.0.0.1, 或者忽略, 0.0.0.0是外网
bind 0.0.0.0
#守护进程启动
daemonize yes
#超时
timeout 300
loglevel notice
#分区
databases 16
save 900 1
save 300 10
save 60 10000
rdbcompression yes
#存储文件
dbfilename dump.rdb
#密码 abcd123
requirepass yanpenggong

修改protected-mode 参数,将其改为 protected-mode no。这样就可以解除redis的保护机制,可以被其他主机连接。

同时还要把对应的端口打开:

1
2
3
4
5
6
7
8
[root@localhost src]# firewall-cmd --query-port=6379/tcp  # 检测端口是否打开
no
[root@localhost src]# firewall-cmd --add-port=6379/tcp --permanent # 返回success说明开启成功,加permanent代表永久有效 不会因为重启防火墙失效
success
[root@localhost src]# firewall-cmd --reload # 配置立即生效
success
[root@localhost src]# firewall-cmd --query-port=6379/tcp # 查看防火墙开放的端口
yes
  1. 查看防火墙所有开放的端口

    1
    firewall-cmd --zone=public --list-ports
  2. 关闭端口

    1
    firewall-cmd --zone=public --remove-port=6379/tcp --permanent
  3. 关闭防火墙

    如果要开放的端口太多,嫌麻烦,可以关闭防火墙,安全性自行评估

    1
    systemctl stop firewalld.service
  4. 查看防火墙状态

    1
    2
    [root@localhost src]# firewall-cmd --state
    running
  5. 查看监听的端口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    [root@localhost src]# netstat -lnpt
    Active Internet connections (only servers)
    Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
    tcp 0 0 127.0.0.1:6379 0.0.0.0:* LISTEN 7293/./redis-server
    tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 1062/sshd
    tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN 1237/master
    tcp6 0 0 ::1:6379 :::* LISTEN 7293/./redis-server
    tcp6 0 0 :::22 :::* LISTEN 1062/sshd
    tcp6 0 0 ::1:25 :::* LISTEN 1237/master

    linux命令报错信息:-bash: netstat: 未找到命令

    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@localhost src]# netstat -lnpt
    -bash: netstat: 未找到命令
    [root@localhost src]# yum -y install net-tools
    已加载插件:fastestmirror
    Loading mirror speeds from cached hostfile
    * base: mirror.lzu.edu.cn
    * extras: mirror.lzu.edu.cn
    * updates: mirrors.aliyun.com
    正在解决依赖关系
    --> 正在检查事务
    ---> 软件包 net-tools.x86_64.0.2.0-0.25.20131004git.el7 将被 安装
    --> 解决依赖关系完成

    依赖关系解决

    =======================================================================================================================
    Package 架构 版本 源 大小
    =======================================================================================================================
    正在安装:
    net-tools x86_64 2.0-0.25.20131004git.el7 base 306 k

    事务概要
    =======================================================================================================================
    安装 1 软件包

    总下载量:306 k
    安装大小:917 k
    Downloading packages:
    net-tools-2.0-0.25.20131004git.el7.x86_64.rpm | 306 kB 00:00:00
    Running transaction check
    Running transaction test
    Transaction test succeeded
    Running transaction
    正在安装 : net-tools-2.0-0.25.20131004git.el7.x86_64 1/1
    验证中 : net-tools-2.0-0.25.20131004git.el7.x86_64 1/1

    已安装:
    net-tools.x86_64 0:2.0-0.25.20131004git.el7

    完毕!
    [root@localhost src]#
  6. 检查端口被哪个进程占用

    1
    2
    3
    4
    [root@localhost src]# netstat -lnpt |grep 6379
    tcp 0 0 127.0.0.1:6379 0.0.0.0:* LISTEN 7293/./redis-server
    tcp6 0 0 ::1:6379 :::* LISTEN 7293/./redis-server
    [root@localhost src]#
  7. 查看进程的详细信息

    1
    2
    3
    4
    5
    6
    7
    [root@localhost src]# ps -ef | grep redis
    root 7293 1 0 14:23 ? 00:00:07 ./redis-server 127.0.0.1:6379
    root 7379 1390 0 14:41 pts/0 00:00:00 grep --color=auto redis
    [root@localhost src]# ps 7293
    PID TTY STAT TIME COMMAND
    7293 ? Ssl 0:07 ./redis-server 127.0.0.1:6379
    [root@localhost src]#
  8. 终止进程

    1
    kill -9 7293

2. Redis 配置

2.1 获取Redis 配置

在 Redis 中,Redis 的根目录中有一个配置文件(redis.conf)。您可以通过 Redis CONFIG 命令获取和设置所有 Redis 配置。

  1. 语法

    以下是 Redis CONFIG 命令的基本语法。

    1
    127.0.0.1:6379> CONFIG GET CONFIG_SETTING_NAME
  2. 实例1: CONFIG GET loglevel

    1
    2
    3
    4
    127.0.0.1:6379> CONFIG GET "loglevel"
    1) "loglevel"
    2) "notice"
    127.0.0.1:6379>
  3. 实例2:CONFIG GET *

    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
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    127.0.0.1:6379> CONFIG GET *
    1) "rdbchecksum"
    2) "yes"
    3) "daemonize"
    4) "yes"
    5) "io-threads-do-reads"
    6) "no"
    7) "lua-replicate-commands"
    8) "yes"
    9) "always-show-logo"
    10) "no"
    11) "protected-mode"
    12) "no"
    13) "rdbcompression"
    14) "yes"
    15) "rdb-del-sync-files"
    16) "no"
    17) "activerehashing"
    18) "yes"
    19) "stop-writes-on-bgsave-error"
    20) "yes"
    21) "set-proc-title"
    22) "yes"
    23) "dynamic-hz"
    24) "yes"
    25) "lazyfree-lazy-eviction"
    26) "no"
    27) "lazyfree-lazy-expire"
    28) "no"
    29) "lazyfree-lazy-server-del"
    30) "no"
    31) "lazyfree-lazy-user-del"
    32) "no"
    33) "lazyfree-lazy-user-flush"
    34) "no"
    35) "repl-disable-tcp-nodelay"
    36) "no"
    37) "repl-diskless-sync"
    38) "no"
    39) "gopher-enabled"
    40) "no"
    41) "aof-rewrite-incremental-fsync"
    42) "yes"
    43) "no-appendfsync-on-rewrite"
    44) "no"
    45) "cluster-require-full-coverage"
    46) "yes"
    47) "rdb-save-incremental-fsync"
    48) "yes"
    49) "aof-load-truncated"
    50) "yes"
    51) "aof-use-rdb-preamble"
    52) "yes"
    53) "cluster-replica-no-failover"
    54) "no"
    55) "cluster-slave-no-failover"
    56) "no"
    57) "replica-lazy-flush"
    58) "no"
    59) "slave-lazy-flush"
    60) "no"
    61) "replica-serve-stale-data"
    62) "yes"
    63) "slave-serve-stale-data"
    64) "yes"
    65) "replica-read-only"
    66) "yes"
    67) "slave-read-only"
    68) "yes"
    69) "replica-ignore-maxmemory"
    70) "yes"
    71) "slave-ignore-maxmemory"
    72) "yes"
    73) "jemalloc-bg-thread"
    74) "yes"
    75) "activedefrag"
    76) "no"
    77) "syslog-enabled"
    78) "no"
    79) "cluster-enabled"
    80) "no"
    81) "appendonly"
    82) "no"
    83) "cluster-allow-reads-when-down"
    84) "no"
    85) "crash-log-enabled"
    86) "yes"
    87) "crash-memcheck-enabled"
    88) "yes"
    89) "use-exit-on-panic"
    90) "no"
    91) "disable-thp"
    92) "yes"
    93) "cluster-allow-replica-migration"
    94) "yes"
    95) "replica-announced"
    96) "yes"
    97) "aclfile"
    98) ""
    99) "unixsocket"
    100) ""
    101) "pidfile"
    102) "/var/run/redis_6379.pid"
    103) "replica-announce-ip"
    104) ""
    105) "slave-announce-ip"
    106) ""
    107) "masteruser"
    108) ""
    109) "cluster-announce-ip"
    110) ""
    111) "syslog-ident"
    112) "redis"
    113) "dbfilename"
    114) "dump.rdb"
    115) "appendfilename"
    116) "appendonly.aof"
    117) "server_cpulist"
    118) ""
    119) "bio_cpulist"
    120) ""
    121) "aof_rewrite_cpulist"
    122) ""
    123) "bgsave_cpulist"
    124) ""
    125) "ignore-warnings"
    126) ""
    127) "proc-title-template"
    128) "{title} {listen-addr} {server-mode}"
    129) "masterauth"
    130) ""
    131) "requirepass"
    132) "yanpenggong"
    133) "supervised"
    134) "no"
    135) "syslog-facility"
    136) "local0"
    137) "repl-diskless-load"
    138) "disabled"
    139) "loglevel"
    140) "notice"
    141) "maxmemory-policy"
    142) "noeviction"
    143) "appendfsync"
    144) "everysec"
    145) "oom-score-adj"
    146) "no"
    147) "acl-pubsub-default"
    148) "allchannels"
    149) "sanitize-dump-payload"
    150) "no"
    151) "databases"
    152) "16"
    153) "port"
    154) "6379"
    155) "io-threads"
    156) "1"
    157) "auto-aof-rewrite-percentage"
    158) "100"
    159) "cluster-replica-validity-factor"
    160) "10"
    161) "cluster-slave-validity-factor"
    162) "10"
    163) "list-max-ziplist-size"
    164) "-2"
    165) "tcp-keepalive"
    166) "300"
    167) "cluster-migration-barrier"
    168) "1"
    169) "active-defrag-cycle-min"
    170) "1"
    171) "active-defrag-cycle-max"
    172) "25"
    173) "active-defrag-threshold-lower"
    174) "10"
    175) "active-defrag-threshold-upper"
    176) "100"
    177) "lfu-log-factor"
    178) "10"
    179) "lfu-decay-time"
    180) "1"
    181) "replica-priority"
    182) "100"
    183) "slave-priority"
    184) "100"
    185) "repl-diskless-sync-delay"
    186) "5"
    187) "maxmemory-samples"
    188) "5"
    189) "maxmemory-eviction-tenacity"
    190) "10"
    191) "timeout"
    192) "300"
    193) "replica-announce-port"
    194) "0"
    195) "slave-announce-port"
    196) "0"
    197) "tcp-backlog"
    198) "511"
    199) "cluster-announce-bus-port"
    200) "0"
    201) "cluster-announce-port"
    202) "0"
    203) "cluster-announce-tls-port"
    204) "0"
    205) "repl-timeout"
    206) "60"
    207) "repl-ping-replica-period"
    208) "10"
    209) "repl-ping-slave-period"
    210) "10"
    211) "list-compress-depth"
    212) "0"
    213) "rdb-key-save-delay"
    214) "0"
    215) "key-load-delay"
    216) "0"
    217) "active-expire-effort"
    218) "1"
    219) "hz"
    220) "10"
    221) "min-replicas-to-write"
    222) "0"
    223) "min-slaves-to-write"
    224) "0"
    225) "min-replicas-max-lag"
    226) "10"
    227) "min-slaves-max-lag"
    228) "10"
    229) "maxclients"
    230) "10000"
    231) "active-defrag-max-scan-fields"
    232) "1000"
    233) "slowlog-max-len"
    234) "128"
    235) "acllog-max-len"
    236) "128"
    237) "lua-time-limit"
    238) "5000"
    239) "cluster-node-timeout"
    240) "15000"
    241) "slowlog-log-slower-than"
    242) "10000"
    243) "latency-monitor-threshold"
    244) "0"
    245) "proto-max-bulk-len"
    246) "536870912"
    247) "stream-node-max-entries"
    248) "100"
    249) "repl-backlog-size"
    250) "1048576"
    251) "maxmemory"
    252) "0"
    253) "hash-max-ziplist-entries"
    254) "512"
    255) "set-max-intset-entries"
    256) "512"
    257) "zset-max-ziplist-entries"
    258) "128"
    259) "active-defrag-ignore-bytes"
    260) "104857600"
    261) "hash-max-ziplist-value"
    262) "64"
    263) "stream-node-max-bytes"
    264) "4096"
    265) "zset-max-ziplist-value"
    266) "64"
    267) "hll-sparse-max-bytes"
    268) "3000"
    269) "tracking-table-max-keys"
    270) "1000000"
    271) "client-query-buffer-limit"
    272) "1073741824"
    273) "repl-backlog-ttl"
    274) "3600"
    275) "auto-aof-rewrite-min-size"
    276) "67108864"
    277) "logfile"
    278) ""
    279) "watchdog-period"
    280) "0"
    281) "dir"
    282) "/opt/software/redis-6.2.6"
    283) "save"
    284) "900 1 300 10 60 10000"
    285) "client-output-buffer-limit"
    286) "normal 0 0 0 slave 268435456 67108864 60 pubsub 33554432 8388608 60"
    287) "unixsocketperm"
    288) "0"
    289) "slaveof"
    290) ""
    291) "notify-keyspace-events"
    292) ""
    293) "bind"
    294) "0.0.0.0"
    295) "oom-score-adj-values"
    296) "0 200 800"
    127.0.0.1:6379>

2.2 编辑配置

要更新配置,可以直接编辑 redis.conf 文件,也可以通过 CONFIG set 命令更新配置。

  1. 语法

    1
    127.0.0.1:6379> CONFIG SET CONFIG_SETTING_NAME NEW_CONFIG_VALUE
  2. 实例

    1
    2
    3
    4
    5
    6
    127.0.0.1:6379> CONFIG SET loglevel "notice"
    OK
    127.0.0.1:6379> CONFIG GET loglevel
    1) "loglevel"
    2) "notice"
    127.0.0.1:6379>
  3. 常用配置参数说明

    redis.conf 配置项说明如下:

    | 序号 | 配置项 | 说明 |
    | —— | —————————————————————————————— | —————————————————————————————— |
    | 1 | daemonize no | Redis 默认不是以守护进程的方式运行,可以通过该配置项修改,使用 yes 启用守护进程(Windows 不支持守护线程的配置为 no ) |
    | 2 | pidfile /var/run/redis.pid | 当 Redis 以守护进程方式运行时,Redis 默认会把 pid 写入 /var/run/redis.pid 文件,可以通过 pidfile 指定 |
    | 3 | port 6379 | 指定 Redis 监听端口,默认端口为 6379,作者在自己的一篇博文中解释了为什么选用 6379 作为默认端口,因为 6379 在手机按键上 MERZ 对应的号码,而 MERZ 取自意大利歌女 Alessia Merz 的名字 |
    | 4 | bind 127.0.0.1 | 绑定的主机地址 |
    | 5 | timeout 300 | 当客户端闲置多长秒后关闭连接,如果指定为 0 ,表示关闭该功能 |
    | 6 | loglevel notice | 指定日志记录级别,Redis 总共支持四个级别:debug、verbose、notice、warning,默认为 notice |
    | 7 | logfile stdout | 日志记录方式,默认为标准输出,如果配置 Redis 为守护进程方式运行,而这里又配置为日志记录方式为标准输出,则日志将会发送给 /dev/null |
    | 8 | databases 16 | 设置数据库的数量,默认数据库为0,可以使用SELECT 命令在连接上指定数据库id |
    | 9 | save <seconds> <changes>
    Redis 默认配置文件中提供了三个条件:
    - save 900 1: 900 秒(15 分钟)内有 1 个更改
    - save 300 10: 300 秒(5 分钟)内有 10 个更改
    - save 60 10000: 60 秒内有 10000 个更改 | 指定在多长时间内,有多少次更新操作,就将数据同步到数据文件,可以多个条件配合 |
    | 10 | rdbcompression yes | 指定存储至本地数据库时是否压缩数据,默认为 yes,Redis 采用 LZF 压缩,如果为了节省 CPU 时间,可以关闭该选项,但会导致数据库文件变的巨大 |
    | 11 | dbfilename dump.rdb | 指定本地数据库文件名,默认值为 dump.rdb |
    | 12 | dir ./ | 指定本地数据库存放目录 |
    | 13 | slaveof <masterip> <masterport> | 设置当本机为 slave 服务时,设置 master 服务的 IP 地址及端口,在 Redis 启动时,它会自动从 master 进行数据同步 |
    | 14 | masterauth <master-password> | 当 master 服务设置了密码保护时,slave 服务连接 master 的密码 |
    | 15 | requirepass foobared | 设置 Redis 连接密码,如果配置了连接密码,客户端在连接 Redis 时需要通过 AUTH <password> 命令提供密码,默认关闭 |
    | 16 | maxclients 128 | 设置同一时间最大客户端连接数,默认无限制,Redis 可以同时打开的客户端连接数为 Redis 进程可以打开的最大文件描述符数,如果设置 maxclients 0,表示不作限制。当客户端连接数到达限制时,Redis 会关闭新的连接并向客户端返回 max number of clients reached 错误信息 |
    | 17 | maxmemory <bytes> | 指定 Redis 最大内存限制,Redis 在启动时会把数据加载到内存中,达到最大内存后,Redis 会先尝试清除已到期或即将到期的 Key,当此方法处理 后,仍然到达最大内存设置,将无法再进行写入操作,但仍然可以进行读取操作。Redis 新的 vm 机制,会把 Key 存放内存,Value 会存放在 swap 区 |
    | 18 | appendonly no | 指定是否在每次更新操作后进行日志记录,
    Redis 在默认情况下是异步的把数据写入磁盘,如果不开启,可能会在断电时导致一段时间内的数据丢失。
    因为 redis 本身同步数据文件是按上面 save 条件来同步的,所以有的数据会在一段时间内只存在于内存中。默认为 no |
    | 19 | appendfilename appendonly.aof | 指定更新日志文件名,默认为 appendonly.aof |
    | 20 | appendfsync everysec | 指定更新日志条件,共有 3 个可选值:
    - no:表示等操作系统进行数据缓存同步到磁盘(快)
    - always:表示每次更新操作后手动调用 fsync() 将数据写到磁盘(慢,安全)
    - everysec:表示每秒同步一次(折中,默认值) |
    | 21 | vm-enabled no | 指定是否启用虚拟内存机制,默认值为 no,
    简单的介绍一下,VM 机制将数据分页存放,由 Redis 将访问量较少的页即冷数据 swap 到磁盘上,访问多的页面由磁盘自动换出到内存中(在后面的内容会仔细分析 Redis 的 VM 机制) |
    | 22 | vm-swap-file /tmp/redis.swap | 虚拟内存文件路径,默认值为 /tmp/redis.swap,不可多个 Redis 实例共享 |
    | 23 | vm-max-memory 0 | 将所有大于 vm-max-memory 的数据存入虚拟内存,无论 vm-max-memory 设置多小,所有索引数据都是内存存储的(Redis 的索引数据 就是 keys),
    也就是说,当 vm-max-memory 设置为 0 的时候,其实是所有 value 都存在于磁盘。默认值为 0 |
    | 24 | vm-page-size 32 | Redis swap 文件分成了很多的 page,一个对象可以保存在多个 page 上面,但一个 page 上不能被多个对象共享,
    vm-page-size 是要根据存储的 数据大小来设定的,
    建议如果存储很多小对象,page 大小最好设置为 32 或者 64bytes;
    如果存储很大大对象,则可以使用更大的 page,如果不确定,就使用默认值 |
    | 25 | vm-pages 134217728 | 设置 swap 文件中的 page 数量,由于页表(一种表示页面空闲或使用的 bitmap)是在放在内存中的,,在磁盘上每 8 个 pages 将消耗 1byte 的内存。 |
    | 26 | vm-max-threads 4 | 设置访问swap文件的线程数,最好不要超过机器的核数,如果设置为0,那么所有对swap文件的操作都是串行的,可能会造成比较长时间的延迟。默认值为4 |
    | 27 | glueoutputbuf yes | 设置在向客户端应答时,是否把较小的包合并为一个包发送,默认为开启 |
    | 28 | hash-max-zipmap-entries 64
    hash-max-zipmap-value 512 | 指定在超过一定的数量或者最大的元素超过某一临界值时,采用一种特殊的哈希算法 |
    | 29 | activerehashing yes | 指定是否激活重置哈希,默认为开启(后面在介绍 Redis 的哈希算法时具体介绍) |
    | 30 | include /path/to/local.conf | 指定包含其它的配置文件,可以在同一主机上多个Redis实例之间使用同一份配置文件,而同时各个实例又拥有自己的特定配置文件 |

3. Redis数据类型

Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合), 位图(Bitmaps), 基数统计(HyperLogLogs)。

各个数据类型应用场景:

类型 简介 特性 场景
String(字符串) 二进制安全 可以包含任何数据,比如jpg图片或者序列化的对象,一个键最大能存储512M —-
Hash(字典) 键值对集合,即编程语言中的Map类型 适合存储对象,并且可以像数据库中update一个属性一样只修改某一项属性值(Memcached中需要取出整个字符串反序列化成对象修改完再序列化存回去) 存储、读取、修改用户属性
List(列表) 链表(双向链表) 增删快,提供了操作某一段元素的API 1,最新消息排行等功能(比如朋友圈的时间线) 2,消息队列
Set(集合) 哈希表实现,元素不重复 1、添加、删除,查找的复杂度都是O(1) 2、为集合提供了求交集、并集、差集等操作 1、共同好友 2、利用唯一性,统计访问网站的所有独立ip 3、好友推荐时,根据tag求交集,大于某个阈值就可以推荐
Sorted Set(有序集合) 将Set中的元素增加一个权重参数score,元素按score有序排列 数据插入集合时,已经进行天然排序 1、排行榜 2、带权重的消息队列

3.1 string(字符串)

string 是 redis 最基本的类型,你可以理解成与 Memcached 一模一样的类型,一个 key 对应一个 value。

string 类型是二进制安全的。意思是 redis 的 string 可以包含任何数据。比如jpg图片或者序列化的对象。

string 类型是 Redis 最基本的数据类型,string 类型的值最大能存储 512MB。

可以在Redis中使用字符串做一些有趣的事情,例如,您可以:

  • 使用INCR系列中的命令将字符串用作原子计数器:INCRDECRINCRBY
  • 使用 APPEND 命令附加到字符串。
  • 使用字符串作为 <a href=”#GETRANGESETRANGE 的随机访问向量。
  • 在小空间中编码大量数据,或使用 GETBITSETBIT 创建Redis支持的Bloom过滤器。

检查所有 可用的字符串命令 以获取更多信息,或阅读==Redis数据类型的简介==。

实例:

1
2
3
4
5
127.0.0.1:6379> SET kungs "yanpenggong"
OK
127.0.0.1:6379> get kungs
"yanpenggong"
127.0.0.1:6379>

在以上实例中,使用了 Redis 的 SETGET 命令。键为 kungs,对应的值为 yanpenggong

注意:一个键最大能存储 512MB。

3.2 hash(哈希)

Redis hash 是一个键值(key=>value)对集合。

Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。

实例:

DEL kungs 用于删除前面测试用过的 key,不然会报错:(error) WRONGTYPE Operation against a key holding the wrong kind of value

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
127.0.0.1:6379> SET kungs "yanpenggong"
OK
127.0.0.1:6379> GET kungs
"yanpenggong"
127.0.0.1:6379> HMSET kungs field1 "Hello" field2 "World"
(error) WRONGTYPE Operation against a key holding the wrong kind of value
127.0.0.1:6379> DEL kungs
(integer) 1
127.0.0.1:6379> HMSET kungs field1 "Hello" field2 "World"
OK
127.0.0.1:6379> HGET kungs field1
"Hello"
127.0.0.1:6379> HGET kungs field2
"World"
127.0.0.1:6379>

实例中我们使用了 Redis HMSET, HGET 命令,HMSET 设置了两个 field=>value 对, HGET 获取对应 field 对应的 value

每个 hash 可以存储 232 -1 键值对(40多亿)。

3.3 list(列表)

Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
127.0.0.1:6379> DEL kungs
(integer) 1
127.0.0.1:6379> lpush kungs redis
(integer) 1
127.0.0.1:6379> lpush kungs mongodb
(integer) 2
127.0.0.1:6379> lpush kungs rabbitmq
(integer) 3
127.0.0.1:6379> lpush kungs cassandra
(integer) 4
127.0.0.1:6379> lrange kungs 0 10
1) "cassandra"
2) "rabbitmq"
3) "mongodb"
4) "redis"
127.0.0.1:6379>

列表最多可存储 $2^{32} - 1$ 元素 (4294967295, 每个列表可存储40多亿)。

3.4 set(集合)

Redis 的 Set 是 string 类型的无序集合。

集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。

  1. sadd 命令

    添加一个 string 元素到 key 对应的 set 集合中,成功返回 1,如果元素已经在集合中返回 0。

    1
    sadd key member
  2. 实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    127.0.0.1:6379> DEL kungs
    (integer) 1
    127.0.0.1:6379> sadd kungs redis
    (integer) 1
    127.0.0.1:6379> sadd kungs mongodb
    (integer) 1
    127.0.0.1:6379> sadd kungs rabbitmq
    (integer) 1
    127.0.0.1:6379> sadd kungs rabbitmq
    (integer) 0
    127.0.0.1:6379> smembers kungs
    1) "rabbitmq"
    2) "mongodb"
    3) "redis"
    127.0.0.1:6379>

    注意:以上实例中 rabbitmq 添加了两次,但根据集合内元素的唯一性,第二次插入的元素将被忽略。

    集合中最大的成员数为 $2^{32} - 1$ (4294967295, 每个集合可存储40多亿个成员)。

3.5 zset(sorted set:有序集合)。

Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。

不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。

zset的成员是唯一的,但分数(score)却可以重复。

  1. zadd 命令

    添加元素到集合,元素在集合中存在则更新对应score

    1
    zadd key score member 
  2. 实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    127.0.0.1:6379> DEL kungs
    Error: Server closed the connection
    127.0.0.1:6379> DEL kungs
    (integer) 1
    127.0.0.1:6379> zadd kungs 0 redis
    (integer) 1
    127.0.0.1:6379> zadd kungs 0 mongodb
    (integer) 1
    127.0.0.1:6379> zadd kungs 0 rabbitmq
    (integer) 1
    127.0.0.1:6379> zadd kungs 0 rabbitmq
    (integer) 0
    127.0.0.1:6379> zrangebyscore kungs 0 1000
    1) "mongodb"
    2) "rabbitmq"
    3) "redis"
    127.0.0.1:6379>

3.6 位图(Bitmaps)

Redis Bitmap 通过类似 map 结构存放 0 或 1 ( bit 位 ) 作为值。

Redis Bitmap 可以用来统计状态,如日活是否浏览过某个东西。

  1. Redis setbit 命令

    1
    SETBIT key offset value
  2. 实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    127.0.0.1:6379> DEL kungs
    (integer) 1
    127.0.0.1:6379> setbit kungs:001 10001 1
    (integer) 0
    127.0.0.1:6379> setbit kungs:001 10002 2
    (error) ERR bit is not an integer or out of range
    127.0.0.1:6379> setbit kungs:001 10002 0
    (integer) 0
    127.0.0.1:6379> setbit kungs:001 10003 1
    (integer) 0
    127.0.0.1:6379> getbit kungs:001 10001
    (integer) 1
    127.0.0.1:6379> getbit kungs:001 10002
    (integer) 0
    127.0.0.1:6379> getbit kungs:001 10003
    (integer) 1
    127.0.0.1:6379>

3.7 基数统计(HyperLogLogs)

Redis HyperLogLog 可以接受多个元素作为输入,并给出输入元素的基数估算值

  • 基数

集合中不同元素的数量,比如 {‘apple’, ‘banana’, ‘cherry’, ‘banana’, ‘apple’} 的基数就是 3

  • 估算值

算法给出的基数并不是精确的,可能会比实际稍微多一些或者稍微少一些,但会控制在合 理的范围之内

HyperLogLog 的优点是:即使输入元素的数量或者体积非常非常大,计算基数所需的空间总是固定的、并且是很小的

在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 264个不同元素的基数。

这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。

因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。

  1. Redis PFADD命令

    Redis PFADD 命令将元素添加至 HyperLogLog

    1
    PFADD key element [element ...]
  2. 实例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> PFADD unique::ip::counter "192.168.0.1"
    (integer) 1
    127.0.0.1:6379> PFADD unique::ip::counter "127.0.0.1"
    (integer) 1
    127.0.0.1:6379> PFADD unique::ip::counter "255.255.255.255"
    (integer) 1
    127.0.0.1:6379> PFCOUNT unique::ip::counter
    (integer) 3
    127.0.0.1:6379>

3.8 数据库的数据注意事项

注意:Redis支持多个数据库,并且每个数据库的数据是隔离的不能共享,并且基于单机才有,如果是集群就没有数据库的概念。

Redis是一个字典结构的存储服务器,而实际上一个Redis实例提供了多个用来存储数据的字典,客户端可以指定将数据存储在哪个字典中。这与我们熟知的在一个关系数据库实例中可以创建多个数据库类似,所以可以将其中的每个字典都理解成一个独立的数据库。

每个数据库对外都是一个从0开始的递增数字命名,Redis默认支持16个数据库(可以通过配置文件支持更多,无上限),可以通过配置databases来修改这一数字。客户端与Redis建立连接后会自动选择0号数据库,不过可以随时使用SELECT命令更换数据库,如要选择1号数据库:

1
2
3
4
5
6
7
8
9
127.0.0.1:6379> set kungs1 "Hello"
OK
127.0.0.1:6379> get kungs1
Hello
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> get kungs1

127.0.0.1:6379[1]>

然而这些以数字命名的数据库又与我们理解的数据库有所区别。

  • 首先Redis不支持自定义数据库的名字,每个数据库都以编号命名,开发者必须自己记录哪些数据库存储了哪些数据。
  • 另外Redis也不支持为每个数据库设置不同的访问密码,所以一个客户端要么可以访问全部数据库,要么连一个数据库也没有权限访问。
  • 最重要的一点是多个数据库之间并不是完全隔离的,比如FLUSHALL命令可以清空一个Redis实例中所有数据库中的数据。

综上所述,这些数据库更像是一种命名空间,而不适宜存储不同应用程序的数据。

比如可以使用0号数据库存储某个应用生产环境中的数据,使用1号数据库存储测试环境中的数据,但不适宜使用0号数据库存储A应用的数据而使用1号数据库B应用的数据,不同的应用应该使用不同的Redis实例存储数据。

由于Redis非常轻量级,一个空Redis实例占用的内存只有1M左右,所以不用担心多个Redis实例会额外占用很多内存。

4. Redis 命令

4.0 Redis 命令

4.0.1 本地执行命令

Redis 命令用于在 redis 服务上执行操作。

要在 redis 服务上执行命令需要一个 redis 客户端。Redis 客户端在我们之前下载的的 redis 的安装包中。

  1. 语法

    1
    [root@00-0C-29-38-42-90 redis-6.2.6]# ./src/redis-cli -a yanpenggong
  2. 实例

    以下实例讲解了如何启动 redis 客户端:

    启动 redis 服务器,打开终端并输入命令 redis-cli,该命令会连接本地的 redis 服务。

    1
    2
    3
    4
    5
    [root@00-0C-29-38-42-90 redis-6.2.6]# ./src/redis-cli -a yanpenggong
    Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
    127.0.0.1:6379> ping
    PONG
    127.0.0.1:6379>

    在以上实例中我们连接到本地的 redis 服务并执行 PING 命令,该命令用于检测 redis 服务是否启动。

4.0.2 在远程服务上执行命令

如果需要在远程 redis 服务上执行命令,同样我们使用的也是 redis-cli 命令。

  1. 语法

    1
    [root@00-0C-29-38-42-90 redis-6.2.6]# ./src/redis-cli -h host -p port -a password
  2. 实例

    以下实例演示了如何连接到主机为 127.0.0.1,端口为 6379 ,密码为 yanpengong 的 redis 服务上。

    1
    2
    3
    4
    5
    [root@00-0C-29-38-42-90 redis-6.2.6]# ./src/redis-cli -h 127.0.0.1 -p 6379 -a "yanpenggong"
    Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
    127.0.0.1:6379> ping
    PONG
    127.0.0.1:6379>

4.0.3 中文乱码解决办法

有时候会有中文乱码。要在 redis-cli 后面加上 --raw

1
2
3
[root@00-0C-29-38-42-90 redis-6.2.6]# ./src/redis-cli -a yanpenggong --raw
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379>

4.1 Redis 键(Keys)

Redis 键命令用于管理 redis 的键。

4.1.1 基本操作

  1. 语法

    1
    127.0.0.1:6379> COMMAND KEY_NAME
  1. 实例

    实例中 DEL 是一个命令, kungs 是一个键。 如果键被删除成功,命令执行后输出 1,否则将输出 0

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> SET kungs redis
    OK
    127.0.0.1:6379> get kungs
    redis
    127.0.0.1:6379> DEL kungs
    1
    127.0.0.1:6379> DEL kungs
    0
    127.0.0.1:6379>

4.1.2 keys 基本命令汇总

序号 命令 描述
1 DEL key 用于在 key 存在时删除 key
2 DUMP key 序列化给定 key ,并返回被序列化的值
3 EXISTS key 检查给定 key 是否存在
4 EXPIRE key seconds 为给定 key 设置过期时间,以秒计
5 EXPIREAT key timestamp EXPIREAT 的作用和 EXPIRE 类似,都用于为 key 设置过期时间。
不同在于 EXPIREAT 命令接受的时间参数是 UNIX 时间戳(unix timestamp)
6 PEXPIRE key milliseconds 设置 key 的过期时间以毫秒计
7 PEXPIREAT key milliseconds-timestamp 设置 key 过期时间的时间戳(unix timestamp) 以毫秒计
8 KEYS pattern 查找所有符合给定模式( pattern)的 key
9 MOVE key db 将当前数据库的 key 移动到给定的数据库 db 当中
10 PERSIST key 移除 key 的过期时间,key 将持久保持
11 PTTL key 以毫秒为单位返回 key 的剩余的过期时间
12 TTL key 以秒为单位,返回给定 key 的剩余生存时间(TTL, time to live)
13 RANDOMKEY 从当前数据库中随机返回一个 key
14 RENAME key newkey 修改 key 的名称
15 RENAMENX key newkey 仅当 newkey 不存在时,将 key 改名为 newkey
16 SCAN cursor [MATCH pattern] [COUNT count] 迭代数据库中的数据库键
17 TYPE key 返回 key 所储存的值的类型

4.2 String(字符串)

Redis 字符串命令用于管理 Redis 中的字符串值。

4.2.1 基本操作

  1. 语法:

    1
    127.0.0.1:6379> COMMAND KEY_NAME
  2. 实例:

    1
    2
    3
    4
    5
    127.0.0.1:6379> SET kungs yanpenggong
    OK
    127.0.0.1:6379> GET kungs
    "yanpenggong"
    127.0.0.1:6379>

    这里,SET 和 GET 是命令,”kungs” 是键。

4.2.2 String 基本命令汇总

序号 命令 描述
1 SET 设置指定 key 的值
2 GET 获取指定 key 的值
3 GETRANGE 返回 key 中字符串值的子字符
4 GETSET 将给定 key 的值设为 value ,并返回 key 的旧值 ( old value )
5 GETBIT 对 key 所储存的字符串值,获取指定偏移量上的位 ( bit )
6 MGET 获取所有(一个或多个)给定 key 的值
7 SETBIT 对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)
8 SETEX 设置 key 的值为 value 同时将过期时间设为 seconds
9 SETNX 只有在 key 不存在时设置 key 的值
10 SETRANGE 从偏移量 offset 开始用 value 覆写给定 key 所储存的字符串值
11 STRLEN 返回 key 所储存的字符串值的长度
12 MSET 同时设置一个或多个 key-value 对
13 MSETNX 同时设置一个或多个 key-value 对
14 PSETEX 以毫秒为单位设置 key 的生存时间
15 INCR 将 key 中储存的数字值增一
16 INCRBY 将 key 所储存的值加上给定的增量值 ( increment )
17 INCRBYFLOAT 将 key 所储存的值加上给定的浮点增量值 ( increment )
18 DECR 将 key 中储存的数字值减一
19 DECRBY 将 key 所储存的值减去给定的减量值 ( decrement )
20 APPEND 将 value 追加到 key 原来的值的末尾

4.3 Hashes(哈希)

Redis hash 是一个 string 类型的 field 和 value 的映射表,hash 特别适合用于存储对象。

Redis 中每个 hash 可以存储 $2^{32} - 1$ 键值对(40多亿)。

4.3.1 基本操作

实例:

在例子中,rediscomcn 是 Redis 哈希,它包含详细信息(name,url,rank,visitors)属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
127.0.0.1:6379> HMSET rediscomcn name "yanpenggong" url "https://blog.csdn.net/yanpenggong" rank 1 visitors 2888
OK
127.0.0.1:6379> HGETALL redisconmcn
(empty array)
127.0.0.1:6379> HGETALL rediscomcn
1) "name"
2) "yanpenggong"
3) "url"
4) "https://blog.csdn.net/yanpenggong"
5) "rank"
6) "1"
7) "visitors"
8) "2888"
127.0.0.1:6379>

4.3.2 Hashes 基本命令汇总

序号 命令 描述
1 HDEL 删除一个或多个哈希表字段
2 HEXISTS 查看哈希表 key 中,指定的字段是否存在
3 HGET 获取存储在哈希表中指定字段的值
4 HGETALL 获取在哈希表中指定 key 的所有字段和值
5 HINCRBY 为哈希表 key 中的指定字段的整数值加上增量 increment
6 HINCRBYFLOAT 为哈希表 key 中的指定字段的浮点数值加上增量 increment
7 HKEYS 获取所有哈希表中的字段
8 HLEN 获取哈希表中字段的数量
9 HMGET 获取所有给定字段的值
10 HMSET 同时将多个 field-value (域-值)对设置到哈希表 key 中
11 HSET 将哈希表 key 中的字段 field 的值设为 value
12 HSETNX 只有在字段 field 不存在时,设置哈希表字段的值
13 HVALS 获取哈希表中所有值
14 HSCAN 迭代哈希表中的键值对
15 HSTRLEN 返回哈希表 key 中, 与给定域 field 相关联的值的字符串长度

4.4 List(列表)

Redis 列表是按插入顺序排序的字符串列表。可以在列表的头部(左边)或尾部(右边)添加元素。

列表可以包含超过 40 亿 个元素 ( $2^{32} - 1$ )。

4.4.1 基本操作

用 LPUSH 命令将三个值插入了名为 language 的列表当中:

1
2
3
4
5
6
7
8
9
10
11
127.0.0.1:6379> LPUSH dbs sql
(integer) 1
127.0.0.1:6379> LPUSH dbs mysql
(integer) 2
127.0.0.1:6379> LPUSH dbs mongodb
(integer) 3
127.0.0.1:6379> LRANGE dbs 0 10
1) "mongodb"
2) "mysql"
3) "sql"
127.0.0.1:6379>

4.4.2 List 基本命令汇总

序号 命令 描述
1 BLPOP 移出并获取列表的第一个元素
2 BRPOP 移出并获取列表的最后一个元素
3 BRPOPLPUSH 从列表中弹出一个值,并将该值插入到另外一个列表中并返回它
4 LINDEX 通过索引获取列表中的元素
5 LINSERT 在列表的元素前或者后插入元素
6 LLEN 获取列表长度
7 LPOP 移出并获取列表的第一个元素
8 LPUSH 将一个或多个值插入到列表头部
9 LPUSHX 将一个值插入到已存在的列表头部
10 LRANGE 获取列表指定范围内的元素
11 LREM 移除列表元素
12 LSET 通过索引设置列表元素的值
13 LTRIM 对一个列表进行修剪(trim)
14 RPOP 移除并获取列表最后一个元素
15 RPOPLPUSH 移除列表的最后一个元素,并将该元素添加到另一个列表并返回
16 RPUSH 在列表中添加一个或多个值
17 RPUSHX 为已存在的列表添加值

4.5 Set(集合)

Redis 的 Set 是 string 类型的无序集合。

集合成员是唯一的,这就意味着集合中没有重复的数据。

在 Redis 中,添加、删除和查找的时间复杂都是 O(1)(不管 Set 中包含多少元素)。

集合中最大的成员数为 $2^{32} – 1$ (4294967295), 每个集合可存储 40 多亿个成员。

4.5.1 基本操作

通过 SADD 命令向名为 rediscomcn 的集合插入的三个元素:

1
2
3
4
5
6
7
8
9
10
11
12
13
127.0.0.1:6379> SADD rediscomcn db2
(integer) 1
127.0.0.1:6379> SADD rediscomcn mongodb
(integer) 1
127.0.0.1:6379> SADD rediscomcn db2
(integer) 0
127.0.0.1:6379> SADD rediscomcn cassandra
(integer) 1
127.0.0.1:6379> SMEMBERS rediscomcn
1) "cassandra"
2) "mongodb"
3) "db2"
127.0.0.1:6379>

在上面的示例中,我们使用 SADD 命令在集合中添加了 4 个元素。但是,使用 SMEMBERS 命令只检索了 3 个元素,因为有一个元素是重复的,Redis 只集合只含唯一元素。

4.5.2 基本命令汇总

序号 命令 描述
1 SADD 向集合添加一个或多个成员
2 SCARD 获取集合的成员数
3 SDIFF 返回给定所有集合的差集
4 SDIFFSTORE 返回给定所有集合的差集并存储在 destination 中
5 SINTER 返回给定所有集合的交集
6 SINTERSTORE 返回给定所有集合的交集并存储在 destination 中
7 SISMEMBER 判断 member 元素是否是集合 key 的成员
8 SMEMBERS 返回集合中的所有成员
9 SMOVE 将 member 元素从 source 集合移动到 destination 集合
10 SPOP 移除并返回集合中的一个随机元素
11 SRANDMEMBER 返回集合中一个或多个随机数
12 SREM 移除集合中一个或多个成员
13 SUNION 返回所有给定集合的并集
14 SUNIONSTORE 所有给定集合的并集存储在 destination 集合中
15 SSCAN 迭代集合中的元素

4.6 Sorted Sets(有序集合)

Redis 有序集合和集合一样也是 string 类型元素的集合,且不允许重复的成员。

不同的是每个元素都会关联一个 double 类型的分数。Redis 正是通过分数来为集合中的成员进行从小到大的排序。

有序集合的成员是唯一的,但分数 ( score ) 却可以重复。

集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是 O(1)。

集合中最大的成员数为 $2^{32} – 1$ ( 4294967295 ) , 每个集合可存储 40 多亿个成员。

4.6.1 基本操作

通过 ZADD 命令向 Redis 的有序集合中添加了三个值并关联分数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
127.0.0.1:6379> ZADD rediscomcn 1 redis
(integer) 1
127.0.0.1:6379> ZADD rediscomcn 2 mongodb
(integer) 1
127.0.0.1:6379> ZADD rediscomcn 3 mongodb
(integer) 0
127.0.0.1:6379> ZADD rediscomcn 3 mysql
(integer) 1
127.0.0.1:6379> ZADD rediscomcn 4 mysql
(integer) 0
127.0.0.1:6379> ZRANGE rediscomcn 0 10 WITHSCORES
1) "redis"
2) "1"
3) "mongodb"
4) "3"
5) "mysql"
6) "4"
127.0.0.1:6379>

4.6.2 基本命令汇总

序号 命令 描述
1 ZADD 向有序集合添加一个或多个成员,或者更新已存在成员的分数
2 ZCARD 获取有序集合的成员数
3 ZCOUNT 计算在有序集合中指定区间分数的成员数
4 ZINCRBY 有序集合中对指定成员的分数加上增量 increment
5 ZINTERSTORE 计算给定的一个或多个有序集的交集并将结果集存储在新的有序集合 key 中
6 ZLEXCOUNT 在有序集合中计算指定字典区间内成员数量
7 ZRANGE 通过索引区间返回有序集合成指定区间内的成员
8 ZRANGEBYLEX 通过字典区间返回有序集合的成员
9 ZRANGEBYSCORE 通过分数返回有序集合指定区间内的成员
10 ZRANK 返回有序集合中指定成员的索引
11 ZREM 移除有序集合中的一个或多个成员
12 ZREMRANGEBYLEX 移除有序集合中给定的字典区间的所有成员
13 ZREMRANGEBYRANK 移除有序集合中给定的排名区间的所有成员
14 ZREMRANGEBYSCORE 移除有序集合中给定的分数区间的所有成员
15 ZREVRANGE 返回有序集中指定区间内的成员,通过索引,分数从高到底
16 ZREVRANGEBYSCORE 返回有序集中指定分数区间内的成员,分数从高到低排序
17 ZREVRANK 返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序
18 ZSCORE 返回有序集中,成员的分数值
19 ZUNIONSTORE 计算一个或多个有序集的并集,并存储在新的 key 中
20 ZSCAN 迭代有序集合中的元素(包括元素成员和元素分值)

4.7 Pub/Sub(发布订阅)

Redis 发布/订阅是一种消息传模式,其中发送者(在Redis术语中称为发布者)发送消息,而接收者(订阅者)接收消息。传递消息的通道称为channel

在Redis中,客户端可以订阅任意数量的频道。

下图展示了频道 channel1 , 以及订阅这个频道的三个客户端 —— client2 、 client5 和 client1 之间的关系:

1
2
3
4
graph BT;
client1-->|subscribe|channel1;
client2-->|subscribe|channel1;
client5-->|subscribe|channel1;

当有新消息通过 PUBLISH 命令发送给频道 channel1 时, 这个消息就会被发送给订阅它的三个客户端:

1
2
3
4
5
6
7
8
9
10
graph TB;
start(PUBLISH channel1 message)-->channel1(channel1);
channel1-->|message|client1(client1);
channel1-->|message|client2(client2);
channel1-->|message|client5(client5);
style start fill:#aaf
style channel1 fill:#90EE90
style client1 fill:#87CEFA
style client2 fill:#87CEFA
style client5 fill:#87CEFA

4.7.1 基本操作

以下实例演示了发布订阅是如何工作的,需要开启两个 redis-cli 客户端。

在我们实例中我们创建了订阅频道名为 rediscomcnChat:

  1. 第一个 redis-cli 客户端

    1
    2
    3
    4
    5
    6
    127.0.0.1:6379> SUBSCRIBE rediscomcnChat
    Reading messages... (press Ctrl-C to quit)
    1) "subscribe"
    2) "rediscomcnChat"
    3) (integer) 1

    现在,我们先重新开启个 redis 客户端(第二个redis-cli 客户端),然后在同一个频道 rediscomcnChat 发布两次消息,订阅者就能接收到消息。

  2. 第二个 redis-cli 客户端

    1
    2
    3
    4
    5
    127.0.0.1:6379> PUBLISH rediscomcnChat "Redis PUBLISH test"
    (integer) 1
    127.0.0.1:6379> PUBLISH rediscomcnChat "Learn redis with python"
    (integer) 1
    127.0.0.1:6379>
  1. 第一个redis-cli 客户端的最新接受信息

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    127.0.0.1:6379> SUBSCRIBE rediscomcnChat
    Reading messages... (press Ctrl-C to quit)
    1) "subscribe"
    2) "rediscomcnChat"
    3) (integer) 1
    1) "message"
    2) "rediscomcnChat"
    3) "Redis PUBLISH test"
    1) "message"
    2) "rediscomcnChat"
    3) "Learn redis with python"

4.7.2 基本命令汇总

序号 命令 描述
1 PSUBSCRIBE 订阅一个或多个符合给定模式的频道。
2 PUBSUB 查看订阅与发布系统状态。
3 PUBLISH 将信息发送到指定的频道。
4 PUNSUBSCRIBE 退订所有给定模式的频道。
5 SUBSCRIBE 订阅给定的一个或多个频道的信息。
6 UNSUBSCRIBE 指退订给定的频道。

4.8 Transaction(事务)

事务是指一个完整的动作,要么全部执行,要么什么也没有做

Redis 事务不是严格意义上的事务,只是用于帮助用户在一个步骤中执行多个命令。单个 Redis 命令的执行是原子性的,但 Redis 没有在事务上增加任何维持原子性的机制,所以 Redis 事务的执行并不是原子性的。

Redis 事务可以理解为一个打包的批量执行脚本,但批量指令并非原子化的操作,中间某条指令的失败不会导致前面已做指令的回滚,也不会造成后续的指令不做。

Redis 事务可以一次执行多个命令, 并且带有以下三个重要的保证:

  • 批量操作在发送 EXEC 命令前被放入队列缓存。
  • 收到 EXEC 命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
  • 在事务执行过程,其他客户端提交的命令请求不会插入到事务执行命令序列中。

一个事务从开始到执行会经历以下三个阶段:

  • 开始事务。
  • 命令入队。
  • 执行事务。

MULTI、EXEC、DISCARD、WATCH 这四个指令构成了 redis 事务处理的基础。

  1. MULTI 用来组装一个事务;
  2. EXEC 用来执行一个事务;
  3. DISCARD 用来取消一个事务;
  4. WATCH 用来监视一些 key,一旦这些 key 在事务执行之前被改变,则取消事务的执行。

在 Redis 中,通过使用MULTI命令启动事务,然后需要传递应在事务中执行的命令列表,之后整个事务由EXEC命令执行。

1
2
3
4
5
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> EXEC
(empty array)
127.0.0.1:6379>

4.8.1 基本操作

1
2
3
4
5
6
7
8
9
10
11
12
13
127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> SET myset redis
QUEUED
127.0.0.1:6379(TX)> GET myset
QUEUED
127.0.0.1:6379(TX)> INCR kungs
QUEUED
127.0.0.1:6379(TX)> EXEC
1) OK
2) "redis"
3) (integer) 1
127.0.0.1:6379>

在上面的例子中,我们看到了 QUEUED 的字样,这表示我们在用 MULTI 组装事务时,每一个命令都会进入到内存队列中缓存起来,如果出现 QUEUED 则表示我们这个命令成功插入了缓存队列,在将来执行 EXEC 时,这些被 QUEUED 的命令都会被组装成一个事务来执行。

对于事务的执行来说,如果 redis 开启了 AOF 持久化的话,那么一旦事务被成功执行,事务中的命令就会通过 write 命令一次性写到磁盘中去,如果在向磁盘中写的过程中恰好出现断电、硬件故障等问题,那么就可能出现只有部分命令进行了 AOF 持久化,这时 AOF 文件就会出现不完整的情况,这时,我们可以使用 redis-check-aof 工具来修复这一问题,这个工具会将 AOF 文件中不完整的信息移除,确保 AOF 文件完整可用。

Redis 事务错误

有关事务,大家经常会遇到的是两类错误:

  • 调用 EXEC 之前的错误
  • 调用 EXEC 之后的错误

调用 EXEC 之前的错误,有可能是由于语法有误导致的,也可能时由于内存不足导致的。只要出现某个命令无法成功写入缓冲队列的情况,redis 都会进行记录,在客户端调用 EXEC 时,redis 会拒绝执行这一事务。(这是 2.6.5 版本之后的策略。在 2.6.5 之前的版本中,redis 会忽略那些入队失败的命令,只执行那些入队成功的命令)。我们来看一个这样的例子:

1
2
3
4
5
6
7
8
9
127.0.0.1:6379> multi
OK
127.0.0.1:6379> haha //一个明显错误的指令
(error) ERR unknown command 'haha'
127.0.0.1:6379> ping
QUEUED
127.0.0.1:6379> exec
//redis无情的拒绝了事务的执行,原因是“之前出现了错误”
(error) EXECABORT Transaction discarded because of previous errors.

而对于调用 EXEC 之后的错误,redis 则采取了完全不同的策略,即 redis 不会理睬这些错误,而是继续向下执行事务中的其他命令。这是因为,对于应用层面的错误,并不是 redis 自身需要考虑和处理的问题,所以一个事务中如果某一条命令执行失败,并不会影响接下来的其他命令的执行。我们也来看一个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set age 23
QUEUED
//age不是集合,所以如下是一条明显错误的指令
127.0.0.1:6379> sadd age 15
QUEUED
127.0.0.1:6379> set age 29
QUEUED
127.0.0.1:6379> exec //执行事务时,redis不会理睬第2条指令执行错误
1) OK
2) (error) WRONGTYPE Operation against a key holding the wrong kind of value
3) OK
127.0.0.1:6379> get age
"29" //可以看出第3条指令被成功执行了

最后,我们来说说最后一个指令WATCH,这是一个很好用的指令,它可以帮我们实现类似于“乐观锁”的效果,即CAS(check and set)

WATCH 本身的作用是监视 key 是否被改动过,而且支持同时监视多个 key,只要还没真正触发事务,WATCH 都会尽职尽责的监视,一旦发现某个 key 被修改了,在执行 EXEC 时就会返回 nil,表示事务无法触发。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
127.0.0.1:6379> set age 23
OK
127.0.0.1:6379> watch age //开始监视age
OK
127.0.0.1:6379> set age 24 //在EXEC之前,age的值被修改了
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379> set age 25
QUEUED
127.0.0.1:6379> get age
QUEUED
127.0.0.1:6379> exec //触发EXEC
(nil) //事务无法被执行

4.8.2 基本命令汇总

序号 命令 描述
1 DISCARD 取消事务,放弃执行事务块内的所有命令
2 EXEC 执行所有事务块内的命令
3 MULTI 标记一个事务块的开始
4 UNWATCH 取消 WATCH 命令对所有 key 的监视
5 WATCH 监视一个(或多个) key

4.9 Script(脚本)

Redis 脚本使用 Lua 解释器来执行脚本。

自版本 2.6.0 开始内嵌于 Redis 中。

用于编写脚本的命令是 EVAL。

4.9.1 基本操作

  • 语法:

    1
    127.0.0.1:6379> EVAL script numkeys key [key ...] arg [arg ...]
  • 实例:

    1
    2
    3
    4
    5
    6
    127.0.0.1:6379> EVAL "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second
    1) "key1"
    2) "key2"
    3) "first"
    4) "second"
    127.0.0.1:6379>

4.9.2 基本命令汇总

序号 命令 描述
1 EVAL script numkeys key [key ...] arg [arg ...] 执行 Lua 脚本。
2 EVALSHA sha1 numkeys key [key ...] arg [arg ...] 执行 Lua 脚本。
3 SCRIPT EXISTS sha1 [sha1 ...] 查看指定的脚本是否已经被保存在缓存当中。
4 SCRIPT FLUSH 从脚本缓存中移除所有脚本。
5 SCRIPT KILL 杀死当前正在运行的 Lua 脚本。
6 SCRIPT LOAD script 将脚本 script 添加到脚本缓存中,但并不立即执行这个脚本。

4.10 Connection(连接)

Redis 连接命令用于控制和管理到 Redis Server 的客户端连接。

4.10.1 基本操作

示例说明客户端如何向 Redis 服务器验证自身并检查服务器是否正在运行。

1
2
3
4
5
6
7
8
[root@localhost redis-6.2.6]# src/redis-cli
127.0.0.1:6379> PING
(error) NOAUTH Authentication required.
127.0.0.1:6379> AUTH "yanpenggong"
OK
127.0.0.1:6379> PING
PONG
127.0.0.1:6379>

注意:在这里您可以看到未设置“密码”,因此您可以直接访问任何命令。

4.10.2 基本命令汇总

序号 命令 描述
1 AUTH password 验证密码是否正确
2 ECHO message 打印字符串
3 PING 查看服务是否运行
4 QUIT 关闭当前连接
5 SELECT index 切换到指定的数据库

4.11 Server(服务器)

Redis Server 命令用于管理 Redis 服务器。

有不同的服务器命令可用于获取服务器信息,统计信息和其他特征。

4.11.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
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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
127.0.0.1:6379> PING
PONG
127.0.0.1:6379> AUTH "password"
(error) WRONGPASS invalid username-password pair or user is disabled.
127.0.0.1:6379> AUTH "yanpenggong"
OK
127.0.0.1:6379> PING
PONG
127.0.0.1:6379> ECHO "Welcome to use redis!"
"Welcome to use redis!"
127.0.0.1:6379> INFO
# Server
redis_version:6.2.6
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:eac5b3c736e2a107
redis_mode:standalone
os:Linux 3.10.0-1160.el7.x86_64 x86_64
arch_bits:64
multiplexing_api:epoll
atomicvar_api:atomic-builtin
gcc_version:4.8.5
process_id:17277
process_supervised:no
run_id:4884ead059e4a0ad9cb88e2231856af69ff9ac7e
tcp_port:6379
server_time_usec:1653053635898059
uptime_in_seconds:112803
uptime_in_days:1
hz:10
configured_hz:10
lru_clock:8886467
executable:/opt/software/redis-6.2.6/./src/redis-server
config_file:/opt/software/redis-6.2.6/./redis.conf
io_threads_active:0

# Clients
connected_clients:1
cluster_connections:0
maxclients:10000
client_recent_max_input_buffer:24
client_recent_max_output_buffer:0
blocked_clients:0
tracking_clients:0
clients_in_timeout_table:0

# Memory
used_memory:879392
used_memory_human:858.78K
used_memory_rss:3112960
used_memory_rss_human:2.97M
used_memory_peak:977792
used_memory_peak_human:954.88K
used_memory_peak_perc:89.94%
used_memory_overhead:832376
used_memory_startup:810112
used_memory_dataset:47016
used_memory_dataset_perc:67.86%
allocator_allocated:924912
allocator_active:1191936
allocator_resident:3473408
total_system_memory:1019572224
total_system_memory_human:972.34M
used_memory_lua:43008
used_memory_lua_human:42.00K
used_memory_scripts:248
used_memory_scripts_human:248B
number_of_cached_scripts:2
maxmemory:0
maxmemory_human:0B
maxmemory_policy:noeviction
allocator_frag_ratio:1.29
allocator_frag_bytes:267024
allocator_rss_ratio:2.91
allocator_rss_bytes:2281472
rss_overhead_ratio:0.90
rss_overhead_bytes:-360448
mem_fragmentation_ratio:3.72
mem_fragmentation_bytes:2276328
mem_not_counted_for_evict:0
mem_replication_backlog:0
mem_clients_slaves:0
mem_clients_normal:20504
mem_aof_buffer:0
mem_allocator:jemalloc-5.1.0
active_defrag_running:0
lazyfree_pending_objects:0
lazyfreed_objects:0

# Persistence
loading:0
current_cow_size:0
current_cow_size_age:0
current_fork_perc:0.00
current_save_keys_processed:0
current_save_keys_total:0
rdb_changes_since_last_save:1
rdb_bgsave_in_progress:0
rdb_last_save_time:1653053235
rdb_last_bgsave_status:ok
rdb_last_bgsave_time_sec:0
rdb_current_bgsave_time_sec:-1
rdb_last_cow_size:462848
aof_enabled:0
aof_rewrite_in_progress:0
aof_rewrite_scheduled:0
aof_last_rewrite_time_sec:-1
aof_current_rewrite_time_sec:-1
aof_last_bgrewrite_status:ok
aof_last_write_status:ok
aof_last_cow_size:0
module_fork_in_progress:0
module_fork_last_cow_size:0

# Stats
total_connections_received:86
total_commands_processed:874
instantaneous_ops_per_sec:0
total_net_input_bytes:34468
total_net_output_bytes:400133
instantaneous_input_kbps:0.00
instantaneous_output_kbps:0.00
rejected_connections:0
sync_full:0
sync_partial_ok:0
sync_partial_err:0
expired_keys:0
expired_stale_perc:0.00
expired_time_cap_reached_count:0
expire_cycle_cpu_milliseconds:6178
evicted_keys:0
keyspace_hits:194
keyspace_misses:13
pubsub_channels:0
pubsub_patterns:0
latest_fork_usec:955
total_forks:72
migrate_cached_sockets:0
slave_expires_tracked_keys:0
active_defrag_hits:0
active_defrag_misses:0
active_defrag_key_hits:0
active_defrag_key_misses:0
tracking_total_keys:0
tracking_total_items:0
tracking_total_prefixes:0
unexpected_error_replies:0
total_error_replies:78
dump_payload_sanitizations:0
total_reads_processed:885
total_writes_processed:872
io_threaded_reads_processed:0
io_threaded_writes_processed:0

# Replication
role:master
connected_slaves:0
master_failover_state:no-failover
master_replid:5747e010248e99df63f6fc7132cd4f5e778e4c23
master_replid2:0000000000000000000000000000000000000000
master_repl_offset:0
second_repl_offset:-1
repl_backlog_active:0
repl_backlog_size:1048576
repl_backlog_first_byte_offset:0
repl_backlog_histlen:0

# CPU
used_cpu_sys:207.781743
used_cpu_user:235.973647
used_cpu_sys_children:0.431789
used_cpu_user_children:0.070083
used_cpu_sys_main_thread:207.720070
used_cpu_user_main_thread:235.938962

# Modules

# Errorstats
errorstat_ERR:count=45
errorstat_NOAUTH:count=13
errorstat_NOTBUSY:count=3
errorstat_WRONGPASS:count=4
errorstat_WRONGTYPE:count=13

# Cluster
cluster_enabled:0

# Keyspace
db0:keys=21,expires=0,avg_ttl=0
db1:keys=5,expires=0,avg_ttl=0
db2:keys=3,expires=0,avg_ttl=0
127.0.0.1:6379>

4.11.2 基本命令汇总

序号 命令 描述
1 BGREWRITEAOF 异步执行一个 AOF(AppendOnly File) 文件重写操作
2 BGSAVE 在后台异步保存当前数据库的数据到磁盘
3 CLIENT KILL 关闭客户端连接
4 CLIENT LIST 获取连接到服务器的客户端连接列表
5 CLIENT GETNAME 获取连接的名称
6 CLIENT PAUSE 在指定时间内终止运行来自客户端的命令
7 CLIENT STNAME 设置当前连接的名称
8 CLUSTER SLOTS 获取集群节点的映射数组
9 COMMAND 获取 Redis 命令总数
10 COMMAND COUNT 获取 Redis 命令总数
11 COMMAND GETKEYS 获取给定命令的所有键
12 TIME 返回当前服务器时间
13 COMMAND INFO 获取指定 Redis 命令描述的数组
14 CONFIG GET 获取指定配置参数的值
15 CONFIG REWRITE 修改 redis.conf 配置文件
16 CONFIG SET 修改 redis 配置参数,无需重启
17 CONFIG RESETSTAT 重置 INFO 命令中的某些统计数据
18 DBSIZE 返回当前数据库的 key 的数量
19 DEBUG OBJECT 获取 key 的调试信息
20 DEBUG SEGFAULT 让 Redis 服务崩溃
21 FLUSHALL 删除所有数据库的所有 key
22 FLUSHDB 删除当前数据库的所有 key
23 INFO 获取 Redis 服务器的各种信息和统计数值
24 LASTSAVE 返回最近一次 Redis 成功将数据保存到磁盘上的时间
25 MONITOR 实时打印出 Redis 服务器接收到的命令,调试用
26 ROLE 返回主从实例所属的角色
27 SAVE 异步保存数据到硬盘
28 SHUTDOWN 异步保存数据到硬盘,并关闭服务器
29 SLAVEOF 将当前服务器转变从属服务器(slave server)
30 SLOWLOG 管理 redis 的慢日志
31 SYNC 用于复制功能 ( replication ) 的内部命令

4.12 HyperLogLog

Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。

在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 264个不同元素的基 数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。

但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素。

4.12.1 基本操作

  • 什么是基数?

    比如数据集 {1, 3, 5, 7, 5, 7, 8}, 那么这个数据集的基数集为 {1, 3, 5 ,7, 8}, 基数(不重复元素)为5。 基数估计就是在误差可接受的范围内,快速计算基数。

  • 实例

    以下实例演示了 HyperLogLog 的工作过程:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> PFADD rediscomcn "redis"
    (integer) 1
    127.0.0.1:6379> PFADD rediscomcn "mongodb"
    (integer) 1
    127.0.0.1:6379> PFADD rediscomcn "mysql"
    (integer) 1
    127.0.0.1:6379> PFCOUNT rediscomcn
    (integer) 3
    127.0.0.1:6379>

4.12.2 基本命令汇总

序号 命令 描述
1 PFADD 添加指定元素到 HyperLogLog 中。
2 PFCOUNT 返回给定 HyperLogLog 的基数估算值。
3 PFMERGE 将多个 HyperLogLog 合并为一个 HyperLogLog

4.13 地理信息

Redis GEO 主要用于存储地理位置信息,并对存储的信息进行操作,该功能在 Redis 3.2 版本新增。

Redis GEO 操作方法有:

  • geoadd:添加地理位置的坐标。
  • geopos:获取地理位置的坐标。
  • geodist:计算两个位置之间的距离。
  • georadius:根据用户给定的经纬度坐标来获取指定范围内的地理位置集合。
  • georadiusbymember:根据储存在位置集合里面的某个地点获取指定范围内的地理位置集合。
  • geohash:返回一个或多个位置对象的 geohash 值。

4.13.1 geoadd

geoadd 用于存储指定的地理空间位置,可以将一个或多个经度(longitude)、纬度(latitude)、位置名称(member)添加到指定的 key 中。

geoadd 语法格式如下:

1
127.0.0.1:6379> GEOADD key longitude latitude member [longitude latitude member ...]

以下实例中 key 为 Sicily、Catania 为位置名称 :

实例:

1
2
3
4
5
6
7
8
9
10
127.0.0.1:6379> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
127.0.0.1:6379> GEODIST Sicily Palermo Catania
"166274.1516"
127.0.0.1:6379> GEORADIUS Sicily 15 37 100 km
1) "Catania"
127.0.0.1:6379> GEORADIUS Sicily 15 37 200 km
1) "Palermo"
2) "Catania"
127.0.0.1:6379>

4.13.2 geopos

geopos 用于从给定的 key 里返回所有指定名称(member)的位置(经度和纬度),不存在的返回 nil。

geopos 语法格式如下:

1
127.0.0.1:6379> GEOPOS key member [member ...]

实例

1
2
3
4
5
6
7
8
9
127.0.0.1:6379> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
127.0.0.1:6379> GEOPOS Sicily Palermo Catania NonExisting
1) 1) "13.36138933897018433"
2) "38.11555639549629859"
2) 1) "15.08726745843887329"
2) "37.50266842333162032"
3) (nil)
127.0.0.1:6379>

4.13.3 geodist

geodist 用于返回两个给定位置之间的距离。

geodist 语法格式如下:

1
127.0.0.1:6379> GEODIST key member1 member2 [m|km|ft|mi]

member1 member2 为两个地理位置。

最后一个距离单位参数说明:

  • m :米,默认单位。
  • km :千米。
  • mi :英里。
  • ft :英尺。

实例: 计算 Palermo 与 Catania 之间的距离实例

1
2
3
4
5
6
7
8
9
10
11
127.0.0.1:6379> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
127.0.0.1:6379> GEODIST Sicily Palermo Catania
"166274.1516"
127.0.0.1:6379> GEODIST Sicily Palermo Catania km
"166.2742"
127.0.0.1:6379> GEODIST Sicily Palermo Catania mi
"103.3182"
127.0.0.1:6379> GEODIST Sicily Foo Bar
(nil)
127.0.0.1:6379>

4.13.4 georadius、georadiusbymember

georadius 以给定的经纬度为中心, 返回键包含的位置元素当中, 与中心的距离不超过给定最大距离的所有位置元素。

georadiusbymember 和 GEORADIUS 命令一样, 都可以找出位于指定范围内的元素, 但是 georadiusbymember 的中心点是由给定的位置元素决定的, 而不是使用经度和纬度来决定中心点。

georadius 与 georadiusbymember 语法格式如下:

1
2
GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]
GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key]

参数说明:

  • m :米,默认单位。
  • km :千米。
  • mi :英里。
  • ft :英尺。
  • WITHDIST: 在返回位置元素的同时, 将位置元素与中心之间的距离也一并返回。
  • WITHCOORD: 将位置元素的经度和维度也一并返回。
  • WITHHASH: 以 52 位有符号整数的形式, 返回位置元素经过原始 geohash 编码的有序集合分值。 这个选项主要用于底层应用或者调试, 实际中的作用并不大。
  • COUNT 限定返回的记录数。
  • ASC: 查找结果根据距离从近到远排序。
  • DESC: 查找结果根据从远到近排序。

    georadius实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
127.0.0.1:6379> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
127.0.0.1:6379> GEORADIUS Sicily 15 37 200 km WITHDIST
1) 1) "Palermo"
2) "190.4424"
2) 1) "Catania"
2) "56.4413"
127.0.0.1:6379> GEORADIUS Sicily 15 37 200 km WITHCOORD
1) 1) "Palermo"
2) 1) "13.36138933897018433"
2) "38.11555639549629859"
2) 1) "Catania"
2) 1) "15.08726745843887329"
2) "37.50266842333162032"
127.0.0.1:6379> GEORADIUS Sicily 15 37 200 km WITHDIST WITHCOORD
1) 1) "Palermo"
2) "190.4424"
3) 1) "13.36138933897018433"
2) "38.11555639549629859"
2) 1) "Catania"
2) "56.4413"
3) 1) "15.08726745843887329"
2) "37.50266842333162032"
127.0.0.1:6379>

georadiusbymember实例:

1
2
3
4
5
6
7
8
127.0.0.1:6379> GEOADD Sicily 13.583333 37.316667 "Agrigento"
(integer) 1
127.0.0.1:6379> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
127.0.0.1:6379> GEORADIUSBYMEMBER Sicily Agrigento 100 km
1) "Agrigento"
2) "Palermo"
127.0.0.1:6379>

4.13.5 geohash

Redis GEO 使用 geohash 来保存地理位置的坐标。

geohash 用于获取一个或多个位置元素的 geohash 值。

geohash 语法格式如下:

1
127.0.0.1:6379> GEOHASH key member [member ...]

geohash实例:

1
2
3
4
5
6
127.0.0.1:6379> GEOADD Sicily 13.361389 38.115556 "Palermo" 15.087269 37.502669 "Catania"
(integer) 2
127.0.0.1:6379> GEOHASH Sicily Palermo Catania
1) "sqc8b49rny0"
2) "sqdtr74hyu0"
127.0.0.1:6379>

4.14 Stream

Redis Stream 是 Redis 5.0 版本新增加的数据结构。

Redis Stream 主要用于消息队列(MQ,Message Queue),Redis 本身是有一个 Redis 发布订阅 (pub/sub) 来实现消息队列的功能,但它有个缺点就是消息无法持久化,如果出现网络断开、Redis 宕机等,消息就会被丢弃。

简单来说发布订阅 (pub/sub) 可以分发消息,但无法记录历史消息。

而 Redis Stream 提供了消息的持久化和主备复制功能,可以让任何客户端访问任何时刻的数据,并且能记住每一个客户端的访问位置,还能保证消息不丢失。

Redis Stream 的结构如下所示,它有一个消息链表,将所有加入的消息都串起来,每个消息都有一个唯一的 ID 和对应的内容:

每个 Stream 都有唯一的名称,它就是 Redis 的 key,在我们首次使用 xadd 指令追加消息时自动创建。

上图解析:

  • Consumer Group :消费组,使用 XGROUP CREATE 命令创建,一个消费组有多个消费者(Consumer)。
  • lastdeliveredid :游标,每个消费组会有个游标 lastdeliveredid,任意一个消费者读取了消息都会使游标 lastdeliveredid 往前移动。
  • pendingids :消费者(Consumer)的状态变量,作用是维护消费者的未确认的 id。 pendingids 记录了当前已经被客户端读取的消息,但是还没有 ack (Acknowledge character:确认字符)。

消息队列相关命令:

  • XADD - 添加消息到末尾
  • XTRIM - 对流进行修剪,限制长度
  • XDEL - 删除消息
  • XLEN - 获取流包含的元素数量,即消息长度
  • XRANGE - 获取消息列表,会自动过滤已经删除的消息
  • XREVRANGE - 反向获取消息列表,ID 从大到小
  • XREAD - 以阻塞或非阻塞方式获取消息列表

消费者组相关命令:

  • XGROUP CREATE - 创建消费者组
  • XREADGROUP GROUP - 读取消费者组中的消息
  • XACK - 将消息标记为”已处理”
  • XGROUP SETID - 为消费者组设置新的最后递送消息ID
  • XGROUP DELCONSUMER - 删除消费者
  • XGROUP DESTROY - 删除消费者组
  • XPENDING - 显示待处理消息的相关信息
  • XCLAIM - 转移消息的归属权
  • XINFO - 查看流和消费者组的相关信息;
  • XINFO GROUPS - 打印消费者组的信息;
  • XINFO STREAM - 打印流信息

4.14.1 XADD

使用 XADD 向队列添加消息,如果指定的队列不存在,则创建一个队列,XADD 语法格式:

1
127.0.0.1:6379> XADD key ID field value [field value ...]
  • key :队列名称,如果不存在就创建
  • ID :消息 id,我们使用 * 表示由 redis 生成,可以自定义,但是要自己保证递增性。
  • field value : 记录。

XADD实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
127.0.0.1:6379> XADD mystream * name Sara surname OConnor
"1653077968353-0"
127.0.0.1:6379> XADD mystream * field1 value1 field2 value2 field3 value3
"1653077976530-0"
127.0.0.1:6379> XLEN mystream
(integer) 2
127.0.0.1:6379> XRANGE mystream - +
1) 1) "1653077968353-0"
2) 1) "name"
2) "Sara"
3) "surname"
4) "OConnor"
2) 1) "1653077976530-0"
2) 1) "field1"
2) "value1"
3) "field2"
4) "value2"
5) "field3"
6) "value3"
127.0.0.1:6379>

4.14.2 XTRIM

使用 XTRIM对流进行修剪,限制长度, 语法格式:

1
XTRIM key MAXLEN [~] count
  • key :队列名称
  • MAXLEN :长度
  • count :数量

XTRIM实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
127.0.0.1:6379> XADD mystream * field1 A field2 B field3 C field4 D
"1653078272108-0"
127.0.0.1:6379> XTRIM mystream MAXLEN 2
(integer) 1
127.0.0.1:6379> XRANGE mystream - +
1) 1) "1653078272108-0"
2) 1) "field1"
2) "A"
3) "field2"
4) "B"
5) "field3"
6) "C"
7) "field4"
8) "D"
127.0.0.1:6379>

4.14.3 XDEL

使用 XDEL 删除消息,语法格式:

1
127.0.0.1:6379> XDEL key ID [ID ...]
  • key:队列名称
  • ID :消息 ID

XDEL实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
127.0.0.1:6379> XADD mystream * a 1
1538561698944-0
127.0.0.1:6379> XADD mystream * b 2
1538561700640-0
127.0.0.1:6379> XADD mystream * c 3
1538561701744-0
127.0.0.1:6379> XDEL mystream 1538561700640-0
(integer) 1
127.0.0.1:6379> XRANGE mystream - +
1) 1) 1538561698944-0
2) 1) "a"
2) "1"
2) 1) 1538561701744-0
2) 1) "c"
2) "3"

4.14.4 XLEN

使用 XLEN 获取流包含的元素数量,即消息长度,语法格式:

1
127.0.0.1:6379> XLEN key
  • key:队列名称

XLEN实例:

1
2
3
4
5
6
7
8
9
127.0.0.1:6379> XADD mystream * item 1
"1601372563177-0"
127.0.0.1:6379> XADD mystream * item 2
"1601372563178-0"
127.0.0.1:6379> XADD mystream * item 3
"1601372563178-1"
127.0.0.1:6379> XLEN mystream
(integer) 3
127.0.0.1:6379>

4.14.5 XRANGE

使用 XRANGE 获取消息列表,会自动过滤已经删除的消息 ,语法格式:

1
127.0.0.1:6379> XRANGE key start end [COUNT count]
  • key :队列名
  • start :开始值, - 表示最小值
  • end :结束值, + 表示最大值
  • count :数量

实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
127.0.0.1:6379> XADD writers * name Virginia surname Woolf
"1601372577811-0"
127.0.0.1:6379> XADD writers * name Jane surname Austen
"1601372577811-1"
127.0.0.1:6379> XADD writers * name Toni surname Morrison
"1601372577811-2"
127.0.0.1:6379> XADD writers * name Agatha surname Christie
"1601372577812-0"
127.0.0.1:6379> XADD writers * name Ngozi surname Adichie
"1601372577812-1"
127.0.0.1:6379> XLEN writers
(integer) 5
127.0.0.1:6379> XRANGE writers - + COUNT 2
1) 1) "1601372577811-0"
2) 1) "name"
2) "Virginia"
3) "surname"
4) "Woolf"
2) 1) "1601372577811-1"
2) 1) "name"
2) "Jane"
3) "surname"
4) "Austen"
127.0.0.1:6379>

4.14.6 XREVRANGE

使用 XREVRANGE 获取消息列表,会自动过滤已经删除的消息 ,语法格式:

1
127.0.0.1:6379> XREVRANGE key end start [COUNT count]
  • key :队列名
  • end :结束值, + 表示最大值
  • start :开始值, - 表示最小值
  • count :数量

XREVRANGE实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
127.0.0.1:6379> XADD writers * name Virginia surname Woolf
"1601372731458-0"
127.0.0.1:6379> XADD writers * name Jane surname Austen
"1601372731459-0"
127.0.0.1:6379> XADD writers * name Toni surname Morrison
"1601372731459-1"
127.0.0.1:6379> XADD writers * name Agatha surname Christie
"1601372731459-2"
127.0.0.1:6379> XADD writers * name Ngozi surname Adichie
"1601372731459-3"
127.0.0.1:6379> XLEN writers
(integer) 5
127.0.0.1:6379> XREVRANGE writers + - COUNT 1
1) 1) "1601372731459-3"
2) 1) "name"
2) "Ngozi"
3) "surname"
4) "Adichie"
127.0.0.1:6379>

4.14.7 XREAD

使用 XREAD 以阻塞或非阻塞方式获取消息列表 ,语法格式:

1
127.0.0.1:6379> XREAD [COUNT count] [BLOCK milliseconds] STREAMS key [key ...] id [id ...]
  • count :数量
  • milliseconds :可选,阻塞毫秒数,没有设置就是非阻塞模式
  • key :队列名
  • id :消息 ID

实例: 从 Stream 头部读取两条消息

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
127.0.0.1:6379> XREAD COUNT 2 STREAMS mystream writers 0-0 0-0
1) 1) "mystream"
2) 1) 1) 1526984818136-0
2) 1) "duration"
2) "1532"
3) "event-id"
4) "5"
5) "user-id"
6) "7782813"
2) 1) 1526999352406-0
2) 1) "duration"
2) "812"
3) "event-id"
4) "9"
5) "user-id"
6) "388234"
2) 1) "writers"
2) 1) 1) 1526985676425-0
2) 1) "name"
2) "Virginia"
3) "surname"
4) "Woolf"
2) 1) 1526985685298-0
2) 1) "name"
2) "Jane"
3) "surname"
4) "Austen"
127.0.0.1:6379>

4.14.8 XGROUP CREATE

使用 XGROUP CREATE 创建消费者组,语法格式:

1
127.0.0.1:6379> XGROUP [CREATE key groupname id-or-$] [SETID key groupname id-or-$] [DESTROY key groupname] [DELCONSUMER key groupname consumername]
  • key :队列名称,如果不存在就创建
  • groupname :组名。
  • $ : 表示从尾部开始消费,只接受新消息,当前 Stream 消息会全部忽略。

从头开始消费:

1
127.0.0.1:6379> XGROUP CREATE mystream consumer-group-name 0-0  

从尾部开始消费:

1
127.0.0.1:6379> XGROUP CREATE mystream consumer-group-name $

4.14.9 XREADGROUP GROUP

使用 XREADGROUP GROUP 读取消费组中的消息,语法格式:

1
127.0.0.1:6379> XREADGROUP GROUP group consumer [COUNT count] [BLOCK milliseconds] [NOACK] STREAMS key [key ...] ID [ID ...]
  • group :消费组名
  • consumer :消费者名。
  • count : 读取数量。
  • milliseconds : 阻塞毫秒数。
  • key : 队列名。
  • ID : 消息 ID。
1
127.0.0.1:6379> XREADGROUP GROUP consumer-group-name consumer-name COUNT 1 STREAMS mystream >

5. Redis 高级功能

5.1 redis备份和恢复

SAVE 命令用于创建当前 Redis 数据库的备份。此命令将通过执行同步 SAVE 在 Redis 目录中创建 dump.rdb 文件。

  • 语法

    1
    127.0.0.1:6379> SAVE
  • 返回值:

    执行成功后,SAVE 命令返回 OK。

5.1.1 Redis备份示例

使用 SAVE 命令创建当前数据库的备份。

1
2
3
127.0.0.1:6379> SAVE
OK
127.0.0.1:6379>

它将在 Redis 目录中创建 dump.rdb 文件。

可以看到 dump.rdb 文件已创建。

1
2
3
4
5
6
7
[root@192 redis-6.2.6]# ls
00-RELEASENOTES COPYING MANIFESTO runtest-moduleapi TLS.md
appendonly.aof deps README.md runtest-sentinel utils
BUGS dump.rdb redis.conf sentinel.conf
CONDUCT INSTALL runtest src
CONTRIBUTING Makefile runtest-cluster tests
[root@192 redis-6.2.6]#

5.1.2 还原Redis数据

将 Redis 备份文件(dump.rdb)移动到 Redis 目录中并启动服务器以恢复 Redis 数据。

查找 Redis 的安装目录,使用 Redis 的 CONFIG 命令,如下所示。

1
2
3
4
127.0.0.1:6379> CONFIG get dir
1) "dir"
2) "/opt/software/redis-6.2.6"
127.0.0.1:6379>

Redis 服务器安装在/opt/software/redis-6.2.6目录中。

5.1.3 BGSAVE命令

BGSAVE 是创建 Redis 备份的备用命令。

此命令将启动备份过程并在后台运行。

  • 语法:

    1
    127.0.0.1:6379> BGSAVE
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    [root@192 redis-6.2.6]# src/redis-cli -a yanpenggong
    Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
    127.0.0.1:6379> CONFIG get dir
    1) "dir"
    2) "/opt/software/redis-6.2.6"
    127.0.0.1:6379> BGSAVE
    Background saving started
    127.0.0.1:6379>

5.2 Redis 持久化

redis 提供了两种持久化的方式,分别是RDB(Redis DataBase)和AOF(Append Only File)。

RDB,简而言之,就是在不同的时间点,将 redis 存储的数据生成快照并存储到磁盘等介质上;

AOF,则是换了一个角度来实现持久化,那就是将 redis 执行过的所有写指令记录下来,在下次 redis 重新启动时,只要把这些写指令从前到后再重复执行一遍,就可以实现数据恢复了。

其实 RDB 和 AOF 两种方式也可以同时使用,在这种情况下,如果 redis 重启的话,则会优先采用 AOF 方式来进行数据恢复,这是因为 AOF 方式的数据恢复完整度更高。

如果你没有数据持久化的需求,也完全可以关闭 RDB 和 AOF 方式,这样的话,redis 将变成一个纯内存数据库,就像 memcache 一样。

5.2.1 redis持久化RDB

RDB 方式,是将 redis 某一时刻的数据持久化到磁盘中,是一种快照式的持久化方法。

redis 在进行数据持久化的过程中,会先将数据写入到一个临时文件中,待持久化过程都结束了,才会用这个临时文件替换上次持久化好的文件。正是这种特性,让我们可以随时来进行备份,因为快照文件总是完整可用的。

对于 RDB 方式,redis 会单独创建(fork)一个子进程来进行持久化,而主进程是不会进行任何 IO 操作的,这样就确保了 redis 极高的性能。

如果需要进行大规模数据的恢复,且对于数据恢复的完整性不是非常敏感,那 RDB 方式要比 AOF 方式更加的高效。

虽然 RDB 有不少优点,但它的缺点也是不容忽视的。如果你对数据的完整性非常敏感,那么 RDB 方式就不太适合你,因为即使你每 5 分钟都持久化一次,当 redis 故障时,仍然会有近 5 分钟的数据丢失。所以,redis 还提供了另一种持久化方式,那就是 AOF。

5.2.2 redis持久化 AOF

AOF,英文是 Append Only File,即只允许追加不允许改写的文件。

如前面介绍的,AOF 方式是将执行过的写指令记录下来,在数据恢复时按照从前到后的顺序再将指令都执行一遍,就这么简单。

我们通过配置 redis.conf 中的 appendonly yes 就可以打开 AOF 功能。如果有写操作(如 SET 等),redis 就会被追加到 AOF 文件的末尾。

默认的 AOF 持久化策略是每秒钟 fsync 一次(fsync 是指把缓存中的写指令记录到磁盘中),因为在这种情况下,redis 仍然可以保持很好的处理性能,即使 redis 故障,也只会丢失最近 1 秒钟的数据。

如果在追加日志时,恰好遇到磁盘空间满、inode 满或断电等情况导致日志写入不完整,也没有关系,redis 提供了 redis-check-aof 工具,可以用来进行日志修复。

因为采用了追加方式,如果不做任何处理的话,AOF 文件会变得越来越大,为此,redis 提供了 AOF 文件重写(rewrite)机制,即当 AOF 文件的大小超过所设定的阈值时,redis 就会启动 AOF 文件的内容压缩,只保留可以恢复数据的最小指令集。举个例子或许更形象,假如我们调用了 100 次 INCR 指令,在 AOF 文件中就要存储 100 条指令,但这明显是很低效的,完全可以把这 100 条指令合并成一条 SET 指令,这就是重写机制的原理。

在进行 AOF 重写时,仍然是采用先写临时文件,全部完成后再替换的流程,所以断电、磁盘满等问题都不会影响 AOF 文件的可用性,这点大家可以放心。

AOF 方式的另一个好处,我们通过一个“场景再现”来说明。某同学在操作 redis 时,不小心执行了 FLUSHALL,导致 redis 内存中的数据全部被清空了,这是很悲剧的事情。不过这也不是世界末日,只要 redis 配置了 AOF 持久化方式,且 AOF 文件还没有被重写(rewrite),我们就可以用最快的速度暂停 redis 并编辑 AOF 文件,将最后一行的 FLUSHALL 命令删除,然后重启 redis,就可以恢复 redis 的所有数据到 FLUSHALL 之前的状态了。是不是很神奇,这就是 AOF 持久化方式的好处之一。但是如果 AOF 文件已经被重写了,那就无法通过这种方法来恢复数据了。

虽然优点多多,但 AOF 方式也同样存在缺陷,比如在同样数据规模的情况下,AOF 文件要比 RDB 文件的体积大。而且,AOF 方式的恢复速度也要慢于 RDB 方式。

如果你直接执行 BGREWRITEAOF 命令,那么 redis 会生成一个全新的 AOF 文件,其中便包括了可以恢复现有数据的最少的命令集。

如果运气比较差,AOF 文件出现了被写坏的情况,也不必过分担忧,redis 并不会贸然加载这个有问题的 AOF 文件,而是报错退出。这时可以通过以下步骤来修复出错的文件:

  1. 备份被写坏的 AOF 文件
  2. 运行 redis-check-aof –fix 进行修复
  3. 用 diff -u 来看下两个文件的差异,确认问题点
  4. 重启 redis,加载修复后的 AOF 文件

5.2.3 redis持久化 – AOF重写

AOF 重写的内部运行原理,我们有必要了解一下。

在重写即将开始之际,redis 会创建(fork)一个“重写子进程”,这个子进程会首先读取现有的 AOF 文件,并将其包含的指令进行分析压缩并写入到一个临时文件中。

与此同时,主工作进程会将新接收到的写指令一边累积到内存缓冲区中,一边继续写入到原有的 AOF 文件中,这样做是保证原有的 AOF 文件的可用性,避免在重写过程中出现意外。

当“重写子进程”完成重写工作后,它会给父进程发一个信号,父进程收到信号后就会将内存中缓存的写指令追加到新 AOF 文件中。

当追加结束后,redis 就会用新 AOF 文件来代替旧 AOF 文件,之后再有新的写指令,就都会追加到新的 AOF 文件中了。

5.2.4 redis持久化 – 如何选择RDB和AOF

对于我们应该选择 RDB 还是 AOF,官方的建议是两个同时使用。这样可以提供更可靠的持久化方案。

5.3 redis安全

对于数据库来说,安全性是非常必要的,以确保数据的安全性。它提供身份验证,因此如果客户端想要建立连接,则需要在执行命令之前进行身份验证。

需要在配置文件中设置密码以保护 Redis 数据库。

实例:

1
2
3
4
127.0.0.1:6379> CONFIG get requirepass
1) "requirepass"
2) ""
127.0.0.1:6379>

可以看到上面的属性为空,表示没有此实例的任何密码。

可以通过执行以下命令来更改此属性并为此实例设置密码。

1
2
3
4
5
6
7
127.0.0.1:6379> CONFIG set requirepass "yanpenggong"
OK
127.0.0.1:6379> quit
[root@192 redis-6.2.6]# src/redis-cli
127.0.0.1:6379> CONFIG get requirepass
(error) NOAUTH Authentication required.
127.0.0.1:6379>

设置此密码时,如果客户端在未经身份验证的情况下运行该命令,则会收到错误“NOAUTH Authentication required。”。因此,客户端需要使用 AUTH 命令来验证自己。

5.3.1 AUTH命令的用法

1
2
3
4
5
6
7
127.0.0.1:6379> AUTH "yanpenggong"
OK
127.0.0.1:6379> SET myset "Hello World"
OK
127.0.0.1:6379> GET myset
"Hello World"
127.0.0.1:6379>

5.4 Redis 基准

Redis 基准测试 redis-benchmark 是一种实用工具,用于通过同时使用 multiple(n) 命令来检查 Redis 的性能。

  • 语法:

    1
    redis-benchmark [option] [option 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
    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
    [root@192 redis-6.2.6]# src/redis-benchmark -n 100000 -a yanpenggong
    ====== PING_INLINE ======
    100000 requests completed in 15.49 seconds
    50 parallel clients
    3 bytes payload
    keep alive: 1
    host configuration "save": 900 1 300 10 60 10000
    host configuration "appendonly": no
    multi-thread: no

    Latency by percentile distribution:
    0.000% <= 2.807 milliseconds (cumulative count 1)
    50.000% <= 5.791 milliseconds (cumulative count 50175)
    75.000% <= 6.711 milliseconds (cumulative count 75143)
    87.500% <= 7.351 milliseconds (cumulative count 87511)
    93.750% <= 8.007 milliseconds (cumulative count 93796)
    96.875% <= 8.671 milliseconds (cumulative count 96890)
    98.438% <= 9.351 milliseconds (cumulative count 98442)
    99.219% <= 10.039 milliseconds (cumulative count 99219)
    99.609% <= 10.783 milliseconds (cumulative count 99613)
    99.805% <= 11.319 milliseconds (cumulative count 99807)
    99.902% <= 11.999 milliseconds (cumulative count 99903)
    99.951% <= 13.351 milliseconds (cumulative count 99952)
    99.976% <= 16.463 milliseconds (cumulative count 99976)
    99.988% <= 29.823 milliseconds (cumulative count 99988)
    99.994% <= 30.511 milliseconds (cumulative count 99994)
    99.997% <= 30.735 milliseconds (cumulative count 99997)
    99.998% <= 30.911 milliseconds (cumulative count 99999)
    99.999% <= 31.023 milliseconds (cumulative count 100000)
    100.000% <= 31.023 milliseconds (cumulative count 100000)

    Cumulative distribution of latencies:
    0.000% <= 0.103 milliseconds (cumulative count 0)
    0.007% <= 3.103 milliseconds (cumulative count 7)
    8.508% <= 4.103 milliseconds (cumulative count 8508)
    32.111% <= 5.103 milliseconds (cumulative count 32111)
    58.966% <= 6.103 milliseconds (cumulative count 58966)
    83.729% <= 7.103 milliseconds (cumulative count 83729)
    94.418% <= 8.103 milliseconds (cumulative count 94418)
    98.012% <= 9.103 milliseconds (cumulative count 98012)
    99.266% <= 10.103 milliseconds (cumulative count 99266)
    99.737% <= 11.103 milliseconds (cumulative count 99737)
    99.915% <= 12.103 milliseconds (cumulative count 99915)
    99.948% <= 13.103 milliseconds (cumulative count 99948)
    99.956% <= 14.103 milliseconds (cumulative count 99956)
    99.962% <= 15.103 milliseconds (cumulative count 99962)
    99.970% <= 16.103 milliseconds (cumulative count 99970)
    99.979% <= 17.103 milliseconds (cumulative count 99979)
    99.980% <= 29.103 milliseconds (cumulative count 99980)
    99.991% <= 30.111 milliseconds (cumulative count 99991)
    100.000% <= 31.103 milliseconds (cumulative count 100000)

    Summary:
    throughput summary: 6454.53 requests per second
    latency summary (msec):
    avg min p50 p95 p99 max
    5.870 2.800 5.791 8.207 9.807 31.023
    ====== PING_MBULK ======
    100000 requests completed in 15.45 seconds
    50 parallel clients
    3 bytes payload
    keep alive: 1
    host configuration "save": 900 1 300 10 60 10000
    host configuration "appendonly": no
    multi-thread: no

    Latency by percentile distribution:
    0.000% <= 2.351 milliseconds (cumulative count 1)
    50.000% <= 5.727 milliseconds (cumulative count 50067)
    75.000% <= 6.671 milliseconds (cumulative count 75131)
    87.500% <= 7.415 milliseconds (cumulative count 87505)
    93.750% <= 8.263 milliseconds (cumulative count 93781)
    96.875% <= 9.119 milliseconds (cumulative count 96886)
    98.438% <= 9.871 milliseconds (cumulative count 98438)
    99.219% <= 10.567 milliseconds (cumulative count 99221)
    99.609% <= 11.207 milliseconds (cumulative count 99611)
    99.805% <= 11.863 milliseconds (cumulative count 99805)
    99.902% <= 12.575 milliseconds (cumulative count 99904)
    99.951% <= 13.471 milliseconds (cumulative count 99952)
    99.976% <= 14.479 milliseconds (cumulative count 99976)
    99.988% <= 15.255 milliseconds (cumulative count 99988)
    99.994% <= 15.703 milliseconds (cumulative count 99994)
    99.997% <= 16.303 milliseconds (cumulative count 99997)
    99.998% <= 16.479 milliseconds (cumulative count 99999)
    99.999% <= 16.607 milliseconds (cumulative count 100000)
    100.000% <= 16.607 milliseconds (cumulative count 100000)

    Cumulative distribution of latencies:
    0.000% <= 0.103 milliseconds (cumulative count 0)
    0.014% <= 3.103 milliseconds (cumulative count 14)
    9.664% <= 4.103 milliseconds (cumulative count 9664)
    33.922% <= 5.103 milliseconds (cumulative count 33922)
    60.409% <= 6.103 milliseconds (cumulative count 60409)
    83.670% <= 7.103 milliseconds (cumulative count 83670)
    92.958% <= 8.103 milliseconds (cumulative count 92958)
    96.842% <= 9.103 milliseconds (cumulative count 96842)
    98.776% <= 10.103 milliseconds (cumulative count 98776)
    99.566% <= 11.103 milliseconds (cumulative count 99566)
    99.843% <= 12.103 milliseconds (cumulative count 99843)
    99.937% <= 13.103 milliseconds (cumulative count 99937)
    99.968% <= 14.103 milliseconds (cumulative count 99968)
    99.985% <= 15.103 milliseconds (cumulative count 99985)
    99.996% <= 16.103 milliseconds (cumulative count 99996)
    100.000% <= 17.103 milliseconds (cumulative count 100000)

    Summary:
    throughput summary: 6472.91 requests per second
    latency summary (msec):
    avg min p50 p95 p99 max
    5.858 2.344 5.727 8.551 10.319 16.607
    SET: rps=7171.3 (overall: 5609.2) avg_msec=5.378 (overall: 6.777)
  • redis 性能测试工具可选参数

    | 序号 | 选项 | 描述 | 默认值 |
    | —— | ——- | ————————————————————— | ————- |
    | 1 | -h | 指定服务器主机名 | 127.0.0.1 |
    | 2 | -p | 指定服务器端口 | 6379 |
    | 3 | -s | 指定服务器 socket | |
    | 4 | -c | 指定并发连接数 | 50 |
    | 5 | -n | 指定请求数 | 10000 |
    | 6 | -d | 以字节的形式指定 SET/GET 值的数据大小 | 2 |
    | 7 | -k | 1=keep alive 0=reconnect | 1 |
    | 8 | -r | SET/GET/INCR 使用随机 key, SADD 使用随机值 | |
    | 9 | -P | 通过管道传输 请求 | 1 |
    | 10 | -q | 强制退出 redis。仅显示 query/sec 值 | |
    | 11 | —csv | 以 CSV 格式输出 | |
    | 12 | -l | 生成循环,永久执行测试 | |
    | 13 | -t | 仅运行以逗号分隔的测试命令列表 | |
    | 14 | -I | Idle 模式。仅打开 N 个 idle 连接并等待 | |

    实例:

    以下实例使用了多个参数来测试 redis 性能:主机为 127.0.0.1,端口号为 6379,执行的命令为 set,lpush,请求数为 10000,通过 -q 参数让结果只显示每秒执行的请求数。

    1
    2
    3
    4
    5
    [root@192 redis-6.2.6]# src/redis-benchmark -h 127.0.0.1 -p 6379 -t set,lpush -n 100000 -q -a yanpenggong
    SET: 6676.46 requests per second, p50=5.639 msec
    LPUSH: 6538.51 requests per second, p50=5.775 msec

    [root@192 redis-6.2.6]#

5.5 Redis客户端连接

Redis 可以在配置的监听 TCP 端口和 Unix 套接字上接受不同类型的客户端连接。

接受新客户端连接时,它将执行以下操作:

  • 由于 Redis 使用多路复用和非阻塞 I/O,因此客户端套接字处于非阻塞状态。
  • 设置 TCP_NODELAY 选项是为了确保我们的连接没有延迟。
  • 创建可读文件事件,以便一旦可以在套接字上读取新数据,Redis 就能够收集客户端查询。

5.5.1 最大客户端数

在 Redis config(redis.conf)中,有一个名为 maxclients 的属性,它指定可以连接到 Redis 的客户端数量。

1
2
3
4
5
6
[root@192 redis-6.2.6]# src/redis-cli -a yanpenggong
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> CONFIG get maxclients
1) "maxclients"
2) "10000"
127.0.0.1:6379>

最大客户端数取决于 OS 的最大文件描述符数限制。它的默认值为 10000,但您可以更改此属性。

实例: 在启动服务器时将最大客户端数设置为 100000。

1
[root@192 redis-6.2.6]# src/redis-server --maxclients 100000

5.5.2 Redis 客户端命令

序号 命令 描述
1 CLIENT LIST 返回连接到 redis 服务的客户端列表
2 CLIENT SETNAME 设置当前连接的名称
3 CLIENT GETNAME 获取通过 CLIENT SETNAME 命令设置的服务名称
4 CLIENT PAUSE 挂起客户端连接,指定挂起的时间以毫秒计
5 CLIENT KILL 关闭客户端连接

5.6 Redis Pipelining 流水线

在了解流水线之前,首先要了解 Redis 的概念:

Redis 是一个支持请求/响应协议的 TCP 服务器。在 Redis 中,请求分两步完成:

  • 客户端通常以阻塞方式向服务器发送命令。
  • 服务器处理该命令并将响应发送回客户端。

5.6.1 什么是流水线

流水线操作有助于客户端向服务器发送多个请求,而无需等待回复,最后只需一步即可读取回复。

: 向 Redis 提交一次命令,Redis 将在一个步骤中提供所有命令的输出。

1
[root@192 redis-6.2.6]# (echo -en  “PING\r\n SET sssit javatraining\r\n GET sssit\r\n INCR visitor\r\n INCR visitor\r\n INCR visitor\r\n” ; sleep  10 ) | nc localhost 6379 

这里:

  • PING 命令用于检查 Redis 连接。
  • 设置名为“sssit”的字符串,其值为“javatraining”。
  • 获得了 key 值并将访问者数量增加了三倍。

每次增加值时都可以看到。

5.6.2 流水线的优势

Redis 流水线操作的主要优点是提高了 Redis 的性能。由于多个命令同时执行,它极大地提高了协议性能。

5.6.3 Pipelining vs Scripting

Redis Scripting 可在 Redis 2.6 或更高版本中使用。

脚本的主要优点是它可以以最小的延迟同时读取和写入数据。它使读取,计算,写入等操作变得非常快。

在流水线操作中,客户端在调用 write 命令之前需要 read 命令的回复。

5.7 redis分区

分区用于将 Redis 数据拆分为多个 Redis 实例,以便每个实例仅包含一部分 key。

它通常用于大型数据库。

5.7.1 分区类型

redis 中有两种类型的分区:

  • 范围分区
  • 哈希分区

5.7.2 范围分区

范围分区是执行分区的最简单方法之一。它通过将对象的范围映射到特定的 Redis 实例来完成。

例如:

假设您有 3000 个用户。因此,您可以说从 ID 0 到 ID 1000 的用户将进入实例 R0,而用户表单 ID 1001 到 ID 2000 将进入实例 R1,用户表单 ID 2001 到 ID 3000 将进入实例 R2,依此类推。

5.7.3 哈希分区

散列分区是 Range 分区的替代方法。在散列分区中,散列函数用于将 key 转换为数字,然后将数据存储在不同的 Redis 实例中。

5.7.4 Redis分区的优点

  • 分区有助于您使用多台计算机的集体内存。例如:对于较大的数据库,您需要大量内存,因此分区可以提供来自不同计算机的内存总和。如果不进行分区,则只能使用单台计算机可以支持的有限内存量。
  • 分区还用于将计算能力扩展到多个核心和多个计算机,以及网络带宽扩展到多个计算机和网络适配器。

5.7.5 Redis分区的缺点

分区存在一些缺点,因为 Redis 的某些功能受到分区的阻碍。

  • 分区通常不支持具有多个键的操作。例如,如果两个集合存储在映射到不同 Redis 实例的键中,则无法执行它们之间的交集。
  • 分区不支持具有多个 key 的事务。
  • 分区粒度是关键,因此不可能使用单个巨大的 key(如非常大的有序集)对数据集进行分片。
  • 使用分区时,数据处理更复杂,例如,您必须处理多个 RDB / AOF 文件,并且需要从多个实例和主机聚合持久性文件来备份数据。
  • 添加和删除容量可能很复杂。例如,Redis Cluster 支持大多数透明的数据重新平衡,能够在运行时添加和删除节点,但客户端分区和代理等其他系统不支持此功能。然而,一种称为预分片的技术在这方面有所帮助。

Redis命令手册

1. 命令集合

1.1 Key(键)

1.1.1 DEL key

Redis DEL 命令用于删除给定的一个或多个 key 。不存在的 key 会被忽略。

  • 语法:

    1
    127.0.0.1:6379> DEL KEY_NAME
  • 返回值:

    整数: 被删除 key 的数量。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> set kungs1 "Hello"
    OK
    127.0.0.1:6379> set kungs2 "World"
    OK
    127.0.0.1:6379> set kungs3 "redis"
    OK
    127.0.0.1:6379> DEL kungs1 kungs2 kungs3 kungs4
    3
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(N) where N is the number of keys that will be removed. When a key to remove holds a value other than a string, the individual complexity for this key is O(M) where M is the number of elements in the list, set, sorted set or hash. Removing a single key that holds a string value is O(1).

1.1.2 DUMP key

Redis DUMP 用于序列化给定 key ,并返回被序列化的值,使用 restore 命令可以将DUMP 的结果反序列化回 Redis 。

序列化格式有以下几个特点:

  • 它带有 64 位的校验和,用于检测错误, restore 在进行反序列化之前会先检查校验和。.
  • 值的编码格式和 RDB 文件保持一致。
  • RDB 版本会被编码在序列化值当中,如果因为 Redis 的版本造成 RDB 格式不兼容,那么 Redis 会拒绝对这个值进行反序列化操作。

序列化的值不包括任何过期(expire)信息。

如果想获得 key 的剩余过期时间,需要使用 PTTL 命令。

如果 key 不存在,那么返回 nil

  • 语法:

    1
    127.0.0.1:6379> DUMP KEY_NAME
  • 返回值:

    多行字符串: 如果 key 不存在,那么返回 nil 。 否则,返回序列化之后的值。

  • 实例:

    1
    2
    3
    4
    5
    127.0.0.1:6379> set kungskey 10
    OK
    127.0.0.1:6379> DUMP kungskey
    "\x00\xc0\n\t\x00\xbem\x06\x89Z(\x00\n"
    127.0.0.1:6379>

可用版本>= 2.6.0.

时间复杂度: O(1) to access the key and additional O(NM) to serialize it, where N is the number of Redis objects composing the value and M their average size. For small string values the time complexity is thus O(1)+O(1M) where M is small, so simply O(1).

1.1.3 EXISTS key [key …]

Redis EXISTS 命令用于检查给定 key 是否存在。

从 Redis 3.0.3 起可以一次检查多个 key 是否存在。这种情况下,返回待检查 key 中存在的 key 的个数。检查单个 key 返回 1 或 0 。

注意:如果相同的 key 在参数列表中出现了多次,它会被计算多次。所以,如果somekey存在, EXISTS somekey somekey 命令返回 2。

  • 语法:

    1
    127.0.0.1:6379> EXISTS KEY_NAME
  • 返回值:

    整数:

    • 1: key存在
    • 0: key不存在
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    127.0.0.1:6379> SET key1 "Hello"
    OK
    127.0.0.1:6379> EXISTS key1
    (integer) 1
    127.0.0.1:6379> EXISTS nosuchkey
    (integer) 0
    127.0.0.1:6379> SET key2 "World"
    OK
    127.0.0.1:6379> EXISTS key1 key2 nosuchkey
    (integer) 2
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.1.4 EXPIRE key seconds

Redis Expire 命令设置 key 的过期时间(seconds)。 设置的时间过期后,key 会被自动删除。带有超时时间的 key 通常被称为易失的(volatile)

超时时间只能使用删除 key 或者覆盖 key 的命令清除,包括 DEL, SET, GETSET 和所有的 *STORE 命令。 对于修改 key 中存储的值,而不是用新值替换旧值的命令,不会修改超时时间。例如,自增 key 中存储的值的 INCR, 向list中新增一个值 LPUSH, 或者修改 hash 域的值 HSET ,这些都不会修改 key 的过期时间。

通过使用 PERSIST 命令把 key 改回持久的(persistent) key,这样 key 的过期时间也可以被清除。

key使用 RENAME 改名后,过期时间被转移到新 key 上。

已存在的旧 key 使用 RENAME 改名,那么新 key 会继承所有旧 key 的属性。例如,一个名为 Key_A 的 key 使用命令 RENAME Key_B Key_A 改名,新的 Key_A 会继承包括超时时间在内的所有 Key_B 的属性。

特别注意,使用负值调用 EXPIRE/PEXPIRE 或使用过去的时间调用 EXPIREAT/PEXPIREAT ,那么 key 会被删除 deleted 而不是过期。 (因为, 触发的key event 将是 del, 而不是 expired).

1.1.5 EXPIREAT key timestamp

EXPIREATEXPIRE 有相同的作用和语义, 不同的是 EXPIREAT 使用绝对 Unix 时间戳 (自1970年1月1日以来的秒数)代替表示过期时间的秒数。使用过去的时间戳将会立即删除该 key。

详细语义功能说明可以参考 EXPIRE

  • 语法:

    1
    127.0.0.1:6379> Expireat KEY_NAME TIME_IN_UNIX_TIMESTAMP
  • 背景:

    EXPIREAT 引入的目的是为了把 AOF 持久化模式的相对时间转换为绝对时间。当然,也可以直接指明某个 key 在未来某个时间过期。

  • 返回值:

    整数:

    • 1: 设置超时成功
    • 0: key不存在
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> SET mykey "Hello"
    OK
    127.0.0.1:6379> EXISTS mykey
    (integer) 1
    127.0.0.1:6379> EXPIREAT mykey 1293840000
    (integer) 1
    127.0.0.1:6379> EXISTS mykey
    (integer) 0
    127.0.0.1:6379>

可用版本>= 1.2.0.

时间复杂度: O(1)

1.1.6 PEXPIRE key milliseconds

PEXPIREEXPIRE 基本一样,只是过期时间单位是毫秒。

  • 语法:

    1
    127.0.0.1:6379> PEXPIRE key milliseconds
  • 返回值:

    整数:

    • 1: 过期设置成功
    • 0: key不存在 或设置失败
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> SET mykey "Hello"
    OK
    127.0.0.1:6379> PEXPIRE mykey 15000
    (integer) 1
    127.0.0.1:6379> TTL mykey
    (integer) 11
    127.0.0.1:6379> PTTL mykey
    (integer) 7039
    127.0.0.1:6379>

可用版本>= 2.6.0.

时间复杂度: O(1)

1.1.7 PEXPIREAT key milliseconds-timestamp

Redis PEXPIREAT 命令用于设置 key 的过期时间,时间的格式是uinx时间戳并精确到毫秒。

  • 语法:

    1
    127.0.0.1:6379> PEXPIREAT KEY_NAME TIME_IN_MILLISECONDS_IN_UNIX_TIMESTAMP
  • 返回值:

    整数:

    • 1: 设置成功返回
    • 0: key不存在
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> SET mykey "Hello"
    OK
    127.0.0.1:6379> PEXPIREAT mykey 150000000000
    (integer) 1
    127.0.0.1:6379> TTL mykey
    (integer) -2
    127.0.0.1:6379> PTTL mykey
    (integer) -2
    127.0.0.1:6379>

可用版本>= 2.6.0.

时间复杂度: O(1)

1.1.8 KEYS pattern

Redis KEYS 命令用于查找所有匹配给定模式 pattern 的 key 。

尽管这个操作的时间复杂度是 O(N),但是常量时间相当小。

例如,在一个普通笔记本上跑 Redis,扫描 100 万个 key 只要40毫秒。

Warning: 生产环境使用 KEYS 命令需要非常小心。在大的数据库上执行命令会影响性能。

这个命令适合用来调试和特殊操作,像改变键空间布局。

不要在你的代码中使用 KEYS 。如果你需要一个寻找键空间中的key子集,考虑使用 SCANSets

匹配模式:

  • h?llo 匹配 hello, hallohxllo
  • h*llo 匹配 hlloheeeello
  • h[ae]llo 匹配 hello and hallo, 不匹配 hillo
  • h[^e]llo 匹配 hallo, hbllo, … 不匹配 hello
  • h[a-b]llo 匹配 hallohbllo

使用 \ 转义你想匹配的特殊字符。

1.1.9 MOVE key db

Redis MOVE 命令用于将当前数据库的 key 移动到选定的数据库 db 当中。

如果 key 在目标数据库中已存在,或者 key 在源数据库中不存,则key 不会被移动。

  • 语法:

    1
    127.0.0.1:6379> MOVE KEY_NAME DESTINATION_DATABASE
  • 返回值:

    整数:

    • 1: key 被移动
    • 0: key 没有被移动
  • 实例:

    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
    # key 存在于当前数据库
    # redis默认使用数据库 0,为了清晰起见,这里再显式指定一次。
    127.0.0.1:6379> select 0
    OK
    127.0.0.1:6379> set kungs "yanpenggong base -Zone"
    OK
    # 将 kungs 移动到数据库 1
    127.0.0.1:6379> move kungs 1
    (integer) 1
    # kungs 已经被移走
    127.0.0.1:6379> exists kungs
    (integer) 0
    # 使用数据库 1
    127.0.0.1:6379> select 1
    OK
    # 证实 kungs 被移到了数据库 1
    # (注意命令提示符变成了"127.0.0.1:6379[1]",表明正在使用数据库 1)
    127.0.0.1:6379[1]> exists kungs
    (integer) 1
    # 当 key 不存在的时候
    127.0.0.1:6379[1]> exists fake_key
    (integer) 0
    # 试图从数据库 1 移动一个不存在的 key 到数据库 0,失败
    127.0.0.1:6379[1]> move fake_key 0
    (integer) 0
    # 使用数据库0
    127.0.0.1:6379[1]> select 0
    OK
    # 证实 fake_key 不存在
    127.0.0.1:6379> exists fake_key
    (integer) 0

    # 当源数据库和目标数据库有相同的 key 时
    # 使用数据库0
    127.0.0.1:6379> select 0
    OK
    127.0.0.1:6379> set fruit "apple"
    OK
    # 使用数据库1
    127.0.0.1:6379> select 1
    OK
    127.0.0.1:6379[1]> set fruit "pineappleC"
    OK
    # 使用数据库0,并试图将 fruit 移动到数据库 1
    127.0.0.1:6379[1]> select 0
    OK
    # 因为两个数据库有相同的 key,MOVE 失败
    127.0.0.1:6379> move fruit 1
    (integer) 0
    # 数据库 0 的 fruit 没变
    127.0.0.1:6379> get fruit
    "apple"
    # 数据库 1 的 fruit 也是
    127.0.0.1:6379> select 1
    OK
    127.0.0.1:6379[1]> get fruit
    "pineappleC"
    127.0.0.1:6379[1]>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.1.10 PERSIST key

Redis PERSIST 命令用于删除给定 key 的过期时间,使得 key 永不过期。

  • 语法:

    1
    127.0.0.1:6379> PERSIST KEY_NAME
  • 返回值:

    整数:

    • 1: 当过期时间移除成功时
    • 0: key不存在或 key 没有设置过期时间
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    127.0.0.1:6379> SET mykey "Hello"
    OK
    # 为 key 设置生存时间
    127.0.0.1:6379> EXPIRE mykey 10
    (integer) 1
    127.0.0.1:6379> TTL mykey
    (integer) 8
    # 移除 key 的生存时间
    127.0.0.1:6379> PERSIST mykey
    (integer) 1
    127.0.0.1:6379> TTL mykey
    (integer) -1
    127.0.0.1:6379>

可用版本>= 2.2.0.

时间复杂度: O(1)

1.1.11 PTTL key

Redis PTTL 命令以毫秒为单位返回 key 的剩余过期时间。

  • 语法:

    1
    127.0.0.1:6379> PTTL KEY_NAME
  • 返回值:

    Redis 2.6 之前的版本如果 key 不存在或者 key 没有关联超时时间则返回 -1

    Redis 2.8 起:

    • key 不存在返回 -2
    • key 存在但是没有关联超时时间返回 -1

    整数:

    • -1: key 存在但没有设置剩余生存时间
    • -2: key 不存在
    • 其它: 以毫秒为单位,返回 key 的剩余生存时间
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    127.0.0.1:6379> set mykey "Hello"
    OK
    # key 存在,但没有设置剩余生存时间
    127.0.0.1:6379> PTTL mykey
    (integer) -1
    127.0.0.1:6379> EXPIRE mykey 1000
    (integer) 1
    # 有剩余生存时间的 key
    127.0.0.1:6379> PTTL mykey
    (integer) 998591
    127.0.0.1:6379>

可用版本>= 2.6.0.

时间复杂度: O(1)

1.1.12 TTL key

Redis TTL 命令以秒为单位返回 key 的剩余过期时间。用户客户端检查 key 还可以存在多久。

  • Redis 2.6 之前的版本如果 key 不存在或者 key 没有关联超时时间则返回 -1 。
  • Redis 2.8 起:
    • key 不存在返回 -2
    • key 存在但是没有关联超时时间返回 -1
    • PTTL 返回以毫秒为单位的剩余超时时间。
  • 返回值:

    整数: 剩余超时秒数,失败返回负数如上。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    127.0.0.1:6379> set mykey "Hello"
    OK
    # key 存在,但没有设置剩余生存时间
    127.0.0.1:6379> TTL mykey
    (integer) -1
    127.0.0.1:6379> EXPIRE mykey 1000
    (integer) 1
    # 有剩余生存时间的 key
    127.0.0.1:6379> TTL mykey
    (integer) 998
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.1.13 RANDOMKEY

Redis RANDOMKEY 命令从当前数据库中随机返回一个 key 。

  • 语法:

    1
    127.0.0.1:6379> RANDOMKEY 
  • 返回值:

    多行字符串: 当数据库不为空时,返回一个 key 。 当数据库为空时,返回 nil 。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    127.0.0.1:6379> MSET fruit "apple" drink "beer" food "cookies"
    OK
    127.0.0.1:6379> KEYS *
    1) "food"
    2) "drink"
    3) "fruit"
    127.0.0.1:6379> RANDOMKEY
    "food"
    127.0.0.1:6379> RANDOMKEY
    "fruit"
    127.0.0.1:6379> FLUSHDB
    OK
    127.0.0.1:6379> RANDOMKEY
    (nil)
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.1.14 RENAME key newkey

Redis RENAME 命令用于修改 key 的名字为 newkey 。若key 不存在返回错误。

在集群模式下,key 和newkey 需要在同一个 hash slot。key 和newkey有相同的 hash tag 才能重命名。

如果 newkey 存在则会被覆盖,此种情况隐式执行了 DEL 操作,所以如果要删除的key的值很大会有一定的延时,即使RENAME 本身是常量时间复杂度的操作。

在集群模式下,key 和newkey 需要在同一个 hash slot。key 和newkey有相同的 hash tag 才能重命名。

  • 历史:

    <= 3.2.0: 源 key 和目的 key 相同返回错误。

  • 返回值:

    字符串

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    # key 存在且 newkey 不存在
    127.0.0.1:6379> set mykey "Hello"
    OK
    127.0.0.1:6379> RENAME mykey mykey1
    OK
    127.0.0.1:6379> get mykey1
    "Hello"
    # 当 key 不存在时,返回错误
    127.0.0.1:6379> RENAME mykey2 mykey22
    (error) ERR no such key
    # newkey 已存在时, RENAME 会覆盖旧 newkey
    127.0.0.1:6379> set pc "macpro"
    OK
    127.0.0.1:6379> set personal_computer "thinkpad"
    OK
    127.0.0.1:6379> RENAME pc personal_computer
    OK
    127.0.0.1:6379> get pc
    (nil)
    # 原来的值 thinkpad 被覆盖了
    127.0.0.1:6379> get personal_computer
    "macpro"
    127.0.0.1:6379>

    可用版本>= 1.0.0.

    时间复杂度: O(1)

1.1.15 RENAMENX key newkey

Redis Renamenx 命令用于在新的 key 不存在时修改 key 的名称 。若 key 不存在返回错误。

在集群模式下,keynewkey 需要在同一个 hash slotkeynewkey有相同的 hash tag 才能重命名。

  • 语法:

    1
    127.0.0.1:6379> RENAMENX OLD_KEY_NAME NEW_KEY_NAME
  • 历史:

  • 返回值:

    整数:

    • 1: rename 成功
    • 0: newkey 已经存在
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    # newkey 不存在,改名成功
    127.0.0.1:6379> set mykey "Hello"
    OK
    127.0.0.1:6379> RENAMENX mykey myotherkey
    (integer) 1
    127.0.0.1:6379> GET myotherkey
    "Hello"
    # newkey存在时,失败
    127.0.0.1:6379> SET animal "bear"
    OK
    127.0.0.1:6379> SET favorite_animal "butterfly"
    OK
    127.0.0.1:6379> RENAMENX animal favorite_animal
    (integer) 0
    127.0.0.1:6379> get animal
    "bear"
    127.0.0.1:6379> get favorite_animal
    "butterfly"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.1.16 SCAN cursor [MATCH pattern] [COUNT count]

Redis SCAN 命令及其相关命令 SSCAN, HSCAN, ZSCAN 命令都是用于增量遍历集合中的元素。

  • SCAN: 命令用于迭代当前数据库中的数据库键
  • SSCAN: 命令用于迭代集合键中的元素。
  • HSCAN: 命令用于迭代哈希键中的键值对。
  • ZSCAN: 命令用于迭代有序集合中的元素(包括元素成员和元素分值)。

以上列出的四个命令都支持增量式迭代, 它们每次执行都只会返回少量元素, 所以这些命令可以用于生产环境, 而不会出现像 KEYS 命令、 SMEMBERS 命令带来的问题 —— 当 KEYS 命令被用于处理一个大的数据库时, 又或者 SMEMBERS 命令被用于处理一个大的集合键时, 它们可能会阻塞服务器达数秒之久。

不过, 增量式迭代命令也不是没有缺点的: 举个例子, 使用 SMEMBERS 命令可以返回集合键某一时刻包含的所有元素, 但是对于 SCAN 这类增量式迭代命令来说, 因为在对键进行增量式迭代的过程中, 键可能会被修改, 所以增量式迭代命令不能完全保证返回所有元素。

因为 SCAN 、 SSCAN 、 HSCAN 和 ZSCAN 四个命令的工作方式都非常相似, 所以这个文档会一并介绍这四个命令, 但是要记住:SSCAN 命令、 HSCAN 命令和 ZSCAN 命令的第一个参数总是一个存储集合的键名。而 SCAN 命令则不需要在第一个参数提供任何数据库键 —— 因为它迭代的是当前数据库中的所包含的键。

  1. SCAN 命令的基本用法

    SCAN 命令是一个基于游标的迭代器,每次被调用之后, 都会向用户返回一个新的游标, 用户在下次迭代时需要使用这个新游标作为 SCAN 命令的游标参数, 以此来延续之前的迭代过程。

    SCAN 返回一个包含两个元素的数组, 第一个元素是用于进行下一次迭代的新游标, 而第二个元素则是一个数组, 这个数组中包含了所有被迭代的元素。当 SCAN 命令的游标参数被设置为 0 时, 服务器将开始一次新的迭代,而当服务器向用户返回值为 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
    127.0.0.1:6379> scan 0
    1) "17"
    2) 1) "key:12"
    2) "key:8"
    3) "key:4"
    4) "key:14"
    5) "key:16"
    6) "key:17"
    7) "key:15"
    8) "key:10"
    9) "key:3"
    10) "key:7"
    11) "key:1"
    127.0.0.1:6379> scan 17
    1) "0"
    2) 1) "key:5"
    2) "key:18"
    3) "key:0"
    4) "key:2"
    5) "key:19"
    6) "key:13"
    7) "key:6"
    8) "key:9"
    9) "key:11"

    在上面这个例子中, 第一次迭代使用 0 作为游标, 表示开始一次新的迭代。第二次迭代使用的是第一次迭代时返回的游标, 也就是命令回复第一个元素的值 —— 17

  1. SCAN 命令的保证

    • 如果有一个元素, 它从遍历开始直到遍历结束期间都存在于被遍历的数据集当中, 那么 SCAN 命令总会在某次迭代中将这个元素返回给用户。
    • 如果有一个元素, 它从遍历开始就已经被删除,且直到遍历结束也没有被添加回来, 那么 SCAN 命令确保不会返回这个元素。

    然而因为 SCAN 命令仅仅使用游标来记录迭代状态, 所以这些命令带有以下缺点:

    • 同一个元素可能会被返回多次。 处理重复元素的工作交由应用程序负责, 比如说, 可以考虑将迭代返回的元素仅仅用于可以安全地重复执行多次的操作上。
    • 如果一个元素是在迭代过程中被添加到数据集的, 又或者是在迭代过程中从数据集中被删除的, 那么这个元素可能会被返回, 也可能不会, 这是未定义的(undefined)。
  1. SCAN 命令每次执行返回的元素数量

    SCAN 命令族并不保证每次执行都返回某个给定数量的元素。增量式命令甚至可能会返回零个元素, 但只要命令返回的游标不是 0 , 应用程序就不应该将迭代视作结束。

    不过命令返回的元素数量总是符合一定规则的, 在实际中:对于一个大数据集来说, 增量式迭代命令每次最多可能会返回数十个元素;而对于一个足够小的数据集来说, 小集合键、小哈希键和小有序集合键, 那么增量迭代命令将在一次调用中返回数据集中的所有元素。

    最后, 用户可以通过增量式迭代命令提供的 COUNT 选项来指定每次迭代返回元素的最大值。

  1. COUNT 选项

    虽然 SCAN 命令不保证每次迭代所返回的元素数量, 但我们可以使用 COUNT选项, 对命令的行为进行一定程度上的调整。 COUNT 选项的作用就是让用户告知迭代命令, 在每次迭代中应该从数据集里返回多少元素。虽然这个选项只是对增量式迭代命令的一种提示(hint), 但是在大多数情况下, 这种提示都是有效的。

    • COUNT 参数的默认值为 10
    • 在迭代一个足够大的、由哈希表实现的数据库、集合键、哈希键或者有序集合键时, 如果用户没有使用 MATCH 选项, 那么命令返回的元素数量通常和 COUNT 选项指定的一样, 或者比 COUNT 选项指定的数量稍多一些。
    • 在迭代一个编码为整数集合(intset,一个只由整数值构成的小集合)、 或者编码为压缩列表(ziplist,由不同值构成的一个小哈希或者一个小有序集合)时, 增量式迭代命令通常会无视 COUNT 选项指定的值, 在第一次迭代就将数据集包含的所有元素都返回给用户。

    Important: 并非每次迭代都要使用相同的 COUNT **值。用户可以在每次迭代中按自己的需要随意改变 COUNT 值, 只要记得将上次迭代返回的游标用到下次迭代里面就可以了。

  1. MATCH 选项

    和 KEYS 命令一样, SCAN命令族也可以通过提供一个 glob 风格的模式参数, 让命令只返回和给定模式相匹配的元素, 这一点可以通过在执行增量式迭代命令时, 通过给定 MATCH <pattern> 参数来实现。

    例如:

    1
    2
    3
    4
    5
    6
    7
    8
    127.0.0.1:6379> sadd myset 1 2 3 foo foobar feelsgood
    (integer) 6
    127.0.0.1:6379> sscan myset 0 match f*
    1) "0"
    2) 1) "foo"
    2) "feelsgood"
    3) "foobar"
    127.0.0.1:6379>

    对元素的模式匹配工作是在命令从数据集中取出元素之后, 向客户端返回元素之前的这段时间内进行的, 所以如果被迭代的数据集中只有少量元素和模式相匹配, 那么迭代命令或许会在多次执行中都不返回任何元素。例如:

    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
    127.0.0.1:6379> scan 0 MATCH *11*
    1) "288"
    2) 1) "key:911"
    127.0.0.1:6379> scan 288 MATCH *11*
    1) "224"
    2) (empty list or set)
    127.0.0.1:6379> scan 224 MATCH *11*
    1) "80"
    2) (empty list or set)
    127.0.0.1:6379> scan 80 MATCH *11*
    1) "176"
    2) (empty list or set)
    127.0.0.1:6379> scan 176 MATCH *11* COUNT 1000
    1) "0"
    2) 1) "key:611"
    2) "key:711"
    3) "key:118"
    4) "key:117"
    5) "key:311"
    6) "key:112"
    7) "key:111"
    8) "key:110"
    9) "key:113"
    10) "key:211"
    11) "key:411"
    12) "key:115"
    13) "key:116"
    14) "key:114"
    15) "key:119"
    16) "key:811"
    17) "key:511"
    18) "key:11"
    127.0.0.1:6379>

    我们可以看到, 以上的大部分迭代都不返回任何元素。

    在最后一次迭代, 我们通过将 COUNT 选项的参数设置为 1000 , 强制命令为本次迭代扫描

更多元素, 从而使得命令返回的元素也变多了

  • 语法:

    1
    SCAN cursor [MATCH pattern] [COUNT count]

    参数说明:

    • cursor - 游标。
    • pattern - 匹配的模式。
    • count - 指定从数据集里返回多少元素,默认值为 10 。
  • 返回值:

    数组列表

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    # 使用 0 作为游标,开始新的迭代
    127.0.0.1:6379> scan 0
    1) "0"
    2) 1) "favorite_animal"
    2) "personal_computer"
    3) "myotherkey"
    4) "mykey1"
    5) "animal"
    # 使用的是第一次迭代时返回的游标 12 开始新的迭代
    127.0.0.1:6379> scan 12
    1) "0"
    2) 1) "favorite_animal"
    2) "personal_computer"
    3) "myotherkey"
    4) "mykey1"
    5) "animal"
    # 使用的是第一次迭代时返回的游标 3 开始新的迭代
    127.0.0.1:6379> scan 3
    1) "0"
    2) 1) "myotherkey"
    2) "mykey1"
    3) "animal"
    127.0.0.1:6379>

可用版本>= 2.8.0.

时间复杂度: O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection.

1.1.17 TYPE key

Redis Type 命令用于返回 key 所储存的值的类型。

  • 语法:

    1
    127.0.0.1:6379> TYPE KEY_NAME 
  • 返回值:

    返回 key 的数据类型,数据类型有:

    • none (key不存在)
    • string (字符串)
    • list (列表)
    • set (集合)
    • zset (有序集)
    • hash (哈希表)
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    127.0.0.1:6379> SET key1 "value"
    OK
    127.0.0.1:6379> LPUSH key2 "value"
    (integer) 1
    127.0.0.1:6379> SADD key3 "value"
    (integer) 1
    127.0.0.1:6379> TYPE key1
    string
    127.0.0.1:6379> TYPE key2
    list
    127.0.0.1:6379> TYPE key3
    set
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.1.18 MIGRATE host port key|\”\” destination-db timeout [COPY] [REPLACE] [AUTH password] [AUTH2 username password] [KEYS key [key …]]

将 key 原子性地从当前实例传送到目标实例的指定数据库上,一旦传送成功, key 会出现在目标实例上,而当前实例上的 key 会被删除。

MIGRATE 命令是一个原子操作,它在执行的时候会阻塞进行迁移的两个实例,直到以下任意结果发生:迁移成功,迁移失败,等待超时。

  • 一次迁移多个 key:

    Redis 3.0.6 起MIGRATE 支持批量迁移。需要使用 KEYS 选项,使用空字符串替换 key,要迁移的 key 列在 KEYS 命令之后:

    1
    MIGRATE 192.168.1.34 6379 "" 0 5000 KEYS key1 key2 key3

    当所有 key 都不存在时返回 NOKEY ,即使只有一个key存在也执行成功。

  • Options:

    • COPY — 复制,不删除源实例中的 key。
    • REPLACE — 替换,替换目标实例中的存在的 key。
    • KEYS — 如果 key 参数是一个空字符串,会迁移 KEYS 命令后所有的 key 。
    • AUTH — 使用密码访问目标数据库。
    • AUTH2 — 使用用户名和密码对访问数据库。 (Redis 6 以上 ACL auth )。
  • 返回值:

    字符串: 迁移成功时返回 OK ,如果在源实例中找不到 key 返回 NOKEY 。

可用版本>= 2.6.0.

时间复杂度: This command actually executes a DUMP+DEL in the source instance, and a RESTORE in the target instance. See the pages of these commands for time complexity. Also an O(N) data transfer between the two instances is performed.

1.2 String(字符串)

1.2.1 SET key value [EX seconds|PX milliseconds|KEEPTTL] [NX|XX] [GET]

Redis SET 命令用于设置给定 key 的值。如果 key 已经存储其他值, SET 就覆写旧值,且无视类型。

  • 语法:

    1
    127.0.0.1:6379> SET KEY_NAME VALUE
  • 返回值:

    • 字符串: 如果SET命令正常执行那么回返回OK

    • 多行字符串: 使用 GET 选项,返回 key 存储的值

    • : key 不存在,否则如果加了NX 或者 XX选项,SET 没执行,那么会返回nil。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> SET mykey "Hello"
    OK
    127.0.0.1:6379> GET mykey
    "Hello"
    127.0.0.1:6379> SET anotherkey "will expire in a minute" EX 60
    OK
    127.0.0.1:6379> get anotherkey
    "will expire in a minute"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.2.2 GET key

返回与键 key 相关联的字符串值,用于获取指定 key 的值。

如果键 key 不存在, 那么返回特殊值 nil ; 否则, 返回键 key 的值。

如果键 key 的值不是字符串类型, 那么返回一个错误, 因为 GET 命令只能用于字符串值。

  • 返回值:

    多行字符串: 返回key中存储的值,key 不存在是返回nil

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    # 对不存在的 key 进行 GET
    127.0.0.1:6379> GET nonexisting
    (nil)
    127.0.0.1:6379> SET mykey "Hello"
    "OK"
    # 对字符串类型 key 进行 GET
    127.0.0.1:6379> GET mykey
    "Hello"
    # 对不是字符串类型的 key 进行 GET
    127.0.0.1:6379> HSET myhash field1 "Hello"
    (integer) 1
    127.0.0.1:6379> GET myhash
    ERR WRONGTYPE Operation against a key holding the wrong kind of value
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.2.3 GETRANGE key start end

GETRANGE 命令返回存储在 key 中的字符串的子串,由 start 和 end 偏移决定(都包括在内)。负数偏移提供相对字符串结尾的偏移。所以, -1 表示最后一个字符, -2 表示倒数第二个字符,以此类推。
GETRANGE 通过将结果范围限制为字符串的实际长度来处理超出范围的请求。
Warning: GETRANGE 是改名而来,在 Redis2.0 以前版本叫做 SUBSTR 。

  • 语法:

    1
    127.0.0.1:6379> GETRANGE KEY_NAME start end
  • 返回值:

    多行字符串:截取得到的子字符串。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    127.0.0.1:6379> SET mykey "This is a string yanpenggong"
    OK
    127.0.0.1:6379> GETRANGE mykey 0 3
    "This"
    127.0.0.1:6379> GETRANGE mykey -3 -1
    "ong"
    127.0.0.1:6379> GETRANGE mykey 0 -1
    "This is a string yanpenggong"
    127.0.0.1:6379> GETRANGE mykey 10 100
    "string yanpenggong"
    127.0.0.1:6379>

可用版本>= 2.4.0.

时间复杂度: O(N) where N is the length of the returned string. The complexity is ultimately determined by the returned length, but because creating a substring from an existing string is very cheap, it can be considered O(1) for small strings.

1.2.4 GETSET key value

将键 key 的值设为 value , 并返回键 key 在被设置之前的旧值。

返回给定键 key 的旧值。

如果键 key 没有旧值, 也即是说, 键 key 在被设置之前并不存在, 那么命令返回 nil

当键 key 存在但不是字符串类型时, 命令返回一个错误。

  • 语法:

    1
    127.0.0.1:6379> GETSET KEY_NAME VALUE
  • 返回值:

    返回给定 key 的旧值。 当 key 没有旧值时,即 key 不存在时,返回 nil 。

    当 key 存在但不是字符串类型时,返回一个错误。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 没有旧值,返回 nil
    127.0.0.1:6379> GETSET db redis
    (nil)
    127.0.0.1:6379> GET db
    "redis"
    # 返回旧值 redis
    127.0.0.1:6379> GETSET db mongodb
    "redis"
    127.0.0.1:6379> GET db
    "mongodb"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.2.5 GETBIT key offset

key 所储存的字符串值,获取指定偏移量上的位(bit)。

offset 比字符串值的长度大,或者 key 不存在时,返回 0

1.2.6 MGET key [key …]

Redis MGET 命令返回所有(一个或多个)给定 key 的值,值的类型是字符串。 如果给定的 key 里面,有某个 key 不存在或者值不是字符串,那么这个 key 返回特殊值 nil

  • 语法:

    1
    127.0.0.1:6379> MGET KEY1 KEY2 .. KEYN
  • 返回值:

    数组: MGET 命令将返回一个列表, 列表中包含了所有给定键的值。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> SET key1 "Hello"
    OK
    127.0.0.1:6379> SET key2 "World"
    OK
    127.0.0.1:6379> MGET key1 key2 nonexisting
    1) "Hello"
    2) "World"
    3) (nil)
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(N) where N is the number of keys to retrieve.

1.2.7 SETBIT key offset value

Redis Setbit 命令用于对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。

根据值 value 是 1 或 0 来决定设置或清除位 bit。当 key 不存在时会创建一个新的字符串。

当字符串不够长时,字符串的长度将增大,以确保它可以在offset位置存储值。

offset 参数需要大于等于0,并且小于 $2^{32}$ (bitmaps 最大 512MB)。

当值字符串变长时,添加的 bit 会被设置为 0。

注意: 当设置的是最后一位 bit (offset 等于 $2^{32} -1$),并且存储在 key 中的字符串还没有存储一个字符串值,或者存储的是一个短的字符串值时,Redis 需要分配所有的中间内存,这会阻塞 Redis 服务器一段时间。

在 2010 年的 MacBook Pro上:

  • 设置 $2^{32} -1$ 位 (分配512MB内存) 需花费 300ms,
  • 设置 $2^{30} -1$ 位 (分配 128MB 内存) 需花费 80m,
  • 设置 $2^{28} -1$ 位 (分配 32MB 内存) 需花费 30ms,
  • 设置 $2^{26} -1$ 位 (分配 8MB 内存) 需花费 8ms。

需要注意的是,一旦上面第一步内存分配被完成,对于同一个 key 接下来调用 SETBIT 将不会有分配内存开销。

  • 语法:

    1
    127.0.0.1:6379> SETBIT key offset value
  • 返回值:

    整数: 存储在 offset 偏移位的原始值。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    127.0.0.1:6379> SETBIT bit 10086 1
    (integer) 0
    127.0.0.1:6379> GETBIT bit 10086
    (integer) 1
    # bit 默认被初始化为 0
    127.0.0.1:6379> GETBIT bit 100
    (integer) 0
    127.0.0.1:6379>

可用版本>= 2.2.0.

时间复杂度: O(1)

1.2.8 SETEX key seconds value

SETEX 命令将键 key 的值设置为 value , 并将键 key 的生存时间设置为 seconds 秒钟。

如果键 key 已经存在, 那么 SETEX 命令将覆盖已有的值。

SETEX 命令的效果和以下两个命令的效果类似:

1
2
127.0.0.1:6379> SET mykey value
127.0.0.1:6379> EXPIRE mykey seconds

SETEX 和这两个命令的不同之处在于 SETEX 是一个原子(atomic)操作, 它可以在同一时间内完成设置值和设置过期时间这两个操作, 因此 SETEX 命令在Redis用做缓存的时候非常实用。

  • 语法:

    1
    127.0.0.1:6379> SETEX KEY_NAME TIMEOUT VALUE
  • 返回值:

    字符串:命令在设置成功时返回 OK 。 当 seconds 参数不合法时, 命令将返回ERR ERR value is not an integer or out of range错误。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    127.0.0.1:6379> SETEX mykey 10 "Hello"
    OK
    127.0.0.1:6379> TTL mykey
    (integer) 9
    127.0.0.1:6379> GET mykey
    "Hello"
    # 等几秒再看看输出
    127.0.0.1:6379> TTL mykey
    (integer) -2
    127.0.0.1:6379> GET mykey
    (nil)
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(1)

1.2.9 SETNX key value

Redis Setnx( SET if Not exists )命令在指定的 key 不存在时,为 key 设置指定的值,这种情况下等同 SET 命令。当 key存在时,什么也不做。

  • 语法:

    1
    127.0.0.1:6379> SETNX KEY_NAME VALUE
  • 返回值:

    整数:

    • 1: 如果key被设置了
    • 0: 如果key没有被设置
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    # mykey 不存在
    127.0.0.1:6379> EXISTS mykey
    (integer) 0
    # mykey 设置成功
    127.0.0.1:6379> SETNX mykey "Hello"
    (integer) 1
    # 尝试覆盖,但是失败
    127.0.0.1:6379> SETNX mykey "World"
    (integer) 0
    # 没有被覆盖
    127.0.0.1:6379> GET mykey
    "Hello"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.2.10 SETRANGE key offset value

SETRANGE 命令从偏移量 offset 开始, 用 value 参数覆盖键 key 储存的字符串值。

不存在的键 key 当作空白字符串处理。

SETRANGE命令会确保字符串足够长以便将 value 设置到指定的偏移量上, 如果键 key 原来储存的字符串长度比偏移量小(比如字符串只有 5 个字符长,但你设置的 offset10 ), 那么原字符和偏移量之间的空白将用零字节(zerobytes, "\x00" )进行填充。

因为 Redis 字符串的大小被限制在 512 兆(megabytes)以内, 所以用户能够使用的最大偏移量为 $2^{29}-1$(536870911) , 如果你需要使用比这更大的空间, 请使用多个 key

Warning: 当生成一个很长的字符串时, Redis 需要分配内存空间, 该操作有时候可能会造成服务器阻塞(block)。 在2010年出产的Macbook Pro上, 设置偏移量为 536870911(512MB 内存分配)将耗费约 300 毫秒, 设置偏移量为 134217728(128MB 内存分配)将耗费约 80 毫秒, 设置偏移量 33554432(32MB 内存分配)将耗费约 30 毫秒, 设置偏移量为 8388608(8MB 内存分配)将耗费约 8 毫秒。

  • 语法:

    1
    127.0.0.1:6379> 
  • 返回值:

    整数: SETRANGE命令会返回被修改之后, 字符串值的长度。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    127.0.0.1:6379> SET key1 "Hello world"
    OK
    127.0.0.1:6379> SETRANGE key1 6 "Redis"
    (integer) 11
    127.0.0.1:6379> GET key1
    "Hello Redis"
    127.0.0.1:6379> SETRANGE key2 6 "Redis"
    (integer) 11
    127.0.0.1:6379> GET key2
    "\x00\x00\x00\x00\x00\x00Redis"
    127.0.0.1:6379>

可用版本>= 2.2.0.

时间复杂度: O(1), not counting the time taken to copy the new string in place. Usually, this string is very small so the amortized complexity is O(1). Otherwise, complexity is O(M) with M being the length of the value argument.

1.2.11 STRLEN key

Redis Strlen 命令用于获取指定 key 所储存的字符串值的长度。当 key 储存的不是字符串类型时,返回错误。

  • 语法:

    1
    127.0.0.1:6379> STRLEN KEY_NAME
  • 返回值

    整数: 字符串的长度,key 不存在时,返回 0 。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 获取字符串的长度
    127.0.0.1:6379> SET mykey "Hello World"
    OK
    127.0.0.1:6379> STRLEN mykey
    (integer) 11
    # 不存在的 key 长度为 0
    127.0.0.1:6379> STRLEN nonexisting
    (integer) 0
    127.0.0.1:6379>

可用版本>= 2.2.0.

时间复杂度: O(1)

1.2.12 MSET key value [key value …]

Redis MSET 命令设置多个 key 的值为各自对应的 value。

MSETSET 一样,会用新值替换旧值。如果你不想覆盖旧值,可以使用 MSETNX

MSET 是原子操作,所有 key 的值同时设置。客户端不会看到有些 key 值被修改,而另一些 key 值没变。

  • 语法:

    1
    127.0.0.1:6379> MSET key1 value1 key2 value2 .. keyN valueN
  • 返回值:

    字符串: 总是返回”OK”,因为 MSET不会失败。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> MSET key1 "Hello" key2 "World"
    OK
    127.0.0.1:6379> GET key1
    "Hello"
    127.0.0.1:6379> GET key2
    "World"
    127.0.0.1:6379>

可用版本>= 1.0.1.

时间复杂度: O(N) where N is the number of keys to set.

1.2.13 MSETNX key value [key value …]

当且仅当所有给定键都不存在时, 为所有给定键设置值。

即使只有一个给定键已经存在, MSETNX 命令也会拒绝执行对所有键的设置操作。

MSETNX 是一个原子性(atomic)操作, 所有给定键要么就全部都被设置, 要么就全部都不设置。

MSETNX 可以用来设置逻辑对象的属性,来确保要么都设置,要么都不设置。

  • 语法:

    1
    127.0.0.1:6379> 
  • 返回值:

    整数:

    • 1: 当所有给定键都设置成功时
    • 0: 某个给定键已经存在而导致设置未能成功
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> MSETNX key1 "Hello" key2 "there"
    (integer) 1
    127.0.0.1:6379> MSETNX key2 "new" key3 "world"
    (integer) 0
    127.0.0.1:6379> MGET key1 key2 key3
    1) "Hello"
    2) "there"
    3) (nil)
    127.0.0.1:6379>

可用版本>= 1.0.1.

时间复杂度: O(N) where N is the number of keys to set.

1.2.14 PSETEX key milliseconds value

PSETEX 命令和 SETEX 命令相似, 但它以毫秒为单位设置 key 的生存时间, 而不是像 SETEX 命令那样以秒为单位进行设置。

  • 语法:

    1
    127.0.0.1:6379> PSETEX key milliseconds value
  • 返回值:

    设置成功时返回”OK”

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> PSETEX mykey 10000 "Hello"
    OK
    127.0.0.1:6379> PTTL mykey
    (integer) 8171
    127.0.0.1:6379> GET mykey
    "Hello"
    127.0.0.1:6379>

可用版本>= 2.6.0.

时间复杂度: O(1)

1.2.15 INCR key

Redis INCR命令将 key 中储存的数字值增一。

如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCR 操作。

如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误 ERR ERR hash value is not an integer。

本操作的值限制在 64 位(bit)有符号数字表示之内。

Note: 本质上这是一个字符串操作,因为Redis没有专门的整数类型。存储在 key 中的字符串被转换为十进制有符号整数,在此基础上加1。

  • 语法:

    1
    127.0.0.1:6379> INCR KEY_NAME
  • 返回值:

    整数: 执行 INCR 命令之后 key 的值。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    127.0.0.1:6379> SET mykey "10"
    OK
    127.0.0.1:6379> INCR mykey
    (integer) 11
    127.0.0.1:6379> GET mykey
    "11"
    # 数字值在 Redis 中以字符串的形式保存
    127.0.0.1:6379> SET mykey 20
    OK
    127.0.0.1:6379> INCR mykey
    (integer) 21
    127.0.0.1:6379> GET mykey
    "21"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.2.16 INCRBY key increment

Redis INCRBY 命令将 key 中储存的数字加上指定的增量值。

如果 key 不存在,那么 key 的值会先被初始化为 0 ,然后再执行 INCRBY 命令。

如果值包含错误的类型,或字符串类型的值不能表示为数字,那么返回一个错误 ERR ERR hash value is not an integer。

本操作的值限制在 64 位(bit)有符号数字表示之内。

关于递增(increment) / 递减(decrement)操作的更多信息, 请参见 INCR 命令的文档。

  • 语法:

    1
    127.0.0.1:6379> INCRBY key increment
  • 返回值:

    整数: 命令执行之后 key 中 存储的值。

  • 实例:

    1
    2
    3
    4
    5
    127.0.0.1:6379> SET mykey "10"
    OK
    127.0.0.1:6379> INCRBY mykey 5
    (integer) 15
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.2.17 INCRBYFLOAT key increment

为键 key 中储存的值加上浮点数增量 increment ,key 中的浮点数是以字符串形式存储的。

如果键 key 不存在, 那么 INCRBYFLOAT 会先将键 key 的值设为 0 , 然后再执行加法操作。

如果命令执行成功, 那么键 key 的值会被更新为执行加法计算之后的新值, 并且新值会以字符串的形式返回给调用者。

无论是键 key 的值还是增量 increment , 都可以使用像 2.0e73e590e-2 那样的指数符号(exponential notation)来表示, 但是, 执行 INCRBYFLOAT 命令之后的值总是以同样的形式储存, 也即是, 它们总是由一个数字, 一个(可选的)小数点和一个任意长度的小数部分组成(比如 3.1469.768 ,诸如此类), 小数部分尾随的 0 会被移除, 如果可能的话, 命令还会将浮点数转换为整数(比如 3.0 会被保存成 3 )。

此外, 无论加法计算所得的浮点数的实际精度有多长, INCRBYFLOAT命令的计算结果最多只保留小数点的后十七位。

当以下任意一个条件发生时, 命令返回一个错误:

  • key 的值不是字符串类型(因为 Redis 中的数字和浮点数都以字符串的形式保存,所以它们都属于字符串类型);
  • key 当前的值或者给定的增量 increment 不能被解释(parse)为双精度浮点数。

  • 语法:

    1
    127.0.0.1:6379> INCRBYFLOAT key increment
  • 返回值:

    多行字符串: 在加上增量 increment 之后, 键 key 的值。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    127.0.0.1:6379> SET mykey 10.50
    OK
    127.0.0.1:6379> INCRBYFLOAT mykey 0.1
    "10.6"
    127.0.0.1:6379> INCRBYFLOAT mykey -5
    "5.6"
    127.0.0.1:6379> SET mykey 5.0e3
    OK
    127.0.0.1:6379> INCRBYFLOAT mykey 2.0e2
    "5200"
    127.0.0.1:6379>
  • 实现细节

    INCR 命令族主要用在复制和 AOF 文件中,用来当做 SET,减少源 SET 命令个数,浮点的实现差异不会是不一致的来源。

可用版本>= 2.6.0.

时间复杂度: O(1)

1.2.18 DECR key

为键 key 储存的数字值减去一。

如果键 key 不存在, 那么键 key 的值会先被初始化为 0 , 然后再执行 DECR 操作。

如果键 key 储存的值不能被解释为数字, 那么 DECR 命令将返回一个错误。

本操作的值限制在 64 位(bit)有符号数字表示之内。

  • 语法:

    1
    127.0.0.1:6379> DECR key
  • 返回值:

    整数: 执行操作之后key中的值

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> SET mykey "10"
    OK
    127.0.0.1:6379> DECR mykey
    (integer) 9
    127.0.0.1:6379> SET mykey "13621873621786345326"
    OK
    127.0.0.1:6379> DECR mykey
    (error) ERR value is not an integer or out of range
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.2.19 DECRBY key decrement

将键 key 储存的整数值减去减量 decrement 。
如果键 key 不存在, 那么键 key 的值会先被初始化为 0 , 然后再执行 DECRBY 命令。
如果键 key 储存的值不能被解释为数字, 那么 DECRBY 命令将返回一个错误。
本操作的值限制在 64 位(bit)有符号数字表示之内。
关于更多递增(increment) / 递减(decrement)操作的更多信息, 请参见 INCR 命令的文档。

  • 语法:

    1
    127.0.0.1:6379> 
  • 返回值:

    整数: DECRBY 命令会返回键在执行减法操作之后的值。

  • 实例:

    1
    2
    3
    4
    5
    127.0.0.1:6379> SET mykey "10"
    OK
    127.0.0.1:6379> DECRBY mykey 3
    (integer) 7
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.2.20 APPEND key value

Redis APPEND 命令用于为指定的 key 追加值。
如果 key 已经存在并且是一个字符串, APPEND 命令将 value 追加到 key 原来的值的末尾。
如果 key 不存在, APPEND 就简单地将给定 key 设为 value ,就像执行 SET key value 一样。

  • 语法:

    1
    127.0.0.1:6379> APPEND KEY_NAME NEW_VALUE
  • 返回值:

    整数: 追加指定值之后, key 中字符串的长度。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    # 确保 myphone 不存在
    127.0.0.1:6379> EXISTS myphone
    (integer) 0
    # 对不存在的key 进行APPEND,等同于 SET myphone "nokia"
    127.0.0.1:6379> APPEND myphone "nokia"
    (integer) 5
    # 对已存在的字符串进行 APPEND。长度从5个字符串增加到11个字符串
    127.0.0.1:6379> APPEND myphone " - 222"
    (integer) 11
    127.0.0.1:6379> GET myphone
    "nokia - 222"
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(1). The amortized time complexity is O(1) assuming the appended value is small and the already present value is of any size, since the dynamic string library used by Redis will double the free space available on every reallocation.

1.3 Hash(哈希表)

1.3.1 HDEL key field [field …]

Redis HDEL 命令用于删除哈希表 key 中的一个或多个指定字段,不存在的字段将被忽略。 如果 key 粗存在,会被当作空哈希表处理并返回 0

  • 语法:

    1
    127.0.0.1:6379> HDEL KEY_NAME FIELD1.. FIELDN 
  • 返回值:

    整数: 被成功删除字段的数量,不包括被忽略的字段。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> HSET myhash field1 "foo"
    (integer) 1
    127.0.0.1:6379> HDEL myhash field1
    (integer) 1
    127.0.0.1:6379> HDEL myhash field2
    (integer) 0
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(N) where N is the number of fields to be removed.

1.3.2 HEXISTS key field

Redis Hexists 命令用于查看哈希表的指定字段field 是否存在。

  • 语法:

    1
    127.0.0.1:6379> HEXISTS KEY_NAME FIELD_NAME 
  • 返回值:

    整数, specifically:

    • 1 哈希表含有给定字段field
    • 0 哈希表不含有给定字段,或 key 不存在。
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> HSET myhash field1 "foo"
    (integer) 1
    127.0.0.1:6379> HEXISTS myhash field1
    (integer) 1
    127.0.0.1:6379> HEXISTS myhash field2
    (integer) 0
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(1)

1.3.3 HGET key field

Redis HGET 命令用于返回哈希表中指定字段 field 的值。

  • 语法:

    1
    127.0.0.1:6379> HGET KEY_NAME FIELD_NAME
  • 返回值:

    多行字符串: 返回给定字段的值。如果给定的字段或 key 不存在时,返回 nil 。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> HSET myhash field1 "foo"
    (integer) 1
    # 字段存在
    127.0.0.1:6379> HGET myhash field1
    "foo"
    # 字段不存在
    127.0.0.1:6379> HGET myhash field2
    (nil)
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(1)

1.3.4 HGETALL key

Redis HGETALL 命令用于返回存储在 key 中的哈希表中所有的域和值。

在返回值里,紧跟每个域(field name)之后是域的值(value),所以返回值的长度是哈希表大小的两倍。

  • 语法:

    1
    127.0.0.1:6379> HGETALL KEY_NAME
  • 返回值:

    数组: 以列表形式返回哈希表的字段及字段值。 若 key 不存在,返回空列表。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    127.0.0.1:6379> HSET myhash field1 "Hello"
    (integer) 1
    127.0.0.1:6379> HSET myhash field2 "World"
    (integer) 1
    127.0.0.1:6379> HGETALL myhash
    1) "field1"
    2) "Hello"
    3) "field2"
    4) "World"
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(N) where N is the size of the hash.

1.3.5 HINCRBY key field increment

为哈希表 key 中的域 field 的值加上增量 increment

增量也可以为负数,相当于对给定域进行减法操作。

如果 key 不存在,一个新的哈希表被创建并执行 HINCRBY 命令。

如果域 field 不存在,那么在执行命令前,域的值被初始化为 0

对一个储存字符串值的域 field 执行 HINCRBY 命令将造成一个错误 ERR ERR hash value is not an integer。

本操作的值被限制在 64 位(bit)有符号数字表示之内。

  • 语法:

    1
    127.0.0.1:6379> HINCRBY KEY_NAME FIELD_NAME INCR_BY_NUMBER 
  • 返回值:

    整数: 执行 HINCRBY 命令之后,哈希表 key 中域 field 的值。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> HSET myhash field 5
    (integer) 1
    127.0.0.1:6379> HINCRBY myhash field 1
    (integer) 6
    127.0.0.1:6379> HINCRBY myhash field -1
    (integer) 5
    127.0.0.1:6379> HINCRBY myhash field -10
    (integer) -5
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(1)

1.3.6 HINCRBYFLOAT key field increment

为哈希表 key 中的域 field 加上浮点数增量 increment

如果哈希表中没有域 field ,那么 INCRBYFLOAT 会先将域 field 的值设为 0 ,然后再执行加法操作。

如果键 key 不存在,那么 INCRBYFLOAT 会先创建一个哈希表,再创建域 field ,最后再执行加法操作。

当以下任意一个条件发生时,返回一个错误:

  • field 的值不是字符串类型(因为 redis 中的数字和浮点数都以字符串的形式保存,所以它们都属于字符串类型)
  • field 当前的值或给定的增量 increment 不能解释(parse)为双精度浮点数(double precision floating point number)

命令的详细功能和 INCRBYFLOAT命令类似,请查看 INCRBYFLOAT命令获取更多相关信息。

  • 语法:

    1
    127.0.0.1:6379> HINCRBYFLOAT key field increment
  • 返回值:

    多行字符串: 执行加法操作之后 field 域的值

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    127.0.0.1:6379> HSET myhash field 10.50
    (integer) 1
    127.0.0.1:6379> HINCRBYFLOAT myhash field 0.1
    "10.6"
    127.0.0.1:6379> HINCRBYFLOAT myhash field -5
    "5.6"
    127.0.0.1:6379> HSET myhash field 5.0e3
    (integer) 0
    127.0.0.1:6379> HINCRBYFLOAT myhash field 2.0e2
    "5200"
    127.0.0.1:6379>

可用版本>= 2.6.0.

时间复杂度: O(1)

1.3.7 HKEYS key

HKEYS 返回存储在 key 中哈希表的所有域。

  • 语法:

    1
    127.0.0.1:6379> HKEYS key
  • 返回值:

    数组: 包含哈希表中所有域的表。当 key 不存在时,返回空表。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    127.0.0.1:6379> HSET myhash field1 "Hello"
    (integer) 1
    127.0.0.1:6379> HSET myhash field2 "World"
    (integer) 1
    127.0.0.1:6379> HKEYS myhash
    1) "field1"
    2) "field2"
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(N) where N is the size of the hash.

1.3.8 HLEN key

Redis HLEN 命令用于获取哈希表中字段(fields)的数量。

  • 语法:

    1
    127.0.0.1:6379> HLEN key
  • 返回值:

    整数: 哈希表中字段的数量。 当 key 不存在时,返回 0 。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> HSET myhash field1 "Hello"
    (integer) 1
    127.0.0.1:6379> HSET myhash field2 "World"
    (integer) 1
    127.0.0.1:6379> HLEN myhash
    (integer) 2
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(1)

1.3.9 HMGET key field [field …]

Redis HMGET 命令用于返回哈希表中,一个或多个给定字段(field)的值。

如果指定的字段(field)不存在于哈希表或者 key 不存在,那么返回一个 nil 值。

  • 语法:

    1
    127.0.0.1:6379> HMGET key field [field ...]
  • 返回值:

    数组: 返回要查询的field对应值的列表,值的顺序field在命令中出现的顺序排列。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> HSET myhash field1 "Hello"
    (integer) 1
    127.0.0.1:6379> HSET myhash field2 "World"
    (integer) 1
    127.0.0.1:6379> HMGET myhash field1 field2 nofield
    1) "Hello"
    2) "World"
    3) (nil)
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(N) where N is the number of fields being requested.

1.3.10 HMSET key field value [field value …]

Redis HMSET 命令用于同时将多个 field-value (字段-值)对设置到哈希表中。

此命令会覆盖哈希表中已存在的字段。

如果哈希表不存在,会创建一个空哈希表,并执行 HMSET 操作。

Redis 4.0.0起,HMSET 被废弃,请使用 HSET 代替。

  • 语法:

    1
    127.0.0.1:6379> HMSET key field value [field value ...]
  • 返回值:

    字符串

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> HMSET myhash field1 "Hello" field2 "World"
    OK
    127.0.0.1:6379> HGET myhash field1
    "Hello"
    127.0.0.1:6379> HGET myhash field2
    "World"
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(N) where N is the number of fields being set.

1.3.11 HSET key field value [field value …]

  • 语法:

    1
    127.0.0.1:6379> HSET key field value [field value ...]
  • 返回值:

    整数: 被修改或增加的 field 个数。

  • 实例:

    1
    2
    3
    4
    5
    127.0.0.1:6379> HSET myhash field1 "Hello"
    (integer) 1
    127.0.0.1:6379> HGET myhash field1
    "Hello"
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(1) for each field/value pair added, so O(N) to add N field/value pairs when the command is called with multiple field/value pairs.

1.3.12 HSETNX key field value

Redis HSETNX 命令用于为哈希表中不存在的字段赋值 。

如果字段已经存在于哈希表中,操作无效。

如果 key 不存在,一个新哈希表被创建并执行 HSETNX 命令。

  • 语法:

    1
    127.0.0.1:6379> HSETNX key field value
  • 返回值:

    整数:

    • 1 field 设置成功。
    • 0 field 已存在,设置失败。
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> HSETNX myhash field "Hello"
    (integer) 1
    127.0.0.1:6379> HSETNX myhash field "World"
    (integer) 0
    127.0.0.1:6379> HGET myhash field
    "Hello"
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(1)

1.3.13 HVALS key

Redis HVALS 命令返回哈希表所有域(field)的值。

  • 语法:

    1
    127.0.0.1:6379> HVALS key
  • 返回值:

    数组: 返回哈希表中所有域(field)值的列表。 当 key 不存在时,返回空表。 not exist.

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> HSET myhash field1 "Hello"
    (integer) 1
    127.0.0.1:6379> HSET myhash field2 "World"
    (integer) 1
    127.0.0.1:6379> HVALS myhash
    1) "Hello"
    2) "World"

可用版本>= 2.0.0.

时间复杂度: O(N) where N is the size of the hash.

1.3.14 HSCAN key cursor [MATCH pattern] [COUNT count]

Redis HSCAN 命令用于遍历哈希表中的键值对。

  • 语法:

    1
    127.0.0.1:6379> HSCAN key cursor [MATCH pattern] [COUNT count]

    参数说明

    • cursor: 游标。
    • pattern: 匹配的模式。
    • count: 指定从数据集里返回多少元素,默认值为 10 。
  • 返回值:

    返回的每个元素都是一个元组,每一个元组元素由一个字段(field) 和值(value)组成。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> HMSET sites google "google.com" kungs "yanpenggong" weibo "weibo.com" 8 "alibaba.com"
    OK
    127.0.0.1:6379> HSCAN sites 0 match "goog*"
    1) "0"
    2) 1) "google"
    2) "google.com"
    127.0.0.1:6379>

可用版本>= 2.8.0.

时间复杂度: O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection..

1.3.15 HSTRLEN key field

Redis HSTRLEN 命令返回存储在 key 中的哈希表里, 与给定域 field 相关联的值的字符串长度(string length)。

如果给定的键或者域不存在, 那么命令返回 0

  • 语法:

    1
    127.0.0.1:6379> HSTRLEN key field
  • 返回值:

    整数: 值的字符串长度,key 或 field 不存在时返回 0。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> HMSET myhash f1 HelloWorld f2 88 f3 -516
    OK
    127.0.0.1:6379> HSTRLEN myhash f1
    (integer) 10
    127.0.0.1:6379> HSTRLEN myhash f2
    (integer) 2
    127.0.0.1:6379> HSTRLEN myhash f3
    (integer) 4
    127.0.0.1:6379>

可用版本>= 3.2.0.

时间复杂度: O(1)

1.4 List(列表)

1.4.1 BLPOP key [key …] timeout

Redis BLPOP 命令移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。它是 LPOP 的阻塞版本。
当给定多个 key 参数时,按参数 key 的先后顺序依次检查各个列表,弹出第一个非空列表的头元素。

  • 语法:

    1
    127.0.0.1:6379> BLPOP LIST1 LIST2 .. LISTN TIMEOUT
  • 返回值:

    数组:

    • 如果列表为空或超时,返回一个 nil
    • 返回一个含有两个元素的列表,第一个元素是被弹出元素所属的 key ,第二个元素是被弹出元素的值。
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    127.0.0.1:6379> DEL list1 list2
    (integer) 1
    127.0.0.1:6379> RPUSH list1 a b c
    (integer) 3
    127.0.0.1:6379> BLPOP list1 list2 0
    1) "list1"
    2) "a"
    127.0.0.1:6379> BLPOP list1 10
    1) "list1"
    2) "b"
    127.0.0.1:6379> BLPOP list1 10
    1) "list1"
    2) "c"
    127.0.0.1:6379> BLPOP list1 10
    (nil)
    (10.08s)
    127.0.0.1:6379> BLPOP list2 10
    (nil)
    (10.07s)
    127.0.0.1:6379>

    在实例中,操作会被阻塞,如果指定的列表 key list2 存在数据则会返回第一个元素,否则在等待10秒后会返回 nil 。

可用版本>= 2.0.0.

时间复杂度: O(1)

1.4.2 BRPOP key [key …] timeout

BRPOP 是阻塞列表的移除原语。从给的列表参数中按顺序检查第一个不空的列表,然后从该列表的尾部移除元素。 BRPOP 是 RPOP 的阻塞版本,因为当没有元素从给定的列表中移除的时候,BRPOP 阻塞连接。

参考 BLPOP documentation 了解更多信息,因为 BRPOP 和 BLPOP 的功能是相同的,除了他们一个是从列表头部(左边),另一个是从列表尾部(右边)移除元素。

  • 语法:

    1
    127.0.0.1:6379> BRPOP LIST1 LIST2 .. LISTN TIMEOUT 
  • 返回值:

    数组:

    • 所有列表为空并且超时时,返回 nil
    • 一个两个成员的数组,第一个元素是被移除元素的key的名字,第二个元素是被移除元素的值。
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    127.0.0.1:6379> DEL list1 list2
    Error: Broken pipe
    127.0.0.1:6379> RPUSH list1 a b c
    (integer) 3
    127.0.0.1:6379> BRPOP list1 list2 0
    1) "list1"
    2) "c"
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(1)

1.4.3 BRPOPLPUSH source destination timeout

Redis BRPOPLPUSH 命令从列表中取出最后一个元素,并插入到另外一个列表的头部; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。
BRPOPLPUSH 是 RPOPLPUSH的阻塞版本,当给定列表 source 不为空时, BRPOPLPUSH的表现和 RPOPLPUSH 一样。
超时参数 timeout 接受一个以秒为单位的数字作为值。超时参数设为 0 表示阻塞时间可以无限期延长(block indefinitely) 。
从 Redis 6.2.0 起,建议使用 BLMOVE 替代 BRPOPLPUSH

  • 语法:

    1
    127.0.0.1:6379> BRPOPLPUSH LIST1 ANOTHER_LIST TIMEOUT
  • 返回值:

    多行字符串: 假如在指定时间内没有任何元素被弹出,则返回一个 nil 和等待时长。 反之,返回一个含有两个元素的列表,第一个元素是被弹出元素的值,第二个元素是等待时长。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    127.0.0.1:6379> RPUSH msg "hello yanpenggong"
    (integer) 1
    127.0.0.1:6379> BRPOPLPUSH msg reciver 10
    "hello yanpenggong"
    127.0.0.1:6379> LLEN reciver
    (integer) 1
    127.0.0.1:6379> LRANGE reciver 0 0
    1) "hello yanpenggong"
    # 空列表
    127.0.0.1:6379> RPOP msg
    (nil)
    127.0.0.1:6379> BRPOPLPUSH msg reciver 10
    (nil)
    (10.05s)
    127.0.0.1:6379>

可用版本>= 2.2.0.

时间复杂度: O(1)

1.4.4 LINDEX key index

LINDEX 返回列表 key 里索引 index 位置存储的元素。

index 下标是从 0 开始索引的,所以 0 是表示第一个元素, 1 表示第二个元素,并以此类推。

负数索引用于指定从列表尾部开始索引的元素,在这种方法下,-1 表示最后一个元素,-2 表示倒数第二个元素,并以此往前推。
当 key 值不是列表的时候,会返回错误。

  • 语法:

    1
    127.0.0.1:6379> LINDEX key index
  • 返回值:

    多行字符串: 查询的元素,index 超出索引范围时返回 nil

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    127.0.0.1:6379> LPUSH mylist "World"
    (integer) 1
    127.0.0.1:6379> LPUSH mylist "Hello"
    (integer) 2
    127.0.0.1:6379> LINDEX mylist 0
    "Hello"
    127.0.0.1:6379> LINDEX mylist -1
    "World"
    127.0.0.1:6379> LINDEX mylist 3
    (nil)
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(N) where N is the number of elements to traverse to get to the element at index. This makes asking for the first or the last element of the list O(1).

1.4.5 LINSERT key BEFORE|AFTER pivot element

Redis LINSERT 用于把 element 插入到列表 key 中,参考值 pivot 的前面或后面。

key 不存在时,这个list会被看作是空list,什么都不执行。

key 存在,值不是列表类型时,返回错误。

  • 语法:

    1
    127.0.0.1:6379> LINSERT key BEFORE|AFTER pivot element
  • 返回值:

    整数: 执行操作后的列表长度,列表中pivot参考值不存在的时候返回 -1

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    127.0.0.1:6379> RPUSH mylist "Hello"
    (integer) 1
    127.0.0.1:6379> RPUSH mylist "World"
    (integer) 2
    127.0.0.1:6379> LINSERT mylist BEFORE "World" "There"
    (integer) 3
    127.0.0.1:6379> LRANGE mylist 0 -1
    1) "Hello"
    2) "There"
    3) "World"
    127.0.0.1:6379>

可用版本>= 2.2.0.

时间复杂度: O(N) where N is the number of elements to traverse before seeing the value pivot. This means that inserting somewhere on the left end on the list (head) can be considered O(1) and inserting somewhere on the right end (tail) is O(N).

1.4.6 LLEN key

Redis LLEN 用于返回存储在 key 中的列表长度。 如果 key 不存在,则 key被解释为一个空列表,返回 0 。 如果 key 不是列表类型,返回一个错误。

  • 语法:

    1
    127.0.0.1:6379> LLEN KEY_NAME
  • 返回值:

    整数: 列表的长度。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    127.0.0.1:6379> LRANGE mylist 0 -1
    (empty array)
    127.0.0.1:6379> LPUSH mylist "World"
    (integer) 1
    127.0.0.1:6379> LPUSH mylist "Hello"
    (integer) 2
    127.0.0.1:6379> LPUSH mylist "yanpenggong"
    (integer) 3
    127.0.0.1:6379> LLEN mylist
    (integer) 3
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.4.7 LPOP key

Redis LPOP 命令用于删除并返回存储在 key 中的列表的第一个元素。

  • 语法:

    1
    127.0.0.1:6379> LPOP key
  • 返回值:

    多行字符串: 列表的首元素,key 不存在的时候返回 nil

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    127.0.0.1:6379> RPUSH mylist "one"
    (integer) 1
    127.0.0.1:6379> RPUSH mylist "two"
    (integer) 2
    127.0.0.1:6379> RPUSH mylist "three"
    (integer) 3
    127.0.0.1:6379> LPOP mylist
    "one"
    127.0.0.1:6379> LRANGE mylist 0 -1
    1) "two"
    2) "three"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.4.8 LPUSH key element [element …]

redis LPUSH 用于将一个或多个值插入到列表key 的头部。

如果 key 不存在,那么在进行 push 操作前会创建一个空列表。

如果 key 对应的值不是 list 类型,那么会返回一个错误。

可以使用一个命令把多个元素 push 进入列表,只需在命令末尾加上多个指定的参数。

元素按在参数中出现的顺序,从左到右依次插入到 list 的头部。

所以对于这个命令例子 LPUSH mylist a b c,返回的列表是 c 为第一个元素, b 为第二个元素, a 为第三个元素。

  • 语法:

    1
    127.0.0.1:6379> LPUSH KEY_NAME VALUE1.. VALUEN
  • 返回值:

    整数: 执行push操作后列表的长度。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    127.0.0.1:6379> LPUSH mylist "world"
    (integer) 1
    127.0.0.1:6379> LPUSH mylist "Hello"
    (integer) 2
    127.0.0.1:6379> LRANGE mylist 0 -1
    1) "Hello"
    2) "world"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1) for each element added, so O(N) to add N elements when the command is called with multiple arguments.

1.4.9 LPUSHX key element [element …]

Redis LPUSHX 在当 key 存在并且存储着一个 list 类型值的时候,向值 list 的头部插入 value。 与 LPUSH 相反,当 key 不存在的时候不会进行任何操作。

  • 语法:

    1
    127.0.0.1:6379> LPUSHX KEY_NAME VALUE1.. VALUEN
  • 返回值:

    整数: 执行push操作后列表list的长度。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    127.0.0.1:6379> LPUSH mylist "world" "Hello"
    (integer) 2
    127.0.0.1:6379> LPUSHX mylist "kungs"
    (integer) 3
    127.0.0.1:6379> LPUSHX mylist1 "kungs"
    (integer) 0
    127.0.0.1:6379> LRANGE mylist 0 -1
    1) "kungs"
    2) "Hello"
    3) "world"
    127.0.0.1:6379> LRANGE mylist1 0 -1
    (empty array)
    127.0.0.1:6379>

可用版本>= 2.2.0.

时间复杂度: O(1) for each element added, so O(N) to add N elements when the command is called with multiple arguments.

1.4.10 LRANGE key start stop

Redis LRANGE 用于返回列表中指定区间内的元素,区间以偏移量 START 和 END 指定。

其中 0 表示列表的第一个元素, 1 表示列表的第二个元素,以此类推。

你也可以使用负数下标,以 -1 表示列表的最后一个元素, -2 表示列表的倒数第二个元素,以此类推。

  • 语法:

    1
    127.0.0.1:6379> LRANGE KEY_NAME START END
  • 返回值:

    数组: 一个列表,包含指定区间内的元素。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    127.0.0.1:6379> RPUSH mylist "one"
    (integer) 1
    127.0.0.1:6379> RPUSH mylist "two"
    (integer) 2
    127.0.0.1:6379> RPUSH mylist "three"
    (integer) 3
    127.0.0.1:6379> LRANGE mylist 0 0
    1) "one"
    127.0.0.1:6379> LRANGE mylist -3 2
    1) "one"
    2) "two"
    3) "three"
    127.0.0.1:6379> LRANGE mylist -100 100
    1) "one"
    2) "two"
    3) "three"
    127.0.0.1:6379> LRANGE mylist 5 10
    (empty array)
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(S+N) where S is the distance of start offset from HEAD for small lists, from nearest end (HEAD or TAIL) for large lists; and N is the number of elements in the specified range.

1.4.11 LREM key count element

Redis LREM 用于从列表 key 中删除前 count 个值等于 element 的元素。 这个 count 参数通过下面几种方式影响这个操作:

1
2
3
count > 0: 从头到尾删除值为 value 的元素。
count < 0: 从尾到头删除值为 value 的元素。
count = 0: 移除所有值为 value 的元素。

比如, LREM list -2 "hello" 会从列表key中删除最后两个出现的 “hello”。

需要注意的是,不存在key会被当作空list处理,所以当 key 不存在的时候,这个命令会返回 0。

  • 语法:

    1
    127.0.0.1:6379> LREM key count VALUE
  • 返回值:

    整数: 删除元素个数。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    127.0.0.1:6379> RPUSH mylist "Hello"
    (integer) 1
    127.0.0.1:6379> RPUSH mylist "Hello"
    (integer) 2
    127.0.0.1:6379> RPUSH mylist "World"
    (integer) 3
    127.0.0.1:6379> RPUSH mylist "Hello"
    (integer) 4
    127.0.0.1:6379> LREM mylist -2 "Hello"
    (integer) 2
    127.0.0.1:6379> LRANGE mylist 0 -1
    1) "Hello"
    2) "World"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(N+M) where N is the length of the list and M is the number of elements removed.

1.4.12 LSET key index element

Redis LSET 用于设置列表 key 中 index 位置的元素值为 element。 更多关于 index 参数的信息,详见 LINDEX

当 index 超出列表索引范围时会返回错误ERR ERR index out of range

  • 语法:

    1
    127.0.0.1:6379> LSET KEY_NAME INDEX VALUE
  • 返回值:

    字符串: 操作成功返回 ok ,否则返回错误信息。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    127.0.0.1:6379> RPUSH mylist "one"
    (integer) 1
    127.0.0.1:6379> RPUSH mylist "two"
    (integer) 2
    127.0.0.1:6379> RPUSH mylist "three"
    (integer) 3
    127.0.0.1:6379> LSET mylist 0 "four"
    OK
    127.0.0.1:6379> LSET mylist -2 "five"
    OK
    127.0.0.1:6379> LRANGE mylist 0 -1
    1) "four"
    2) "five"
    3) "three"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(N) where N is the length of the list. Setting either the first or the last element of the list is O(1).

1.4.13 LTRIM key start stop

Redis Ltrim 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。

start 和 stop 都是由0开始计数的, 这里的 0 是列表里的第一个元素(表头),1 是第二个元素,以此类推。

start 和 end 也可以用负数来表示与表尾的偏移量,比如 -1 表示列表里的最后一个元素, -2 表示倒数第二个,等等。

超过范围的下标并不会产生错误:如果 start 超过列表尾部,或者 start > end,结果会是列表变成空表(即该 key 会被移除)。 如果 end 超过列表尾部,Redis 会将其当作列表的最后一个元素。

  • 语法:

    1
    127.0.0.1:6379> LTRIM KEY_NAME START STOP
  • 返回值:

    字符串: 命令执行成功时,返回 ok 。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    127.0.0.1:6379> RPUSH mylist "one"
    (integer) 1
    127.0.0.1:6379> RPUSH mylist "two"
    (integer) 2
    127.0.0.1:6379> RPUSH mylist "three"
    (integer) 3
    127.0.0.1:6379> LTRIM mylist 1 -1
    OK
    127.0.0.1:6379> LRANGE mylist 0 -1
    1) "two"
    2) "three"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(N) where N is the number of elements to be removed by the operation.

1.4.14 RPOP key

Redis RPOP 用于移除并返回列表 key 的最后一个元素。

  • 语法:

    1
    127.0.0.1:6379> RPOP KEY_NAME 
  • 返回值:

    多行字符串: 最后一个元素的值,key 不存在时返回 nil

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    127.0.0.1:6379> RPUSH mylist "one"
    (integer) 1
    127.0.0.1:6379> RPUSH mylist "two"
    (integer) 2
    127.0.0.1:6379> RPUSH mylist "three"
    (integer) 3
    127.0.0.1:6379> RPOP mylist
    "three"
    127.0.0.1:6379> LRANGE mylist 0 -1
    1) "one"
    2) "two"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.4.15 RPOPLPUSH source destination

用于原子地从列表 source 中移除并返回最后一个元素,然后把这个元素插入为列表destination 的第一个元素。

例如: 假设 source 列表成员为 a,b,c,列表 destination 成员为 x,y,z

执行 RPOPLPUSH source destination 的结果是列表 source 成员为a,b ,列表 destination 成员为c,x,y,z

如果列表 source 不存在,返回 nil ,什么也不执行。

如果列表 sourcedestination 相同,相当于从列表的一端删除元素,在放入列表的另一端,所以可以当做一个列表循环命令。

LMOVE 用来替换废弃的指令 RPOPLPUSH,相当于执行LMOVE RIGHT LEFT

从 Redis 6.2.0起, RPOPLPUSH 被废弃,使用 LMOVE替代。

  • 语法:

    1
    127.0.0.1:6379> RPOPLPUSH SOURCE_KEY_NAME DESTINATION_KEY_NAME
  • 返回值:

    多行字符串: 移除并又插入的元素。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    127.0.0.1:6379> RPUSH mylist "one"
    (integer) 1
    127.0.0.1:6379> RPUSH mylist "two"
    (integer) 2
    127.0.0.1:6379> RPUSH mylist "three"
    (integer) 3
    127.0.0.1:6379> RPOPLPUSH mylist myotherlist
    "three"
    127.0.0.1:6379> LRANGE mylist 0 -1
    1) "one"
    2) "two"
    127.0.0.1:6379> LRANGE myotherlist 0 -1
    1) "three"
    127.0.0.1:6379>

可用版本>= 1.2.0.

时间复杂度: O(1)

1.4.16 RPUSH key element [element …]

RPUSH 向存存储在 key 中的列表的尾部插入所有指定的值。如果 key 不存在,那么会创建一个空的列表然后再进行 push 操作。 当 key 保存的不是列表,那么会返回一个错误。

可以使用RPUSH命令把多个元素插入队列,只需要在命令后面指定多个参数。元素是从左到右按序从列表尾部插入。 比如命令 RPUSH mylist a b c 会返回一个列表,其第一个元素是 a ,第二个元素是 b ,第三个元素是 c。

  • 语法:

    1
    127.0.0.1:6379> RPUSH KEY_NAME VALUE1..VALUEN
  • 返回值:

    整数: 执行 push 操作后的列表长度。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    127.0.0.1:6379> RPUSH mylist "Hello"
    (integer) 1
    127.0.0.1:6379> RPUSH mylist "World"
    (integer) 2
    127.0.0.1:6379> LRANGE mylist 0 -1
    1) "Hello"
    2) "World"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1) for each element added, so O(N) to add N elements when the command is called with multiple arguments.

1.4.17 RPUSHX key element [element …]

RPUSHX将值 value 插入到列表 key 的表尾, 当且仅当 key 存在并且是一个列表。 和 RPUSH命令相反, 当 key 不存在时,RPUSHX 命令什么也不做。

  • 语法:

    1
    127.0.0.1:6379> RPUSHX KEY_NAME VALUE1..VALUEN
  • 返回值:

    整数: RPUSHX 命令执行之后列表的长度。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    127.0.0.1:6379> RPUSH mylist "Hello"
    (integer) 1
    127.0.0.1:6379> RPUSH mylist "World"
    (integer) 2
    127.0.0.1:6379> RPUSHX myotherlist "World"
    (integer) 0
    127.0.0.1:6379> LRANGE mylist 0 -1
    1) "Hello"
    2) "World"
    127.0.0.1:6379> LRANGE myotherlist 0 -1
    (empty array)
    127.0.0.1:6379>

可用版本>= 2.2.0.

时间复杂度: O(1) for each element added, so O(N) to add N elements when the command is called with multiple arguments.

1.5 Sets(集合)

1.5.1 SADD key member [member …]

Redis Sadd 命令将一个或多个成员元素加入到集合中,已经存在于集合的成员元素将被忽略。

假如集合 key 不存在,则创建一个只包含被添加的元素作为成员的集合。

当集合 key 不是集合类型时,返回一个错误。

注意:在 Redis2.4 版本以前, SADD 只接受单个成员值。

  • 语法:

    1
    127.0.0.1:6379> SADD KEY_NAME VALUE1..VALUEN
  • 返回值:

    整数: 返回新成功添加到集合里元素的数量,不包括已经存在于集合中的元素。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    127.0.0.1:6379> SADD myset "Hello"
    (integer) 1
    127.0.0.1:6379> SADD myset "World"
    (integer) 1
    127.0.0.1:6379> SMEMBERS myset
    1) "World"
    2) "Hello"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1) for each element added, so O(N) to add N elements when the command is called with multiple arguments.

1.5.2 SCARD key

Redis SCARD 命令返回集合中元素的数量。

  • 语法:

    1
    127.0.0.1:6379> SCARD KEY_NAME
  • 返回值:

    整数: 集合中成员的数量。 当集合 key 不存在时,返回 0 。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> SADD myset "Hello"
    (integer) 1
    127.0.0.1:6379> SADD myset "World"
    (integer) 1
    127.0.0.1:6379> SCARD myset
    (integer) 2
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.5.3 SDIFF key [key …]

Redis SDIFF 命令返回第一个集合与其他集合之间的差异,也可以认为说第一个集合中独有的元素。不存在的集合 key 将视为空集。

  • 语法:

    1
    127.0.0.1:6379> SDIFF FIRST_KEY OTHER_KEY1..OTHER_KEYN 
  • 返回值:

    数组: 包含差集成员的列表。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    127.0.0.1:6379> SADD key1 a b c d
    (integer) 4
    127.0.0.1:6379> SADD key2 c
    (integer) 1
    127.0.0.1:6379> SADD key3 a c e
    (integer) 3
    127.0.0.1:6379> SDIFF key1 key2 key3
    1) "b"
    2) "d"
    127.0.0.1:6379> SDIFF key1 key2
    1) "a"
    2) "b"
    3) "d"
    127.0.0.1:6379>
    可用版本>= 1.0.0.

时间复杂度: O(N) where N is the total number of elements in all given sets.

1.5.4 SDIFFSTORE destination key [key …]

SDIFFSTORE 命令的作用和SDIFF类似,不同的是它将结果保存到 destination 集合,而把结果集返回给客户端。

如果 destination 集合已经存在,则将其覆盖。

  • 语法:

    1
    127.0.0.1:6379> SDIFFSTORE DESTINATION_KEY KEY1..KEYN
  • 返回值:

    整数: 结果集中成员数量。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    127.0.0.1:6379> SADD key1 a b c d
    (integer) 4
    127.0.0.1:6379> SADD key2 c d e
    (integer) 3
    127.0.0.1:6379> SDIFFSTORE key key1 key2
    (integer) 2
    127.0.0.1:6379> SMEMBERS key
    1) "a"
    2) "b"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(N) where N is the total number of elements in all given sets.

1.5.5 SINTER key [key …]

对于不存在的 key 可以认为是空集合。

如果给定的key中有一个空集合,那么结果集一定是空集合。

  • 语法:

    1
    127.0.0.1:6379> SINTER KEY KEY1..KEYN 
  • 返回值:

    数组: 结果集成员个数。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    127.0.0.1:6379> SADD key1 a b c d
    (integer) 4
    127.0.0.1:6379> SADD key2 c d e
    (integer) 3
    127.0.0.1:6379> SINTER key1 key2
    1) "d"
    2) "c"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(N*M) worst case where N is the cardinality of the smallest set and M is the number of sets.

1.5.6 SINTERSTORE destination key [key …]

SINTERSTORE 命令与 SINTER 命令类似,不同的是它并不是直接返回结果集,而是将结果保存在 destination 集合中。
如果 destination 集合存在, 则会被覆盖。

  • 语法:

    1
    127.0.0.1:6379> SINTERSTORE DESTINATION_KEY KEY KEY1..KEYN
  • 返回值:

    整数: 结果集中成员数量。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    127.0.0.1:6379> DEL key key1key2 key3
    (integer) 1
    127.0.0.1:6379> DEL key key1 key2 key3
    (integer) 2
    127.0.0.1:6379> SADD key1 a b c
    (integer) 3
    127.0.0.1:6379> SADD key2 c d e
    (integer) 3
    127.0.0.1:6379> SINTERSTORE key key1 key2
    (integer) 1
    127.0.0.1:6379> SMEMBERS key
    1) "c"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(N*M) worst case where N is the cardinality of the smallest set and M is the number of sets.

1.5.7 SISMEMBER key member

Redis SISMEMBER 用于判断元素 member 是否集合 key 的成员。

  • 语法:

    1
    127.0.0.1:6379> SISMEMBER KEY MEMBER
  • 返回值:

    整数:

    • 1: 如果成员元素是集合的成员,返回 1 。
    • 0: 如果成员元素不是集合的成员,或 key 不存在,返回 0 。
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> SADD myset "one"
    (integer) 1
    127.0.0.1:6379> SISMEMBER myset "one"
    (integer) 1
    127.0.0.1:6379> SISMEMBER myset "two"
    (integer) 0
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.5.8 SMEMBERS key

Redis SISMEMBER 命令返回存储在 key 中的集合的所有的成员。 不存在的集合被视为空集合。
SISMEMBER 与运行带有一个参数 key 的 SINTER 有同样的效果。

  • 语法:

    1
    127.0.0.1:6379> SMEMBERS key
  • 返回值:

    数组: 集合中的所有成员。

  • 实例:

    1
    2
    3
    4
    5
    6
    127.0.0.1:6379> SADD myset "Hello" "World"
    (integer) 2
    127.0.0.1:6379> SMEMBERS myset
    1) "World"
    2) "Hello"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(N) where N is the set cardinality.

1.5.9 SMOVE source destination member

Redis SMOVE 命令用于从集合source 中移动成员member 到集合 destination。 这个操作是原子操作。 在任何时刻,member 只会存在于sourcedestination 其中之一。

如果集合source 不存在,或者要移动的成员不是集合source 的成员,什么也不执行并返回 0

否则,其它情况下,从集合source 中删除成员并添加到集合 destination

如果要移动的元素在集合 destination中已经存在,那么只是从集合source中删除该成员。

如果 sourcedestination 不是集合类型则返回错误。

  • 语法:

    1
    127.0.0.1:6379> SMOVE SOURCE DESTINATION MEMBER
  • 返回值:

    整数:

    • 1: 移动元素成功。
    • 0: 如果要移动的 element 不是source 的成员,什么也不执行。
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    127.0.0.1:6379> SADD myset "one" "two"
    (integer) 2
    127.0.0.1:6379> SADD myotherset "three"
    (integer) 1
    127.0.0.1:6379> SMOVE myset myotherset "two"
    (integer) 1
    127.0.0.1:6379> SMEMBERS myset
    1) "one"
    127.0.0.1:6379> SMEMBERS myotherset
    1) "two"
    2) "three"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.5.10 SPOP key [count]

Redis SPOP 命令用于从集合 key中删除并返回一个或多个随机元素。

这个命令和 SRANDMEMBER 相似, SRANDMEMBER 只返回随机成员但是不删除这些返回的成员。

参数 count 从 Redis 3.2 起可用

  • 语法:

    1
    127.0.0.1:6379> SPOP key [count]
  • 返回值:

    多行字符串: 被删除的元素,当key不存在时返回nil

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    127.0.0.1:6379> SADD myset "one" "two" "three"
    (integer) 3
    127.0.0.1:6379> SPOP myset
    "one"
    127.0.0.1:6379> SMEMBERS myset
    1) "two"
    2) "three"
    127.0.0.1:6379> SADD myset "four" "five"
    (integer) 2
    127.0.0.1:6379> SPOP myset 3
    1) "four"
    2) "three"
    3) "two"
    127.0.0.1:6379> SMEMBERS myset
    1) "five"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(1)

1.5.11 SRANDMEMBER key [count]

Redis SRANDMEMBER 命令仅使用key 参数,那么随机返回集合key 中的一个随机元素。

Redis 2.6开始,可以接受 count 参数,如果count是整数且小于元素的个数,返回含有 count 个不同的元素的数组,如果count是个整数且大于集合中元素的个数时,返回整个集合的所有元素,当count是负数,则会返回一个包含count的绝对值的个数元素的数组,如果count的绝对值大于元素的个数,则返回的结果集里会出现一个元素出现多次的情况.

仅提供key参数时,该命令作用类似于SPOP命令,不同的是SPOP命令会将被选择的随机元素从集合中移除,而SRANDMEMBER 仅仅是返回该随记元素,而不对原集合做任何操作。

传递count参数时的行为规范

当传递了一个值为正数的count参数,返回的元素就好像从集合中移除了每个选中的元素一样(就像在宾果游戏中提取数字一样)。但是元素不会从集合中移除。所以基本上:

  • 不会返回重复的元素。
  • 如果count参数的值大于集合内的元素数量,此命令将会仅返回整个集合,没有额外的元素。

相反,当count参数的值为负数时,此命令的行为将发生改变,并且提取操作就像在每次提取后,重新将取出的元素放回包里一样,因此,可能返回重复的元素,以及总是会返回我们请求的数量的元素,因为我们可以一次又一次地重复相同的元素,除了当集合为空(或者不存在key)的时候,将总是会返回一个空数组。

返回元素的分布

当集合中的元素数量很少时,返回元素分布远不够完美,这是因为我们使用了一个近似随机元素函数,它并不能保证良好的分布。

所使用的算法(在dict.c中实现)对哈希表桶进行采样以找到非空桶。一旦找到非空桶,由于我们在哈希表的实现中使用了链接法,因此会检查桶中的元素数量,并且选出一个随机元素。

这意味着,如果你在整个哈希表中有两个非空桶,其中一个有三个元素,另一个只有一个元素,那么其桶中单独存在的元素将以更高的概率返回。

  • 语法:

    1
    127.0.0.1:6379> SRANDMEMBER KEY [count]
  • 返回值:

    多行字符串: 不使用count 参数的情况下该命令返回随机的元素,如果key不存在则返回nil。

    数组: 使用count参数,则返回一个随机的元素数组,如果key不存在则返回一个空的数组。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    127.0.0.1:6379> SADD myset one two three
    (integer) 3
    127.0.0.1:6379> SRANDMEMBER myset
    "three"
    127.0.0.1:6379> SRANDMEMBER myset 2
    1) "one"
    2) "two"
    127.0.0.1:6379> SRANDMEMBER myset -5
    1) "three"
    2) "one"
    3) "two"
    4) "three"
    5) "three"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: Without the count argument O(1), otherwise O(N) where N is the absolute value of the passed count.

1.5.12 SREM key member [member …]

SREM 用于在集合中删除指定的元素。如果指定的元素不是集合成员则被忽略。

如果集合 key 不存在则被视为一个空的集合,该命令返回0。

如果key的类型不是一个集合,则返回 ERR WRONGTYPE Operation against a key holding the wrong kind of value 错误

  • 语法:

    1
    127.0.0.1:6379> SREM KEY MEMBER1..MEMBERN
  • 返回值:

    整数: 被删除元素个数,不含不存在的元素。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    127.0.0.1:6379> SADD myset "one" "two" "three"
    (integer) 3
    127.0.0.1:6379> SREM myset "one"
    (integer) 1
    127.0.0.1:6379> SREM myset "four"
    (integer) 0
    127.0.0.1:6379> SMEMBERS myset
    1) "two"
    2) "three"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(N) where N is the number of members to be removed.

1.5.13 SUNION key [key …]

SUNION 命令用于返回所有给定集合的并集。例如:

对于不存在 key 被当做空集合处理。

  • 语法:

    1
    127.0.0.1:6379> SUNION KEY KEY1..KEYN
  • 返回值:

    数组: 结果集中成员数量。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    127.0.0.1:6379> SADD key1 "a" "b" "c"
    (integer) 3
    127.0.0.1:6379> SADD key2 "c" "d" "e"
    (integer) 3
    127.0.0.1:6379> SUNION key1 key2
    1) "e"
    2) "b"
    3) "c"
    4) "a"
    5) "d"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(N) where N is the total number of elements in all given sets.

1.5.14 SUNIONSTORE destination key [key …]

SUNIONSTORE 命令的功能类似于 SUNION,不同的是不反回结果集,而是存储在 destination 中。

如果 destination 已经存在,则被覆盖。

  • 语法:

    1
    127.0.0.1:6379> 
  • 返回值:

    整数: 结果集中的成员数量。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    127.0.0.1:6379> SADD key1 "a" "b" "c"
    (integer) 3
    127.0.0.1:6379> SADD key2 "c" "d" "e"
    (integer) 3
    127.0.0.1:6379> SUNIONSTORE key key1 key2
    (integer) 5
    127.0.0.1:6379> SMEMBERS key
    1) "e"
    2) "b"
    3) "c"
    4) "a"
    5) "d"
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度: O(N) where N is the total number of elements in all given sets.

1.5.15 SSCAN key cursor [MATCH pattern] [COUNT count]

Redis SSCAN 命令用于遍历集合中键的元素,SSCAN 继承自SCAN。

  • 语法:

    1
    127.0.0.1:6379> SSCAN key cursor [MATCH pattern] [COUNT count]

    参数说明

    • cursor - 游标。
    • pattern - 匹配的模式。
    • count - 指定从数据集里返回多少元素,默认值为 10
  • 返回值:

    数组列表。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    127.0.0.1:6379> SADD myset "Mongodb" "Redis" "hive"
    (integer) 3
    127.0.0.1:6379> SSCAN myset 0 match "R*"
    1) "0"
    2) 1) "Redis"
    127.0.0.1:6379> SSCAN myset 2 match "R*"
    1) "0"
    2) (empty array)
    127.0.0.1:6379> SSCAN myset -4 match R*
    1) "0"
    2) 1) "Redis"
    127.0.0.1:6379> SSCAN myset 2 match *o*
    1) "0"
    2) 1) "Mongodb"
    127.0.0.1:6379>

可用版本>= 2.8.0.

时间复杂度: O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection..

1.6 Sorted Sets(有序集合)

1.6.1 ZADD key [NX|XX] [GT|LT] [CH] [INCR]score member [score member …]

Redis ZADD 命令用于将一个或多个 member 元素及其 score 值加入到有序集 key 当中。

如果某个 member 已经是有序集的成员,那么更新这个 memberscore值,并通过重新插入这个 member 元素,来保证该 member 在正确的位置上。

如果有序集合 key 不存在,则创建一个空的有序集并执行 ZADD 操作。

key 存在但不是有序集类型时,返回一个错误。

score 值可以是整数值或双精度浮点数,score 可为正也可以为负。

注意: 在 Redis 2.4 版本以前, ZADD 每次只能添加一个元素。

  • 语法:

    1
    127.0.0.1:6379> ZADD key [NX|XX] [GT|LT] [CH] [INCR]score member [score member ...]
    1. 参数说明

      • XX: 仅更新存在的成员,不添加新成员。
      • NX: 不更新存在的成员。只添加新成员。

      • LT: 更新新的分值比当前分值小的成员,不存在则新增。

      • GT: 更新新的分值比当前分值大的成员,不存在则新增。

      • CH: 返回变更成员的数量。变更的成员是指 新增成员score值更新的成员,命令指明的和之前score值相同的成员不计在内。 注意: 在通常情况下,ZADD返回值只计算新添加成员的数量。

      • INCR: ZADD 使用该参数与 ZINCRBY 功能一样。一次只能操作一个score-element对。

      注意: GT, LTNX 三者互斥不能同时使用。

    2. scores 有效值范围

      Redis 有序集合的分数使用双精度64位浮点数表示。在Redis所支持的平台上,称为IEEE 754 floating point number,它能包括的整数范围是-(2^53)+(2^53)。或者说是-9007199254740992 到 9007199254740992。更大的整数在内部用指数形式表示,所以,如果为分数设置一个非常大的整数,你得到的是一个近似的十进制数。

    3. Sorted sets 101

      有序集合按照分数以递增的方式进行排序。相同的成员(member)只存在一次,有序集合不允许存在重复的成员。 分数可以通过ZADD命令进行更新或者也可以通过ZINCRBY命令递增来修改之前的值,相应的他们的排序位置也会随着分数变化而改变。

      获取一个成员当前的分数可以使用 ZSCORE 命令,也可以用它来验证成员是否存在。

    4. 相同分数的成员

      有序集合里面的成员是不能重复的都是唯一的,但是,不同成员间有可能有相同的分数。当多个成员有相同的分数时,他们将是按字典排序(ordered lexicographically)(仍由分数作为第一排序条件,然后,相同分数的成员按照字典序排序)。

      字典顺序排序用的是二进制,它比较的是字符串的字节数组。

      如果用户将所有元素设置相同分数(例如0),有序集合里面的所有元素将按照字典顺序进行排序,范围查询元素可以使用 ZRANGEBYLEX 命令(注:范围查询分数可以使用 ZRANGEBYSCORE 命令)。

  • 返回值:

    整数:

    • 被成功添加的新成员的数量,不包括那些被更新分数的、已经存在的成员。

    如果使用 INCR 选项,则返回 多行字符串:

    • 以字符串形式表示的 member 的 score 值(双精度浮点数)。(双精度浮点数) , 执行失败返回 nil (当使用 XXNX 选项)。
  • 实例:

    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
    # 添加单个元素
    127.0.0.1:6379> ZADD page_rank 10 google.com
    (integer) 1
    # 添加多个元素
    127.0.0.1:6379> ZADD page_rank 9 baidu.com 8 github.com
    (integer) 2
    127.0.0.1:6379> ZRANGE page_rank 0 -1 WITHSCORES
    1) "github.com"
    2) "8"
    3) "baidu.com"
    4) "9"
    5) "google.com"
    6) "10"
    # 添加已存在元素,且 score 值不变,发现没有改变
    127.0.0.1:6379> ZADD page_rank 10 google.com
    (integer) 0
    127.0.0.1:6379> ZRANGE page_rank 0 -1 WITHSCORES
    1) "github.com"
    2) "8"
    3) "baidu.com"
    4) "9"
    5) "google.com"
    6) "10"
    # 添加已存在元素,但是改变 score 值
    127.0.0.1:6379> ZADD page_rank 6 github.com
    (integer) 0
    # "github.com"的值被改变
    127.0.0.1:6379> ZRANGE page_rank 0 -1 WITHSCORES
    1) "github.com"
    2) "6"
    3) "baidu.com"
    4) "9"
    5) "google.com"
    6) "10"
    127.0.0.1:6379>

可用版本>= 1.2.0.

时间复杂度: O(log(N)) for each item added, where N is the number of elements in the sorted set.

1.6.2 ZCARD key

Redis ZCARD 命令用于返回有序集的成员个数。

  • 语法:

    1
    127.0.0.1:6379> ZCARD KEY_NAME
  • 返回值:

    整数: 返回有序集的成员个数,当 key 不存在时,返回 0

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> ZADD myset 1 "one"
    (integer) 1
    127.0.0.1:6379> ZADD myset 2 "two"
    (integer) 1
    127.0.0.1:6379> ZCARD myset
    (integer) 2
    127.0.0.1:6379>

可用版本>= 1.2.0.

时间复杂度: O(1)

1.6.3 ZCOUNT key min max

ZCOUNT 返回有序集 key 中, score 值在 minmax 之间(默认包括 score 值等于 minmax )的成员的数量。

关于参数 minmax 的详细使用方法,请参考ZRANGEBYSCORE.

注意: ZCOUNT 命令的时间复杂度是 O(log(N)),因为 ZCOUNT 使用有序成员来实现范围查询,不需要遍历整个集合。

  • 语法:

    1
    127.0.0.1:6379> 
  • 返回值:

    整数: score 值在 min 和 max 之间的成员的数量。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    127.0.0.1:6379> ZADD myset 1 "one"
    (integer) 1
    127.0.0.1:6379> ZADD myset 2 "two"
    (integer) 1
    127.0.0.1:6379> ZADD myset 3 "three"
    (integer) 1
    127.0.0.1:6379> ZCOUNT myset -inf +inf
    (integer) 3
    127.0.0.1:6379> ZCOUNT myset (1 3
    (integer) 2
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(log(N)) with N being the number of elements in the sorted set.

1.6.4 ZINCRBY key increment member

ZINCRBY 为有序集 key 的成员 memberscore 值加上增量 increment

key 不存在,或 member 不是 key 的成员时, ZINCRBY key increment member 等同于 ZADD key increment member

key 不是有序集类型时,返回”ERR WRONGTYPE Operation against a key holding the wrong kind of value”。

score 值可以是字符串形式表示的整数值或双精度浮点数。

可以通过传递一个负数值 increment ,让 score 减去相应的值,比如 ZINCRBY key -2 member ,就是让 memberscore 值减去 2

  • 语法:

    1
    127.0.0.1:6379> 
  • 返回值:

    多行字符串: 以字符串形式表示的 member 成员的新 score 值(双精度浮点数)。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    127.0.0.1:6379> ZADD myset 1 "one"
    (integer) 1
    127.0.0.1:6379> ZADD myset 2 "two"
    (integer) 1
    127.0.0.1:6379> ZINCRBY myset 2 "one"
    "3"
    127.0.0.1:6379> ZRANGE myset 0 -1 WITHSCORES
    1) "two"
    2) "2"
    3) "one"
    4) "3"
    127.0.0.1:6379>

可用版本>= 1.2.0.

时间复杂度: O(log(N)) where N is the number of elements in the sorted set.

1.6.5 ZINTERSTORE destination numkeys key [key …] [WEIGHTS weight [weight …]] [AGGREGATE SUM|MIN|MAX]

计算 numkeys 个有序集合的交集,并且把结果放到 destination 中。 在给定要计算的 key 和其它参数之前,必须先给定 key 个数(numberkeys)。

默认情况下,结果集中元素的分数是各有序集合中该元素分数之和。

对于WEIGHTS和AGGREGATE参数的描述,参见命令 ZUNIONSTORE。

如果destination存在,会被覆盖。

  • 语法:

    1
    127.0.0.1:6379> INTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]
  • 返回值:

    整数:结果集 destination 中元素个数。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    127.0.0.1:6379> ZADD zset1 1 "one" 2 "two"
    (integer) 2
    127.0.0.1:6379> ZADD zset2 1 "one" 2 "two" 3 "three"
    (integer) 3
    # zset1 * 2 + zset2 * 3
    127.0.0.1:6379> ZINTERSTORE out 2 zset1 zset2 WEIGHTS 2 3
    (integer) 2
    127.0.0.1:6379> ZRANGE out 0 -1 WITHSCORES
    1) "one"
    2) "5"
    3) "two"
    4) "10"
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(NK)+O(Mlog(M)) worst case with N being the smallest input sorted set, K being the number of input sorted sets and M being the number of elements in the resulting sorted set.

1.6.6 ZLEXCOUNT key min max

当有序集中的所有成员都有相同的score, ZLEXCOUNT 命令返回有序集中值在 minmax之间的成员个数。

minmax 详见ZRANGEBYLEX。时间复 O(log(N))。

  • 语法:

    1
    127.0.0.1:6379> ZLEXCOUNT key min max
  • 返回值:

    整数: 返回特定分值元素个数。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> ZADD myset 0 a 0 b 0 c 0 d 0 e
    (integer) 5
    127.0.0.1:6379> ZADD myset 0 f 0 g
    (integer) 2
    127.0.0.1:6379> ZLEXCOUNT myset - +
    (integer) 7
    127.0.0.1:6379> ZLEXCOUNT myset [b [f
    (integer) 5
    127.0.0.1:6379>

可用版本>= 2.8.9.

时间复杂度: O(log(N)) with N being the number of elements in the sorted set.

1.6.7 ZRANGE key start stop [WITHSCORES]

Redis ZRANGE 命令返回有序集中,指定区间内的成员,其中成员的按分数值递增(从小到大)来排序,具有相同分数值的成员按字典序(lexicographical order )来排列。

如果你需要成员按值递减(从大到小)来排列,请使用 ZREVRANGE命令。

下标参数 startstop 都以 0 为底,也就是说,以 0 表示有序集第一个成员,以 1 表示有序集第二个成员,以此类推。

你也可以使用负数下标,以 -1 表示最后一个成员, -2 表示倒数第二个成员,以此类推。

startstop 都是包含在内的区间,因此例如 ZRANGE myzset 0 1 将会返回有序集合的第一个和第二个元素。

超出范围的索引不会产生错误。 如果 start 参数的值大于有序集合中的最大索引,或者 start > stop ,将会返回一个空列表。 如果 stop 的值大于有序集合的末尾,Redis 会将其视为有序集合的最后一个元素。

可以传递 WITHSCORES 选项,以便将元素的分数与元素一起返回。这样返回的列表将包含 value1,score1,...,valueN,scoreN ,而不是 value1,...,valueN 。 客户端类库可以自由地返回更合适的数据类型(建议:具有值和得分的数组或元组)。

  • 语法:

    1
    127.0.0.1:6379> ZRANGE key start stop [WITHSCORES]
  • 返回值:

    数组: 给定范围内的元素列表(如果指定了WITHSCORES选项,将同时返回它们的得分)。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    127.0.0.1:6379> ZADD myset 1 "one" 2 "two" 3 "three"
    (integer) 3
    127.0.0.1:6379> ZRANGE myset 0 -1
    1) "one"
    2) "two"
    3) "three"
    127.0.0.1:6379> ZRANGE myset 2 3
    1) "three"
    127.0.0.1:6379> ZRANGE myset -2 -1
    1) "two"
    2) "three"
    127.0.0.1:6379> ZRANGE myset 0 1 WITHSCORES
    1) "one"
    2) "1"
    3) "two"
    4) "2"
    127.0.0.1:6379> ZRANGE myset 0 -1 WITHSCORES
    1) "one"
    2) "1"
    3) "two"
    4) "2"
    5) "three"
    6) "3"
    127.0.0.1:6379>

可用版本>= 1.2.0.

时间复杂度: O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements returned.

1.6.8 ZRANGEBYLEX key min max [LIMIT offset count]

Redis Zrangebylex 通过字典区间返回有序集合的成员。

  • 语法:

    1
    127.0.0.1:6379> ZRANGEBYLEX key min max [LIMIT offset count]
  • 返回值:

    数组: 指定区间内的元素列表。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    127.0.0.1:6379> ZADD myset 0 a 0 b 0 c 0 d 0 e 0 f 0 g
    (integer) 7
    127.0.0.1:6379> ZRANGEBYLEX myset - [c
    1) "a"
    2) "b"
    3) "c"
    127.0.0.1:6379> ZRANGEBYLEX myset - (c
    1) "a"
    2) "b"
    127.0.0.1:6379> ZRANGEBYLEX myset [aaa (g
    1) "b"
    2) "c"
    3) "d"
    4) "e"
    5) "f"
    127.0.0.1:6379>

可用版本>= 2.8.9.

时间复杂度: O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).

1.6.9 ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]

Redis ZRANGEBYSCORE 返回有序集 key 中,所有 score 值介于 minmax 之间(包括等于 minmax )的成员。有序集成员按 score 值递增(从小到大)次序排列。

具有相同 score 值的成员按字典序(lexicographical order)来排列(该属性是有序集提供的,不需要额外的计算)。

可选的 LIMIT 参数指定返回结果的数量及区间(就像SQL中的 SELECT LIMIT offset, count ),注意当 offset 很大时,定位 offset 的操作可能需要遍历整个有序集,此过程最坏复杂度为 O(N) 时间。

可选的 WITHSCORES 参数决定结果集是单单返回有序集的成员,还是将有序集成员及其 score 值一起返回。 该选项自 Redis 2.0 版本起可用。

互斥区间与无穷大:

minmax 可以是 -inf+inf ,这样一来,你就可以在不知道有序集的最低和最高 score 值的情况下,获取所有成员。

默认情况下,区间的取值使用闭区间 (小于等于或大于等于),你也可以通过给参数前增加 ( 符号来使用可选的开区间 (小于或大于)。

举个例子:

1
ZRANGEBYSCORE zset (1 5

返回所有符合条件 1 < score <= 5 的成员:

1
ZRANGEBYSCORE zset (5 (10

则返回所有符合条件 5 < score < 10 的成员。

  • 语法:

    1
    127.0.0.1:6379> ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
  • 返回值:

    数组: 指定区间内的有序集成员的列表(带有 score 值(可选))。

  • 实例:

    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
    127.0.0.1:6379> ZADD myset 1 "one" 2 "two" 3 "three"
    (integer) 3
    # 显示整个有序集
    127.0.0.1:6379> ZRANGEBYSCORE myset -inf +inf
    1) "one"
    2) "two"
    3) "three"
    # 显示整个有序集及成员的 score 值
    127.0.0.1:6379> ZRANGEBYSCORE myset -inf +inf WITHSCORES
    1) "one"
    2) "1"
    3) "two"
    4) "2"
    5) "three"
    6) "3"
    # 显示大于等于 1 小于等于 2 的成员
    127.0.0.1:6379> ZRANGEBYSCORE myset 1 2
    1) "one"
    2) "two"
    # 显示大于 1 小于等于 2 的成员
    127.0.0.1:6379> ZRANGEBYSCORE myset (1 2
    1) "two"
    # 显示大于 1 小于 2 的成员
    127.0.0.1:6379> ZRANGEBYSCORE myset (1 (2
    (empty array)
    127.0.0.1:6379>

可用版本>= 1.0.5.

时间复杂度: O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).

1.6.10 ZRANK key member

RedisZRANK 命令返回有序集key中成员member的排名,其中有序集成员按score值从低到高排列。

排名从0开始,也就是说,score值最低的成员排名为0

使用ZREVRANK命令可以获得成员按score值递增(从高到低)排列的排名。

  • 语法:

    1
    127.0.0.1:6379> 
  • 返回值:

    • 如果member是有序集key的成员,整数: member 的排名。
    • 如果member不是有序集key的成员, 或 key 不存在,多行字符串: nil
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> ZADD myset 1 "one" 2 "two" 3 "three"
    (integer) 3
    127.0.0.1:6379> ZRANK myset "three"
    (integer) 2
    127.0.0.1:6379> ZRANK myset "four"
    (nil)
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(log(N))

1.6.11 ZREM key member [member …]

Redis ZREM 命令用于从有序集合key中删除指定的成员member

如果member不存在则被忽略。

当key存在,但是不是有序集合类型时,返回类型错误。

  • 语法:

    1
    127.0.0.1:6379> ZREM key member [member ...]
  • 返回值:

    整数: 返回的是从有序集合中删除的成员个数,不包括不存在的成员。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    127.0.0.1:6379> ZADD myset 1 "one" 2 "two" 3 "three"
    (integer) 3
    127.0.0.1:6379> ZREM myset "two"
    (integer) 1
    127.0.0.1:6379> ZRANGE myset 0 -1 WITHSCORES
    1) "one"
    2) "1"
    3) "three"
    4) "3"
    127.0.0.1:6379>

可用版本>= 1.2.0.

时间复杂度: O(M*log(N)) with N being the number of elements in the sorted set and M the number of elements to be removed.

1.6.12 ZREMRANGEBYLEX key min max

Reids ZREMRANGEBYLEX 命令用于删除成员名称按字典由低到高排序介于minmax 之间的所有成员(集合中所有成员的分数相同)。 不要在成员分数不同的有序集合中使用此命令,因为它是基于分数一致的有序集合设计的,如果使用,会导致删除的结果不正确。

命令中 minmax 的含义与 ZRANGEBYLEX 命令相同。该命令会与使用相同minmax参数的 ZRANGEBYLEX 返回相同的结果。

  • 语法:

    1
    127.0.0.1:6379> ZREMRANGEBYLEX key min max
  • 返回值:

    整数: 删除元素的个数。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    127.0.0.1:6379> ZADD myset 0 aaa 0 b 0 c 0 d 0 e 0 f 0 zap 0 zip 0 ALPHA 0 alpha

    (integer) 10
    127.0.0.1:6379> ZRANGE myset 0 -1
    1) "ALPHA"
    2) "aaa"
    3) "alpha"
    4) "b"
    5) "c"
    6) "d"
    7) "e"
    8) "f"
    9) "zap"
    10) "zip"
    127.0.0.1:6379> ZREMRANGEBYLEX myset [alpha [omega
    (integer) 6
    127.0.0.1:6379> ZRANGE myset 0 -1
    1) "ALPHA"
    2) "aaa"
    3) "zap"
    4) "zip"
    127.0.0.1:6379>

可用版本>= 2.8.9.

时间复杂度: O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements removed by the operation.

1.6.13 ZREMRANGEBYRANK key start stop

Redis ZREMRANGEBYRANK 移除有序集key中,指定排名(rank)区间 startstop 内的所有成员。下标参数start和stop都是从0开始计数,0是分数最小的那个元素。索引也可是负数,表示位移从最高分处开始数。例如,-1是分数最高的元素,-2是分数第二高的,依次类推。

  • 语法:

    1
    127.0.0.1:6379> ZREMRANGEBYRANK key start stop
  • 返回值:

    整数: 删除元素的个数。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    127.0.0.1:6379> ZADD myset 1 "one" 2 "two" 3 "three"
    (integer) 3
    127.0.0.1:6379> ZREMRANGEBYRANK myset 0 1
    (integer) 2
    127.0.0.1:6379> ZRANGE myset 0 -1 WITHSCORES
    1) "three"
    2) "3"
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements removed by the operation.

1.6.14 ZREMRANGEBYSCORE key min max

Redis ZREMRANGEBYSCORE 命令移除有序集key中,所有score值介于min和max之间(包括等于min或max)的成员。

自版本2.1.6开始,score值等于min或max的成员也可以不包括在内,语法请参见ZRANGEBYSCORE命令。

  • 语法:

    1
    127.0.0.1:6379> ZREMRANGEBYSCORE key min max
  • 返回值:

    整数: 删除元素的个数。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    127.0.0.1:6379> ZADD myset 1 "one" 2 "two" 3 "three"
    (integer) 3
    127.0.0.1:6379> ZREMRANGEBYSCORE myset -inf (2
    (integer) 1
    127.0.0.1:6379> ZRANGE myset 0 -1 WITHSCORES
    1) "two"
    2) "2"
    3) "three"
    4) "3"
    127.0.0.1:6379>

可用版本>= 1.2.0.

时间复杂度: O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements removed by the operation.

1.6.15 ZREVRANGE key start stop [WITHSCORES]

Redis ZREVRANGE 命令返回有序集key中,指定区间内的成员。其中成员的位置按score值递减(从高到低)来排列。

具有相同score值的成员按字典序的反序排列。 除了成员排序相反外,ZREVRANGE命令的其他方面和ZRANGE命令一样。

  • 语法:

    1
    127.0.0.1:6379> ZREVRANGE key start stop [WITHSCORES]
  • 返回值:

    数组: 指定范围的元素列表(可选是否含有分数)。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    127.0.0.1:6379> ZADD myset 1 "one" 2 "two" 3 "three"
    (integer) 3
    127.0.0.1:6379> ZREVRANGE myset 0 -1
    1) "three"
    2) "two"
    3) "one"
    127.0.0.1:6379> ZREVRANGE myset 2 3
    1) "one"
    127.0.0.1:6379> ZREVRANGE myset -2 -1
    1) "two"
    2) "one"
    127.0.0.1:6379>

可用版本>= 1.2.0.

时间复杂度: O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements returned.

1.6.16 ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]

Redis Zrangebyscore 返回有序集合中指定分数区间的成员列表。有序集成员按分数值递增(从小到大)次序排列。

具有相同分数值的成员按字典序来排列(该属性是有序集提供的,不需要额外的计算)。

默认情况下,区间的取值使用闭区间 (小于等于或大于等于),你也可以通过给参数前增加 ( 符号来使用可选的开区间 (小于或大于)。

可选的LIMIT参数指定返回结果的数量及区间(类似SQL中SELECT LIMIT offset, count)。注意,如果offset太大,定位offset就可能遍历整个有序集合,这会增加O(N)的复杂度。

可选参数WITHSCORES会返回元素和其分数,而不只是元素。这个选项在redis2.0之后的版本都可用。

##区间及无限

min和max可以是-inf和+inf,这样一来,你就可以在不知道有序集的最低和最高score值的情况下,使用ZRANGEBYSCORE这类命令。

默认情况下,区间的取值使用闭区间(小于等于或大于等于),你也可以通过给参数前增加(符号来使用可选的开区间(小于或大于)。

  • 语法:

    1
    127.0.0.1:6379> ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]
  • 返回值:

    数组: 指定分数范围的元素列表(也可以返回他们的分数)。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    127.0.0.1:6379> ZADD myset 1 "one" 2 "two" 3 "three"
    (integer) 3
    127.0.0.1:6379> ZREVRANGEBYSCORE myset +inf -inf
    1) "three"
    2) "two"
    3) "one"
    127.0.0.1:6379> ZREVRANGEBYSCORE myset 2 1
    1) "two"
    2) "one"
    127.0.0.1:6379> ZREVRANGEBYSCORE myset 2 (1
    1) "two"
    127.0.0.1:6379> ZREVRANGEBYSCORE myset (2 (1
    (empty array)
    127.0.0.1:6379>

可用版本>= 2.2.0.

时间复杂度: O(log(N)+M) with N being the number of elements in the sorted set and M the number of elements being returned. If M is constant (e.g. always asking for the first 10 elements with LIMIT), you can consider it O(log(N)).

1.6.17 ZREVRANK key member

Redis ZREVRANK 命令返回有序集key中成员member的排名,其中有序集成员按score值从高到低排列。

排名从0开始,也就是说,score值最大的成员排名为0

使用ZRANK命令可以获得成员按score值递增(从低到高)排列的排名。

  • 语法:

    1
    127.0.0.1:6379> ZREVRANK key member
  • 返回值:

    • 如果member是有序集key的成员,整数: member的排名。
    • 如果member不是有序集key的成员, 或 key 不存在,多行字符串: nil
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> ZADD myset 1 "one" 2 "two" 3 "three"
    (integer) 3
    127.0.0.1:6379> ZREVRANK myset "one"
    (integer) 2
    127.0.0.1:6379> ZREVRANK myset "two"
    (integer) 1
    127.0.0.1:6379> ZREVRANK myset "four"
    (nil)
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(log(N))

1.6.18 ZSCORE key member

Redis zscore 命令用于返回有序集 key.中成员 member 的分数。

如果有续集中 不存在 member ,或者 key 不存在,返回 nil

  • 语法:

    1
    127.0.0.1:6379> ZSCORE key member
  • 返回值:

    多行字符串: 成员的分数。(双精度浮点数,字符串格式)

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> ZADD myset 1 "one" 2 "two"
    (integer) 2
    127.0.0.1:6379> ZSCORE myset "two"
    "2"
    127.0.0.1:6379> ZSCORE myset "one"
    "1"
    127.0.0.1:6379>

可用版本>= 1.2.0.

时间复杂度: O(1)

1.6.19 ZUNIONSTORE destination numkeys key [key …] [WEIGHTS weight [weight …]] [AGGREGATE SUM|MIN|MAX]

Redis ZUNIONSTORE 用于计算给定的numkeys个有序集合的并集,并且把结果放到destination中。

在给定要计算的key和其它参数之前,必须先给定key个数(numkeys)。

默认情况下,结果集中某个成员的score值是所有给定集中该成员score值之和。

使用WEIGHTS选项,你可以为每个给定的有序集指定一个乘法因子,意思就是,每个给定有序集的所有成员的score值在传递给聚合函数之前都要先乘以该因子。如果WEIGHTS没有给定,默认是 1

使用AGGREGATE选项,你可以指定并集的结果集的聚合方式。默认使用的参数SUM,可以将所有集合中某个成员的score值之和作为结果集中该成员的score值。如果使用参数MIN或者MAX,结果集就是所有集合中该元素最小或最大score。

如果destination存在,会被覆盖。

  • 语法:

    1
    127.0.0.1:6379> ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]
  • 返回值:

    整数: 结果集destination中成员的数量。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    127.0.0.1:6379> ZADD myset1 1 "one" 2 "two"
    (integer) 2
    127.0.0.1:6379> ZADD myset2 1 "one" 2 "two" 3 "three"
    (integer) 3
    127.0.0.1:6379> ZUNIONSTORE out 2 myset1 myset2 WEIGHTS 2 3
    (integer) 3
    127.0.0.1:6379> ZRANGE out 0 -1 WITHSCORES
    1) "one"
    2) "5"
    3) "three"
    4) "9"
    5) "two"
    6) "10"
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(N)+O(M log(M)) with N being the sum of the sizes of the input sorted sets, and M being the number of elements in the resulting sorted set.

1.6.20 ZSCAN key cursor [MATCH pattern] [COUNT count]

查看 SCAN 获取关于 ZSCAN 命令的信息。

  • 语法:

    1
    127.0.0.1:6379> ZSCAN key cursor [MATCH pattern] [COUNT count]

    参数说明:

    • cursor: 游标。
    • pattern: 匹配的模式。
    • count: 指定从数据集里返回多少元素,默认值为 10
  • 返回值:

    返回的每个元素都是一个有序集合元素,一个有序集合元素由一个成员(member)和一个分值(score)组成。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> ZADD myset 1 "one" 2 "two" 3 "three"
    (integer) 3
    127.0.0.1:6379> ZSCAN myset 0 match *w*
    1) "0"
    2) 1) "two"
    2) "2"
    127.0.0.1:6379>

可用版本>= 2.8.0.

时间复杂度: O(1) for every call. O(N) for a complete iteration, including enough command calls for the cursor to return back to 0. N is the number of elements inside the collection..

1.7 Redis 发布订阅

1.7.1 PSUBSCRIBE pattern [pattern …]

Redis PSUBSCRIBE 命令用于订阅一个或多个符合给定模式的频道。

模式支持 glob 风格的正则表达式。每个模式以 * 作为匹配符,比如 it* 匹配所有以 it 开头的频道( it.newsit.blogit.tweets 等等), news.* 匹配所有以 news. 开头的频道( news.itnews.global.today 等等),诸如此类。

特殊字符使用 \ 转义。

  • 语法:

    1
    127.0.0.1:6379> PSUBSCRIBE pattern [pattern ...]
  • 返回值:

    接收到的信息。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    127.0.0.1:6379> SUBSCRIBE rediscomcnChat
    Reading messages... (press Ctrl-C to quit)
    1) "subscribe"
    2) "rediscomcnChat"
    3) (integer) 1
    1) "message"
    2) "rediscomcnChat"
    3) "Redis PUBLISH test"
    1) "message"
    2) "rediscomcnChat"
    3) "Learn redis with python"

可用版本>= 2.0.0.

时间复杂度: O(N) where N is the number of patterns the client is already subscribed to.

1.7.2 PUBSUB subcommand [argument [argument …]]

Redis Pubsub 命令用于查看订阅与发布系统状态,它由数个不同格式的子命令组成。

  1. PUBSUB CHANNELS [pattern]

    列出当前的活跃频道。

    活跃频道指的是那些至少有一个订阅者的频道, 订阅模式的客户端不计算在内。

    pattern 参数是可选的:

    • 如果不给出 pattern 参数,那么列出订阅与发布系统中的所有活跃频道。
    • 如果给出 pattern 参数,那么只列出和给定模式 pattern 相匹配的那些活跃频道。

    返回值:

    数组: 一个由活跃频道组成的列表。

  2. PUBSUB NUMSUB [channel-1 ... channel-N]

    返回给定频道的订阅者数量, 订阅模式的客户端不计算在内。

    返回值:

    数组: 一个多条批量回复(Multi-bulk reply),回复中包含给定的频道,以及频道的订阅者数量。

    格式为:频道 channel-1channel-1 的订阅者数量,频道 channel-2channel-2 的订阅者数量,诸如此类。

    回复中频道的排列顺序和执行命令时给定频道的排列顺序一致。

    不给定任何频道而直接调用这个命令也是可以的, 在这种情况下, 命令只返回一个空列表。

  3. PUBSUB NUMPAT

    返回订阅模式的数量。

    注意, 这个命令返回的不是订阅模式的客户端的数量, 而是客户端订阅的所有模式的数量总和。

    返回值:

    整数: 所有客户端订阅的所有模式的数量总和。

  • 语法:

    1
    127.0.0.1:6379> PUBSUB subcommand [argument [argument ...]]
  • 返回值:

    数组: 一个由活跃频道组成的列表。

  • 实例:

    1
    2
    3
    127.0.0.1:6379> PUBSUB CHANNELS
    (empty array)
    127.0.0.1:6379>

可用版本>= 2.8.0.

时间复杂度: O(N) for the CHANNELS subcommand, where N is the number of active channels, and assuming constant time pattern matching (relatively short channels and patterns). O(N) for the NUMSUB subcommand, where N is the number of requested channels. O(1) for the NUMPAT subcommand.

1.7.3 PUBLISH channel message

Redis PUBLISH 命令用于将信息 message 发送到指定的频道 channel

  • 语法:

    1
    127.0.0.1:6379> PUBLISH channel message
  • 返回值:

    整数: 接收到信息 message 的订阅者数量。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 对没有订阅者的频道发送信息
    127.0.0.1:6379> PUBLISH bad_channel "can any body hear me?"
    (integer) 0
    # 向有一个订阅者的频道发送信息
    127.0.0.1:6379> PUBLISH rediscomcnChat "Hello World"
    (integer) 1
    # # 向有多个订阅者的频道发送信息(前提是,启动了多个订阅者)
    127.0.0.1:6379> PUBLISH rediscomcnChat1 "two channel infos"
    (integer) 2
    127.0.0.1:6379>

    在订阅者频道可以接收到最新消息:

    l lsh l
    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> SUBSCRIBE rediscomcnChat
    Reading messages... (press Ctrl-C to quit)
    1) "subscribe"
    2) "rediscomcnChat"
    3) (integer) 1
    1) "message"
    2) "rediscomcnChat"
    3) "Hello World"

可用版本>= 2.0.0.

时间复杂度: O(N+M) where N is the number of clients subscribed to the receiving channel and M is the total number of subscribed patterns (by any client).

1.7.4 PUNSUBSCRIBE [pattern [pattern …]]

Redis PUNSUBSCRIBE 命令用于客户端退订所有给定模式。

如果没有模式被指定,也即是,一个无参数的 PUNSUBSCRIBE 调用被执行,那么客户端使用PSUBSCRIBE 命令订阅的所有模式都会被退订。在这种情况下,命令会返回一个信息,告知客户端所有被退订的模式。

  • 语法:

    1
    127.0.0.1:6379> PUNSUBSCRIBE [pattern [pattern ...]]
  • 返回值:

    这个命令在不同的客户端中有不同的表现。

  • 实例:

    1
    2
    3
    4
    5
    127.0.0.1:6379> PUNSUBSCRIBE rediscomcnChat1
    1) "punsubscribe"
    2) "rediscomcnChat1"
    3) (integer) 0
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(N+M) where N is the number of patterns the client is already subscribed and M is the number of total patterns subscribed in the system (by any client).

1.7.5 SUBSCRIBE channel [channel …]

Redis SUBSCRIBE 命令用于订阅给定的一个或多个频道的信息。

进入订阅模式后只能执行如下命令: SUBSCRIBE, PSUBSCRIBE, UNSUBSCRIBE, PUNSUBSCRIBE, PING 和QUIT 。

  • 语法:

    1
    127.0.0.1:6379> SUBSCRIBE channel [channel ...]
  • 返回值:

    接收到的信息

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> SUBSCRIBE rediscomcnChat
    Reading messages... (press Ctrl-C to quit)
    1) "subscribe"
    2) "rediscomcnChat"
    3) (integer) 1
    1) "message"
    2) "rediscomcnChat"
    3) "Hello World"

可用版本>= 2.0.0.

时间复杂度: O(N) where N is the number of channels to subscribe to.

1.7.6 UNSUBSCRIBE [channel [channel …]]

Redis UNSUBSCRIBE 命令用于指示客户端退订给定的频道。

如果没有频道被指定,一个无参数的 UNSUBSCRIBE 调用被执行,那么客户端使用 SUBSCRIBE 命令订阅的所有频道都会被退订。在这种情况下,命令会返回一个信息,告知客户端所有被退订的频道。

  • 语法:

    1
    127.0.0.1:6379> UNSUBSCRIBE [channel [channel ...]]
  • 返回值:

    这个命令在不同的客户端中有不同的表现。

  • 实例:

    1
    2
    3
    4
    5
    127.0.0.1:6379> UNSUBSCRIBE rediscomcnChat1
    1) "unsubscribe"
    2) "rediscomcnChat1"
    3) (integer) 0
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(N) where N is the number of clients already subscribed to a channel.

1.8 Redis 事务

1.8.1 DISCARD

DISCARD 命令取消事务,放弃执行事务队列内的所有命令,恢复连接为非 (transaction) 模式。

如果正在使用 WATCH 命令监视某个(或某些) key,那么取消所有监视,等同于执行命令 UNWATCH 。

  • 语法:

    1
    127.0.0.1:6379> DISCARD
  • 返回值:

    字符串: OK.

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379(TX)> ping
    QUEUED
    127.0.0.1:6379(TX)> SET myset "kungs"
    QUEUED
    127.0.0.1:6379(TX)> DISCARD
    OK
    127.0.0.1:6379>

可用版本>= 2.0.0.

1.8.2 EXEC

Redis EXEC 命令用于执行事务 (transaction )队列内的所有命令。

假如某个(或某些) key 正处于 WATCH 命令的监视之下,且事务块中有和这个(或这些) key 相关的命令,那么EXEC 命令只在这个(或这些) key 没有被其他命令所改动的情况下执行并生效,否则该事务被打断(abort)。 check-and-set mechanism.

  • 语法:

    1
    127.0.0.1:6379> EXEC
  • 返回值:

    事务块内所有命令的返回值,按命令执行的先后顺序排列。当操作被打断时,返回空值 nil

  • 实例:

    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
    # 事务被成功执行
    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379(TX)> INCR user_id
    QUEUED
    127.0.0.1:6379(TX)> INCR user_id
    QUEUED
    127.0.0.1:6379(TX)> INCR user_id
    QUEUED
    127.0.0.1:6379(TX)> PING
    QUEUED
    127.0.0.1:6379(TX)> EXEC
    1) (integer) 1
    2) (integer) 2
    3) (integer) 3
    4) PONG
    # 监视 key ,且事务成功执行
    127.0.0.1:6379> WATCH lock lock_times
    OK
    127.0.0.1:6379>
    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379(TX)> SET lock "huangz"
    QUEUED
    127.0.0.1:6379(TX)> INCR lock_times
    QUEUED
    127.0.0.1:6379(TX)> EXEC
    1) OK
    2) (integer) 1
    # 监视 key ,且事务被打断
    127.0.0.1:6379> WATCH lock lock_times
    OK
    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379(TX)> SET lock "joe" # 就在这时,另一个客户端修改了 lock_times 的值
    QUEUED
    127.0.0.1:6379(TX)> INCR lock_times
    QUEUED
    127.0.0.1:6379(TX)> EXEC # 因为 lock_times 被修改, joe 的事务执行失败
    (nil)
    127.0.0.1:6379>

可用版本>= 1.2.0.

1.8.3 MULTI

Redis MULTI 命令用于标记一个事务块的开始。

事务块内的多条命令会按照先后顺序被放进一个队列当中,最后由 EXEC 命令原子性(atomic)地执行。

  • 语法:

    1
    127.0.0.1:6379> MULTI
  • 返回值:

    字符串: 总是返回 OK.

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    127.0.0.1:6379> MULTI
    OK
    127.0.0.1:6379(TX)> INCR user_id
    QUEUED
    127.0.0.1:6379(TX)> INCR user_id
    QUEUED
    127.0.0.1:6379(TX)> INCR user_id
    QUEUED
    127.0.0.1:6379(TX)> PING
    QUEUED
    127.0.0.1:6379(TX)> EXEC
    1) (integer) 1
    2) (integer) 2
    3) (integer) 3
    4) PONG
    127.0.0.1:6379>

可用版本>= 1.2.0.

1.8.4 UNWATCH

Redis UNWATCH命令用于取消 WATCH 命令对所有 key 的监视。
详细参考 transaction.
如果执行过 EXEC 或DISCARD,无需再执行 UNWATCH。
因为 EXEC 命令会执行事务,因此 WATCH 命令的效果已经产生了;而 DISCARD命令在取消事务的同时也会取消所有对 key 的监视,因此这两个命令执行之后,就没有必要执行 UNWATCH了。

  • 语法:

    1
    127.0.0.1:6379> UNWATCH
  • 返回值:

    字符串: 总是返回 OK.

  • 实例:

    1
    2
    3
    4
    5
    127.0.0.1:6379>  WATCH lock lock_times
    OK
    127.0.0.1:6379> UNWATCH
    OK
    127.0.0.1:6379>

可用版本>= 2.2.0.

时间复杂度: O(1)

1.8.5 WATCH key [key …]

Redis WATCH 命令用于标记要监视的key,以便有条件地执行事务(更多参考transaction)。

WATCH 命令可以监控一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会执行。

监控一直持续到EXEC命令(事务中的命令是在EXEC之后才执行的,所以在MULTI命令后可以修改WATCH监控的键值)

  • 语法:

    1
    127.0.0.1:6379> WATCH key [key ...]
  • 返回值:

    字符串: 总是返回OK

  • 实例:

    1
    2
    3
    127.0.0.1:6379>  WATCH lock lock_times
    OK
    127.0.0.1:6379>

可用版本>= 2.2.0.

时间复杂度: O(1) for every key.

1.9 Script(脚本)

1.9.1 EVAL script numkeys key [key ...] arg [arg ...]

Redis Eval 命令使用 Lua 解释器执行脚本。

  • 语法:

    1
    127.0.0.1:6379> EVAL script numkeys key [key ...] arg [arg ...]

    参数说明

    • script: 参数是一段 Lua 5.1 脚本程序。脚本不必(也不应该)定义为一个 Lua 函数。
    • numkeys: 用于指定键名参数的个数。
    • key [key …]: 从 EVAL 的第三个参数开始算起,表示在脚本中所用到的那些 Redis 键(key),这些键名参数可以在 Lua 中通过全局变量 KEYS 数组,用 1 为基址的形式访问( KEYS[1] , KEYS[2] ,以此类推)。
    • arg [arg …]: 附加参数,在 Lua 中通过全局变量 ARGV 数组访问,访问的形式和 KEYS 变量类似( ARGV[1] 、 ARGV[2] ,诸如此类)。
  • 返回值:

    返回需要执行的输出内容。

  • 实例:

    1
    2
    3
    4
    5
    6
    127.0.0.1:6379> eval "return {KEYS[1],KEYS[2],ARGV[1],ARGV[2]}" 2 key1 key2 first second
    1) "key1"
    2) "key2"
    3) "first"
    4) "second"
    127.0.0.1:6379>

可用版本>= 2.6.0.

1.9.2 EVALSHA sha1 numkeys key [key ...] arg [arg ...]

Redis Evalsha 命令根据给定的 sha1 校验码,执行缓存在服务器中的脚本。

将脚本缓存到服务器的操作可以通过 SCRIPT LOAD 命令进行。

这个命令的其他地方,比如参数的传入方式,都和 EVAL 命令一样。

  • 语法:

    1
    127.0.0.1:6379> EVALSHA sha1 numkeys key [key ...] arg [arg ...]

    参数说明:

    • sha1 : 通过 SCRIPT LOAD 生成的 sha1 校验码。
    • numkeys: 用于指定键名参数的个数。
    • key [key …]: 从 EVAL 的第三个参数开始算起,表示在脚本中所用到的那些 Redis 键(key),这些键名参数可以在 Lua 中通过全局变量 KEYS 数组,用 1 为基址的形式访问( KEYS[1] , KEYS[2] ,以此类推)。
    • arg [arg …]: 附加参数,在 Lua 中通过全局变量 ARGV 数组访问,访问的形式和 KEYS 变量类似( ARGV[1] 、 ARGV[2] ,诸如此类)。
  • 返回值:

    输出缓存的数据内容。

  • 实例:

    1
    2
    3
    4
    5
    127.0.0.1:6379> SCRIPT LOAD "return 'hello moto'"
    "232fd51614574cf0867b83d384a5e898cfd24e5a"
    127.0.0.1:6379> EVALSHA "232fd51614574cf0867b83d384a5e898cfd24e5a" 0
    "hello moto"
    127.0.0.1:6379>

可用版本>= 2.6.0.

1.9.3 SCRIPT EXISTS sha1 [sha1 ...]

Redis Script Exists 命令用于校验指定的脚本是否已经被保存在缓存当中。

  • 语法:

    1
    127.0.0.1:6379> SCRIPT EXISTS sha1 [sha1 ...]
  • 返回值:

    一个列表,包含 0 和 1 ,前者表示脚本不存在于缓存,后者表示脚本已经在缓存里面了。

    列表中的元素和给定的 SHA1 校验和保持对应关系,比如列表的第三个元素的值就表示第三个 SHA1 校验和所指定的脚本在缓存中的状态。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 载入一个脚本
    127.0.0.1:6379> SCRIPT LOAD "return 'hello moto'"
    "232fd51614574cf0867b83d384a5e898cfd24e5a"
    127.0.0.1:6379> SCRIPT EXISTS "232fd51614574cf0867b83d384a5e898cfd24e5a"
    1) (integer) 1
    # 清空缓存
    127.0.0.1:6379> SCRIPT FLUSH
    OK
    127.0.0.1:6379> SCRIPT EXISTS "232fd51614574cf0867b83d384a5e898cfd24e5a"
    1) (integer) 0
    127.0.0.1:6379>

可用版本>= 2.6.0.

1.9.4 SCRIPT FLUSH

Redis Script Flush 命令用于清除所有 Lua 脚本缓存。

  • 语法:

    1
    127.0.0.1:6379> SCRIPT FLUSH
  • 返回值:

    字符串: 总是返回 OK.

  • 实例:

    1
    2
    3
    127.0.0.1:6379> SCRIPT FLUSH
    OK
    127.0.0.1:6379>

可用版本>= 2.6.0.

1.9.5 SCRIPT KILL

Redis Script kill 命令用于杀死当前正在运行的 Lua 脚本,当且仅当这个脚本没有执行过任何写操作时,这个命令才生效。

这个命令主要用于终止运行时间过长的脚本,比如一个因为 BUG 而发生无限循环的脚本。

SCRIPT KILL 执行之后,当前正在运行的脚本会被杀死,执行这个脚本的客户端会从 EVAL 命令的阻塞当中退出,并收到一个错误作为返回值。

  • 语法:

    1
    127.0.0.1:6379> SCRIPT KILL
  • 返回值:

    字符串: 总是返回 OK.

  • 实例:

    1
    2
    3
    127.0.0.1:6379> SCRIPT KILL
    OK
    127.0.0.1:6379>

可用版本>= 2.6.0.

1.9.6 SCRIPT LOAD script

Redis Script Load 命令用于将脚本 script 添加到脚本缓存中,但并不立即执行这个脚本。

EVAL 命令也会将脚本添加到脚本缓存中,但是它会立即对输入的脚本进行求值。

如果给定的脚本已经在缓存里面了,那么不执行任何操作。

在脚本被加入到缓存之后,通过 EVALSHA 命令,可以使用脚本的 SHA1 校验和来调用这个脚本。

脚本可以在缓存中保留无限长的时间,直到执行 SCRIPT FLUSH 为止。

关于使用 Redis 对 Lua 脚本进行求值的更多信息,请参见 EVAL 命令。

  • 语法:

    1
    127.0.0.1:6379> SCRIPT LOAD script
  • 返回值:

    给定脚本的 SHA1 校验和

  • 实例:

    1
    2
    3
    127.0.0.1:6379> SCRIPT LOAD "return 1"
    "e0e1f9fabfc9d4800c877a703b823ac0578ff8db"
    127.0.0.1:6379>

可用版本>= 2.6.0.

1.10 Connection(连接)

1.10.1 AUTH [username] password

Redis AUTH 命令用来设置如下两种方式对访问Redis进行权限控制:

  1. 通过 requirepass 设置访问密码。If the Redis server is password protected via the requirepass option.
  2. Redis 6.0 起,支持ACL权限控制,具体参考 Redis ACL system

对应于配置文件中的 requirepass 命令。通过配置 requirepass ,可以使 Redis 拒绝未使用 AUTH 验证访问权限的客户端链接。

如果 AUTH 命令验证的密码与配置文件requirepass 配置的相同,则密码验证通过,服务器返回OK,并开始接受客户端的命令。

密码验证失败,则返回提示信息重新输入密码。

安全注意

因为redis的高性能能在短时间接受非常多的尝试性密码,所以请务必设置一个足够复杂的密码以防止可能的攻击。推荐使用 ACL GENPASS 命令生成密码。

  • 语法:

    当使用 Redis ACLs 权限控制时,AUTH 验证格式如下:

    1
    127.0.0.1:6379> AUTH [username] password

    通过验证用户名密码的方式验证访问权限,详细参考 ACL guide

    在 ACLs 模式下,如果传递一个密码参数给 AUTH,那么会隐式设置用户名 “default”。

  • 返回值:

    字符串: 验证失败时返回错误。

  • 实例:

    1
    2
    3
    4
    5
    6
    127.0.0.1:6379> AUTH PASSWORD
    (error) ERR Client sent AUTH, but no password is set
    127.0.0.1:6379> CONFIG SET requirepass "yanpenggong"
    OK
    127.0.0.1:6379> AUTH mypass
    Ok

可用版本>= 1.0.0.

1.10.2 ECHO message

Redis ECHO 命令用于打印一个给定的信息 message ,测试时使用。

  • 语法:

    1
    127.0.0.1:6379> ECHO message
  • 返回值:

    多行字符串:返回字符串message本身。

  • 实例:

    1
    2
    3
    127.0.0.1:6379> ECHO "Hello World"
    "Hello World"
    127.0.0.1:6379>

可用版本>= 1.0.0.

1.10.3 PING

Redis PING 命令用于客户端向 Redis 服务器发送一个 PING ,如果服务器运作正常的话,会返回一个 PONG 。PING 命令不带参数返回 PONG 。带参数则返回参数 message

PING 通常用来测试连接是否存活,或者测试延迟。

如果客户端订阅某个频道或某个模式,不带参数执行命令会返回一个数组第一个元素是 “pong” ,第二个元素是空,带参数执行同样返回参数 message

  • 语法:

    1
    127.0.0.1:6379> PING
  • 返回值:

    字符串:如果连接正常就返回一个 PONG ,否则返回一个连接错误。

  • 实例:

    1
    2
    3
    4
    5
    127.0.0.1:6379> PING
    PONG
    127.0.0.1:6379> PING "Hello World"
    "Hello World"
    127.0.0.1:6379>

可用版本>= 1.0.0.

1.10.4 QUIT

Redis QUIT 命令用于请求服务器关闭连接。在当前连接上的待处理请求完成后,立刻断开连接。

  • 语法:

    1
    127.0.0.1:6379> QUIT
  • 返回值:

    字符串: 总是返回 OK。

  • 实例:

    1
    2
    127.0.0.1:6379> QUIT
    [root@localhost redis-6.2.6]#

可用版本>= 1.0.0.

1.10.5 SELECT index

Redis SELECT 命令用于切换到指定的数据库,index 是从 0 开始的整数。默认使用数据库 0 。
Redis 可选择的数据库是一种逻辑命名空间格式:物理上所有的数据库还是持久化在一起的,在同一个RDB/AOF文件中。不同的数据库中可以有同名的 key, FLUSHDB, SWAPDB或 RANDOMKEY 这些命令都是针对选定的数据库有效。
从实际应用角度出发,Redis databases 主要用来表示不同的 key 属于同一个应用,而不是一个 Redis 实例对应多个不同的应用。
Reids 分片(Cluster)不能使用 SELECT 。因为 Redis 分片只支持数据库 0 。Redis 分片的情况下,有多个数据库是没有用的。
当前选定的数据库是连接的一个属性,客户端应该记录当前连接的数据库并在重连的时候重新选择对应的数据库。
没有查询当前连接所选择的数据库的命令,可以使用 CLIENT LIST 输出所有用户当前选择的数据库。

  • 语法:

    1
    127.0.0.1:6379> SELECT index
  • 返回值:

    字符串:总是返回 OK 。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    # 默认使用 0 号数据库
    127.0.0.1:6379> SET dn_number 0
    OK
    # 使用 1 号数据库
    127.0.0.1:6379> SELECT 1
    OK
    # 已经切换到 1 号数据库,注意 Redis 现在的命令提示符多了个 [1]
    127.0.0.1:6379[1]> GET db_number
    (nil)
    127.0.0.1:6379[1]> SET db_number 1
    OK
    127.0.0.1:6379[1]> GET db_number
    "1"
    # 再切换到 3 号数据库
    127.0.0.1:6379[1]> SELECT 3
    OK
    # 提示符从 [1] 改变成了 [3]
    127.0.0.1:6379[3]>

可用版本>= 1.0.0.

1.11 SERVER(服务器)

1.11.1 BGREWRITEAOF

Redis BGREWRITEAOF 命令用于异步执行一个 AOF(Append Only File ) 文件重写操作。重写会创建一个当前 AOF 文件的体积优化版本。

即使 Bgrewriteaof 执行失败,也不会有任何数据丢失,因为旧的 AOF 文件在 Bgrewriteaof 成功之前不会被修改。

注意:从 Redis 2.4 开始, AOF 重写由 Redis 自行触发, BGREWRITEAOF 仅仅用于手动触发重写操作。

只有当后台没有正在运行的持久化进程的时候,重写才会被 Redis 触发。

具体来说:

  • 如果一个 redis 的子进程在创建磁盘快照,AOF 重写被列入执行计划但是不会执行直到生成 RDB 的子程序退出。在这种情况下 BGREWRITEAOF 将仍然返回OK状态码, 不过使用一个合适的提示信息。你可以检查一个 AOF 重写是否被例入执行计划通过查询 INFO 命令。
  • 如果一个 AOF rewrite 已经在运行,那么这个命令将会返回错误并且不会有 AOF rewrite 命令被列入后续的执行计划中。
  • 如果 AOF 重启可以启动,但是在运行开始的时候失败(例如创建子进程失败),会返回错误信息给调用者。

从 Redis 2.4 起 AOF rewrite 是被自动触发的,当然 BGREWRITEAOF 命令可以用来在任何时间触发重写。

请参考 Redis持久化文档 获取更多信息。

  • 语法:

    1
    127.0.0.1:6379> BGREWRITEAOF
  • 返回值:

    字符串: 启动重写的提示信息或者执行错误信息。

  • 实例:

    1
    2
    3
    127.0.0.1:6379> BGREWRITEAOF
    Background append only file rewriting started
    127.0.0.1:6379>

可用版本>= 1.0.0.

1.11.2 BGSAVE

后台保存DB。一般立即返回 OK 状态码。 Redis forks, 父进程继续提供服务以供客户端调用,子进程将DB数据保存到磁盘然后退出。

如果有运行中的SAVE或AOF返回错误。

如果使用 BGSAVE SCHEDULE 那么立即返回 OK ,如果后台正好有运行中的AOF,SAVE操作会在下次运行。

客户端可以通过 LASTSAVE 命令查看相关信息,判断 BGSAVE 命令是否执行成功。

请移步 持久化文档 查看更多相关细节。

  • 语法:

    1
    127.0.0.1:6379> BGSAVE [SCHEDULE]
  • 返回值:

    字符串: Background saving startedBackground saving scheduled 使用 SCHEDULE 时。

  • 实例:

    1
    2
    3
    127.0.0.1:6379> BGSAVE
    Background saving started
    127.0.0.1:6379>

可用版本>= 1.0.0.

1.11.3 CLIENT KILL

Redis CLIENT KILL 命令用于关闭地址为 ip:port 的客户端连接。

  • 语法:

    1
    127.0.0.1:6379> CLIENT KILL [ip:port] [ID client-id] [TYPE normal|master|slave|pubsub] [USER username] [ADDR ip:port] [SKIPME yes/no]

    ip:port 应该和 CLIENT LIST 命令返回的结果中 addr 列其中一行匹配。

    因为 Redis 使用单线程设计,所以当 Redis 正在执行命令的时候,不会有客户端被断开连接。

    如果要被断开连接的客户端正在执行命令,那么当这个命令执行之后,在发送下一个命令的时候,它就会收到一个网络错误,告知它自身的连接已被关闭。

    可以根据不同属性杀死客户端而不是只按地址杀死。他们有以下选项:

    • CLIENT KILL ADDR ip:port 和旧版的三个参数时的行为完全一样。
    • CLIENT KILL ID client-id 可以通过唯一ID字段杀死一个客户端,唯一ID可以通过Redis2.8.12的CLIENT LIST命令查询。
    • CLIENT KILL TYPE type 这里的 type 可以是 normal, slave, pubsub。 这将关闭给定烈性的所有客户端。请注意MONITOR命令阻塞的客户端是 normal 类型。
    • CLIENT KILL USER username 关闭使用 ACL username 连接的客户端。如果不存在 ACL user 则返回错误。
    • CLIENT KILL SKIPME yes/no 默认情况下是 yes, 调用该命令的客户端自身不被删掉,如果为 no 也会删除自身。
  • 返回值:

    三参数格式执行命令:字符串: 连接存在并被关闭返回 OK

    新格式:整数: 被杀死的客户端个数。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    # 列出所有已连接客户端
    127.0.0.1:6379> CLIENT list
    id=90 addr=127.0.0.1:34566 laddr=127.0.0.1:6379 fd=7 name= age=0 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=40928 argv-mem=10 obl=0 oll=0 omem=0 tot-mem=61466 events=r cmd=client user=default redir=-1
    # 杀死当前客户端的连接
    127.0.0.1:6379> CLIENT KILL 127.0.0.1:34566
    OK
    # 之前的连接已经被关闭,CLI 客户端又重新建立了连接
    # 之前的端口是 34566 ,现在是 34568
    127.0.0.1:6379> CLIENT list
    id=91 addr=127.0.0.1:34568 laddr=127.0.0.1:6379 fd=7 name= age=0 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=40928 argv-mem=10 obl=0 oll=0 omem=0 tot-mem=61466 events=r cmd=client user=default redir=-1
    127.0.0.1:6379>

可用版本>= 2.4.0.

时间复杂度: O(N) where N is the number of client connections

1.11.4 CLIENT LIST

Redis CLIENT LIST 命令用于返回所有连接到服务器的客户端信息和统计数据。

从 v5.0 起,TYPE type 子命令可以用来过滤客户端类型,type 可以是 normal, master, replicapubsub

注意,被 MONITOR 阻塞的客户端被归类为 normal 类型。

  • 语法:

    1
    127.0.0.1:6379> CLIENT LIST [TYPE normal|master|replica|pubsub]
  • 返回值:

    命令返回多行字符串,这些字符串按以下形式被格式化:

    • 每个已连接客户端对应一行(以 LF 分割)
    • 每行字符串由一系列 属性=值 形式的域组成,每个域之间以空格分开

    以下是域的含义:

    • addr : 客户端的地址和端口
    • fd : 套接字所使用的文件描述符
    • age : 以秒计算的已连接时长
    • idle : 以秒计算的空闲时长
    • flags : 客户端 flag
    • db : 该客户端正在使用的数据库 ID
    • sub : 已订阅频道的数量
    • psub : 已订阅模式的数量
    • multi : 在事务中被执行的命令数量
    • qbuf : 查询缓冲区的长度(字节为单位, 0 表示没有分配查询缓冲区)
    • qbuf-free : 查询缓冲区剩余空间的长度(字节为单位, 0 表示没有剩余空间)
    • obl : 输出缓冲区的长度(字节为单位, 0 表示没有分配输出缓冲区)
    • oll : 输出列表包含的对象数量(当输出缓冲区没有剩余空间时,命令回复会以字符串对象的形式被入队到这个队列里)
    • omem : 输出缓冲区和输出列表占用的内存总量
    • events : 文件描述符事件
    • cmd : 最近一次执行的命令

    客户端 flag 可以由以下部分组成:

    • O : 客户端是 MONITOR 模式下的附属节点(slave)
    • S : 客户端是一般模式下(normal)的附属节点
    • M : 客户端是主节点(master)
    • x : 客户端正在执行事务
    • b : 客户端正在等待阻塞事件
    • i : 客户端正在等待 VM I/O 操作(已废弃)
    • d : 一个受监视(watched)的键已被修改, EXEC 命令将失败
    • c : 在将回复完整地写出之后,关闭链接
    • u : 客户端未被阻塞(unblocked)
    • A : 尽可能快地关闭连接
    • N : 未设置任何 flag

    文件描述符事件可以是:

    • r : 客户端套接字(在事件 loop 中)是可读的(readable)
    • w : 客户端套接字(在事件 loop 中)是可写的(writeable)
  • 实例:

    1
    2
    3
    127.0.0.1:6379> CLIENT LIST
    id=92 addr=127.0.0.1:34570 laddr=127.0.0.1:6379 fd=7 name= age=0 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=40928 argv-mem=10 obl=0 oll=0 omem=0 tot-mem=61466 events=r cmd=client user=default redir=-1
    127.0.0.1:6379>

可用版本>= 2.4.0.

时间复杂度: O(N) where N is the number of client connections

1.11.5 CLIENT GETNAME

Redis CLIENT GETNAME 命令用于返回 CLIENT SETNAME命令为当前连接设置的名字。 因为新创建的连接默认是没有名字的, 对于没有名字的连接, CLIENT GETNAME 返回空白回复。

  • 语法:

    1
    127.0.0.1:6379> CLIENT GETNAME
  • 返回值:

    多行字符串: 如果连接没有设置名字,那么返回空白回复; 如果有设置名字,那么返回名字。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    # 新连接默认没有名字
    127.0.0.1:6379> CLIENT GETNAME
    (nil)
    # 设置名字
    127.0.0.1:6379> CLIENT SETNAME hello-world-connection
    OK
    # 返回名字
    127.0.0.1:6379> CLIENT GETNAME
    "hello-world-connection"
    127.0.0.1:6379>

可用版本>= 2.6.9.

时间复杂度: O(1)

1.11.6 CLIENT PAUSE

CLIENT PAUSE 是连接控制命令,它可以将所有客户端的访问暂停给定的毫秒数。

该命令执行如下:

  • 它会停止处理所有来自一般客户端或者pub/sub客户端的命令。但是和slaves的复制命令不受影响。
  • 因为它会立刻返回OK给调用者,所以CLIENT PAUSE 不会被自己暂停。
  • 当给定的时间结束,所有的客户端都被解除阻塞:这时所有客户端的查询缓存里积累的所有命令都会被处理。

CLIENT PAUSE 命令可以可控的将客户端从一个Redis实例切换至另一个实例。

比如,当需要升级一个实例时,管理员可以作如下操作:

  • 使用CLIENT PAUSE 暂停所有客户端
  • 等待数秒,让slaves 节点处理完所有来自master的复制命令
  • 将一个salve节点切换为 master
  • 重配客户端以来接新的 master 节点

可以在MULTI/EXEC中一起使用CLIENT PAUSE 和INFO replication以在阻塞的同时获取当前master的偏移量。用这种方法,可以检查slaves处理至给定的复制偏移节点,确保复制完整。

从 3.2.10 / 4.0.0 起,该命令也会停止过期和淘汰在暂停时期,保持数据处于静止不变的状态。

  • 语法:

    1
    127.0.0.1:6379> CLIENT PAUSE timeout 
  • 返回值:

    字符串: OK 或者 error timeout is invalid。

  • 实例:

    1
    2
    3
    127.0.0.1:6379> CLIENT PAUSE 10
    OK
    127.0.0.1:6379>

可用版本>= 2.9.50.

时间复杂度: O(1)

1.11.7 CLIENT SETNAME

Redis CLIENT SETNAME 命令为当前连接设置一个名字。

这个名字会显示在CLIENT LIST命令的结果中, 用于客户端识别当前与服务器之间的连接。

例如, 在使用 Redis 构建队列(queue)时, 可以根据连接负责的任务(role), 为信息生产者(producer)和信息消费者(consumer)分别设置不同的名字。

名字使用 Redis 的字符串类型来保存, 最大可以占用 512 MB 。 另外, 为了避免和CLIENT LIST 命令的输出格式发生冲突, 名字里不允许使用空格。

要移除一个连接的名字, 可以将连接的名字设为空字符串 “” 。

使用 CLIENT GETNAME 命令可以取出连接的名字。

新创建的连接默认是没有名字的。

提示:在 Redis 应用程序发生连接泄漏时,为连接设置名字是一种很好的 debug 手段。

  • 语法:

    1
    127.0.0.1:6379> CLIENT SETNAME connection-name
  • 返回值:

    字符串: OK 设置成功。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    # 新连接默认没有名字
    127.0.0.1:6379> CLIENT GETNAME
    (nil)
    # 设置名字
    127.0.0.1:6379> CLIENT SETNAME link1-connection
    OK
    # 返回名字
    127.0.0.1:6379> CLIENT GETNAME
    "link1-connection"
    # 在客户端列表中查看
    127.0.0.1:6379> CLIENT LIST
    id=94 addr=127.0.0.1:34574 laddr=127.0.0.1:6379 fd=7 name=link1-connection age=49 idle=0 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=26 qbuf-free=40928 argv-mem=10 obl=0 oll=0 omem=0 tot-mem=61466 events=r cmd=client user=default redir=-1
    # 清除名字
    127.0.0.1:6379> CLIENT SETNAME # 只用空格是不行的!
    (error) ERR Unknown subcommand or wrong number of arguments for 'SETNAME'. Try CLIENT HELP.
    127.0.0.1:6379> CLIENT SETNAME "" # 必须双引号显示包围
    OK
    127.0.0.1:6379> CLIENT GETNAME # 清除完毕
    (nil)
    127.0.0.1:6379>

可用版本>= 2.6.9.

时间复杂度: O(1)

1.11.8 CLUSTER SLOTS

Redis Client Slots 命令用于当前的集群状态,以数组形式展示。

  • 语法:

    1
    127.0.0.1:6379> CLUSTER SLOT
  • 返回值:

    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
    127.0.0.1:6379> cluster slots
    1) 1) (integer) 0
    2) (integer) 4095
    3) 1) "127.0.0.1"
    2) (integer) 7000
    4) 1) "127.0.0.1"
    2) (integer) 7004
    2) 1) (integer) 12288
    2) (integer) 16383
    3) 1) "127.0.0.1"
    2) (integer) 7003
    4) 1) "127.0.0.1"
    2) (integer) 7007
    3) 1) (integer) 4096
    2) (integer) 8191
    3) 1) "127.0.0.1"
    2) (integer) 7001
    4) 1) "127.0.0.1"
    2) (integer) 7005
    4) 1) (integer) 8192
    2) (integer) 12287
    3) 1) "127.0.0.1"
    2) (integer) 7002
    4) 1) "127.0.0.1"
    2) (integer) 7006

可用版本>= 3.0.0.

时间复杂度: O(N) where N is the total number of Cluster nodes

1.11.9 COMMAND

Redis COMMAND 命令以数组的形式返回有关所有 Redis 命令的详细信息。

如果集群客户端必须知道命令中 key 的位置,以便命令可以转到匹配的实例, 但是 Redis 命令在接收一个 key,多个 key 甚至由其他数据分隔开的多个 key 之间会有所不同。

你可以使用 COMMAND 来为每一个命令缓存命令和 key 位置之间的映射关系,以实现命令到集群的精确路由。

  1. 嵌套结果数组:

    每一个顶级结果包含了六个嵌套的结果。每一个嵌套结果是:

    • 命令名称

    • 命令参数个数

    • 嵌套的命令选项

    • 参数列表中第一个 key 的位置

    • 参数列表中最后一个 key 的位置

    • 用于定位重复 key 的步数

  2. 命令名称

    命令名称是以小写字符串形式返回的命令。

  1. 命令参数个数

    | | |
    | —————————————————————————————— | —————————————————————————————— |
    | 1) 1) “get”
    2) (integer) 2
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1 | 1) 1) “mget”
    2) (integer) -2
    3) 1) readonly
    4) (integer) 1
    5) (integer) -1
    6) (integer) 1 |

    命令参数个数遵循一个简单的模式

    • 正数:命令拥有固定数量的必需参数。
    • 负数:命令拥有最小数量的必需参数,可以有更多的参数。

    命令参数个数包含计算命令名称本身。

    例如:

    • GET 参数个数是 2,因为该命令仅接收一个参数,并且命令格式始终是 GET _key_
    • MGET 的参数个数是 -2,因为该命令接收至少一个参数,但最多可以接收无限数量:MGET _key1_ [key2] [key3] ...

    MGET 中同样需要注意,『最后一个key的位置』的值是 -1,这表示 key 列表可以具有无限长度。

  2. 选项

    命令标志是包含一个或多个状态回复的数组:

    • write - 命令可能会导致修改
    • readonly - 命令永远不会修改键
    • denyoom - 如果当前发生OOM,则拒绝该命令
    • admin - 服务器管理命令
    • pubsub - 发布订阅相关的命令
    • noscript - 在脚本中将会拒绝此命令
    • random - 命令具有随机结果,在脚本中使用很危险
    • sort\for*script* - 如果从脚本调用,则排序输出
    • loading - 允许在数据库加载时使用此命令
    • stale - 允许在从节点具有陈旧数据时使用此命令
    • skip_monitor - 在MONITOR中不会显示此命令
    • asking - 集群相关的 - 即使正在导入数据也接受此命令
    • fast - 命令以常量或log(N)时间运行。用于延迟监控。
    • movablekeys - key在命令中没有预先确定的位置。你必须自己发现key
  3. 可变位置的 Key

    1
    2
    3
    4
    5
    6
    7
    8
    1) 1) "sort"
    2) (integer) -2
    3) 1) write
    2) denyoom
    3) movablekeys
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1

    某些 Redis 命令没有预先确定 key 的位置。对于那些命令,标志 movablekeys会被添加到命令的选项中。 Redis 集群客户端需要解析标记为 movabkeleys 的命令,以便定位所有相关的 key 的位置。

    目前需要解析 key 位置的完整命令列表:

    • SORT - 可选的 STORE key,可选的 BY 权重,可选的 GET keys
    • ZUNIONSTORE - keys 参数列表在 WEIGHT或者 AGGREGATE之前
    • ZINTERSTORE - keys 参数列表在 WEIGHT或者AGGREGATE之前
    • EVAL - keys 列表是在参数 numkeys 之后的 numkeys个参数
    • EVALSHA - keys 列表是在参数 numkeys之后的 numkeys 个参数

    另请参阅 COMMAND GETKEYS 来让 Redis 服务器告诉你任意给定完整命令中的 keys 在哪里。

  4. 参数列表中的第一个Key

    对大部分命令来说,第一个 key 的位置是 1。位置 0 始终是命令名称本身。

  5. 参数列表中的最后一个 Key

    Redis 命令通常可以接收一个 key,两个 key 或者无限数量的 key 。

    如果命令只接收一个 key,那么第一个 key 和最后一个 key 的位置都是1。

    如果命令接收两个 key(例如:BRPOPLPUSHSMOVERENAME等),那么最后一个 key 的位置是最后一个 key 在参数列表中的位置。

    如果命令接收无限数量的 key,那么最后一个 key 的位置是 -1。

  6. 步数

1) 1) “mset”
2) (integer) -3
3) 1) write
2) denyoom
4) (integer) 1
5) (integer) -1
6) (integer) 2
1) 1) “mget”
2) (integer) -2
3) 1) readonly
4) (integer) 1
5) (integer) -1
6) (integer) 1

Key 的步数允许我们在命令中查找 key 的位置,比如 MSET,其格式是 MSET _key1_ _val1_ [key2] [val2] [key3] [val3]...

MSET 的用例中,key 是每隔一个位置出现,所以步数的值是 2。对比上面的 MGET,其步数是 1。

  • 语法:

    1
    127.0.0.1:6379> COMMAND
  • 返回值:

    数组: 嵌套的命令详细信息列表。命令以随机的顺序返回。

  • 实例:

    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
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    459
    460
    461
    462
    463
    464
    465
    466
    467
    468
    469
    470
    471
    472
    473
    474
    475
    476
    477
    478
    479
    480
    481
    482
    483
    484
    485
    486
    487
    488
    489
    490
    491
    492
    493
    494
    495
    496
    497
    498
    499
    500
    501
    502
    503
    504
    505
    506
    507
    508
    509
    510
    511
    512
    513
    514
    515
    516
    517
    518
    519
    520
    521
    522
    523
    524
    525
    526
    527
    528
    529
    530
    531
    532
    533
    534
    535
    536
    537
    538
    539
    540
    541
    542
    543
    544
    545
    546
    547
    548
    549
    550
    551
    552
    553
    554
    555
    556
    557
    558
    559
    560
    561
    562
    563
    564
    565
    566
    567
    568
    569
    570
    571
    572
    573
    574
    575
    576
    577
    578
    579
    580
    581
    582
    583
    584
    585
    586
    587
    588
    589
    590
    591
    592
    593
    594
    595
    596
    597
    598
    599
    600
    601
    602
    603
    604
    605
    606
    607
    608
    609
    610
    611
    612
    613
    614
    615
    616
    617
    618
    619
    620
    621
    622
    623
    624
    625
    626
    627
    628
    629
    630
    631
    632
    633
    634
    635
    636
    637
    638
    639
    640
    641
    642
    643
    644
    645
    646
    647
    648
    649
    650
    651
    652
    653
    654
    655
    656
    657
    658
    659
    660
    661
    662
    663
    664
    665
    666
    667
    668
    669
    670
    671
    672
    673
    674
    675
    676
    677
    678
    679
    680
    681
    682
    683
    684
    685
    686
    687
    688
    689
    690
    691
    692
    693
    694
    695
    696
    697
    698
    699
    700
    701
    702
    703
    704
    705
    706
    707
    708
    709
    710
    711
    712
    713
    714
    715
    716
    717
    718
    719
    720
    721
    722
    723
    724
    725
    726
    727
    728
    729
    730
    731
    732
    733
    734
    735
    736
    737
    738
    739
    740
    741
    742
    743
    744
    745
    746
    747
    748
    749
    750
    751
    752
    753
    754
    755
    756
    757
    758
    759
    760
    761
    762
    763
    764
    765
    766
    767
    768
    769
    770
    771
    772
    773
    774
    775
    776
    777
    778
    779
    780
    781
    782
    783
    784
    785
    786
    787
    788
    789
    790
    791
    792
    793
    794
    795
    796
    797
    798
    799
    800
    801
    802
    803
    804
    805
    806
    807
    808
    809
    810
    811
    812
    813
    814
    815
    816
    817
    818
    819
    820
    821
    822
    823
    824
    825
    826
    827
    828
    829
    830
    831
    832
    833
    834
    835
    836
    837
    838
    839
    840
    841
    842
    843
    844
    845
    846
    847
    848
    849
    850
    851
    852
    853
    854
    855
    856
    857
    858
    859
    860
    861
    862
    863
    864
    865
    866
    867
    868
    869
    870
    871
    872
    873
    874
    875
    876
    877
    878
    879
    880
    881
    882
    883
    884
    885
    886
    887
    888
    889
    890
    891
    892
    893
    894
    895
    896
    897
    898
    899
    900
    901
    902
    903
    904
    905
    906
    907
    908
    909
    910
    911
    912
    913
    914
    915
    916
    917
    918
    919
    920
    921
    922
    923
    924
    925
    926
    927
    928
    929
    930
    931
    932
    933
    934
    935
    936
    937
    938
    939
    940
    941
    942
    943
    944
    945
    946
    947
    948
    949
    950
    951
    952
    953
    954
    955
    956
    957
    958
    959
    960
    961
    962
    963
    964
    965
    966
    967
    968
    969
    970
    971
    972
    973
    974
    975
    976
    977
    978
    979
    980
    981
    982
    983
    984
    985
    986
    987
    988
    989
    990
    991
    992
    993
    994
    995
    996
    997
    998
    999
    1000
    1001
    1002
    1003
    1004
    1005
    1006
    1007
    1008
    1009
    1010
    1011
    1012
    1013
    1014
    1015
    1016
    1017
    1018
    1019
    1020
    1021
    1022
    1023
    1024
    1025
    1026
    1027
    1028
    1029
    1030
    1031
    1032
    1033
    1034
    1035
    1036
    1037
    1038
    1039
    1040
    1041
    1042
    1043
    1044
    1045
    1046
    1047
    1048
    1049
    1050
    1051
    1052
    1053
    1054
    1055
    1056
    1057
    1058
    1059
    1060
    1061
    1062
    1063
    1064
    1065
    1066
    1067
    1068
    1069
    1070
    1071
    1072
    1073
    1074
    1075
    1076
    1077
    1078
    1079
    1080
    1081
    1082
    1083
    1084
    1085
    1086
    1087
    1088
    1089
    1090
    1091
    1092
    1093
    1094
    1095
    1096
    1097
    1098
    1099
    1100
    1101
    1102
    1103
    1104
    1105
    1106
    1107
    1108
    1109
    1110
    1111
    1112
    1113
    1114
    1115
    1116
    1117
    1118
    1119
    1120
    1121
    1122
    1123
    1124
    1125
    1126
    1127
    1128
    1129
    1130
    1131
    1132
    1133
    1134
    1135
    1136
    1137
    1138
    1139
    1140
    1141
    1142
    1143
    1144
    1145
    1146
    1147
    1148
    1149
    1150
    1151
    1152
    1153
    1154
    1155
    1156
    1157
    1158
    1159
    1160
    1161
    1162
    1163
    1164
    1165
    1166
    1167
    1168
    1169
    1170
    1171
    1172
    1173
    1174
    1175
    1176
    1177
    1178
    1179
    1180
    1181
    1182
    1183
    1184
    1185
    1186
    1187
    1188
    1189
    1190
    1191
    1192
    1193
    1194
    1195
    1196
    1197
    1198
    1199
    1200
    1201
    1202
    1203
    1204
    1205
    1206
    1207
    1208
    1209
    1210
    1211
    1212
    1213
    1214
    1215
    1216
    1217
    1218
    1219
    1220
    1221
    1222
    1223
    1224
    1225
    1226
    1227
    1228
    1229
    1230
    1231
    1232
    1233
    1234
    1235
    1236
    1237
    1238
    1239
    1240
    1241
    1242
    1243
    1244
    1245
    1246
    1247
    1248
    1249
    1250
    1251
    1252
    1253
    1254
    1255
    1256
    1257
    1258
    1259
    1260
    1261
    1262
    1263
    1264
    1265
    1266
    1267
    1268
    1269
    1270
    1271
    1272
    1273
    1274
    1275
    1276
    1277
    1278
    1279
    1280
    1281
    1282
    1283
    1284
    1285
    1286
    1287
    1288
    1289
    1290
    1291
    1292
    1293
    1294
    1295
    1296
    1297
    1298
    1299
    1300
    1301
    1302
    1303
    1304
    1305
    1306
    1307
    1308
    1309
    1310
    1311
    1312
    1313
    1314
    1315
    1316
    1317
    1318
    1319
    1320
    1321
    1322
    1323
    1324
    1325
    1326
    1327
    1328
    1329
    1330
    1331
    1332
    1333
    1334
    1335
    1336
    1337
    1338
    1339
    1340
    1341
    1342
    1343
    1344
    1345
    1346
    1347
    1348
    1349
    1350
    1351
    1352
    1353
    1354
    1355
    1356
    1357
    1358
    1359
    1360
    1361
    1362
    1363
    1364
    1365
    1366
    1367
    1368
    1369
    1370
    1371
    1372
    1373
    1374
    1375
    1376
    1377
    1378
    1379
    1380
    1381
    1382
    1383
    1384
    1385
    1386
    1387
    1388
    1389
    1390
    1391
    1392
    1393
    1394
    1395
    1396
    1397
    1398
    1399
    1400
    1401
    1402
    1403
    1404
    1405
    1406
    1407
    1408
    1409
    1410
    1411
    1412
    1413
    1414
    1415
    1416
    1417
    1418
    1419
    1420
    1421
    1422
    1423
    1424
    1425
    1426
    1427
    1428
    1429
    1430
    1431
    1432
    1433
    1434
    1435
    1436
    1437
    1438
    1439
    1440
    1441
    1442
    1443
    1444
    1445
    1446
    1447
    1448
    1449
    1450
    1451
    1452
    1453
    1454
    1455
    1456
    1457
    1458
    1459
    1460
    1461
    1462
    1463
    1464
    1465
    1466
    1467
    1468
    1469
    1470
    1471
    1472
    1473
    1474
    1475
    1476
    1477
    1478
    1479
    1480
    1481
    1482
    1483
    1484
    1485
    1486
    1487
    1488
    1489
    1490
    1491
    1492
    1493
    1494
    1495
    1496
    1497
    1498
    1499
    1500
    1501
    1502
    1503
    1504
    1505
    1506
    1507
    1508
    1509
    1510
    1511
    1512
    1513
    1514
    1515
    1516
    1517
    1518
    1519
    1520
    1521
    1522
    1523
    1524
    1525
    1526
    1527
    1528
    1529
    1530
    1531
    1532
    1533
    1534
    1535
    1536
    1537
    1538
    1539
    1540
    1541
    1542
    1543
    1544
    1545
    1546
    1547
    1548
    1549
    1550
    1551
    1552
    1553
    1554
    1555
    1556
    1557
    1558
    1559
    1560
    1561
    1562
    1563
    1564
    1565
    1566
    1567
    1568
    1569
    1570
    1571
    1572
    1573
    1574
    1575
    1576
    1577
    1578
    1579
    1580
    1581
    1582
    1583
    1584
    1585
    1586
    1587
    1588
    1589
    1590
    1591
    1592
    1593
    1594
    1595
    1596
    1597
    1598
    1599
    1600
    1601
    1602
    1603
    1604
    1605
    1606
    1607
    1608
    1609
    1610
    1611
    1612
    1613
    1614
    1615
    1616
    1617
    1618
    1619
    1620
    1621
    1622
    1623
    1624
    1625
    1626
    1627
    1628
    1629
    1630
    1631
    1632
    1633
    1634
    1635
    1636
    1637
    1638
    1639
    1640
    1641
    1642
    1643
    1644
    1645
    1646
    1647
    1648
    1649
    1650
    1651
    1652
    1653
    1654
    1655
    1656
    1657
    1658
    1659
    1660
    1661
    1662
    1663
    1664
    1665
    1666
    1667
    1668
    1669
    1670
    1671
    1672
    1673
    1674
    1675
    1676
    1677
    1678
    1679
    1680
    1681
    1682
    1683
    1684
    1685
    1686
    1687
    1688
    1689
    1690
    1691
    1692
    1693
    1694
    1695
    1696
    1697
    1698
    1699
    1700
    1701
    1702
    1703
    1704
    1705
    1706
    1707
    1708
    1709
    1710
    1711
    1712
    1713
    1714
    1715
    1716
    1717
    1718
    1719
    1720
    1721
    1722
    1723
    1724
    1725
    1726
    1727
    1728
    1729
    1730
    1731
    1732
    1733
    1734
    1735
    1736
    1737
    1738
    1739
    1740
    1741
    1742
    1743
    1744
    1745
    1746
    1747
    1748
    1749
    1750
    1751
    1752
    1753
    1754
    1755
    1756
    1757
    1758
    1759
    1760
    1761
    1762
    1763
    1764
    1765
    1766
    1767
    1768
    1769
    1770
    1771
    1772
    1773
    1774
    1775
    1776
    1777
    1778
    1779
    1780
    1781
    1782
    1783
    1784
    1785
    1786
    1787
    1788
    1789
    1790
    1791
    1792
    1793
    1794
    1795
    1796
    1797
    1798
    1799
    1800
    1801
    1802
    1803
    1804
    1805
    1806
    1807
    1808
    1809
    1810
    1811
    1812
    1813
    1814
    1815
    1816
    1817
    1818
    1819
    1820
    1821
    1822
    1823
    1824
    1825
    1826
    1827
    1828
    1829
    1830
    1831
    1832
    1833
    1834
    1835
    1836
    1837
    1838
    1839
    1840
    1841
    1842
    1843
    1844
    1845
    1846
    1847
    1848
    1849
    1850
    1851
    1852
    1853
    1854
    1855
    1856
    1857
    1858
    1859
    1860
    1861
    1862
    1863
    1864
    1865
    1866
    1867
    1868
    1869
    1870
    1871
    1872
    1873
    1874
    1875
    1876
    1877
    1878
    1879
    1880
    1881
    1882
    1883
    1884
    1885
    1886
    1887
    1888
    1889
    1890
    1891
    1892
    1893
    1894
    1895
    1896
    1897
    1898
    1899
    1900
    1901
    1902
    1903
    1904
    1905
    1906
    1907
    1908
    1909
    1910
    1911
    1912
    1913
    1914
    1915
    1916
    1917
    1918
    1919
    1920
    1921
    1922
    1923
    1924
    1925
    1926
    1927
    1928
    1929
    1930
    1931
    1932
    1933
    1934
    1935
    1936
    1937
    1938
    1939
    1940
    1941
    1942
    1943
    1944
    1945
    1946
    1947
    1948
    1949
    1950
    1951
    1952
    1953
    1954
    1955
    1956
    1957
    1958
    1959
    1960
    1961
    1962
    1963
    1964
    1965
    1966
    1967
    1968
    1969
    1970
    1971
    1972
    1973
    1974
    1975
    1976
    1977
    1978
    1979
    1980
    1981
    1982
    1983
    1984
    1985
    1986
    1987
    1988
    1989
    1990
    1991
    1992
    1993
    1994
    1995
    1996
    1997
    1998
    1999
    2000
    2001
    2002
    2003
    2004
    2005
    2006
    2007
    2008
    2009
    2010
    2011
    2012
    2013
    2014
    2015
    2016
    2017
    2018
    2019
    2020
    2021
    2022
    2023
    2024
    2025
    2026
    2027
    2028
    2029
    2030
    2031
    2032
    2033
    2034
    2035
    2036
    2037
    2038
    2039
    2040
    2041
    2042
    2043
    2044
    2045
    2046
    2047
    2048
    2049
    2050
    2051
    2052
    2053
    2054
    2055
    2056
    2057
    2058
    2059
    2060
    2061
    2062
    2063
    2064
    2065
    2066
    2067
    2068
    2069
    2070
    2071
    2072
    2073
    2074
    2075
    2076
    2077
    2078
    2079
    2080
    2081
    2082
    2083
    2084
    2085
    2086
    2087
    2088
    2089
    2090
    2091
    2092
    2093
    2094
    2095
    2096
    2097
    2098
    2099
    2100
    2101
    2102
    2103
    2104
    2105
    2106
    2107
    2108
    2109
    2110
    2111
    2112
    2113
    2114
    2115
    2116
    2117
    2118
    2119
    2120
    2121
    2122
    2123
    2124
    2125
    2126
    2127
    2128
    2129
    2130
    2131
    2132
    2133
    2134
    2135
    2136
    2137
    2138
    2139
    2140
    2141
    2142
    2143
    2144
    2145
    2146
    2147
    2148
    2149
    2150
    2151
    2152
    2153
    2154
    2155
    2156
    2157
    2158
    2159
    2160
    2161
    2162
    2163
    2164
    2165
    2166
    2167
    2168
    2169
    2170
    2171
    2172
    2173
    2174
    2175
    2176
    2177
    2178
    2179
    2180
    2181
    2182
    2183
    2184
    2185
    2186
    2187
    2188
    2189
    2190
    2191
    2192
    2193
    2194
    2195
    2196
    2197
    2198
    2199
    2200
    2201
    2202
    2203
    2204
    2205
    2206
    2207
    2208
    2209
    2210
    2211
    2212
    2213
    2214
    2215
    2216
    2217
    2218
    2219
    2220
    2221
    2222
    2223
    2224
    2225
    2226
    2227
    2228
    2229
    2230
    2231
    2232
    2233
    2234
    2235
    2236
    2237
    2238
    2239
    2240
    2241
    2242
    2243
    2244
    2245
    2246
    2247
    2248
    2249
    2250
    2251
    2252
    2253
    2254
    2255
    2256
    2257
    2258
    2259
    2260
    2261
    2262
    2263
    2264
    2265
    2266
    2267
    2268
    2269
    2270
    2271
    2272
    2273
    2274
    2275
    2276
    2277
    2278
    2279
    2280
    2281
    2282
    2283
    2284
    2285
    2286
    2287
    2288
    2289
    2290
    2291
    2292
    2293
    2294
    2295
    2296
    2297
    2298
    2299
    2300
    2301
    2302
    2303
    2304
    2305
    2306
    2307
    127.0.0.1:6379> COMMAND
    1) 1) "xsetid"
    2) (integer) 3
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @stream
    3) @fast
    2) 1) "lpop"
    2) (integer) -2
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @fast
    3) 1) "xautoclaim"
    2) (integer) -6
    3) 1) write
    2) random
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @stream
    3) @fast
    4) 1) "discard"
    2) (integer) 1
    3) 1) noscript
    2) loading
    3) stale
    4) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @fast
    2) @transaction
    5) 1) "copy"
    2) (integer) -3
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) 2
    6) (integer) 1
    7) 1) @keyspace
    2) @write
    3) @slow
    6) 1) "type"
    2) (integer) 2
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @keyspace
    2) @read
    3) @fast
    7) 1) "failover"
    2) (integer) -1
    3) 1) admin
    2) noscript
    3) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    8) 1) "setnx"
    2) (integer) 3
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @string
    3) @fast
    9) 1) "bgrewriteaof"
    2) (integer) 1
    3) 1) admin
    2) noscript
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    10) 1) "psync"
    2) (integer) -3
    3) 1) admin
    2) noscript
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    11) 1) "smove"
    2) (integer) 4
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 2
    6) (integer) 1
    7) 1) @write
    2) @set
    3) @fast
    12) 1) "zrevrangebylex"
    2) (integer) -4
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @sortedset
    3) @slow
    13) 1) "zinter"
    2) (integer) -3
    3) 1) readonly
    2) movablekeys
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @read
    2) @sortedset
    3) @slow
    14) 1) "geopos"
    2) (integer) -2
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @geo
    3) @slow
    15) 1) "readwrite"
    2) (integer) 1
    3) 1) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @keyspace
    2) @fast
    16) 1) "hincrby"
    2) (integer) 4
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @hash
    3) @fast
    17) 1) "keys"
    2) (integer) 2
    3) 1) readonly
    2) sort_for_script
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @keyspace
    2) @read
    3) @slow
    4) @dangerous
    18) 1) "lpos"
    2) (integer) -3
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @list
    3) @slow
    19) 1) "exec"
    2) (integer) 1
    3) 1) noscript
    2) loading
    3) stale
    4) skip_slowlog
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @slow
    2) @transaction
    20) 1) "zcount"
    2) (integer) 4
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @sortedset
    3) @fast
    21) 1) "zdiffstore"
    2) (integer) -4
    3) 1) write
    2) denyoom
    3) movablekeys
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @sortedset
    3) @slow
    22) 1) "replconf"
    2) (integer) -1
    3) 1) admin
    2) noscript
    3) loading
    4) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    23) 1) "rpush"
    2) (integer) -3
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @fast
    24) 1) "getdel"
    2) (integer) 2
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @string
    3) @fast
    25) 1) "brpop"
    2) (integer) -3
    3) 1) write
    2) noscript
    4) (integer) 1
    5) (integer) -2
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @slow
    4) @blocking
    26) 1) "georadius"
    2) (integer) -6
    3) 1) write
    2) denyoom
    3) movablekeys
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @geo
    3) @slow
    27) 1) "persist"
    2) (integer) 2
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @keyspace
    2) @write
    3) @fast
    28) 1) "blpop"
    2) (integer) -3
    3) 1) write
    2) noscript
    4) (integer) 1
    5) (integer) -2
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @slow
    4) @blocking
    29) 1) "zrangebylex"
    2) (integer) -4
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @sortedset
    3) @slow
    30) 1) "sadd"
    2) (integer) -3
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @set
    3) @fast
    31) 1) "unlink"
    2) (integer) -2
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) -1
    6) (integer) 1
    7) 1) @keyspace
    2) @write
    3) @fast
    32) 1) "hello"
    2) (integer) -1
    3) 1) noscript
    2) loading
    3) stale
    4) fast
    5) no_auth
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @fast
    2) @connection
    33) 1) "smismember"
    2) (integer) -3
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @set
    3) @fast
    34) 1) "msetnx"
    2) (integer) -3
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) -1
    6) (integer) 2
    7) 1) @write
    2) @string
    3) @slow
    35) 1) "zrange"
    2) (integer) -4
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @sortedset
    3) @slow
    36) 1) "zscan"
    2) (integer) -3
    3) 1) readonly
    2) random
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @sortedset
    3) @slow
    37) 1) "ltrim"
    2) (integer) 4
    3) 1) write
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @slow
    38) 1) "save"
    2) (integer) 1
    3) 1) admin
    2) noscript
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    39) 1) "replicaof"
    2) (integer) 3
    3) 1) admin
    2) noscript
    3) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    40) 1) "sscan"
    2) (integer) -3
    3) 1) readonly
    2) random
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @set
    3) @slow
    41) 1) "decr"
    2) (integer) 2
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @string
    3) @fast
    42) 1) "flushdb"
    2) (integer) -1
    3) 1) write
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @keyspace
    2) @write
    3) @slow
    4) @dangerous
    43) 1) "object"
    2) (integer) -2
    3) 1) readonly
    2) random
    4) (integer) 2
    5) (integer) 2
    6) (integer) 1
    7) 1) @keyspace
    2) @read
    3) @slow
    44) 1) "zmscore"
    2) (integer) -3
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @sortedset
    3) @fast
    45) 1) "geosearchstore"
    2) (integer) -8
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) 2
    6) (integer) 1
    7) 1) @write
    2) @geo
    3) @slow
    46) 1) "srem"
    2) (integer) -3
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @set
    3) @fast
    47) 1) "rpoplpush"
    2) (integer) 3
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) 2
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @slow
    48) 1) "zunion"
    2) (integer) -3
    3) 1) readonly
    2) movablekeys
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @read
    2) @sortedset
    3) @slow
    49) 1) "pfselftest"
    2) (integer) 1
    3) 1) admin
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @hyperloglog
    2) @admin
    3) @slow
    4) @dangerous
    50) 1) "shutdown"
    2) (integer) -1
    3) 1) admin
    2) noscript
    3) loading
    4) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    51) 1) "pfdebug"
    2) (integer) -3
    3) 1) write
    2) denyoom
    3) admin
    4) (integer) 2
    5) (integer) 2
    6) (integer) 1
    7) 1) @write
    2) @hyperloglog
    3) @admin
    4) @slow
    5) @dangerous
    52) 1) "pexpireat"
    2) (integer) 3
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @keyspace
    2) @write
    3) @fast
    53) 1) "lset"
    2) (integer) 4
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @slow
    54) 1) "zrem"
    2) (integer) -3
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @sortedset
    3) @fast
    55) 1) "sync"
    2) (integer) 1
    3) 1) admin
    2) noscript
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    56) 1) "geodist"
    2) (integer) -4
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @geo
    3) @slow
    57) 1) "setrange"
    2) (integer) 4
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @string
    3) @slow
    58) 1) "lmove"
    2) (integer) 5
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) 2
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @slow
    59) 1) "expireat"
    2) (integer) 3
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @keyspace
    2) @write
    3) @fast
    60) 1) "slaveof"
    2) (integer) 3
    3) 1) admin
    2) noscript
    3) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    61) 1) "ttl"
    2) (integer) 2
    3) 1) readonly
    2) random
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @keyspace
    2) @read
    3) @fast
    62) 1) "incrby"
    2) (integer) 3
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @string
    3) @fast
    63) 1) "move"
    2) (integer) 3
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @keyspace
    2) @write
    3) @fast
    64) 1) "monitor"
    2) (integer) 1
    3) 1) admin
    2) noscript
    3) loading
    4) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    65) 1) "lastsave"
    2) (integer) 1
    3) 1) random
    2) loading
    3) stale
    4) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @fast
    3) @dangerous
    66) 1) "del"
    2) (integer) -2
    3) 1) write
    4) (integer) 1
    5) (integer) -1
    6) (integer) 1
    7) 1) @keyspace
    2) @write
    3) @slow
    67) 1) "flushall"
    2) (integer) -1
    3) 1) write
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @keyspace
    2) @write
    3) @slow
    4) @dangerous
    68) 1) "debug"
    2) (integer) -2
    3) 1) admin
    2) noscript
    3) loading
    4) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    69) 1) "zincrby"
    2) (integer) 4
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @sortedset
    3) @fast
    70) 1) "pttl"
    2) (integer) 2
    3) 1) readonly
    2) random
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @keyspace
    2) @read
    3) @fast
    71) 1) "restore"
    2) (integer) -4
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @keyspace
    2) @write
    3) @slow
    4) @dangerous
    72) 1) "xreadgroup"
    2) (integer) -7
    3) 1) write
    2) movablekeys
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @write
    2) @stream
    3) @slow
    4) @blocking
    73) 1) "restore-asking"
    2) (integer) -4
    3) 1) write
    2) denyoom
    3) asking
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @keyspace
    2) @write
    3) @slow
    4) @dangerous
    74) 1) "dbsize"
    2) (integer) 1
    3) 1) readonly
    2) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @keyspace
    2) @read
    3) @fast
    75) 1) "geoadd"
    2) (integer) -5
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @geo
    3) @slow
    76) 1) "reset"
    2) (integer) 1
    3) 1) noscript
    2) loading
    3) stale
    4) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @fast
    2) @connection
    77) 1) "zremrangebyscore"
    2) (integer) 4
    3) 1) write
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @sortedset
    3) @slow
    78) 1) "zscore"
    2) (integer) 3
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @sortedset
    3) @fast
    79) 1) "hscan"
    2) (integer) -3
    3) 1) readonly
    2) random
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @hash
    3) @slow
    80) 1) "sunion"
    2) (integer) -2
    3) 1) readonly
    2) sort_for_script
    4) (integer) 1
    5) (integer) -1
    6) (integer) 1
    7) 1) @read
    2) @set
    3) @slow
    81) 1) "migrate"
    2) (integer) -6
    3) 1) write
    2) random
    3) movablekeys
    4) (integer) 3
    5) (integer) 3
    6) (integer) 1
    7) 1) @keyspace
    2) @write
    3) @slow
    4) @dangerous
    82) 1) "zunionstore"
    2) (integer) -4
    3) 1) write
    2) denyoom
    3) movablekeys
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @sortedset
    3) @slow
    83) 1) "xack"
    2) (integer) -4
    3) 1) write
    2) random
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @stream
    3) @fast
    84) 1) "rpushx"
    2) (integer) -3
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @fast
    85) 1) "role"
    2) (integer) 1
    3) 1) noscript
    2) loading
    3) stale
    4) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @fast
    2) @dangerous
    86) 1) "pexpire"
    2) (integer) 3
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @keyspace
    2) @write
    3) @fast
    87) 1) "rename"
    2) (integer) 3
    3) 1) write
    4) (integer) 1
    5) (integer) 2
    6) (integer) 1
    7) 1) @keyspace
    2) @write
    3) @slow
    88) 1) "blmove"
    2) (integer) 6
    3) 1) write
    2) denyoom
    3) noscript
    4) (integer) 1
    5) (integer) 2
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @slow
    4) @blocking
    89) 1) "zremrangebylex"
    2) (integer) 4
    3) 1) write
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @sortedset
    3) @slow
    90) 1) "zrevrange"
    2) (integer) -4
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @sortedset
    3) @slow
    91) 1) "hkeys"
    2) (integer) 2
    3) 1) readonly
    2) sort_for_script
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @hash
    3) @slow
    92) 1) "mget"
    2) (integer) -2
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) -1
    6) (integer) 1
    7) 1) @read
    2) @string
    3) @fast
    93) 1) "dump"
    2) (integer) 2
    3) 1) readonly
    2) random
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @keyspace
    2) @read
    3) @slow
    94) 1) "srandmember"
    2) (integer) -2
    3) 1) readonly
    2) random
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @set
    3) @slow
    95) 1) "randomkey"
    2) (integer) 1
    3) 1) readonly
    2) random
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @keyspace
    2) @read
    3) @slow
    96) 1) "georadiusbymember"
    2) (integer) -5
    3) 1) write
    2) denyoom
    3) movablekeys
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @geo
    3) @slow
    97) 1) "zrangestore"
    2) (integer) -5
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) 2
    6) (integer) 1
    7) 1) @write
    2) @sortedset
    3) @slow
    98) 1) "incrbyfloat"
    2) (integer) 3
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @string
    3) @fast
    99) 1) "zrandmember"
    2) (integer) -2
    3) 1) readonly
    2) random
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @sortedset
    3) @slow
    100) 1) "substr"
    2) (integer) 4
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @string
    3) @slow
    101) 1) "incr"
    2) (integer) 2
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @string
    3) @fast
    102) 1) "post"
    2) (integer) -1
    3) 1) readonly
    2) loading
    3) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @read
    2) @slow
    103) 1) "zrank"
    2) (integer) 3
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @sortedset
    3) @fast
    104) 1) "hrandfield"
    2) (integer) -2
    3) 1) readonly
    2) random
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @hash
    3) @slow
    105) 1) "zdiff"
    2) (integer) -3
    3) 1) readonly
    2) movablekeys
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @read
    2) @sortedset
    3) @slow
    106) 1) "zrevrangebyscore"
    2) (integer) -4
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @sortedset
    3) @slow
    107) 1) "zadd"
    2) (integer) -4
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @sortedset
    3) @fast
    108) 1) "append"
    2) (integer) 3
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @string
    3) @fast
    109) 1) "sdiffstore"
    2) (integer) -3
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) -1
    6) (integer) 1
    7) 1) @write
    2) @set
    3) @slow
    110) 1) "hstrlen"
    2) (integer) 3
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @hash
    3) @fast
    111) 1) "linsert"
    2) (integer) 5
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @slow
    112) 1) "zrevrank"
    2) (integer) 3
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @sortedset
    3) @fast
    113) 1) "watch"
    2) (integer) -2
    3) 1) noscript
    2) loading
    3) stale
    4) fast
    4) (integer) 1
    5) (integer) -1
    6) (integer) 1
    7) 1) @fast
    2) @transaction
    114) 1) "hdel"
    2) (integer) -3
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @hash
    3) @fast
    115) 1) "script"
    2) (integer) -2
    3) 1) noscript
    2) may_replicate
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @slow
    2) @scripting
    116) 1) "punsubscribe"
    2) (integer) -1
    3) 1) pubsub
    2) noscript
    3) loading
    4) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @pubsub
    2) @slow
    117) 1) "lolwut"
    2) (integer) -1
    3) 1) readonly
    2) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @read
    2) @fast
    118) 1) "xinfo"
    2) (integer) -2
    3) 1) readonly
    2) random
    4) (integer) 2
    5) (integer) 2
    6) (integer) 1
    7) 1) @read
    2) @stream
    3) @slow
    119) 1) "hgetall"
    2) (integer) 2
    3) 1) readonly
    2) random
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @hash
    3) @slow
    120) 1) "hexists"
    2) (integer) 3
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @hash
    3) @fast
    121) 1) "multi"
    2) (integer) 1
    3) 1) noscript
    2) loading
    3) stale
    4) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @fast
    2) @transaction
    122) 1) "lindex"
    2) (integer) 3
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @list
    3) @slow
    123) 1) "strlen"
    2) (integer) 2
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @string
    3) @fast
    124) 1) "zlexcount"
    2) (integer) 4
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @sortedset
    3) @fast
    125) 1) "xclaim"
    2) (integer) -6
    3) 1) write
    2) random
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @stream
    3) @fast
    126) 1) "zcard"
    2) (integer) 2
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @sortedset
    3) @fast
    127) 1) "stralgo"
    2) (integer) -2
    3) 1) readonly
    2) movablekeys
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @read
    2) @string
    3) @slow
    128) 1) "host:"
    2) (integer) -1
    3) 1) readonly
    2) loading
    3) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @read
    2) @slow
    129) 1) "scard"
    2) (integer) 2
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @set
    3) @fast
    130) 1) "xgroup"
    2) (integer) -2
    3) 1) write
    2) denyoom
    4) (integer) 2
    5) (integer) 2
    6) (integer) 1
    7) 1) @write
    2) @stream
    3) @slow
    131) 1) "rpop"
    2) (integer) -2
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @fast
    132) 1) "unwatch"
    2) (integer) 1
    3) 1) noscript
    2) loading
    3) stale
    4) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @fast
    2) @transaction
    133) 1) "spop"
    2) (integer) -2
    3) 1) write
    2) random
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @set
    3) @fast
    134) 1) "hget"
    2) (integer) 3
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @hash
    3) @fast
    135) 1) "pubsub"
    2) (integer) -2
    3) 1) pubsub
    2) random
    3) loading
    4) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @pubsub
    2) @slow
    136) 1) "lrange"
    2) (integer) 4
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @list
    3) @slow
    137) 1) "set"
    2) (integer) -3
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @string
    3) @slow
    138) 1) "renamenx"
    2) (integer) 3
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 2
    6) (integer) 1
    7) 1) @keyspace
    2) @write
    3) @fast
    139) 1) "hvals"
    2) (integer) 2
    3) 1) readonly
    2) sort_for_script
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @hash
    3) @slow
    140) 1) "bgsave"
    2) (integer) -1
    3) 1) admin
    2) noscript
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    141) 1) "georadiusbymember_ro"
    2) (integer) -5
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @geo
    3) @slow
    142) 1) "setbit"
    2) (integer) 4
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @bitmap
    3) @slow
    143) 1) "exists"
    2) (integer) -2
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) -1
    6) (integer) 1
    7) 1) @keyspace
    2) @read
    3) @fast
    144) 1) "readonly"
    2) (integer) 1
    3) 1) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @keyspace
    2) @fast
    145) 1) "zrangebyscore"
    2) (integer) -4
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @sortedset
    3) @slow
    146) 1) "info"
    2) (integer) -1
    3) 1) random
    2) loading
    3) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @slow
    2) @dangerous
    147) 1) "xpending"
    2) (integer) -3
    3) 1) readonly
    2) random
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @stream
    3) @slow
    148) 1) "lpush"
    2) (integer) -3
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @fast
    149) 1) "scan"
    2) (integer) -2
    3) 1) readonly
    2) random
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @keyspace
    2) @read
    3) @slow
    150) 1) "getbit"
    2) (integer) 3
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @bitmap
    3) @fast
    151) 1) "geosearch"
    2) (integer) -7
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @geo
    3) @slow
    152) 1) "unsubscribe"
    2) (integer) -1
    3) 1) pubsub
    2) noscript
    3) loading
    4) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @pubsub
    2) @slow
    153) 1) "zinterstore"
    2) (integer) -4
    3) 1) write
    2) denyoom
    3) movablekeys
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @sortedset
    3) @slow
    154) 1) "geohash"
    2) (integer) -2
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @geo
    3) @slow
    155) 1) "bitfield"
    2) (integer) -2
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @bitmap
    3) @slow
    156) 1) "bitop"
    2) (integer) -4
    3) 1) write
    2) denyoom
    4) (integer) 2
    5) (integer) -1
    6) (integer) 1
    7) 1) @write
    2) @bitmap
    3) @slow
    157) 1) "get"
    2) (integer) 2
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @string
    3) @fast
    158) 1) "xread"
    2) (integer) -4
    3) 1) readonly
    2) movablekeys
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @read
    2) @stream
    3) @slow
    4) @blocking
    159) 1) "bitfield_ro"
    2) (integer) -2
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @bitmap
    3) @fast
    160) 1) "sunionstore"
    2) (integer) -3
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) -1
    6) (integer) 1
    7) 1) @write
    2) @set
    3) @slow
    161) 1) "decrby"
    2) (integer) 3
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @string
    3) @fast
    162) 1) "sort"
    2) (integer) -2
    3) 1) write
    2) denyoom
    3) movablekeys
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @set
    3) @sortedset
    4) @list
    5) @slow
    6) @dangerous
    163) 1) "hmget"
    2) (integer) -3
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @hash
    3) @fast
    164) 1) "sdiff"
    2) (integer) -2
    3) 1) readonly
    2) sort_for_script
    4) (integer) 1
    5) (integer) -1
    6) (integer) 1
    7) 1) @read
    2) @set
    3) @slow
    165) 1) "evalsha"
    2) (integer) -3
    3) 1) noscript
    2) skip_monitor
    3) may_replicate
    4) movablekeys
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @slow
    2) @scripting
    166) 1) "psetex"
    2) (integer) 4
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @string
    3) @slow
    167) 1) "client"
    2) (integer) -2
    3) 1) admin
    2) noscript
    3) random
    4) loading
    5) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    4) @connection
    168) 1) "sinter"
    2) (integer) -2
    3) 1) readonly
    2) sort_for_script
    4) (integer) 1
    5) (integer) -1
    6) (integer) 1
    7) 1) @read
    2) @set
    3) @slow
    169) 1) "zpopmax"
    2) (integer) -2
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @sortedset
    3) @fast
    170) 1) "publish"
    2) (integer) 3
    3) 1) pubsub
    2) loading
    3) stale
    4) fast
    5) may_replicate
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @pubsub
    2) @fast
    171) 1) "subscribe"
    2) (integer) -2
    3) 1) pubsub
    2) noscript
    3) loading
    4) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @pubsub
    2) @slow
    172) 1) "xadd"
    2) (integer) -5
    3) 1) write
    2) denyoom
    3) random
    4) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @stream
    3) @fast
    173) 1) "swapdb"
    2) (integer) 3
    3) 1) write
    2) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @keyspace
    2) @write
    3) @fast
    4) @dangerous
    174) 1) "lrem"
    2) (integer) 4
    3) 1) write
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @slow
    175) 1) "llen"
    2) (integer) 2
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @list
    3) @fast
    176) 1) "select"
    2) (integer) 2
    3) 1) loading
    2) stale
    3) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @keyspace
    2) @fast
    177) 1) "wait"
    2) (integer) 3
    3) 1) noscript
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @keyspace
    2) @slow
    178) 1) "time"
    2) (integer) 1
    3) 1) random
    2) loading
    3) stale
    4) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @fast
    179) 1) "brpoplpush"
    2) (integer) 4
    3) 1) write
    2) denyoom
    3) noscript
    4) (integer) 1
    5) (integer) 2
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @slow
    4) @blocking
    180) 1) "setex"
    2) (integer) 4
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @string
    3) @slow
    181) 1) "touch"
    2) (integer) -2
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) -1
    6) (integer) 1
    7) 1) @keyspace
    2) @read
    3) @fast
    182) 1) "hlen"
    2) (integer) 2
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @hash
    3) @fast
    183) 1) "echo"
    2) (integer) 2
    3) 1) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @fast
    2) @connection
    184) 1) "sismember"
    2) (integer) 3
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @set
    3) @fast
    185) 1) "command"
    2) (integer) -1
    3) 1) random
    2) loading
    3) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @slow
    2) @connection
    186) 1) "xlen"
    2) (integer) 2
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @stream
    3) @fast
    187) 1) "xdel"
    2) (integer) -3
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @stream
    3) @fast
    188) 1) "slowlog"
    2) (integer) -2
    3) 1) admin
    2) random
    3) loading
    4) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    189) 1) "bzpopmax"
    2) (integer) -3
    3) 1) write
    2) noscript
    3) fast
    4) (integer) 1
    5) (integer) -2
    6) (integer) 1
    7) 1) @write
    2) @sortedset
    3) @fast
    4) @blocking
    190) 1) "hsetnx"
    2) (integer) 4
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @hash
    3) @fast
    191) 1) "expire"
    2) (integer) 3
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @keyspace
    2) @write
    3) @fast
    192) 1) "ping"
    2) (integer) -1
    3) 1) stale
    2) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @fast
    2) @connection
    193) 1) "bzpopmin"
    2) (integer) -3
    3) 1) write
    2) noscript
    3) fast
    4) (integer) 1
    5) (integer) -2
    6) (integer) 1
    7) 1) @write
    2) @sortedset
    3) @fast
    4) @blocking
    194) 1) "memory"
    2) (integer) -2
    3) 1) readonly
    2) random
    3) movablekeys
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @read
    2) @slow
    195) 1) "xrevrange"
    2) (integer) -4
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @stream
    3) @slow
    196) 1) "pfadd"
    2) (integer) -2
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @hyperloglog
    3) @fast
    197) 1) "config"
    2) (integer) -2
    3) 1) admin
    2) noscript
    3) loading
    4) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    198) 1) "hmset"
    2) (integer) -4
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @hash
    3) @fast
    199) 1) "acl"
    2) (integer) -2
    3) 1) admin
    2) noscript
    3) loading
    4) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    200) 1) "xrange"
    2) (integer) -4
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @stream
    3) @slow
    201) 1) "zpopmin"
    2) (integer) -2
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @sortedset
    3) @fast
    202) 1) "lpushx"
    2) (integer) -3
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @list
    3) @fast
    203) 1) "auth"
    2) (integer) -2
    3) 1) noscript
    2) loading
    3) stale
    4) fast
    5) no_auth
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @fast
    2) @connection
    204) 1) "pfmerge"
    2) (integer) -2
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) -1
    6) (integer) 1
    7) 1) @write
    2) @hyperloglog
    3) @slow
    205) 1) "getrange"
    2) (integer) 4
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @string
    3) @slow
    206) 1) "bitcount"
    2) (integer) -2
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @bitmap
    3) @slow
    207) 1) "getex"
    2) (integer) -2
    3) 1) write
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @string
    3) @fast
    208) 1) "psubscribe"
    2) (integer) -2
    3) 1) pubsub
    2) noscript
    3) loading
    4) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @pubsub
    2) @slow
    209) 1) "smembers"
    2) (integer) 2
    3) 1) readonly
    2) sort_for_script
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @set
    3) @slow
    210) 1) "cluster"
    2) (integer) -2
    3) 1) admin
    2) random
    3) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    211) 1) "zremrangebyrank"
    2) (integer) 4
    3) 1) write
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @sortedset
    3) @slow
    212) 1) "pfcount"
    2) (integer) -2
    3) 1) readonly
    2) may_replicate
    4) (integer) 1
    5) (integer) -1
    6) (integer) 1
    7) 1) @read
    2) @hyperloglog
    3) @slow
    213) 1) "bitpos"
    2) (integer) -3
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @bitmap
    3) @slow
    214) 1) "latency"
    2) (integer) -2
    3) 1) admin
    2) noscript
    3) loading
    4) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    215) 1) "hincrbyfloat"
    2) (integer) 4
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @hash
    3) @fast
    216) 1) "mset"
    2) (integer) -3
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) -1
    6) (integer) 2
    7) 1) @write
    2) @string
    3) @slow
    217) 1) "asking"
    2) (integer) 1
    3) 1) fast
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @keyspace
    2) @fast
    218) 1) "xtrim"
    2) (integer) -4
    3) 1) write
    2) random
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @stream
    3) @slow
    219) 1) "hset"
    2) (integer) -4
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @hash
    3) @fast
    220) 1) "sinterstore"
    2) (integer) -3
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) -1
    6) (integer) 1
    7) 1) @write
    2) @set
    3) @slow
    221) 1) "module"
    2) (integer) -2
    3) 1) admin
    2) noscript
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    222) 1) "eval"
    2) (integer) -3
    3) 1) noscript
    2) skip_monitor
    3) may_replicate
    4) movablekeys
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @slow
    2) @scripting
    223) 1) "getset"
    2) (integer) 3
    3) 1) write
    2) denyoom
    3) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @string
    3) @fast
    224) 1) "georadius_ro"
    2) (integer) -6
    3) 1) readonly
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @geo
    3) @slow

可用版本>= 2.8.13.

时间复杂度: O(N) where N is the total number of Redis commands

1.11.10 COMMAND COUNT

Redis Command Count 命令用于统计 redis 命令的个数。

  • 语法:

    1
    127.0.0.1:6379> COMMAND COUNT
  • 返回值:

    整数: 支持的命令类型总数。

  • 实例:

    1
    2
    3
    127.0.0.1:6379> COMMAND COUNT
    (integer) 224
    127.0.0.1:6379>

可用版本>= 2.8.13.

时间复杂度: O(1)

1.11.11 COMMAND GETKEYS

以数据的形式检测一个 Redis 命令 中的 key。

COMMAND GETKEYS是一个辅助命令,让你可以从 Redis 命令中找到key。

COMMAND显示了某些命令拥有可变位置的key,这意味着必须分析完整的命令才能找到要存储或者检索的 key。 你可以使用COMMAND GETKEYS直接从 Redis 解析命令的方式来发现 key 的位置。

  • 语法:

    1
    127.0.0.1:6379> COMMAND GETKEYS
  • 返回值:

    数组: 命令参数中的 key。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    127.0.0.1:6379> COMMAND GETKEYS MSET a b c d e f
    1) "a"
    2) "c"
    3) "e"
    127.0.0.1:6379> COMMAND GETKEYS EVAL "not consulted" 3 key1 key2 key3 arg1 arg2 arg3 argN
    1) "key1"
    2) "key2"
    3) "key3"
    127.0.0.1:6379> COMMAND GETKEYS SORT mylist ALPHA STORE outlist
    1) "mylist"
    2) "outlist"
    127.0.0.1:6379>

可用版本>= 2.8.13.

时间复杂度: O(N) where N is the number of arguments to the command

1.11.12 TIME

TIME 命令返回当前服务器的时间,包含两个条目 Unix 时间戳和这一秒已经过去的微秒数。基本上,该接口非常相似 gettimeofday。

  • 语法:

    1
    127.0.0.1:6379> TIME
  • 返回值:

    数组:

    返回内容包含两个元素

    • UNIX时间戳(单位:秒)
    • 微秒
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> TIME
    1) "1653066894"
    2) "387030"
    127.0.0.1:6379> TIME
    1) "1653066896"
    2) "328152"
    127.0.0.1:6379>

可用版本>= 2.6.0.

时间复杂度: O(1)

1.11.13 COMMAND INFO

以数组的形式返回多个Redis命令的详细信息。

此命令返回的结果与COMMAND相同,但是你可以指定返回哪些命令。

如果你指定了一些不存在的命令,那么在它们的返回位置将会是nil。

  • 语法:

    1
    127.0.0.1:6379> COMMAND INFO command-name [command-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
    58
    59
    127.0.0.1:6379> COMMAND INFO get set eval
    1) 1) "get"
    2) (integer) 2
    3) 1) readonly
    2) fast
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @read
    2) @string
    3) @fast
    2) 1) "set"
    2) (integer) -3
    3) 1) write
    2) denyoom
    4) (integer) 1
    5) (integer) 1
    6) (integer) 1
    7) 1) @write
    2) @string
    3) @slow
    3) 1) "eval"
    2) (integer) -3
    3) 1) noscript
    2) skip_monitor
    3) may_replicate
    4) movablekeys
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @slow
    2) @scripting
    127.0.0.1:6379> COMMAND INFO foo evalsha config bar
    1) (nil)
    2) 1) "evalsha"
    2) (integer) -3
    3) 1) noscript
    2) skip_monitor
    3) may_replicate
    4) movablekeys
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @slow
    2) @scripting
    3) 1) "config"
    2) (integer) -2
    3) 1) admin
    2) noscript
    3) loading
    4) stale
    4) (integer) 0
    5) (integer) 0
    6) (integer) 0
    7) 1) @admin
    2) @slow
    3) @dangerous
    4) (nil)
    127.0.0.1:6379>

可用版本>= 2.8.13.

时间复杂度: O(N) when N is number of commands to look up

1.11.14 CONFIG GET

Redis Config Get 命令用于获取 redis 服务的配置参数。

在 Redis 2.4 版本中, 有部分参数没有办法用 CONFIG GET 访问,但是在最新的 Redis 2.6 版本中,所有配置参数都已经可以用 CONFIG GET 访问了。

CONFIG GET对应的是修改运行时参数的命令 CONFIG SET.

CONFIG GET命令只接受一个 glob 风格的正则参数,所有配置参数都采用key-value的形式。 例如:

1
2
3
4
5
6
7
redis> config get *max-*-entries*
1) "hash-max-zipmap-entries"
2) "512"
3) "list-max-ziplist-entries"
4) "512"
5) "set-max-intset-entries"
6) "512"

通过 redis-cli 提示符下输入 CONFIG GET * 可以查看 Redis 所有支持的参数。

所有支持的参数都与 redis.conf 里面的一样,除了如下的重要差异:

  • 10kb2gb 这些在配置文件中所使用的储存单位缩写,不可以用在 CONFIG 命令中, CONFIG SET 的值只能通过数字值显式地设定。像 CONFIG SET xxx 1k 这样的命令是错误的,正确的格式是 CONFIG SET xxx 1000
  • save 选项在 redis.conf 中是用多行文字储存的,但在 CONFIG GET命令中,它只打印一行文字。

例如,redis.conf 里面的有如下配置:

1
2
save 900 1
save 300 10

它的意思是:如果900秒内有一个数据发生变化,或者300秒内有10个数据发生变化则执行 SAVE ,那么使用 CONFIG GET查看时将会看到 “900 1 300 10”。

  • 语法:

    1
    127.0.0.1:6379> CONFIG GET parameter
  • 返回值:

    数组: 给定配置参数的值。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    127.0.0.1:6379> config get *max-*-entries* 
    1) "hash-max-ziplist-entries"
    2) "512"
    3) "set-max-intset-entries"
    4) "512"
    5) "zset-max-ziplist-entries"
    6) "128"
    127.0.0.1:6379>

可用版本>= 2.0.0.

1.11.15 CONFIG REWRITE

Redis CONFIG REWRITE 命令对启动 Redis 服务器时所指定的 redis.conf 配置文件进行改写。
CONFIG SET 命令可以对服务器的当前配置进行修改, 而修改后的配置可能和 redis.conf 文件中所描述的配置不一样, CONFIG REWRITE 的作用就是通过尽可能少的修改, 将服务器当前所使用的配置记录到 redis.conf 文件中。

  1. 重写以非常保守的方式执行

    • 注释和原始 redis.conf 文件的整体结构会尽可能的保留下来。
    • 如果一个选项在旧的 redis.conf 文件中已经存在,那么它会在相同的位置(行号)被重写。
    • 如果某个选项在配置文件中尚不存在,但被设置为了该选项的默认值,那么他将不会被重写进程写入配置文件。
    • 如果某个选项在配置文件中尚不存在,但被设置了一个非默认值,那么它会被追加到文件的末尾。
    • 未使用的行将会留空。例如,如果你之前在配置文件中有多个 save 配置项,但由于你禁用了 RDB 持久化,当前的 save 配置变少了或者变为空,那么所有的那些行将会是空行。

    如果原始文件由于某些原因不再存在,CONFIG REWRITE 也能够从头开始重写配置文件。但是,如果服务器启动的时候没有指定任何配置文件,则 CONFIG REWRITE 将只会返回一个错误。

  2. 原子重写过程

    为了保证redis.conf文件始终是一致的,也即,在异常或者崩溃的时候,你的配置文件要么是旧的文件,或者是重写完的新文件。重写是通过一次具有足够内容的write(2)调用来执行的,至少和旧的文件一样大。有时会以注释的形式添加额外的padding,以确保生成的文件足够大,稍后文件会被截断以删除末尾的padding。

  • 语法:

    1
    127.0.0.1:6379> CONFIG REWRITE parameter
  • 返回值:

    字符串: 当配置被正确重写时返回OK,否则返回错误。

  • 实例:

    以下是执行 CONFIG REWRITE 前, 被载入到 Redis 服务器的 redis.conf 文件中关于 appendonly 选项的设置:

    1
    2
    3
    4
    5
    # ... 其他选项

    appendonly no

    # ... 其他选项

    在执行以下命令之后:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    127.0.0.1:6379> CONFIG GET appendonly       # appendonly 处于关闭状态
    1) "appendonly"
    2) "no"
    127.0.0.1:6379> CONFIG SET appendonly yes # 打开 appendonly
    OK
    127.0.0.1:6379> CONFIG GET appendonly
    1) "appendonly"
    2) "yes"
    127.0.0.1:6379> CONFIG REWRITE # 将 appendonly 的修改写入到 redis.conf 中
    OK
    127.0.0.1:6379>

    重写后的 redis.conf 文件中的 appendonly 选项将被改写:

    1
    2
    3
    4
    5
    # ... 其他选项

    appendonly yes

    # ... 其他选项

可用版本>= 2.8.0.

1.11.16 CONFIG SET

CONFIG SET 命令用于在服务器运行期间重写某些配置,而不用重启 Redis。可以使用此命令更改不重要的参数或从一个参数切换到另一个持久性选项。

可以通过 CONFIG GET * 获得CONFIG SET命令支持的配置参数列表,该命令是用于获取有关正在运行的 Redis 实例的配置信息的对称命令。

所有使用CONFIG SET设置的配置参数将会立即被 Redis 加载,并从下一个执行的命令开始生效。

所有支持的参数与 [redis.conf][hgcarr22rc] 文件中使用的等效配置参数具有相同含义,但有以下重要区别:

  • 在指定字节或其他数量的选项中,不能使用在redis.conf中使用的简写形式(如10k2gb等),所有内容都应该指定为格式良好的64位整数,以配置指令的基本单位表示。但从Redis3.0以及更高版本开始,可以将CONFIG SET与内存单元一起用于maxmemory、客户端输出缓冲以及复制积压大小(repl-backlog-size)指定内存单位。
  • save参数是一个以空格分隔的整数字符串。每对整数代表一个秒/修改阈值。

例如在 redis.conf 中看起来像这样:

1
2
save 900 1
save 300 10

这意味着,如果数据集有 1 个以上变更,则在 900 秒后保存;如果有 10 个以上变更,则在 300 秒后就保存,应使用CONFIG SET SAVE “900 1 300 10” 来设置。

可以使用CONFIG SET命令将持久化从 RDB 快照切换到 AOF 文件(或其他相似的方式)。 有关如何执行此操作的详细信息,请查看persistencepage

一般来说,你应该知道将 appendonly 参数设置为 yes 将启动后台进程以保存初始 AOF 文件(从内存数据集中获取),并将所有后续命令追加到 AOF 文件,从而达到了与一个 Redis 服务器从一开始就开启了 AOF 选项相同的效果。

如果你愿意,可以同时开启 AOF 和 RDB 快照,这两个选项不是互斥的。

  • 语法:

    1
    127.0.0.1:6379> CONFIG Set parameter value
  • 返回值:

    字符串: 当配置被正确设置时返回OK,否则将返回错误。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> CONFIG GET slowlog-max-len
    1) "slowlog-max-len"
    2) "128"
    127.0.0.1:6379> CONFIG SET slowlog-max-len 10086
    OK
    127.0.0.1:6379> CONFIG GET slowlog-max-len
    1) "slowlog-max-len"
    2) "10086"
    127.0.0.1:6379>

可用版本>= 2.0.0.

1.11.17 CONFIG RESETSTAT

Redis CONFIG RESETSTAT 命令用于重置 INFO 命令中的某些统计数据,包括:

1
2
3
4
5
6
7
8
- Keyspace hits (键空间命中次数)
- Keyspace misses (键空间不命中次数)
- Number of commands processed (执行命令的次数)
- Number of connections received (连接服务器的次数)
- Number of expired keys (过期key的数量)
- Number of rejected connections (被拒绝的连接数量)
- Latest fork(2) time(最后执行 fork(2) 的时间)
- The aof_delayed_fsync counter(aof_delayed_fsync 计数器的值)
  • 语法:

    1
    127.0.0.1:6379> CONFIG RESETSTAT
  • 返回值:

    字符串: OK.

  • 实例:

    重置前 INFO 命令输出信息:

    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
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    127.0.0.1:6379> INFO
    # Server
    redis_version:6.2.6
    redis_git_sha1:00000000
    redis_git_dirty:0
    redis_build_id:eac5b3c736e2a107
    redis_mode:standalone
    os:Linux 3.10.0-1160.el7.x86_64 x86_64
    arch_bits:64
    multiplexing_api:epoll
    atomicvar_api:atomic-builtin
    gcc_version:4.8.5
    process_id:17277
    process_supervised:no
    run_id:4884ead059e4a0ad9cb88e2231856af69ff9ac7e
    tcp_port:6379
    server_time_usec:1653069721652249
    uptime_in_seconds:128889
    uptime_in_days:1
    hz:10
    configured_hz:10
    lru_clock:8902553
    executable:/opt/software/redis-6.2.6/./src/redis-server
    config_file:/opt/software/redis-6.2.6/./redis.conf
    io_threads_active:0

    # Clients
    connected_clients:1
    cluster_connections:0
    maxclients:10000
    client_recent_max_input_buffer:0
    client_recent_max_output_buffer:0
    blocked_clients:0
    tracking_clients:0
    clients_in_timeout_table:0

    # Memory
    used_memory:879352
    used_memory_human:858.74K
    used_memory_rss:3055616
    used_memory_rss_human:2.91M
    used_memory_peak:977792
    used_memory_peak_human:954.88K
    used_memory_peak_perc:89.93%
    used_memory_overhead:811872
    used_memory_startup:810112
    used_memory_dataset:67480
    used_memory_dataset_perc:97.46%
    allocator_allocated:988920
    allocator_active:1265664
    allocator_resident:3502080
    total_system_memory:1019572224
    total_system_memory_human:972.34M
    used_memory_lua:43008
    used_memory_lua_human:42.00K
    used_memory_scripts:248
    used_memory_scripts_human:248B
    number_of_cached_scripts:2
    maxmemory:0
    maxmemory_human:0B
    maxmemory_policy:noeviction
    allocator_frag_ratio:1.28
    allocator_frag_bytes:276744
    allocator_rss_ratio:2.77
    allocator_rss_bytes:2236416
    rss_overhead_ratio:0.87
    rss_overhead_bytes:-446464
    mem_fragmentation_ratio:3.75
    mem_fragmentation_bytes:2239976
    mem_not_counted_for_evict:0
    mem_replication_backlog:0
    mem_clients_slaves:0
    mem_clients_normal:0
    mem_aof_buffer:0
    mem_allocator:jemalloc-5.1.0
    active_defrag_running:0
    lazyfree_pending_objects:0
    lazyfreed_objects:0

    # Persistence
    loading:0
    current_cow_size:0
    current_cow_size_age:0
    current_fork_perc:0.00
    current_save_keys_processed:0
    current_save_keys_total:0
    rdb_changes_since_last_save:0
    rdb_bgsave_in_progress:0
    rdb_last_save_time:1653062505
    rdb_last_bgsave_status:ok
    rdb_last_bgsave_time_sec:0
    rdb_current_bgsave_time_sec:-1
    rdb_last_cow_size:475136
    aof_enabled:0
    aof_rewrite_in_progress:0
    aof_rewrite_scheduled:0
    aof_last_rewrite_time_sec:1
    aof_current_rewrite_time_sec:-1
    aof_last_bgrewrite_status:ok
    aof_last_write_status:ok
    aof_last_cow_size:561152
    module_fork_in_progress:0
    module_fork_last_cow_size:0

    # Stats
    total_connections_received:95
    total_commands_processed:933
    instantaneous_ops_per_sec:0
    total_net_input_bytes:36763
    total_net_output_bytes:432050
    instantaneous_input_kbps:0.00
    instantaneous_output_kbps:0.00
    rejected_connections:0
    sync_full:0
    sync_partial_ok:0
    sync_partial_err:0
    expired_keys:0
    expired_stale_perc:0.00
    expired_time_cap_reached_count:0
    expire_cycle_cpu_milliseconds:6902
    evicted_keys:0
    keyspace_hits:194
    keyspace_misses:13
    pubsub_channels:0
    pubsub_patterns:0
    latest_fork_usec:668
    total_forks:76
    migrate_cached_sockets:0
    slave_expires_tracked_keys:0
    active_defrag_hits:0
    active_defrag_misses:0
    active_defrag_key_hits:0
    active_defrag_key_misses:0
    tracking_total_keys:0
    tracking_total_items:0
    tracking_total_prefixes:0
    unexpected_error_replies:0
    total_error_replies:84
    dump_payload_sanitizations:0
    total_reads_processed:944
    total_writes_processed:931
    io_threaded_reads_processed:0
    io_threaded_writes_processed:0

    # Replication
    role:master
    connected_slaves:0
    master_failover_state:no-failover
    master_replid:5747e010248e99df63f6fc7132cd4f5e778e4c23
    master_replid2:0000000000000000000000000000000000000000
    master_repl_offset:0
    second_repl_offset:-1
    repl_backlog_active:0
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:0
    repl_backlog_histlen:0

    # CPU
    used_cpu_sys:250.581855
    used_cpu_user:278.320178
    used_cpu_sys_children:0.452773
    used_cpu_user_children:0.073380
    used_cpu_sys_main_thread:250.516158
    used_cpu_user_main_thread:278.278268

    # Modules

    # Errorstats
    errorstat_ERR:count=51
    errorstat_NOAUTH:count=13
    errorstat_NOTBUSY:count=3
    errorstat_WRONGPASS:count=4
    errorstat_WRONGTYPE:count=13

    # Cluster
    cluster_enabled:0

    # Keyspace
    db0:keys=21,expires=0,avg_ttl=0
    db1:keys=5,expires=0,avg_ttl=0
    db2:keys=3,expires=0,avg_ttl=0

    重置后查看 INFO 命令输出信息:

    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
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    # 重置操作
    127.0.0.1:6379> CONFIG RESETSTAT
    OK
    # 重置后查看 INFO 命令输出信息:
    127.0.0.1:6379> INFO
    # Server
    redis_version:6.2.6
    redis_git_sha1:00000000
    redis_git_dirty:0
    redis_build_id:eac5b3c736e2a107
    redis_mode:standalone
    os:Linux 3.10.0-1160.el7.x86_64 x86_64
    arch_bits:64
    multiplexing_api:epoll
    atomicvar_api:atomic-builtin
    gcc_version:4.8.5
    process_id:17277
    process_supervised:no
    run_id:4884ead059e4a0ad9cb88e2231856af69ff9ac7e
    tcp_port:6379
    server_time_usec:1653069741529106
    uptime_in_seconds:128909
    uptime_in_days:1
    hz:10
    configured_hz:10
    lru_clock:8902573
    executable:/opt/software/redis-6.2.6/./src/redis-server
    config_file:/opt/software/redis-6.2.6/./redis.conf
    io_threads_active:0

    # Clients
    connected_clients:1
    cluster_connections:0
    maxclients:10000
    client_recent_max_input_buffer:24
    client_recent_max_output_buffer:0
    blocked_clients:0
    tracking_clients:0
    clients_in_timeout_table:0

    # Memory
    used_memory:879048
    used_memory_human:858.45K
    used_memory_rss:3051520
    used_memory_rss_human:2.91M
    used_memory_peak:977792
    used_memory_peak_human:954.88K
    used_memory_peak_perc:89.90%
    used_memory_overhead:832376
    used_memory_startup:810112
    used_memory_dataset:46672
    used_memory_dataset_perc:67.70%
    allocator_allocated:1026488
    allocator_active:1343488
    allocator_resident:3624960
    total_system_memory:1019572224
    total_system_memory_human:972.34M
    used_memory_lua:43008
    used_memory_lua_human:42.00K
    used_memory_scripts:248
    used_memory_scripts_human:248B
    number_of_cached_scripts:2
    maxmemory:0
    maxmemory_human:0B
    maxmemory_policy:noeviction
    allocator_frag_ratio:1.31
    allocator_frag_bytes:317000
    allocator_rss_ratio:2.70
    allocator_rss_bytes:2281472
    rss_overhead_ratio:0.84
    rss_overhead_bytes:-573440
    mem_fragmentation_ratio:3.65
    mem_fragmentation_bytes:2215232
    mem_not_counted_for_evict:0
    mem_replication_backlog:0
    mem_clients_slaves:0
    mem_clients_normal:20504
    mem_aof_buffer:0
    mem_allocator:jemalloc-5.1.0
    active_defrag_running:0
    lazyfree_pending_objects:0
    lazyfreed_objects:0

    # Persistence
    loading:0
    current_cow_size:0
    current_cow_size_age:0
    current_fork_perc:0.00
    current_save_keys_processed:0
    current_save_keys_total:0
    rdb_changes_since_last_save:0
    rdb_bgsave_in_progress:0
    rdb_last_save_time:1653062505
    rdb_last_bgsave_status:ok
    rdb_last_bgsave_time_sec:0
    rdb_current_bgsave_time_sec:-1
    rdb_last_cow_size:475136
    aof_enabled:0
    aof_rewrite_in_progress:0
    aof_rewrite_scheduled:0
    aof_last_rewrite_time_sec:1
    aof_current_rewrite_time_sec:-1
    aof_last_bgrewrite_status:ok
    aof_last_write_status:ok
    aof_last_cow_size:561152
    module_fork_in_progress:0
    module_fork_last_cow_size:0

    # Stats
    total_connections_received:0
    total_commands_processed:1
    instantaneous_ops_per_sec:0
    total_net_input_bytes:14
    total_net_output_bytes:5
    instantaneous_input_kbps:0.00
    instantaneous_output_kbps:0.00
    rejected_connections:0
    sync_full:0
    sync_partial_ok:0
    sync_partial_err:0
    expired_keys:0
    expired_stale_perc:0.00
    expired_time_cap_reached_count:0
    expire_cycle_cpu_milliseconds:0
    evicted_keys:0
    keyspace_hits:0
    keyspace_misses:0
    pubsub_channels:0
    pubsub_patterns:0
    latest_fork_usec:0
    total_forks:0
    migrate_cached_sockets:0
    slave_expires_tracked_keys:0
    active_defrag_hits:0
    active_defrag_misses:0
    active_defrag_key_hits:0
    active_defrag_key_misses:0
    tracking_total_keys:0
    tracking_total_items:0
    tracking_total_prefixes:0
    unexpected_error_replies:0
    total_error_replies:0
    dump_payload_sanitizations:0
    total_reads_processed:1
    total_writes_processed:1
    io_threaded_reads_processed:0
    io_threaded_writes_processed:0

    # Replication
    role:master
    connected_slaves:0
    master_failover_state:no-failover
    master_replid:5747e010248e99df63f6fc7132cd4f5e778e4c23
    master_replid2:0000000000000000000000000000000000000000
    master_repl_offset:0
    second_repl_offset:-1
    repl_backlog_active:0
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:0
    repl_backlog_histlen:0

    # CPU
    used_cpu_sys:250.620934
    used_cpu_user:278.359987
    used_cpu_sys_children:0.452773
    used_cpu_user_children:0.073380
    used_cpu_sys_main_thread:250.556253
    used_cpu_user_main_thread:278.316859

    # Modules

    # Errorstats

    # Cluster
    cluster_enabled:0

    # Keyspace
    db0:keys=21,expires=0,avg_ttl=0
    db1:keys=5,expires=0,avg_ttl=0
    db2:keys=3,expires=0,avg_ttl=0
    127.0.0.1:6379>

可用版本>= 2.0.0.

时间复杂度: O(1)

1.11.18 DBSIZE

Redis DBSIZE 返回当前数据库中 key 的数量。

  • 语法:

    1
    127.0.0.1:6379> DBSIZE
  • 返回值:

    整数:当前数据库中 key 的数量。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    127.0.0.1:6379> DBSIZE
    (integer) 21
    # 增加一个key,再看看效果
    127.0.0.1:6379> SET new_key "hello kungs"
    OK
    127.0.0.1:6379> DBSIZE
    (integer) 22
    127.0.0.1:6379>

可用版本>= 1.0.0.

1.11.19 DEBUG OBJECT

Redis DEBUG OBJECT 是一个调试命令,它不应该被客户端所使用。
查看 OBJECT 命令获取更多信息。

  • 语法:

    1
    127.0.0.1:6379> DEBUG OBJECT key
  • 返回值:

    字符串: 当 key 存在时,返回有关信息。 当 key 不存在时,返回 (error) ERR no such key。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> SET new_key "hello kungs"
    OK
    127.0.0.1:6379> DEBUG OBJECT new_key
    Value at:0x7fceb660e9e0 refcount:1 encoding:embstr serializedlength:12 lru:8902992 lru_seconds_idle:4
    127.0.0.1:6379> DEBUG OBJECT new_key1
    (error) ERR no such key
    127.0.0.1:6379>

可用版本>= 1.0.0.

1.11.20 DEBUG SEGFAULT

DEBUG SEGFAULT 执行一个不合法的内存访问从而让 Redis 崩溃,仅在开发时用于模拟 BUG 。

  • 语法:

    1
    127.0.0.1:6379> DEBUG SEGFAULT
  • 返回值:

    字符串

  • 实例:

    1
    2
    3
    4
    127.0.0.1:6379> DEBUG SEGFAULT
    Error: Server closed the connection
    (0.69s)
    127.0.0.1:6379>

可用版本>= 1.0.0.

1.11.21 FLUSHALL

清空整个 Redis 中的数据(清空所有数据库的所有 key,不仅仅是当前 select 的数据库 )。

此命令不会失败。

FLUSHALL ASYNC (Redis 4.0.0 or greater)

支持在后台单独的线程执行删除 key 的操作而不阻塞 Redis。

FLUSHALLFLUSHDB 增加了ASYNC 来使整个数据集或单个数据库异步释放。

异步FLUSHALLFLUSHDB 命令仅仅删除它们被调用时已经存在的 key。命令调用之后,删除 key 的过程中新建的 key 不受影响。

  • 语法:

    1
    127.0.0.1:6379> FLUSHALL
  • 返回值:

    字符串: OK

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    # 0 号数据库的 key 数量
    127.0.0.1:6379> DBSIZE
    (integer) 22
    # 切换到 1 号数据库
    127.0.0.1:6379> SELECT 1
    OK
    # 1 号数据库的 key 数量
    127.0.0.1:6379[1]> DBSIZE
    (integer) 5
    # 清空所有数据库的所有 key
    127.0.0.1:6379[1]> FLUSHALL
    OK
    # 不但 1 号数据库被清空了
    127.0.0.1:6379[1]> DBSIZE
    (integer) 0
    # 0 号数据库(以及其他所有数据库)也一样
    127.0.0.1:6379[1]> SELECT 0
    OK
    127.0.0.1:6379> DBSIZE
    (integer) 0
    127.0.0.1:6379>

可用版本>= 1.0.0.

时间复杂度是 O(N), N 代表所有数据库中 key 的总数。

1.11.22 FLUSHDB

清空当前 select 数据库中的所有 key。此命令不会失败。

  • 语法:

    1
    127.0.0.1:6379> FLUSHDB
  • 返回值:

    字符串: OK

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    # 清空前的 key 数量
    127.0.0.1:6379> DBSIZE
    (integer) 4
    127.0.0.1:6379> FLUSHDB
    OK
    # 清空后的 key 数量
    redis 127.0.0.1:6379> DBSIZE
    (integer) 0

可用版本>= 1.0.0.

时间复杂度是 O(N), N 代表当前数据库中 key 的总数。

1.11.23 INFO

INFO命令以一种易于理解和阅读的格式,返回关于Redis服务器的各种信息和统计数值。

通过给定可选的参数 section ,可以让命令只返回某一部分的信息:

  • server: 查看 Redis 服务器信息,如 Redis 的版本
  • clients: 客户端的连接部分
  • memory: 内存消耗相关信息
  • persistence: RDB和AOF相关信息
  • stats: 一般统计
  • replication: 主/从复制信息
  • cpu: 统计CPU的消耗
  • commandstats: Redis命令统计
  • cluster: Redis集群信息
  • keyspace: 数据库的相关统计
  • modules: Module 相关信息

它也可以采取以下值:

  • all: 返回所有信息
  • default: 值返回默认设置的信息
  • everything: 包括 allmodules

如果没有使用任何参数时,默认为default

注意:

请注意不同Redis版本会添加或者删除一些字段。一个健壮的客户端应用解析该命令的结果时,应该跳过未知的字段,并且优雅的处理缺少的字段。

以下是Redis >= 2.4的字段说明。

下面是所有 server 相关的信息:

  • redis_version: Redis 服务器版本
  • redis_git_sha1: Git SHA1
  • redis_git_dirty: Git dirty flag
  • redis_build_id: 构建ID
  • redis_mode: 服务器模式(standalone,sentinel或者cluster)
  • os: Redis 服务器的宿主操作系统
  • arch_bits: 架构(32 或 64 位)
  • multiplexing_api: Redis 所使用的事件处理机制
  • atomicvar_api: Redis使用的Atomicvar API
  • gcc_version: 编译 Redis 时所使用的 GCC 版本
  • process_id: 服务器进程的 PID
  • run_id: Redis 服务器的随机标识符(用于 Sentinel 和集群)
  • tcp_port: TCP/IP 监听端口
  • uptime_in_seconds: 自 Redis 服务器启动以来,经过的秒数
  • uptime_in_days: 自 Redis 服务器启动以来,经过的天数
  • hz: 服务器的频率设置
  • lru_clock: 以分钟为单位进行自增的时钟,用于 LRU 管理
  • executable: 服务器的可执行文件路径
  • config_file: 配置文件路径

下面是所有 clients 相关的信息:

  • connected_clients: 已连接客户端的数量(不包括通过从属服务器连接的客户端)
  • client_longest_output_list: 当前连接的客户端当中,最长的输出列表
  • client_biggest_input_buf: 当前连接的客户端当中,最大输入缓存
  • blocked_clients: 正在等待阻塞命令(BLPOP、BRPOP、BRPOPLPUSH)的客户端的数量

下面是所有 memory 相关的信息:

  • used_memory: 由 Redis 分配器分配的内存总量,以字节(byte)为单位
  • used_memory_human: 以人类可读的格式返回 Redis 分配的内存总量
  • used_memory_rss: 从操作系统的角度,返回 Redis 已分配的内存总量(俗称常驻集大小)。这个值和 top 、 ps 等命令的输出一致。
  • used_memory_peak: Redis 的内存消耗峰值(以字节为单位)
  • used_memory_peak_human: 以人类可读的格式返回 Redis 的内存消耗峰值
  • used_memory_peak_perc: 使用内存占峰值内存的百分比
  • used_memory_overhead: 服务器为管理其内部数据结构而分配的所有开销的总和(以字节为单位)
  • used_memory_startup: Redis在启动时消耗的初始内存大小(以字节为单位)
  • used_memory_dataset: 以字节为单位的数据集大小(usedmemory减去usedmemory_overhead)
  • used_memory_dataset_perc: usedmemorydataset占净内存使用量的百分比(usedmemory减去usedmemory_startup)
  • total_system_memory: Redis主机具有的内存总量
  • total_system_memory_human: 以人类可读的格式返回 Redis主机具有的内存总量
  • used_memory_lua: Lua 引擎所使用的内存大小(以字节为单位)
  • used_memory_lua_human: 以人类可读的格式返回 Lua 引擎所使用的内存大小
  • maxmemory: maxmemory配置指令的值
  • maxmemory_human: 以人类可读的格式返回 maxmemory配置指令的值
  • maxmemory_policy: maxmemory-policy配置指令的值
  • mem_fragmentation_ratio: used_memory_rssused_memory之间的比率
  • mem_allocator: 在编译时指定的, Redis 所使用的内存分配器。可以是 libc 、 jemalloc 或者 tcmalloc 。
  • active_defrag_running: 指示活动碎片整理是否处于活动状态的标志
  • lazyfree_pending_objects: 等待释放的对象数(由于使用ASYNC选项调用UNLINK或FLUSHDB和FLUSHALL)

在理想情况下, usedmemoryrss 的值应该只比 used_memory 稍微高一点儿。

当 rss > used ,且两者的值相差较大时,表示存在(内部或外部的)内存碎片。

内存碎片的比率可以通过 memfragmentationratio 的值看出。

当 used > rss 时,表示 Redis 的部分内存被操作系统换出到交换空间了,在这种情况下,操作可能会产生明显的延迟。

由于Redis无法控制其分配的内存如何映射到内存页,因此常住内存(usedmemoryrss)很高通常是内存使用量激增的结果。

当 Redis 释放内存时,内存将返回给分配器,分配器可能会,也可能不会,将内存返还给操作系统。

如果 Redis 释放了内存,却没有将内存返还给操作系统,那么 used_memory 的值可能和操作系统显示的 Redis 内存占用并不一致。

查看 usedmemorypeak 的值可以验证这种情况是否发生。

要获得有关服务器内存的其他内省信息,可以参考MEMORY STATSMEMORY DOCTOR

下面是所有 persistence 相关的信息:

  • loading: 指示转储文件(dump)的加载是否正在进行的标志
  • rdb_changes_since_last_save: 自上次转储以来的更改次数
  • rdb_bgsave_in_progress: 指示RDB文件是否正在保存的标志
  • rdb_last_save_time: 上次成功保存RDB的基于纪年的时间戳
  • rdb_last_bgsave_status: 上次RDB保存操作的状态
  • rdb_last_bgsave_time_sec: 上次RDB保存操作的持续时间(以秒为单位)
  • rdb_current_bgsave_time_sec: 正在进行的RDB保存操作的持续时间(如果有)
  • rdb_last_cow_size: 上次RDB保存操作期间copy-on-write分配的字节大小
  • aof_enabled: 表示AOF记录已激活的标志
  • aof_rewrite_in_progress: 表示AOF重写操作正在进行的标志
  • aof_rewrite_scheduled: 表示一旦进行中的RDB保存操作完成,就会安排进行AOF重写操作的标志
  • aof_last_rewrite_time_sec: 上次AOF重写操作的持续时间,以秒为单位
  • aof_current_rewrite_time_sec: 正在进行的AOF重写操作的持续时间(如果有)
  • aof_last_bgrewrite_status: 上次AOF重写操作的状态
  • aof_last_write_status: 上一次AOF写入操作的状态
  • aof_last_cow_size: 上次AOF重写操作期间copy-on-write分配的字节大小

changes_since_last_save指的是从上次调用SAVE或者BGSAVE以来,在数据集中产生某种变化的操作的数量。

如果启用了AOF,则会添加以下这些额外的字段:

  • aof_current_size: 当前的AOF文件大小
  • aof_base_size: 上次启动或重写时的AOF文件大小
  • aof_pending_rewrite: 指示AOF重写操作是否会在当前RDB保存操作完成后立即执行的标志。
  • aof_buffer_length: AOF缓冲区大小
  • aof_rewrite_buffer_length: AOF重写缓冲区大小
  • aof_pending_bio_fsync: 在后台IO队列中等待fsync处理的任务数
  • aof_delayed_fsync: 延迟fsync计数器

如果正在执行加载操作,将会添加这些额外的字段:

  • loading_start_time: 加载操作的开始时间(基于纪元的时间戳)
  • loading_total_bytes: 文件总大小
  • loading_loaded_bytes: 已经加载的字节数
  • loading_loaded_perc: 已经加载的百分比
  • loading_eta_seconds: 预计加载完成所需的剩余秒数

下面是所有 stats 相关的信息:

  • total_connections_received: 服务器接受的连接总数
  • total_commands_processed: 服务器处理的命令总数
  • instantaneous_ops_per_sec: 每秒处理的命令数
  • rejected_connections: 由于maxclients限制而拒绝的连接数
  • expired_keys: key到期事件的总数
  • evicted_keys: 由于maxmemory限制而导致被驱逐的key的数量
  • keyspace_hits: 在主字典中成功查找到key的次数
  • keyspace_misses: 在主字典中查找key失败的次数
  • pubsub_channels: 拥有客户端订阅的全局pub/sub通道数
  • pubsub_patterns: 拥有客户端订阅的全局pub/sub模式数
  • latest_fork_usec: 最新fork操作的持续时间,以微秒为单位

下面是所有 replication 相关的信息:

  • role: 如果实例不是任何节点的从节点,则值是”master”,如果实例从某个节点同步数据,则是”slave”。 请注意,一个从节点可以是另一个从节点的主节点(菊花链)。

如果实例是从节点,则会提供以下这些额外字段:

  • master_host: 主节点的Host名称或IP地址
  • master_port: 主节点监听的TCP端口
  • master_link_status: 连接状态(up或者down)
  • master_last_io_seconds_ago: 自上次与主节点交互以来,经过的秒数
  • master_sync_in_progress: 指示主节点正在与从节点同步

如果SYNC操作正在进行,则会提供以下这些字段:

  • master_sync_left_bytes: 同步完成前剩余的字节数
  • master_sync_last_io_seconds_ago: 在SYNC操作期间自上次传输IO以来的秒数

如果主从节点之间的连接断开了,则会提供一个额外的字段:

  • master_link_down_since_seconds: 自连接断开以来,经过的秒数

以下字段将始终提供:

  • connected_slaves: 已连接的从节点数

对每个从节点,将会添加以下行:

  • slaveXXX: id,地址,端口号,状态

下面是所有 cpu 相关的信息:

  • used_cpu_sys: 由Redis服务器消耗的系统CPU
  • used_cpu_user: 由Redis服务器消耗的用户CPU
  • used_cpu_sys_children: 由后台进程消耗的系统CPU
  • used_cpu_user_children: 由后台进程消耗的用户CPU

commandstats部分提供基于命令类型的统计,包含调用次数,这些命令消耗的总CPU时间,以及每个命令执行所消耗的平均CPU。

对于每一个命令类型,添加以下行:

  • cmdstat_XXX: calls=XXX,usec=XXX,usec_per_call=XXX

cluster部分当前只包含一个唯一的字段:

  • cluster_enabled: 表示已启用Redis集群

keyspace部分提供有关每个数据库的主字典的统计,统计信息是key的总数和带有过期key的总数。

对于每个数据库,提供以下行:

  • dbXXX: keys=XXX,expires=XXX
  • 语法:

    1
    127.0.0.1:6379> 
  • 返回值:

    多行字符串: 文本行的合集

    每一行包含了包含一种信息或者属性(从#字符开始)。 所有的属性都是以字段:值(field:value)的形式,以\r\n结尾。

  • 实例:

    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
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    127.0.0.1:6379> INFO
    # Server
    redis_version:6.2.6
    redis_git_sha1:00000000
    redis_git_dirty:0
    redis_build_id:eac5b3c736e2a107
    redis_mode:standalone
    os:Linux 3.10.0-1160.el7.x86_64 x86_64
    arch_bits:64
    multiplexing_api:epoll
    atomicvar_api:atomic-builtin
    gcc_version:4.8.5
    process_id:19069
    process_supervised:no
    run_id:94c6005986e59722cbf438a37cf5513236a5d841
    tcp_port:6379
    server_time_usec:1653071002486948
    uptime_in_seconds:449
    uptime_in_days:0
    hz:10
    configured_hz:10
    lru_clock:8903834
    executable:/opt/software/redis-6.2.6/src/redis-server
    config_file:/opt/software/redis-6.2.6/./redis.conf
    io_threads_active:0

    # Clients
    connected_clients:1
    cluster_connections:0
    maxclients:10000
    client_recent_max_input_buffer:0
    client_recent_max_output_buffer:0
    blocked_clients:0
    tracking_clients:0
    clients_in_timeout_table:0

    # Memory
    used_memory:873840
    used_memory_human:853.36K
    used_memory_rss:3063808
    used_memory_rss_human:2.92M
    used_memory_peak:935096
    used_memory_peak_human:913.18K
    used_memory_peak_perc:93.45%
    used_memory_overhead:810112
    used_memory_startup:810112
    used_memory_dataset:63728
    used_memory_dataset_perc:100.00%
    allocator_allocated:1032136
    allocator_active:1355776
    allocator_resident:3592192
    total_system_memory:1019572224
    total_system_memory_human:972.34M
    used_memory_lua:37888
    used_memory_lua_human:37.00K
    used_memory_scripts:0
    used_memory_scripts_human:0B
    number_of_cached_scripts:0
    maxmemory:0
    maxmemory_human:0B
    maxmemory_policy:noeviction
    allocator_frag_ratio:1.31
    allocator_frag_bytes:323640
    allocator_rss_ratio:2.65
    allocator_rss_bytes:2236416
    rss_overhead_ratio:0.85
    rss_overhead_bytes:-528384
    mem_fragmentation_ratio:3.78
    mem_fragmentation_bytes:2253680
    mem_not_counted_for_evict:0
    mem_replication_backlog:0
    mem_clients_slaves:0
    mem_clients_normal:0
    mem_aof_buffer:0
    mem_allocator:jemalloc-5.1.0
    active_defrag_running:0
    lazyfree_pending_objects:0
    lazyfreed_objects:0

    # Persistence
    loading:0
    current_cow_size:0
    current_cow_size_age:0
    current_fork_perc:0.00
    current_save_keys_processed:0
    current_save_keys_total:0
    rdb_changes_since_last_save:0
    rdb_bgsave_in_progress:0
    rdb_last_save_time:1653070888
    rdb_last_bgsave_status:ok
    rdb_last_bgsave_time_sec:0
    rdb_current_bgsave_time_sec:-1
    rdb_last_cow_size:180224
    aof_enabled:0
    aof_rewrite_in_progress:0
    aof_rewrite_scheduled:0
    aof_last_rewrite_time_sec:-1
    aof_current_rewrite_time_sec:-1
    aof_last_bgrewrite_status:ok
    aof_last_write_status:ok
    aof_last_cow_size:0
    module_fork_in_progress:0
    module_fork_last_cow_size:0

    # Stats
    total_connections_received:2
    total_commands_processed:11
    instantaneous_ops_per_sec:0
    total_net_input_bytes:237
    total_net_output_bytes:20373
    instantaneous_input_kbps:0.00
    instantaneous_output_kbps:0.00
    rejected_connections:0
    sync_full:0
    sync_partial_ok:0
    sync_partial_err:0
    expired_keys:0
    expired_stale_perc:0.00
    expired_time_cap_reached_count:0
    expire_cycle_cpu_milliseconds:21
    evicted_keys:0
    keyspace_hits:0
    keyspace_misses:0
    pubsub_channels:0
    pubsub_patterns:0
    latest_fork_usec:245
    total_forks:1
    migrate_cached_sockets:0
    slave_expires_tracked_keys:0
    active_defrag_hits:0
    active_defrag_misses:0
    active_defrag_key_hits:0
    active_defrag_key_misses:0
    tracking_total_keys:0
    tracking_total_items:0
    tracking_total_prefixes:0
    unexpected_error_replies:0
    total_error_replies:0
    dump_payload_sanitizations:0
    total_reads_processed:12
    total_writes_processed:11
    io_threaded_reads_processed:0
    io_threaded_writes_processed:0

    # Replication
    role:master
    connected_slaves:0
    master_failover_state:no-failover
    master_replid:6a79d6f2d97cb3525136444bb32aae6dd41d07e1
    master_replid2:0000000000000000000000000000000000000000
    master_repl_offset:0
    second_repl_offset:-1
    repl_backlog_active:0
    repl_backlog_size:1048576
    repl_backlog_first_byte_offset:0
    repl_backlog_histlen:0

    # CPU
    used_cpu_sys:1.938793
    used_cpu_user:1.406728
    used_cpu_sys_children:0.002974
    used_cpu_user_children:0.000991
    used_cpu_sys_main_thread:1.937100
    used_cpu_user_main_thread:1.407383

    # Modules

    # Errorstats

    # Cluster
    cluster_enabled:0

    # Keyspace
    127.0.0.1:6379>

可用版本>= 1.0.0.

1.11.24 LASTSAVE

以 UNIX 时间戳格式返回最近一次 Redis 成功将数据保存到磁盘上的时间。

LASTSAVE 通常被用来检查 BGSAVE 命令是否执行完成。通常是每隔几秒钟看一下 LASTSAVE 的是是否有变化。

  • 语法:

    1
    127.0.0.1:6379> LASTSAVE
  • 返回值:

    整数: 一个 UNIX 时间戳。

  • 实例:

    1
    2
    3
    127.0.0.1:6379> LASTSAVE
    (integer) 1653070888
    127.0.0.1:6379>

可用版本>= 1.0.0.

1.11.25 MONITOR

Redis MONITOR 命令用于实时打印出 Redis 服务器接收到的命令,调试用。

MONITOR 用来帮助我们知道数库正在做什么。可以通过 redis-clitelnet 调用 MONITOR

当 Redis 用做数据库或者分布式缓存时,MONITOR 可以帮助我们发现程序中的 bug 。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[root@localhost redis-6.2.6]# ./src/redis-cli -a yanpenggong
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> dbsize
(integer) 0
127.0.0.1:6379> set x 6
OK
127.0.0.1:6379> get x
"6"
127.0.0.1:6379> del x
(integer) 1
127.0.0.1:6379> GET x
(nil)
127.0.0.1:6379> QUIT
[root@localhost redis-6.2.6]#

通过 redis-cli 运行 MONITOR 时,可以发送 SIGINT (Ctrl+C) 信号来停止退出。

1
2
3
4
5
6
7
8
9
10
11
127.0.0.1:6379> MONITOR
OK
+1339518083.107412 [0 127.0.0.1:60866] "keys" "*"
+1339518087.877697 [0 127.0.0.1:60866] "dbsize"
+1339518090.420270 [0 127.0.0.1:60866] "set" "x" "6"
+1339518096.506257 [0 127.0.0.1:60866] "get" "x"
+1339518099.363765 [0 127.0.0.1:60866] "del" "x"
+1339518100.544926 [0 127.0.0.1:60866] "get" "x"
QUIT
+OK
Connection closed by foreign host.

通过 telnet 运行 MONITOR 时,可以发送 QUIT来停止退出。

  1. MONITOR 不记录的命令:

    处于安全方面的考虑,所有的管理相关的命令不会记录到 MONITOR的输出者。

    下面几个命令也不会记录:

    • AUTH
    • EXEC
    • HELLO
    • QUIT
  2. MONITOR 的消耗:

    因为 MONITOR流返回所有命令,所以用起来会有一定的消耗。 下面是一个基准测试对比:

    不带 MONITOR命令:

    1
    2
    3
    4
    5
    6
    $ src/redis-benchmark -c 10 -n 100000 -q
    PING_INLINE: 101936.80 requests per second
    PING_BULK: 102880.66 requests per second
    SET: 95419.85 requests per second
    GET: 104275.29 requests per second
    INCR: 93283.58 requests per second

    MONITOR命令 (redis-cli monitor > /dev/null):

    1
    2
    3
    4
    5
    6
    $ src/redis-benchmark -c 10 -n 100000 -q
    PING_INLINE: 58479.53 requests per second
    PING_BULK: 59136.61 requests per second
    SET: 41823.50 requests per second
    GET: 45330.91 requests per second
    INCR: 41771.09 requests per second

    通过上面的例子可以看到运行一个 MONITOR命令降低了超过 50% 的吞吐量。 运行多个 MONITOR会进一步降低性能。

  • 语法:

    1
    127.0.0.1:6379> MONITOR
  • 返回值:

    输出Redis服务器处理的指令流直到退出。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    127.0.0.1:6379> MONITOR
    OK
    +1339518083.107412 [0 127.0.0.1:60866] "keys" "*"
    +1339518087.877697 [0 127.0.0.1:60866] "dbsize"
    +1339518090.420270 [0 127.0.0.1:60866] "set" "x" "6"
    +1339518096.506257 [0 127.0.0.1:60866] "get" "x"
    +1339518099.363765 [0 127.0.0.1:60866] "del" "x"
    +1339518100.544926 [0 127.0.0.1:60866] "get" "x"

可用版本>= 1.0.0.

1.11.26 ROLE

Redis ROLE 命令返回实例在复制中担任的角色, 这个角色可以是 masterslave 或者 sentinel

除了角色之外, 命令还会返回与该角色相关的其他信息, 其中:

  • 主服务器将返回属下从服务器的 IP 地址和端口。
  • 从服务器将返回自己正在复制的主服务器的 IP 地址、端口、连接状态以及复制偏移量。
  • Sentinel 将返回自己正在监视的主服务器列表。
  • 语法:

    1
    127.0.0.1:6379> ROLE
  • 返回值:

    数组:第一个参数是 master, slave, sentinel 三个中的一个。

  • 实例:

    1
    2
    3
    4
    5
    127.0.0.1:6379> ROLE
    1) "master"
    2) (integer) 0
    3) (empty array)
    127.0.0.1:6379>

可用版本>= 2.8.12.

1.11.27 SAVE

Redis SAVE 命令用于执行同步保存操作,把 Redis 实例中某一时点的所有数据的快照以 RDB 文件的形式保存到磁盘上。

生产环境不要执行 SAVE 命令,因为这会阻塞所有其它的客户端。

可以使用 BGSAVE 代替。尽管如此,BGSAVE 也有执行失败的危险,SAVE 是转存最新数据集的最好也是最后一个方法。

详细参考 persistence documentation

  • 语法:

    1
    127.0.0.1:6379> SAVE
  • 返回值:

    字符串: 成功时返回 “OK”。

  • 实例:

    1
    2
    3
    127.0.0.1:6379> SAVE 
    OK
    127.0.0.1:6379>

可用版本>= 1.0.0.

1.11.28 SHUTDOWN

SHUTDOWN 命令执行如下操作:

1
2
3
4
- 停止所有客户端
- 如果配置了save 策略 则执行一个阻塞的save命令
- 如果开启了AOF,则刷新aof文件
- 关闭redis服务进程(redis-server)

如果配置了持久化策略,那么这个命令将能够保证在关闭redis服务进程的时候数据不会丢失。

如果仅仅在客户端执行 QUIT 命令,然后 执行 QUIT 命令,那么数据的完整性将不会被保证,因为其他客户端可能在执行这两个命令的期间修改数据库的数据。

注意: 一个没有配置持久化策略的redis实例 (没有aof配置, 没有 “save” 命令) 将不会在执行SHUTDOWN命令的时候转存一个rdb文件,可以提高关闭的速度,例如仅用来做缓存的 redis 不需要配置持久化转存。

  1. SAVE 和 NOSAVE 修饰符

    通过指定一个可选的修饰符可以改变这个命令的表现形式,比如:

    • SHUTDOWN SAVE 能够在即使没有配置持久化的情况下强制数据库存储。
    • SHUTDOWN NOSAVE 能够在配置一个或者多个持久化策略的情况下阻止数据库存储. (你可以假想它为一个中断服务的 ABORT 命令)。
  2. SHUTDOWN 关闭失败的情况

    当配置了 AOF 时,shutdown 可能会失败由于系统处于不允许立刻执行磁盘持久化操纵。

    当有一个AOF的子进程在执行AOF重写时,Redis 会简单的kill 该子进程。有两种列外的情况,SHUTDOWN 会返回失败:

    • AOF 刚刚打开,首次进行 AOF rewrite 创建初始的 AOF 文件。这种情况下停止redis将会丢失所有数据:一旦停止 redis时,虽然开启了AOF,但是还没有创建任何AOF文件。
    • 复制节点打开了 AOF,向 master 发起重连,执行数据全同步,然后重起AOF,创建初始AOF文件。可能会丢失复制自master节点的数据。

    如果我们只是想立刻关闭redis,而不管其它情况。正确的做法是先发送CONFIG appendonly no ,然后执行SHUTDOWN NOSAVE.。前一个命令关闭 AOF(如果打开AOF),终止可能存在的 AOF 重写子进程,这样后一个命令关闭不会失败。

  • 语法:

    1
    127.0.0.1:6379> SHUTDOWN [NOSAVE] [SAVE] 
  • 返回值:

    字符串: 当发生错误的时候返回状态码 . 当成功的时候不返回任何值,因为服务退出,链接关闭。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    127.0.0.1:6379> PING
    Error: Server closed the connection
    127.0.0.1:6379> PING
    PONG
    127.0.0.1:6379> SHUTDOWN
    not connected> redis
    Could not connect to Redis at 127.0.0.1:6379: Connection refused
    not connected>

可用版本>= 1.0.0.

1.11.29 SLAVEOF

Redis SLAVEOF 命令可以将当前服务器转变为指定服务器的从属服务器(slave server)。

注意: 从 Redis 5 起使用 REPLICAOF 替代 SLAVEOF。当然,为了向后兼容 SLAVEOF 命令仍然可用。

SLAVEOF 命令可以临时修改从节点的复制配置。如果当前服务器已经是某个主服务器(master server)的从属服务器,SLAVEOF NO ONE 命令会停止复制,把节点改为主节点。

SLAVEOF hostname port 可以使正在复制其它节点的 Redis 改为复制新的 hostname 和 port。

SLAVEOF hostname port 将会停止从旧的主节点复制,丢弃已经同步的旧的数据,并开始从新的节点同步数据。

SLAVEOF NO ONE 用来停止复制,把从节点改为主节点,但是不会丢弃已复制的数据。所以,当 Master 主节点出现问题时,可以把从节点变成 Master 主节点,使应用读/写新的主节点。当原来的主节点修复之后,可以把新的 Master 节点重新配置为从节点。

利用『 SLAVEOF NO ONE 不会丢弃同步所得数据集』这个特性,可以在主服务器失败的时候,将从属服务器用作新的主服务器,从而实现无间断运行。

  • 语法:

    1
    127.0.0.1:6379> SLAVEOF host port
  • 返回值:

    字符串:总是返回 OK 。

  • 实例:

    1
    2
    3
    4
    127.0.0.1:6379> SLAVEOF 127.0.0.1 6379
    OK
    127.0.0.1:6379> SLAVEOF NO ONE
    OK

可用版本>= 1.0.0.

1.11.30 SLOWLOG

Redis slowlog 是 Redis 用来记录查询执行时间的日志系统。

查询执行时间指的是不包括像客户端响应(talking)、发送回复等 IO 操作,而单单是执行一个查询命令所耗费的时间。

另外,slow log 保存在内存里面,读写速度非常快,因此你可以放心地使用它,不必担心因为开启 slow log 而损害 Redis 的速度。

  1. 读取 slow log

    慢日志记录在内存中,不会写到文件上。所以即使记录所有执行的命令到慢日志中性能开销也很小。

    读取慢日志命令:

    SLOWLOG GET 返回每一条慢日志。

    SLOWLOG GET n 返回最新的n条慢日志。

    注意:请使用新版 redis-cli 以便能解析慢日志输出,较老版本的 redis-cli 不支持多行嵌套。

  2. 响应输出格式

    1. 1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      redis 127.0.0.1:6379> slowlog get 2
      1) 1) (integer) 14
      2) (integer) 1309448221
      3) (integer) 15
      4) 1) "ping"
      2) 1) (integer) 13
      2) (integer) 1309448128
      3) (integer) 30
      4) 1) "slowlog"
      2) "get"
      3) "100"

    Redis 4.0 及之后版本新增域:

    1
    2
    5) "127.0.0.1:58217"
    6) "worker-123"

    每条慢日志由 4 或 6 部分组成:

    • 每条慢日志有一个递增的唯一 ID。
    • 记录慢日志的 Unix 时间戳。
    • 执行这个命令花费的时间,单位是微妙。
    • 数组形式的命令参数。
    • 客户端 ip 和端口 (4.0 only)。
    • 通过 CLIENT SETNAME 命令设置的客户端名字 (4.0 only)。

    可以用唯一 ID 来避免慢日志被处理多次(例如你有一个每当产生新的慢日志发送报警的脚本)。

    ID 在 Redis 运行期间不会重置,Redis 重启之后会重置 ID。

  3. 查询当前 slowlog 的长度

    SLOWLOG LEN 获取 slow log 的长度。

  4. 重置 slow log

    SLOWLOG RESET 命令用来重置 slowlog。一旦删除 slowlog 不可恢复。

  • 语法:

    1
    127.0.0.1:6379> SLOWLOG subcommand [argument]
  • 返回值:

    取决于不同命令,返回不同的值。

  • 实例:

    查看日志信息:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    127.0.0.1:6379> slowlog get 2
    1) 1) (integer) 14
    2) (integer) 1309448221
    3) (integer) 15
    4) 1) "ping"
    2) 1) (integer) 13
    2) (integer) 1309448128
    3) (integer) 30
    4) 1) "slowlog"
    2) "get"
    3) "100"

    查看当前日志的数量:

    1
    2
    127.0.0.1:6379> SLOWLOG LEN
    (integer) 14

    使用命令 SLOWLOG RESET 可以清空 slow log 。

    1
    2
    3
    4
    5
    6
    127.0.0.1:6379> SLOWLOG LEN
    (integer) 14
    127.0.0.1:6379> SLOWLOG RESET
    OK
    127.0.0.1:6379> SLOWLOG LEN
    (integer) 0

可用版本>= 2.2.12.

1.11.31 SYNC

从主服务节点初始化流复制。

Redis 从节点调用 SYNC 来从主节点启动流复制。在 redis 新版本中已经被 PSYNC 代替。

更多信息可以参考 Redis 复制

  • 语法:

    1
    127.0.0.1:6379> SYNC
  • 返回值:

    非标准数据, bulk 数据 + PING + 来自master的写请求。

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    127.0.0.1:6379> SYNC
    Entering replica output mode... (press Ctrl-C to quit)
    SYNC with master, discarding 175 bytes of bulk transfer...
    SYNC done. Logging commands from master.
    "ping"
    "ping"

可用版本>= 1.0.0.

1.12 Redis HyperLogLog

1.12.1 PFADD

Redis Pfadd 命令将所有元素参数添加到 HyperLogLog 数据结构中。

作为这个命令的副作用, HyperLogLog 内部可能会被更新, 以便反映一个不同的唯一元素估计数量(也即是集合的基数)。

如果 HyperLogLog 估计的近似基数(approximated cardinality)在命令执行之后出现了变化, 那么命令返回 1 , 否则返回 0 。 如果命令执行时给定的键不存在, 那么程序将先创建一个空的 HyperLogLog 结构, 然后再执行命令。

调用 PFADD 命令时可以只给定键名而不给定元素:

  • 如果给定键已经是一个 HyperLogLog , 那么这种调用不会产生任何效果;
  • 但如果给定的键不存在, 那么命令会创建一个空的 HyperLogLog , 并向客户端返回 1

要了解更多关于 HyperLogLog 数据结构的介绍知识, 请查阅 PFCOUNT命令的文档。

  • 语法:

    1
    127.0.0.1:6379> PFADD key element [element ...]
  • 返回值:

    整数, specifically:

    • 如果 HyperLogLog 的内部储存被修改了, 那么返回 1 , 否则返回 0 。
  • 实例:

    1
    2
    3
    4
    5
    127.0.0.1:6379> PFADD myset a b c d e f g
    (integer) 1
    127.0.0.1:6379> PFCOUNT myset
    (integer) 7
    127.0.0.1:6379>

可用版本>= 2.8.9.

时间复杂度: O(1) to add every element.

1.12.2 PFCOUNT

Redis PFCOUNT 命令返回给定 HyperLogLog 的基数估算值。
PFCOUNT 命令作用于单个键时, 返回储存在给定键的 HyperLogLog 的近似基数, 如果键不存在, 那么返回 0 。
PFCOUNT 命令作用于多个键时, 返回所有给定 HyperLogLog 的并集的近似基数, 这个近似基数是通过将所有给定 HyperLogLog 合并至一个临时 HyperLogLog 来计算得出的。
通过 HyperLogLog 数据结构, 用户可以使用少量固定大小的内存, 来储存集合中的唯一元素 (每个 HyperLogLog 只需使用 12k 字节内存,以及几个字节的内存来储存键本身)。
命令返回的可见集合(observed set)基数并不是精确值, 而是一个带有 0.81% 标准错误(standard error)的近似值。
举个例子, 为了记录一天会执行多少次各不相同的搜索查询, 一个程序可以在每次执行搜索查询时调用一次 PFADD, 并通过调用 PFCOUNT命令来获取这个记录的近似结果。

  • 语法:

    1
    127.0.0.1:6379> PFCOUNT key [key ...]
  • 返回值:

    整数, specifically:

    • 给定 HyperLogLog 包含的唯一元素的近似数量。
  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    127.0.0.1:6379> PFADD myset kungs1 kungs2 kungs3
    (integer) 1
    127.0.0.1:6379> PFADD myset kungs1 kungs2 kungs4
    (integer) 1
    127.0.0.1:6379> PFADD myset kungs1 kungs1 kungs1
    (integer) 0
    127.0.0.1:6379> PFADD myset kungs1 kungs2
    (integer) 0
    127.0.0.1:6379> PFCOUNT myset
    (integer) 4
    127.0.0.1:6379> PFADD myset-other a b c
    (integer) 1
    127.0.0.1:6379> PFCOUNT myset myset-other
    (integer) 7
    127.0.0.1:6379>

可用版本>= 2.8.9.

时间复杂度: O(1) with a very small average constant time when called with a single key. O(N) with N being the number of keys, and much bigger constant times, when called with multiple keys.

1.12.3 PFMERGE

Redis PFMERGE 命令将多个 HyperLogLog 合并为一个 HyperLogLog ,合并后的 HyperLogLog 的基数估算值是通过对所有 给定 HyperLogLog 进行并集计算得出的。

合并得出的 HyperLogLog 会被储存在 destkey 键里面, 如果该键并不存在, 那么命令在执行之前, 会先为该键创建一个空的 HyperLogLog 。

  • 语法:

    1
    127.0.0.1:6379> PFMERGE destkey sourcekey [sourcekey ...]
  • 返回值:

    字符串: OK.

  • 实例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    127.0.0.1:6379> PFADD myset kungs1 kungs2 kungs3
    (integer) 1
    127.0.0.1:6379> PFADD myset-other a b c
    (integer) 1
    127.0.0.1:6379> PFMERGE out myset myset-other
    OK
    127.0.0.1:6379> PFCOUNT out
    (integer) 6
    127.0.0.1:6379>

可用版本>= 2.8.9.

时间复杂度: O(N) to merge N HyperLogLogs, but with high constant times.

Redis协议详细规范

Redis客户端和服务器端通信使用名为 RESP (REdis Serialization Protocol) 的协议。虽然这个协议是专门为Redis设计的,它也可以用在其它 client-server 通信模式的软件上。

RESP 是下面条件的折中:

  • 实现起来简单。
  • 解析速度快。
  • 有可读性。

RESP 能序列化不同的数据类型,例如整型(integers)、字符串(strings)、数组(arrays)。额外还有特殊的错误类型。请求从客户端以字符串数组的形式发送到redis服务器,这些字符串表示要执行的命令的参数。Redis用特定于命令的数据类型回复。

RESP 是二进制安全的,并且不需要处理从一个进程发到另外一个进程的批量数据,因为它使用前缀长度来传输批量数据。

注意:这里概述的协议仅用于客户机-服务器通信。Redis集群使用不同的二进制协议在节点之间交换消息。

1. 网络层

连到Redis服务器的客户端建立了一个到6379端口的TCP连接。

虽然RESP在技术上不特定于TCP,但是在Redis的上下文中,该协议仅用于TCP连接(或类似的面向流的连接,如unix套接字)。

2. 请求-响应模型

Redis接受由不同参数组成的命令。一旦收到命令,就会对其进行处理,并将应答发送回客户端。

这是最简单的模型,但是有两个例外:

  • Redis 支持管道pipelining。所以,客户端可以一次发送多个命令,然后再等待应答。
  • 当一个Redis客户端订阅一个频道,那么协议会改变语义并变成pushprotocol, 也就是说,客户客户端不再需要发送命令,因为服务器端会一收到新消息,就会自动发送给客户端。

除了上面两个例外情况,Redis协议是一个简单的请求-响应协议。

3. RESP 协议解释

RESP 协议在Redis1.2被引入,直到Redis2.0才成为和Redis服务器通信的标准。这个协议需要在你的Redis客户端实现。

RESP 是一个支持多种数据类型的序列化协议:简单字符串(Simple Strings),错误( Errors),整型( Integers), 大容量字符串(Bulk Strings)和数组(Arrays)。

RESP在Redis中作为一个请求-响应协议以如下方式使用:

  • 客户端以大容量字符串RESP数组的方式发送命令给服务器端。
  • 服务器端根据命令的具体实现返回某一种RESP数据类型。

在 RESP 中,数据的类型依赖于首字节:

  • 单行字符串(Simple Strings): 响应的首字节是 “+”
  • 错误(Errors): 响应的首字节是 “-“
  • 整型(Integers): 响应的首字节是 “:”
  • 多行字符串(Bulk Strings): 响应的首字节是“$“
  • 数组(Arrays): 响应的首字节是 “*

另外,RESP可以使用大容量字符串或者数组类型的特殊变量表示空值,下面会具体解释。RESP协议的不同部分总是以 “\r\n” (CRLF) 结束。

4. RESP 单行字符串

单行字符串编码方法: 加号后面跟着一个不包含回车或换行字符的字符串 (不允许出现换行),以CRLF(“\r\n”)结尾。

单行字符串通常被用来传输非二进制安全字符串并且消耗极小。例如,许多redis命令在成功时回复”OK”,即简单字符串用以下5个字节编码:

1
"+OK\r\n"

为了发送二进制安全的字符串,需要使用RESP的多行字符串(Bulk Strings)替代。

当Redis返回单行字符串(Simple String)时,客户端lib应该返回去掉首字符加号和结尾CRLF字符的字符串给调用者。

5. RESP 错误

RESP 有特殊类型来处理错误。errors类型除了首字符是减号 ‘-‘不是加号以外,其它跟简单字符串一样。RESP中简单字符和错误的真正区别是:错误被客户端当作异常处理,组成错误类型的字符串是错误消息自身。

基本格式如下:

1
"-Error message\r\n"

错误应答只在发生异常时发送,例如,要执行命令的参数数据类型不匹配或者命令不存在等。当收到错误返回时,客户端lib应该抛出一个异常。

错误返回例子:

1
2
-ERR unknown command 'foobar'
-WRONGTYPE Operation against a key holding the wrong kind of value

从”-“后面第一个单词起,直到第一个空格或者换行,表示返回的错误类型。这是Redis的一种约定,并不是RESP协议的要求。

ERR 是一个通用错误, 而 WRONGTYPE 是表示更具体的错误,意味着客户端在错误的数据类型上执行操作。这被叫做错误前缀(Error Prefix), 使客户端不用依赖具体错误消息就知道返回的错误类型,错误消息可能会随着时间而变化。

客户端实现可能会对不同异常返回不同类型的错误,或者可能提供一种通用的方式来捕获错误,通过以字符串的形式直接返回错误名给调用者。

尽管如此,这种特性不能认为很重要,因为它很少被使用。一小部分客户端的实现可能会返回通用错误条件,例如false。

6. RESP 整数

整数类型是由以冒号开头,CRLF结尾,中间是字符串形式表示的数字。 例如 “:0\r\n”, 或 “:1000\r\n” 都是整数回复。

很多Redis命令返回RESP整数,像 INCR, LLENLASTSAVE.

返回的整数并没有特别的意义, INCR 返回的是一个递增的数字, LASTSAVE 返回的是Unix时间戳等。返回的整数有效值需要在有符号64位整数范围内。

整数返回也被广泛的用来返回 true 或 false。比如 EXISTSSISMEMBER 命令返回1表示true,返回0表示false。

其它命令像 SADD, SREMSETNX 如果操作被执行则返回1,否则返回0。

返回整数回复的命令: SETNX, DEL, EXISTS, INCR, INCRBY, DECR, DECRBY, DBSIZE, LASTSAVE, RENAMENX, MOVE, LLEN, SADD, SREM, SISMEMBER, SCARD.

6. RESP 多行字符串

多行字符串被用来表示最大512MB长的二进制安全字符串。

多行字符串编码方式:

  • 美元符 “$“ 后面跟着组成字符串的字节数(前缀长度),并以 CRLF 结尾。
  • 实际的字符串数据。
  • 结尾是 CRLF。

所以,字符串 “foobar” 编码如下:

1
"$6\r\nfoobar\r\n"

空字符串编码格式:

1
"$0\r\n\r\n"

RESP 多行字符串(Bulk Strings) 也可以使用一个特殊的用来表示空值的格式表示不存在的值。在这种格式里长度值为-1,数据部分不存在,所以空(Null)用如下方式表示:

1
"$-1\r\n"

叫做空的多行字符串Null Bulk String。

客户端API库不应该返回空串,当服务器端响应一个空的多行字符串时,API库可以返回一个空对象给调用者。例如,Ruby库应该返回 ‘nil’ ,而C库应该返回NULL。

7. RESP 数组

客户端使用 RESP 数组发送命令到 Redis 服务端。同样地,某些命令的应答使用RESP数组返回元素的集合给Redis客户端。 LRANGE 命令返回元素列表就是一个例子。

RESP 数组使用如下格式发送:

  • 以星号* 为首字符,接着是表示数组中元素个数的十进制数,最后以 CRLF 结尾。
  • 外加数组中每个 RESP 类型的元素。

空数组表示:

1
"*0\r\n"

有两个 RESP 多行字符串”foo” 和”bar”元素的 RESP 数组 :

1
"*2\r\n$3\r\nfoo\r\n$3\r\nbar\r\n"

在前缀 *<count>CRLF 的后面,组成数组的其它数据类型一个接在另一个后面。 例如包含三个整数的数组编码方式:

1
"*3\r\n:1\r\n:2\r\n:3\r\n"

数组可以包含混合类型,不一定必须是同一种类型。例如,4个整型和1个多行字符串编码方式:

1
2
3
4
5
6
7
*5\r\n
:1\r\n
:2\r\n
:3\r\n
:4\r\n
$6\r\n
foobar\r\n

(为了方便阅读,应答分成多行来展示)

第一个行表示 *5\r\n 说明后面有5个应答。这些应答组成一个大的应答一起发送。

空数组的概念也是存在的,另一个表示空值的方式(通常使用多行空字符串,历史遗留导致有这两种格式)。

例如,当 BLPOP 命令超时,它会返回一个空数组,数组的计数器是-1 :

1
"*-1\r\n"

当 Redis 返回一个空数组的时候,Redis客户端库API应该返回一个空对象而不是返回一个空数组。 这对区分空列表和其它不同情况(像 BLPOP 命令超时情况)是必要的。

数组的数组也是可行的。例如,一个含有两个数组元素的数组编码方式:

1
2
3
4
5
6
7
8
*2\r\n
*3\r\n
:1\r\n
:2\r\n
:3\r\n
*2\r\n
+Foo\r\n
-Bar\r\n

(为了方便阅读,分成多行来展示).

上面的 RESP 数据类型包含两个数组,一个数组包含三个整数1, 2, 3 ,另一个是简单字符串和一个错误类型。

8. 数组中的空元素

数组中可以有为空的元素。主要使用在Redis应答中,为了表示这个元素丢失并且不是一个空的字符串。当SORT命令使用GET 模式选项,并且特定的key丢失的时会出现这种应答。 含有有空元素的应答数组例子:

1
2
3
4
5
6
*3\r\n
$3\r\n
foo\r\n
$-1\r\n
$3\r\n
bar\r\n

第二个元素是空,客户端库应该返回像下面这样的数据:

1
["foo",nil,"bar"]

这不是前面提到的异常情况,这只是说明协议的一个例子。

9. 发送命令到Redis服务器

至此,我们已经很熟悉RESP序列化格式,写一个Redis客户端库的实现会变得很容易。我们可以进一步说明客户端和服务端如何交互工作:

  • 客户端发送包含只有多行字符串的数组给Redis服务器。
  • Redis 服务器给客户端发送任意有效的 RESP 数据类型作为应答。

下面是一个典型的交互过程例子:

客户端发送命令 LLEN mylist 来获取存储在 mylist 键中列表的长读,然后服务器端返回整数应答(C: 代表客户端, S: 代表服务器端).

1
2
3
4
5
6
7
C: *2\r\n
C: $4\r\n
C: LLEN\r\n
C: $6\r\n
C: mylist\r\n

S: :48293\r\n

为了方便理解我们用换行把协议分成不同部分,实际上客户端发送的是一个整体没有换行:*2\r\n$4\r\nLLEN\r\n$6\r\nmylist\r\n as a whole.

10. 管道和多个命令

客户端可以使用同一个连接发送多个命令。通过管道客户端可以一次写操作发送多个命令,发送下一个命令前不需要等待前一个命令的应答。所有应答可以在最后被读取。

关于管道详细参考 page about Pipelining.

11. 内联命令

有时你手边只能操作telnet 并且需要给Redis 服务器端发送命令。虽然Redis协议是容易实现的,但并不适合用在交互会话。redis-cli 也不是随时都能可用。因此,redis还以一种特殊的方式接受为人类设计的命令,称为内联命令格式。

以下是使用内联命令进行服务器/客户端聊天的示例(服务器聊天以s开头,客户端聊天以c开头)。

1
2
C: PING
S: +PONG

以下是返回整数的内联命令的另一个示例:

1
2
C: EXISTS somekey
S: :0

基本上,您只需在telnet会话中编写空格分隔的参数。由于统一请求协议中没有以*开头的命令,因此Redis能够检测到这种情况并解析您的命令。

12. Redis 协议的高性能解析器

虽然redis协议是非常容易被人阅读和实现的,但是它可以以类似于二进制协议的性能来实现。

RESP 使用带前缀的长度来传输批量数据,因此不需要像使用json那样扫描有效负载以查找特殊字符,也不需要引用需要发送到服务器的有效负载。

批量和多批量长度可以使用代码进行处理,代码对每个字符执行单个操作,同时扫描CR字符,如以下C代码:

RESP 使用带前缀的长度来传输多行数据,因此不需要像使用json那样扫描有效负载以查找特殊字符,也不需要引用需要发送到服务器的有效负载。

多行和多个多行长度可以使用代码进行处理,代码对每个字符执行单个操作,同时扫描CR字符,如以下C代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>

int main(void) {
unsigned char *p = "$123\r\n";
int len = 0;

p++;
while(*p != '\r') {
len = (len*10)+(*p - '0');
p++;
}

/* Now p points at '\r', and the len is in bulk_len. */
printf("%d\n", len);
return 0;
}

在识别出第一个CR之后,可以跳过它和下面的LF,而不需要任何处理。然后,可以使用不以任何方式检查有效负载的单个读取操作读取大容量数据。最后,剩余的CR和LF字符将被丢弃,而不进行任何处理。

Redis协议有着与二进制协议可比的性能,更重要的是易于在大多数高级语言中实现,从而减少了客户端软件中的错误数量。

Redis键空间通知

重要:键空间通知功能自2.8.0版本开始可用。

1. 功能概述

键空间通知允许客户端订阅发布/订阅频道,以便以某种方式接收影响Redis数据集的事件。可能接收的事件示例如下:

  • 所有影响给定键的命令。
  • 所有接收LPUSH操作的键。
  • 所有在数据库0中到期的键。

事件使用Redis的普通发布/订阅层传递,因此实现了发布/订阅的客户端无需修改即可使用此功能。由于Redis的发布/订阅是fire and forget,因此如果你的应用要求可靠的事件通知,目前还不能使用这个功能,也就是说,如果你的发布/订阅客户端断开连接,并在稍后重连,那么所有在客户端断开期间发送的事件将会丢失。将来有计划允许更可靠的事件传递,但可能会在更一般的层面上解决,要么为发布/订阅本身带来可靠性,要么允许Lua脚本拦截发布/订阅的消息以执行推送等操作,就像往队列里推送事件一样。

2. 事件类型

键空间通知的实现是为每一个影响Redis数据空间的操作发送两个不同类型的事件。例如,在数据库0中名为mykey的键上执行DEL操作,将触发两条消息的传递,完全等同于下面两个PUBLISH命令:

1
2
PUBLISH __keyspace@0__:mykey del
PUBLISH __keyevent@0__:del mykey

以上很容易看到,一个频道允许监听所有以键mykey为目标的所有事件,以及另一个频道允许获取有关所有DEL操作目标键的信息。第一种事件,在频道中使用keyspace前缀的被叫做键空间通知,第二种,使用keyevent前缀的,被叫做键事件通知。在以上例子中,为键mykey生成了一个del事件。 会发生什么:

  • 键空间频道接收到的消息是事件的名称。
  • 键事件频道接收到的消息是键的名称。

可以只启用其中一种通知,以便只传递我们感兴趣的事件子集。

3. 配置

默认情况下,键空间事件通知是不启用的,因为虽然不太明智,但该功能会消耗一些CPU。可以使用redis.conf中的notify-keyspace-events或者使用CONFIG SET命令来开启通知。将参数设置为空字符串会禁用通知。 为了开启通知功能,使用了一个非空字符串,由多个字符组成,每一个字符都有其特殊的含义,具体参见下表:

1
2
3
4
5
6
7
8
9
10
11
K     键空间事件,以__keyspace@<db>__前缀发布。
E 键事件事件,以__keyevent@<db>__前缀发布。
g 通用命令(非类型特定),如DEL,EXPIRE,RENAME等等
$ 字符串命令
l 列表命令
s 集合命令
h 哈希命令
z 有序集合命令
x 过期事件(每次键到期时生成的事件)
e 被驱逐的事件(当一个键由于达到最大内存而被驱逐时产生的事件)
A g$lshzxe的别名,因此字符串AKE表示所有的事件。

字符串中应当至少存在K或者E,否则将不会传递事件,不管字符串中其余部分是什么。例如,要为列表开启键空间事件,则配置参数必须设置为Kl,以此类推。字符串KEA可以用于开启所有可能的事件。

4. 不同的命令生成的事件

根据以下列表,不同的命令产生不同种类的事件。

  • DEL命令为每一个删除的key生成一个del事件。
  • RENAME生成两个事件,一个是为源key生成的rename_from事件,一个是为目标key生成的rename_to事件。
  • EXPIRE在给一个键设置有效期时,会生成一个expire事件,或者每当设置有效期导致键被删除时,生成expired事件(请查阅EXPIRE文档以获取更多信息)。
  • SORT会在使用STORE选项将结果存储到新键时,生成一个sortstore事件。如果结果列表为空,且使用了STORE选项,并且已经存在具有该名称的键时,那个键将被删除,因此在这种场景下会生成一个del事件。
  • SET以及所有其变种(SETEXSETNXGETSET)生成set事件。但是SETEX还会生成一个expire事件。
  • MSET为每一个key生成一个set事件。
  • SETRANGE生成一个setrange事件。
  • INCRDECRINCRBYDECRBY命令都生成incrby事件。
  • INCRBYFLOAT生成一个incrbyfloat事件。
  • APPEND生成一个append事件。
  • LPUSHLPUSHX生成一个lpush事件,即使在可变参数情况下也是如此。
  • RPUSHRPUSHX生成一个rpush事件,即使在可变参数情况下也是如此。
  • RPOP生成rpop事件。此外,如果键由于列表中的最后一个元素弹出而被删除,则会生成一个del事件。
  • LPOP生成lpop事件。此外,如果键由于列表中的最后一个元素弹出而被删除,则会生成一个del事件。
  • LINSERT生成一个linsert事件。
  • LSET生成一个lset事件。
  • LTRIM生成ltrim事件,此外,如果结果列表为空或者键被移除,将会生成一个del事件。
  • RPOPLPUSHBRPOPLPUSH生成rpop事件和lpush事件。这两种情况下,顺序都将得到保证(lpush事件将总是在rpop事件之后传递)。此外,如果结果列表长度为零且键被删除,则会生成一个del事件。
  • HSETHSETNX以及HMSET都生成一个hset事件。
  • HINCRBY生成一个hincrby事件。
  • HINCRBYFLOAT生成一个hincrbyfloat事件。
  • HDEL生成一个hdel事件,此外,如果结果哈希集为空或者键被移除,将生成一个del事件。
  • SADD生成一个sadd事件,即使在可变参数情况下也是如此。
  • SREM生成一个srem事件,此外,如果结果集合为空或者键被移除,将生成一个del事件。
  • SMOVE为每一个源key生成一个srem事件,以及为每一个目标key生成一个sadd事件。
  • SPOP生成一个spop事件,此外,如果结果集合为空或者键被移除,将生成一个del事件。
  • SINTERSTORESUNIONSTORESDIFFSTORE分别生成sinterstoresunionostoresdiffstore事件。在特殊情况下,结果集是空的,并且存储结果的键已经存在,因为删除了键,所以会生成del事件。
  • ZINCR生成一个zincr事件。
  • ZADD生成一个zadd事件,即使添加了多个元素。
  • ZREM生成一个zrem事件,即使删除了多个元素。当结果有序集合为空且生成了键,则会生成额外的del事件。
  • ZREMBYSCORE生成一个zrembyscore事件。当结果有序集合为空且生成了键,则会生成额外的del事件。
  • ZREMBYRANK生成一个zrembyrank事件。当结果有序集合为空且生成了键,则会生成额外的del事件。
  • ZINTERSTOREZUNIONSTORE分别生成zinterstorezunionstore事件。在特殊情况下,结果有序集合是空的,并且存储结果的键已经存在,因为删除了键,所以会生成del事件。
  • 每次一个拥有过期时间的键由于过期而从数据集中移除时,将生成一个expired事件。
  • 每次一个键由于maxmemory策略而被从数据集中驱逐,以便释放内存时,将生成一个evicted事件。

重要 所有命令仅在真正修改目标键时才生成事件。例如,使用SREM命令从集合中删除一个不存在的元素将不会改变键的值,因此不会生成任何事件。如果对某个命令如何生成事件有疑问,最简单的方法是自己观察:

1
2
3
4
$ redis-cli config set notify-keyspace-events KEA
$ redis-cli --csv psubscribe '__key*__:*'
Reading messages... (press Ctrl-C to quit)
"psubscribe","__key*__:*",1

此时,在另外一个终端使用redis-cli发送命令到Redis服务器,并观察生成的事件:

1
2
3
"pmessage","__key*__:*","__keyspace@0__:foo","set"
"pmessage","__key*__:*","__keyevent@0__:set","foo"
...

5. 过期事件的时间安排

设置了生存时间的键由Redis以两种方式过期:

  • 当命令访问键时,发现键已过期。
  • 通过后台系统在后台逐步查找过期的键,以便能够收集那些从未被访问的键。

当通过以上系统之一访问键且发现键已经过期时,将生成expired事件。因此无法保证Redis服务器在键过期的那一刻同时生成expired事件。如果没有命令不断地访问键,并且有很多键都有关联的TTL,那么在键的生存时间降至零到生成expired事件之间,将会有明显的延迟。基本上,expired事件是在Redis服务器删除键的时候生成的,而不是在理论上生存时间达到零值时生成的。

Redis复制

在 Redis 复制的基础上,使用和配置主从复制非常简单,能使得从 Redis 服务器(下文称 slave)能精确得复制主 Redis 服务器(下文称 master)的内容。每次当 slave 和 master 之间的连接断开时, slave 会自动重连到 master 上,并且无论这期间 master 发生了什么, slave 都将尝试让自身成为 master 的精确副本。

这个系统的运行依靠三个主要的机制:

  • 当一个 master 实例和一个 slave 实例连接正常时, master 会发送一连串的命令流来保持对 slave 的更新,以便于将自身数据集的改变复制给 slave , :包括客户端的写入、key 的过期或被逐出等等。
  • 当 master 和 slave 之间的连接断开之后,因为网络问题、或者是主从意识到连接超时, slave 重新连接上 master 并会尝试进行部分重同步:这意味着它会尝试只获取在断开连接期间内丢失的命令流。
  • 当无法进行部分重同步时, slave 会请求进行全量重同步。这会涉及到一个更复杂的过程,例如 master 需要创建所有数据的快照,将之发送给 slave ,之后在数据集更改时持续发送命令流到 slave 。

Redis使用默认的异步复制,其特点是低延迟和高性能,是绝大多数 Redis 用例的自然复制模式。但是,从 Redis 服务器会异步地确认其从主 Redis 服务器周期接收到的数据量。

客户端可以使用 WAIT 命令来请求同步复制某些特定的数据。但是,WAIT 命令只能确保在其他 Redis 实例中有指定数量的已确认的副本:在故障转移期间,由于不同原因的故障转移或是由于 Redis 持久性的实际配置,故障转移期间确认的写入操作可能仍然会丢失。你可以查看 Sentinel 或 Redis 集群文档,了解关于高可用性和故障转移的更多信息。本文的其余部分主要描述 Redis 基本复制功能的基本特性。

接下来的是一些关于 Redis 复制的非常重要的事实:

  • Redis 使用异步复制,slave 和 master 之间异步地确认处理的数据量
  • 一个 master 可以拥有多个 slave
  • slave 可以接受其他 slave 的连接。除了多个 slave 可以连接到同一个 master 之外, slave 之间也可以像层叠状的结构(cascading-like structure)连接到其他 slave 。自 Redis 4.0 起,所有的 sub-slave 将会从 master 收到完全一样的复制流。
  • Redis 复制在 master 侧是非阻塞的。这意味着 master 在一个或多个 slave 进行初次同步或者是部分重同步时,可以继续处理查询请求。
  • 复制在 slave 侧大部分也是非阻塞的。当 slave 进行初次同步时,它可以使用旧数据集处理查询请求,假设你在 redis.conf 中配置了让 Redis 这样做的话。否则,你可以配置如果复制流断开, Redis slave 会返回一个 error 给客户端。但是,在初次同步之后,旧数据集必须被删除,同时加载新的数据集。 slave 在这个短暂的时间窗口内(如果数据集很大,会持续较长时间),会阻塞到来的连接请求。自 Redis 4.0 开始,可以配置 Redis 使删除旧数据集的操作在另一个不同的线程中进行,但是,加载新数据集的操作依然需要在主线程中进行并且会阻塞 slave 。
  • 复制既可以被用在可伸缩性,以便只读查询可以有多个 slave 进行(例如 O(N) 复杂度的慢操作可以被下放到 slave ),或者仅用于数据安全。
  • 可以使用复制来避免 master 将全部数据集写入磁盘造成的开销:一种典型的技术是配置你的 master Redis.conf 以避免对磁盘进行持久化,然后连接一个 slave ,其配置为不定期保存或是启用 AOF。但是,这个设置必须小心处理,因为重新启动的 master 程序将从一个空数据集开始:如果一个 slave 试图与它同步,那么这个 slave 也会被清空。

1. 当 master 关闭持久化时,复制的安全性

在使用 Redis 复制功能时的设置中,强烈建议在 master 和在 slave 中启用持久化。当不可能启用时,例如由于非常慢的磁盘性能而导致的延迟问题,应该配置实例来避免重置后自动重启

为了更好地理解为什么关闭了持久化并配置了自动重启的 master 是危险的,检查以下故障模式,这些故障模式中数据会从 master 和所有 slave 中被删除:

  1. 我们设置节点 A 为 master 并关闭它的持久化设置,节点 B 和 C 从 节点 A 复制数据。
  2. 节点 A 崩溃,但是他有一些自动重启的系统可以重启进程。但是由于持久化被关闭了,节点重启后其数据集合为空。
  3. 节点 B 和 节点 C 会从节点 A 复制数据,但是节点 A 的数据集是空的,因此复制的结果是它们会销毁自身之前的数据副本。

当 Redis Sentinel 被用于高可用并且 master 关闭持久化,这时如果允许自动重启进程也是很危险的。例如, master 可以重启的足够快以致于 Sentinel 没有探测到故障,因此上述的故障模式也会发生。

任何时候数据安全性都是很重要的,所以如果 master 使用复制功能的同时未配置持久化,那么自动重启进程这项应该被禁用。

2. Redis 复制功能是如何工作的

每一个 Redis master 都有一个 replication ID :这是一个较大的伪随机字符串,标记了一个给定的数据集。每个 master 也持有一个偏移量,master 将自己产生的复制流发送给 slave 时,发送多少个字节的数据,自身的偏移量就会增加多少,目的是当有新的操作修改自己的数据集时,它可以以此更新 slave 的状态。复制偏移量即使在没有一个 slave 连接到 master 时,也会自增,所以基本上每一对给定的

Replication ID, offset

都会标识一个 master 数据集的确切版本。

当 slave 连接到 master 时,它们使用 PSYNC 命令来发送它们记录的旧的 master replication ID 和它们至今为止处理的偏移量。通过这种方式, master 能够仅发送 slave 所需的增量部分。但是如果 master 的缓冲区中没有足够的命令积压缓冲记录,或者如果 slave 引用了不再知道的历史记录(replication ID),则会转而进行一个全量重同步:在这种情况下, slave 会得到一个完整的数据集副本,从头开始。

下面是一个全量同步的工作细节:

master 开启一个后台保存进程,以便于生产一个 RDB 文件。同时它开始缓冲所有从客户端接收到的新的写入命令。当后台保存完成时, master 将数据集文件传输给 slave, slave将之保存在磁盘上,然后加载文件到内存。再然后 master 会发送所有缓冲的命令发给 slave。这个过程以指令流的形式完成并且和 Redis 协议本身的格式相同。

你可以用 telnet 自己进行尝试。在服务器正在做一些工作的同时连接到 Redis 端口并发出 SYNC 命令。你将会看到一个批量传输,并且之后每一个 master 接收到的命令都将在 telnet 回话中被重新发出。事实上 SYNC 是一个旧协议,在新的 Redis 实例中已经不再被使用,但是其仍然向后兼容:但它不允许部分重同步,所以现在 PSYNC 被用来替代 SYNC。

之前说过,当主从之间的连接因为一些原因崩溃之后, slave 能够自动重连。如果 master 收到了多个 slave 要求同步的请求,它会执行一个单独的后台保存,以便于为多个 slave 服务。

3. 无需磁盘参与的复制

正常情况下,一个全量重同步要求在磁盘上创建一个 RDB 文件,然后将它从磁盘加载进内存,然后 slave以此进行数据同步。

如果磁盘性能很低的话,这对 master 是一个压力很大的操作。Redis 2.8.18 是第一个支持无磁盘复制的版本。在此设置中,子进程直接发送 RDB 文件给 slave,无需使用磁盘作为中间储存介质。

4. 配置

配置基本的 Redis 复制功能是很简单的:只需要将以下内容加进 slave 的配置文件:

slaveof 192.168.1.1 6379

当然你需要用你自己的 master IP 地址(或者主机名)和端口替换掉 192.168.1.1 6379。另一种方法,你也可以使用 SLAVEOF 命令, master 会开启一个跟 slave 间的同步。

还有一些参数用于调节内存中保存的缓冲积压部分(replication backlog),以便执行部分重同步。详见 redis.conf 和 Redis Distribution 了解更多信息。

无磁盘复制可以使用 repl-diskless-sync 配置参数。repl-diskless-sync-delay 参数可以延迟启动数据传输,目的可以在第一个 slave就绪后,等待更多的 slave就绪。可以在 Redis Distribution 例子中的 redis.conf 中看到更多细节信息。

5. 只读性质的 slave

自从 Redis 2.6 之后, slave 支持只读模式且默认开启。redis.conf 文件中的 slave-read-only 变量控制这个行为,且可以在运行时使用 CONFIG SET 来随时开启或者关闭。

只读模式下的 slave 将会拒绝所有写入命令,因此实践中不可能由于某种出错而将数据写入 slave 。但这并不意味着该特性旨在将一个 slave 实例暴露到 Internet ,或者更广泛地说,将之暴露在存在不可信客户端的网络,因为像 DEBUG 或者 CONFIG 这样的管理员命令仍在启用。但是,在 redis.conf 文件中使用 rename-command 指令可以禁用上述管理员命令以提高只读实例的安全性。

您也许想知道为什么可以还原只读设置,并有可以通过写入操作来设置 slave 实例。如果 slave 跟 master 在同步或者 slave 在重启,那么这些写操作将会无效,但是将短暂数据存储在 writable slave 中还是有一些合理的用例的。

例如,计算 slow Set 或者 Sorted Set 的操作并将它们存储在本地 key 中是多次观察到的使用 writable slave 的用例。

但是注意,4.0 版本之前的 writable slaves 不能用生存时间来淘汰 key 。这意味着,如果你使用 EXPIRE 或者其他命令为 key 设置了最大 TTL 的话,你将会在键值计数(count of keys)中看到这个 key ,并且它还在内存中。所以总的来说,将 writable slaves 和设置过 TTL 的 key 混用将会导致问题。

Redis 4.0 RC3 及更高版本彻底解决了这个问题,现在 writable slaves 能够像 master 一样驱逐 TTL 设置过的 key 了,但 DB 编号大于 63(但默认情况下,Redis实例只有16个数据库)的 key 除外。

另请注意,由于 Redis 4.0 writable slaves 仅能本地,并且不会将数据传播到与该实例相连的 sub-slave 上。sub-slave 将总是接收与最顶层 master 向 intermediate slaves 发送的复制流相同的复制流。所以例如在以下设置中:

A —-> B ——> C

及时节点 B 是可写的,C 也不会看到 B 的写入,而是将拥有和 master 实例 A 相同的数据集。

6. 设置一个 slave 对 master 进行验证

如果你的 master 通过 requirepass 设置了密码,则在所有同步操作中配置 slave 使用该密码是很简单的。

要在正在运行的实例上执行此操作,请使用 redis-cli 并输入:

config set masterauth

要永久设置的话,请将其添加到您的配置文件中:

masterauth

7. 允许只写入 N 个附加的副本

从Redis 2.8开始,只有当至少有 N 个 slave 连接到 master 时,才有可能配置 Redis master 接受写查询。

但是,由于 Redis 使用异步复制,因此无法确保 slave 是否实际接收到给定的写命令,因此总会有一个数据丢失窗口。

以下是该特性的工作原理:

  • Redis slave 每秒钟都会 ping master,确认已处理的复制流的数量。
  • Redis master 会记得上一次从每个 slave 都收到 ping 的时间。
  • 用户可以配置一个最小的 slave 数量,使得它滞后 <= 最大秒数。

如果至少有 N 个 slave ,并且滞后小于 M 秒,则写入将被接受。

你可能认为这是一个尽力而为的数据安全机制,对于给定的写入来说,不能保证一致性,但至少数据丢失的时间窗限制在给定的秒数内。一般来说,绑定的数据丢失比不绑定的更好。

如果条件不满足,master 将会回复一个 error 并且写入将不被接受。

这个特性有两个配置参数:

  • min-slaves-to-write
  • min-slaves-max-lag <秒数>

有关更多信息,请查看随 Redis 源代码发行版一起提供的示例 redis.conf 文件。

8. Redis 复制如何处理 key 的过期

Redis 的过期机制可以限制 key 的生存时间。此功能取决于 Redis 实例计算时间的能力,但是,即使使用 Lua 脚本更改了这些 key,Redis slaves 也能正确地复制具有过期时间的 key。

为了实现这样的功能,Redis 不能依靠主从使用同步时钟,因为这是一个无法解决的并且会导致 race condition 和数据集不一致的问题,所以 Redis 使用三种主要的技术使过期的 key 的复制能够正确工作:

  • slave 不会让 key 过期,而是等待 master 让 key 过期。当一个 master 让一个 key 到期(或由于 LRU 算法将之驱逐)时,它会合成一个 DEL 命令并传输到所有的 slave。
  • 但是,由于这是 master 驱动的 key 过期行为,master 无法及时提供 DEL 命令,所以有时候 slave 的内存中仍然可能存在在逻辑上已经过期的 key 。为了处理这个问题,slave 使用它的逻辑时钟以报告只有在不违反数据集的一致性的读取操作(从主机的新命令到达)中才存在 key。用这种方法,slave 避免报告逻辑过期的 key 仍然存在。在实际应用中,使用 slave 程序进行缩放的 HTML 碎片缓存,将避免返回已经比期望的时间更早的数据项。
  • 在Lua脚本执行期间,不执行任何 key 过期操作。当一个Lua脚本运行时,从概念上讲,master 中的时间是被冻结的,这样脚本运行的时候,一个给定的键要么存在要么不存在。这可以防止 key 在脚本中间过期,保证将相同的脚本发送到 slave ,从而在二者的数据集中产生相同的效果。

一旦一个 slave 被提升为一个 master ,它将开始独立地过期 key,而不需要任何旧 master 的帮助。

9. 在 Docker 和 NAT 中配置复制

当使用 Docker 或其他类型的容器使用端口转发或网络地址转换时,Redis 复制需要特别小心,特别是在使用 Redis Sentinel 或其他系统(其中扫描 master INFO 或 ROLE 命令的输出情况以便于发现 slave 地址的)。

问题是 ROLE 命令和 INFO 输出的复制部分在发布到 master 实例中时,将显示 slave 具有的用于连接到 master 的 IP 地址,而在使用 NAT 的环境中,和 slave 实例的逻辑地址(客户机用来连接 slave 的地址)相比较可能会不同。

类似地,slaves 将以 redis.conf 文件中监听的端口为序列出,在重新映射端口的情况下,该端口可能与转发的端口不同。

为了解决这两个问题,从 Redis 3.2.2 开始,可以强制一个 slave 向 master 通告一对任意的 IP 和端口。使用的两个配置指令是:

slave-announce-ip 5.5.5.5

slave-announce-port 1234

在近期 Redis distributions 中的 redis.conf 的样例中可以找到记录。

10. INFO 和 ROLE 命令

有两个 Redis 命令可以提供有关主从实例当前复制参数的很多信息。一个是INFO。如果使用复制参数像 INFO replication 调用该命令,,则只显示与复制相关的信息。另一个更加 computer-friendly 的命令是 ROLE,它提供 master 和 slave 的复制状态以及它们的复制偏移量,连接的 slaves 列表等等。

11. 重新启动和故障转移后的部分重同步

从 Redis 4.0 开始,当一个实例在故障转移后被提升为 master 时,它仍然能够与旧 master 的 slaves 进行部分重同步。为此,slave 会记住旧 master 的旧 replication ID 和复制偏移量,因此即使询问旧的 replication ID,其也可以将部分复制缓冲提供给连接的 slave 。

但是,升级的 slave 的新 replication ID 将不同,因为它构成了数据集的不同历史记录。例如,master 可以返回可用,并且可以在一段时间内继续接受写入命令,因此在被提升的 slave 中使用相同的 replication ID 将违反一对复制标识和偏移对只能标识单一数据集的规则。

另外,slave 在关机并重新启动后,能够在 RDB 文件中存储所需信息,以便与 master 进行重同步。这在升级的情况下很有用。当需要时,最好使用 SHUTDOWN 命令来执行 slave 的保存和退出操作。

使用Github搭建图床
Author: yanpenggong       Email: yanpenggong@163.com
Github: kungs8      CSDN: https://blog.csdn.net/yanpenggong

[TOC]

一、图床简介

程序员应该都了解 Typora 是专注于编写 Markdown 格式的编辑软件,使用方便,支持多种格式导出。

PicGo 是一款免费的图床管理应用,支持拖拽上传,剪切板上传等方式。你可以用它快捷地将图片上传到图床并获得网络链接。

注意:请不要把 PicGo 安装到 C 盘 Program Files 下

1. 什么是图床

对于写博客的朋友们来讲,图床这个东西一定不会陌生,而且在一定程度上也给大家造成过一定困扰。

对于不清楚这个东西的朋友,我就在这儿大概说一下图床是个啥东西。所谓图床,其实可以就相当于我们手机上的相册,不过他是在线的,而且是对大家开放的,大家都可以访问查看,但是编辑删除这些功能仅限于拥有者,就相当于用百度云分享的公开照片,你可以查看,也可以下载下来编辑,但是拥有权还是属于分享者。

那你可能会疑惑,那这个东西和写博客的我们有啥关系呢?

你想想,我们写博客,是不是有很多图片需要插入,我们这些博客要保留在本地的时候你可以预览到图片,但一旦你要把它发布到网上,这时候问题来了!发现图片上传失败,那是因为你本地的图片都是存在本地的,平台不会自动给你上传,那这个时候就凸显出图床的重要性了。当然了,如果你是直接在平台进行编辑,那着一点就不用担心了,基本平台都会自动给你上传到它自己的服务器。
有了图床,我们在本地写好博客之后,就能够任意复制到其他平台,不用担心图片丢失问题了。

今天的文章就是给大家分享一个搭建免费图床的教程,既是方便自己后续的复习,也希望对大家也有所帮助。

2. 个人需要搭建自己图床的需求

Markdown 可以理解为增强版的文本文档,语法简单,支持更多的风格样式,相比 word 更加轻便,文件大小更小,同时可导出为指定格式,目前大多是技术博客论坛已支持 Markdown 格式,基本上可以做到一次编写多处使用。当然 Markdown 也存在缺点,比如图片。

Markdown 文档编写时可使用本地图片,但是无法在网络上使用。图床的作用可以理解为将文档中的图片放到网络上,直接引用网络地址,这样可以做到无论在那个平台都可以使用统一的图片地址。

3. 个人搭建的图床必须具备的特性

存储的图片数据必须要安全存储;

访问速度要快;

尽可能是免费的,如果是收费,希望便宜些;

可以批量导出图片数据等……

4. PicGo可以使用的图床

感觉比较靠谱的图床:

阿里云OSS、腾讯云COS、七牛图床、Github图床……

5. github作为图床的优点

  • 每一个 IT 人都会具备一个github账号,因此用其做为自己的图床很好。

  • 虽然github打开会比较慢,但是用了cdn加速后,效果是非常ok的,高级。

  • 使用gitbub作为图床可以进一步熟悉 github 和 git。

二、准备工作

一个 Github 账号

三、搭建过程

1. 登录github并创建仓库

登录自己的 Github并创建一个新的仓库:

2. 填写仓库信息

填写仓库相关信息,一般只需要选一个合适的仓库名,然后确保仓库为 public 其他的保持默认就好;

自己本次填写信息:blog_imgs

3. 查看创建好的仓库

一般创建成功之后,会出现如下界面,至此,我们的图床算是创建好了,接下来就是如何上传图片了;

4. 上传图片(配置 PicGo )

通过上面的步骤,我们的图床时搭建好了,但是通过传统的方法向 Github 上传图片太麻烦了,这里我们推荐使用一个开源图床工具 PicGo 来作为我们的图片上传工具;

PicGo 的安装就不说了,去 官网 下载对应版本进行安装即可,我们主要讲讲如何用它来上传图片。安装后,打开软件其主页面如下:

接下来就是配置 PicGo 的过程了。

  1. 先要去 Github 创建一个 token

    依次打开 Settings -> Developer settings -> Personal access tokens,最后点击 generate new token

  2. 填写及勾选相关信息,然后点击 Genetate token 即可

    ==这里注意下:==

    默认这个token有效期为30天,我们为了稳定性起见,可以直接改为no expiration

  3. token 生成

    注意它只会显示一次,所以你最好把它复制下来到你的备忘录存好,方便下次使用,否则下次有需要重新新建

  4. 配置 PicGo,依次打开 图床设置 -> Github 图床

    填写相关信息,最后点击 确定即可,要将其作为默认图床的话,点击设为默认图床;

  5. 上传图片

    通过上传区上传即可(Ctrl V 或者将图片拖拽都可以),也可以通过快捷键的方式上传(默认上传键为 Ctrl + Shift + P

    首先这里我没有打开科学上网,观察下图片上传速度和在线查看md文件时图片的显示速度;

    这里通过typora里配置了picgo,进行测试下效果:

    查看typora配置的参数:

    点击严重突破上传选项,可以测试是否上传成功。

    直接在 Typora 中粘贴图片后,再右击进行上传图片。上传完成,我们发现图像的路径变成 url 链接了。

5. 加速访问

大家可能会发现,我们上传到 Github 的图片有时候访问太慢了,有时候甚至直接加载不出来!那该咋办呢?
这时候我们就可以用 jsDelivr 进行免费加速,而设置的方法也很简单,只需要在我们 PicGo 图床配置中添加如下自定义域名即可;
https://cdn.jsdelivr.net/gh/用户名/仓库名

1
https://www.jsdelivr.com/?docs=gh

比如我的就是: https://cdn.jsdelivr.net/gh/kungs8/blog_imgs

现在我们再次测试下效果:

测试粘贴到typora里图片的上传速度、打开md文档时图片的显示速度:

此时本地 无科学上网:

=测试:上传 可能会耗时3-4s,但在其他终端打开md文档,里面图片的展示时间几乎是0ms,效果很不错;

6. 图床推荐

除开用 Github 搭建的方式之后,我们也可以用 Gitee 进行搭建,搭建方式和本文大致相同。此外,我也推荐几个免费的图床给大家,大家可以根据自己的喜好进行选择;

四、总结

1
2
3
4
5
1. 准备一个 Github 账号;
2. 搭建图床仓库;
3. 上传图片设置;
4. 加速访问;
5. 免费图床推荐;

五、注意事项

  1. 禁止上传私密信息

    使用github作为自己的云笔记图床时,切记图片上不能包含一些隐私信息:例如密码等信息;

  2. 上传同名文件时会报错

  3. 即使后期gitbub倒闭或者cdn加速失效时,也可以批量把文件给下载下来

    1
    git clone https://github.com/kungs8/blog_imgs.git

自我搭建博客
Author: yanpenggong       Email: yanpenggong@163.com
Github: kungs8      CSDN: https://blog.csdn.net/yanpenggong

[TOC]

由于 NightTeam 的域名是 nightteam.cn,所以这里官方博客使用了二级域名 blog.nightteam.cn,官方主页使用了根域名 nightteam.cn,现在站点都已经稳定运行在 GitHub Pages 上面了,大家如果感兴趣可以去看一下。

•NightTeam HomePage:https://nightteam.cn/

下面是两个站点的预览图:

这个是个人搭建好的blog效果:

这里的主页就是用一个基本的静态页面搭建了,没有什么技术含量。博客相对复杂一点,使用了 Hexo 框架,采用了 Next 主题,在搭建的过程中我就顺手把搭建的流程大致记录下来了,在这里扩充一下形成一篇记录,毕竟好记性不如烂笔头。

于是,这篇《利用 GitHub 从零开始搭建一个博客》的文章就诞生了。

一、准备条件

在这里先跟大家说一些准备条件,有些同学可能一听到搭建博客就望而却步。弄个博客网站,不得有台服务器吗?不得搞数据库吗?不得注册域名吗?没事,如果都没有,那照样是能搭建一个博客的。

GitHub 是个好东西啊,它提供了 GitHub Pages 帮助我们来架设一个静态网站,这就解决了服务器的问题。

Hexo 这个博客框架没有那么重量级,它是 MarkDown 直接写文章的,然后 Hexo 可以直接将文章编译成静态网页文件并发布,所以这样文章的内容、标题、标签等信息就没必要存数据库里面了,是直接纯静态页面了,这就解决了数据库的问题。

GitHub Pages 允许每个账户创建一个名为 {username}.github.io 的仓库,另外它还会自动为这个仓库分配一个 github.io 的二级域名,这就解决了域名的问题,当然如果想要自定义域名的话,也可以支持。

所以说,基本上,先注册个 GitHub 账号就能搞了,下面我们来正式开始吧。

二、新建项目

首先在 GitHub 新建一个仓库(Repository),名称为 {username}.github.io,注意这个名比较特殊,必须要是 github.io 为后缀结尾的。比如 kungs8 的 GitHub 用户名就叫 yanpenggong,那我就新建一个 kungs8.github.io,新建完成之后就可以进行后续操作了。

另外如果 GitHub 没有配置 SSH 连接的建议配置一下,这样后面在部署博客的时候会更方便。

三、安装环境

1.安装 Node.js

首先在自己的电脑上安装 Node.js,下载地址:https://nodejs.org/zh-cn/download/,可以安装 Stable 版本。

安装完毕之后,确保环境变量配置好,能正常使用 npm 命令。

2.安装 Hexo

接下来就需要安装 Hexo 了,这是一个博客框架,Hexo 官方还提供了一个命令行工具,用于快速创建项目、页面、编译、部署 Hexo 博客,所以在这之前我们需要先安装 Hexo 的命令行工具。

命令如下:

1
npm install -g hexo-cli

安装完毕之后,确保环境变量配置好,能正常使用 hexo 命令。

四、初始化项目

接下来我们使用 Hexo 的命令行创建一个项目,并将其在本地跑起来,整体跑通看看。

首先使用如下命令创建项目:

1
hexo init {name}

这里的 name 就是项目名,我这里要创建 yanpenggong 的博客,我就把项目取名为 yanpenggong 了,用了纯小写,命令如下:

1
hexo init yanpenggong

这样 yanpenggong 文件夹下就会出现 Hexo 的初始化文件,包括 themes、scaffolds、source 等文件夹,这些内容暂且先不用管是做什么的,我们先知道有什么,然后一步步走下去看看都发生了什么变化。

接下来我们首先进入新生成的文件夹里面,然后调用 Hexo 的 generate 命令,将 Hexo 编译生成 HTML 代码,命令如下:

1
2
3
(base) kungs@kungsMac GitBlogLearning % cd yanpenggong
(base) kungs@kungsMac yanpenggong % npm install
(base) kungs@kungsMac yanpenggong % hexo generate

输出:

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
(base) kungs@kungsMac GitBlogLearning % cd yanpenggong 
(base) kungs@kungsMac yanpenggong % npm install
npm WARN deprecated source-map-url@0.4.1: See https://github.com/lydell/source-map-url#deprecated
npm WARN deprecated urix@0.1.0: Please see https://github.com/lydell/urix#deprecated
npm WARN deprecated resolve-url@0.2.1: https://github.com/lydell/resolve-url#deprecated
npm WARN deprecated source-map-resolve@0.5.3: See https://github.com/lydell/source-map-resolve#deprecated

added 250 packages, and audited 251 packages in 40s

18 packages are looking for funding
run `npm fund` for details

found 0 vulnerabilities
(base) kungs@kungsMac yanpenggong % hexo generate
INFO Validating config
INFO Start processing
INFO Files loaded in 148 ms
(node:46252) Warning: Accessing non-existent property 'lineno' of module exports inside circular dependency
(Use `node --trace-warnings ...` to show where the warning was created)
(node:46252) Warning: Accessing non-existent property 'column' of module exports inside circular dependency
(node:46252) Warning: Accessing non-existent property 'filename' of module exports inside circular dependency
(node:46252) Warning: Accessing non-existent property 'lineno' of module exports inside circular dependency
(node:46252) Warning: Accessing non-existent property 'column' of module exports inside circular dependency
(node:46252) Warning: Accessing non-existent property 'filename' of module exports inside circular dependency
INFO Generated: archives/index.html
INFO Generated: archives/2022/index.html
INFO Generated: archives/2022/04/index.html
INFO Generated: index.html
INFO Generated: js/script.js
INFO Generated: fancybox/jquery.fancybox.min.css
INFO Generated: css/style.css
INFO Generated: css/fonts/fontawesome-webfont.woff2
INFO Generated: fancybox/jquery.fancybox.min.js
INFO Generated: js/jquery-3.4.1.min.js
INFO Generated: css/fonts/fontawesome-webfont.woff
INFO Generated: css/fonts/FontAwesome.otf
INFO Generated: css/fonts/fontawesome-webfont.ttf
INFO Generated: css/fonts/fontawesome-webfont.eot
INFO Generated: 2022/04/20/hello-world/index.html
INFO Generated: css/images/banner.jpg
INFO Generated: css/fonts/fontawesome-webfont.svg
INFO 17 files generated in 486 ms

可以看到输出结果里面包含了 js、css、font 等内容,并发现他们都处在了项目根目录下的 public 文件夹下面了。

然后我们利用 Hexo 提供的 serve 命令把博客在本地运行起来,命令如下:

1
(base) kungs@kungsMac yanpenggong % hexo serve

运行之后命令行输出如下:

1
2
INFO  Start processing
INFO Hexo is running at http://localhost:4000 . Press Ctrl+C to stop.

它告诉我们在本地 4000 端口上就可以查看博客站点了,如图所示:

这样一个博客的架子就出来了,我们只用了三个命令就完成了。

五、部署设置

接下来我们来将这个初始化的博客进行一下部署,放到 GitHub Pages 上面验证一下其可用性。成功之后我们可以再进行后续的修改,比如修改主题、修改页面配置等等。

那么怎么把这个页面部署到 GitHub Pages 上面呢,其实 Hexo 已经给我们提供一个命令,利用它我们可以直接将博客一键部署,不需要手动去配置服务器或进行其他的各项配置。

部署命令如下:

1
2
(base) kungs@kungsMac yanpenggong % hexo deploy
INFO Validating config

在部署之前,我们需要先知道博客的部署地址,它需要对应 GitHub 的一个 Repository 的地址,这个信息需要我们来配置一下。

打开根目录下的 _config.yml 文件,找到 Deployment 这个地方,把刚才新建的 Repository 的地址贴过来,然后指定分支为 master 分支,最终修改为如下内容:

1
2
3
4
5
6
# Deployment
## Docs: https://hexo.io/docs/deployment.html
deploy:
type: git
repo: {git repo ssh address}
branch: master

我的就修改为如下内容:

1
2
3
4
5
6
# Deployment
## Docs: https://hexo.io/docs/deployment.html
deploy:
type: git
repo: git@github.com:kungs8/kungs8.github.io.git
branch: master

另外我们还需要额外安装一个支持 Git 的部署插件,名字叫做 hexo-deployer-git,有了它我们才可以顺利将其部署到 GitHub 上面,如果不安装的话,在执行部署命令时会报如下错误:

1
Deployer not found: git

好,那就让我们安装下这个插件,在项目目录下执行安装命令如下:

1
(base) kungs@kungsMac yanpenggong % npm install hexo-deployer-git --save

安装成功之后,执行部署命令:

1
(base) kungs@kungsMac yanpenggong % hexo deploy

运行结果类似如下:

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
(base) kungs@kungsMac yanpenggong % hexo deploy                         
INFO Validating config
INFO Deploying: git
INFO Setting up Git deployment...
已初始化空的 Git 仓库于 /Users/kungs/GGG/GitLearning/GitBlogLearning/yanpenggong/.deploy_git/.git/
[master(根提交) 9358c6b] First commit
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 placeholder
INFO Clearing .deploy_git folder...
INFO Copying files from public folder...
INFO Copying files from extend dirs...
[master 2040ad5] Site updated: 2022-04-20 11:27:22
18 files changed, 5174 insertions(+)
create mode 100644 2022/04/20/hello-world/index.html
create mode 100644 archives/2022/04/index.html
create mode 100644 archives/2022/index.html
create mode 100644 archives/index.html
create mode 100644 css/fonts/FontAwesome.otf
create mode 100644 css/fonts/fontawesome-webfont.eot
create mode 100644 css/fonts/fontawesome-webfont.svg
create mode 100644 css/fonts/fontawesome-webfont.ttf
create mode 100644 css/fonts/fontawesome-webfont.woff
create mode 100644 css/fonts/fontawesome-webfont.woff2
create mode 100644 css/images/banner.jpg
create mode 100644 css/style.css
create mode 100644 fancybox/jquery.fancybox.min.css
create mode 100644 fancybox/jquery.fancybox.min.js
create mode 100644 index.html
create mode 100644 js/jquery-3.4.1.min.js
create mode 100644 js/script.js
delete mode 100644 placeholder
枚举对象中: 34, 完成.
对象计数中: 100% (34/34), 完成.
使用 4 个线程进行压缩
压缩对象中: 100% (26/26), 完成.
写入对象中: 100% (34/34), 882.40 KiB | 2.38 MiB/s, 完成.
总共 34(差异 3),复用 0(差异 0),包复用 0
remote: Resolving deltas: 100% (3/3), done.
remote:
remote: Create a pull request for 'master' on GitHub by visiting:
remote: https://github.com/kungs8/kungs8.github.io/pull/new/master
remote:
To github.com:kungs8/kungs8.github.io.git
* [new branch] HEAD -> master
分支 'master' 设置为跟踪来自 'git@github.com:kungs8/kungs8.github.io.git' 的远程分支 'master'。
INFO Deploy done: git

如果出现类似上面的内容,就证明我们的博客已经成功部署到 GitHub Pages 上面了,这时候我们访问一下 GitHub Repository 同名的链接,比如我的 kungs8 博客的 Repository 名称取的是 kungs8.github.io,那我就访问 http://kungs8.github.io,这时候我们就可以看到跟本地一模一样的博客内容了。

这时候我们去 GitHub 上面看看 Hexo 上传了什么内容,打开之后可以看到 master 分支有了这样的内容:

仔细看看,这实际上是博客文件夹下面的 public 文件夹下的所有内容,Hexo 把编译之后的静态页面内容上传到 GitHub 的 master 分支上面去了。

这时候可能就有人有疑问了,那我博客的源码也想放到 GitHub 上面怎么办呢?其实很简单,新建一个其他的分支就好了,比如我这边就新建了一个 source 分支,代表博客源码的意思。

具体的添加过程就很简单了,参加如下命令:

1
2
3
4
5
6
git init
git checkout -b source
git add -A
git commit -m "init blog"
git remote add origin git@github.com:{username}/{username}.github.io.git
git push origin source

成功之后,可以到 GitHub 上再切换下默认分支,比如我就把默认的分支设置为了 source,当然不换也可以。

1. 配置站点信息

完成如上内容之后,实际上我们只完成了博客搭建的一小步,因为我们仅仅是把初始化的页面部署成功了,博客里面还没有设置任何有效的信息。下面就让我们来进行一下博客的基本配置,另外换一个好看的主题,配置一些其他的内容,让博客真正变成属于我们自己的博客吧。

下面我就以自己的站点 NightTeam 为例,修改一些基本的配置,比如站点名、站点描述等等。

修改根目录下的 _config.yml 文件,找到 Site 区域,这里面可以配置站点标题 title、副标题 subtitle 等内容、关键字 keywords 等内容,比如我的就修改为如下内容:

1
2
3
4
5
6
7
8
# Site
title: yanpenggong大数据实验室
subtitle: 一个专注于科研前线的大数据团队,致力于打造更好更牛的大数据平台
description: 涉猎的主要编程语言为 Python、C++、Matlab、R,领域涵盖爬虫、数据挖掘、深度学习、良率分析、目标检测、工业异常检测、服务研发和对象存储等。
keywords: "Python, C++, Matlab, R, 爬虫, 数据挖掘, 深度学习, 良率分析, 目标检测, 工业异常检测, 服务研发, 对象存储"
author: yanpenggong
language: en
timezone:

这里大家可以参照格式把内容改成自己的。

另外还可以设置一下语言,如果要设置为汉语的话可以将 language 的字段设置为 zh-CN,修改如下:

1
language: zh-CN

这样就完成了站点基本信息的配置,完成之后可以看到一些基本信息就修改过来了,页面效果如下:

2. 修改主题

目前来看,整个页面的样式个人感觉并不是那么好看,想换一个风格,这就涉及到主题的配置了。目前 Hexo 里面应用最多的主题基本就是 Next 主题了,个人感觉这个主题还是挺好看的,另外它支持的插件和功能也极为丰富,配置了这个主题,我们的博客可以支持更多的扩展功能,比如阅览进度条、中英文空格排版、图片懒加载等等。

那么首先就让我们来安装下 Next 这个主题吧,目前 Next 主题已经更新到 7.x 版本了,我们可以直接到 Next 主题的 GitHub Repository 上把这个主题下载下来。

主题的 GitHub 地址是:https://github.com/theme-next/hexo-theme-next,我们可以直接把 master 分支 Clone 下来。

首先命令行进入到项目的根目录,执行如下命令即可:

1
2
3
4
5
6
(base) kungs@kungsMac yanpenggong % git clone https://github.com/theme-next/hexo-theme-next themes/next
正克隆到 'themes/next'...
remote: Enumerating objects: 12582, done.
remote: Total 12582 (delta 0), reused 0 (delta 0), pack-reused 12582
接收对象中: 100% (12582/12582), 8.03 MiB | 533.00 KiB/s, 完成.
处理 delta 中: 100% (7990/7990), 完成.

执行完毕之后 Next 主题的源码就会出现在项目的 themes/next 文件夹下。

然后我们需要修改下博客所用的主题名称,修改项目根目录下的 _config.yml 文件,找到 theme 字段,修改为 next 即可,修改如下:

1
theme: next

然后本地重新开启服务,访问刷新下页面,就可以看到 next 主题就切换成功了,预览效果如下:

3. 主题配置

现在我们已经成功切换到 next 主题上面了,接下来我们就对主题进行进一步地详细配置吧,比如修改样式、增加其他各项功能的支持,下面逐项道来。

Next 主题内部也提供了一个配置文件,名字同样叫做 _config.yml,只不过位置不一样,它在 themes/next 文件夹下,Next 主题里面所有的功能都可以通过这个配置文件来控制,下文所述的内容都是修改的 themes/next/_config.yml 文件。

3.1. 样式

Next 主题还提供了多种样式,风格都是类似黑白的搭配,但整个布局位置不太一样,通过修改配置文件的 scheme 字段即可,我选了 Pisces 样式,修改 _config.yml (注意是 themes/next/_config.yml 文件)如下:

1
scheme: Pisces

刷新页面之后就会变成这种样式,如图所示:

另外还有几个可选项,比如:

1
2
3
4
#scheme: Muse
#scheme: Mist
scheme: Pisces
#scheme: Gemini

大家可以自行根据喜好选择。

3.2. favicon

favicon 就是站点标签栏的小图标,默认是用的 Hexo 的小图标,如果我们有站点 Logo 的图片的话,我们可以自己定制小图标。

但这并不意味着我们需要自己用 PS 自己来设计,已经有一个网站可以直接将图片转化为站点小图标,站点链接为:https://realfavicongenerator.net,到这里上传一张图,便可以直接打包下载各种尺寸和适配不同设备的小图标。

图标下载下来之后把它放在 themes/next/source/images 目录下面。

然后在配置文件里面找到 favicon 配置项,把一些相关路径配置进去即可,示例如下:

1
2
3
4
5
favicon:
small: /images/favicon-16x16.png
medium: /images/favicon-32x32.png
apple_touch_icon: /images/apple-touch-icon.png
safari_pinned_tab: /images/safari-pinned-tab.svg

配置完成之后刷新页面,整个页面的标签图标就被更新了。

3.3. avatar

avatar 这个就类似站点的头像,如果设置了这个,会在站点的作者信息旁边额外显示一个头像,比如我这边有一张 cat.jpg 图片:

将其放置到 themes/next/source/images/cat.jpg 路径,然后在主题 themes/next/_config.yml 文件下编辑 avatar 的配置,修改为正确的路径即可。

1
2
3
4
5
6
7
8
9
10
# Sidebar Avatar
avatar:
# In theme directory (source/images): /images/avatar.gif
# In site directory (source/uploads): /uploads/avatar.gif
# You can also use other linking images.
url: /images/cat.jpg
# If true, the avatar would be dispalyed in circle.
rounded: true
# If true, the avatar would be rotated with the cursor.
rotated: true

这里有 rounded 选项是是否显示圆形,rotated 是是否带有旋转效果,大家可以根据喜好选择是否开启。

效果如下:

配置完成之后就会显示头像。

3.4. rss

博客一般是需要 RSS 订阅的,如果要开启 RSS 订阅,这里需要安装一个插件,叫做 hexo-generator-feed,安装完成之后,站点会自动生成 RSS Feed 文件,安装命令如下:

1
(base) kungs@kungsMac yanpenggong % npm install hexo-generator-feed --save

在项目根目录下运行这个命令,安装完成之后不需要其他的配置,以后每次编译生成站点的时候就会自动生成 RSS Feed 文件了。

3.5. code

作为程序猿,代码块的显示还是需要很讲究的,默认的代码块我个人不是特别喜欢,因此我把代码的颜色修改为黑色,并把复制按钮的样式修改为类似 Mac 的样式,修改 themes/next/_config.yml 文件的 codeblock 区块如下:

1
2
3
4
5
6
7
8
9
10
11
12
codeblock:
# Code Highlight theme
# Available values: normal | night | night eighties | night blue | night bright | solarized | solarized dark | galactic
# See: https://github.com/chriskempson/tomorrow-theme
highlight_theme: night bright
# Add copy button on codeblock
copy_button:
enable: true
# Show text copy result.
show_result: true
# Available values: default | flat | mac
style: mac

修改前的代码样式:

修改后的代码样式:

嗯,个人觉得整体看起来逼格高了不少。

3.6. top

我们在浏览网页的时候,如果已经看完了想快速返回到网站的上端,一般都是有一个按钮来辅助的,这里也支持它的配置,修改 themes/next/_config.yml 的 back2top 字段即可,我的设置如下:

1
2
3
4
5
6
back2top:
enable: true
# Back to top in sidebar.
sidebar: false
# Scroll percent label in b2t button.
scrollpercent: true

enable 默认为 true,即默认显示。sidebar 如果设置为 true,按钮会出现在侧栏下方,个人觉得并不是很好看,就取消了,scrollpercent 就是显示阅读百分比,个人觉得还不错,就将其设置为 true。

具体的效果大家可以设置后根据喜好选择。

3.7. reading_process

reading_process,阅读进度。大家可能注意到有些站点的最上侧会出现一个细细的进度条,代表页面加载进度和阅读进度,如果大家想设置的话也可以试试,我将其打开了,修改 themes/next/_config.yml 如下:

1
2
3
4
5
6
reading_progress:
enable: true
# Available values: top | bottom
position: top
color: "#222"
height: 2pxreading_progress: enable: true # Available values: top | bottom position: top color: "#222" height: 2px

设置之后显示效果如下:

3.8. bookmark

书签,可以根据阅读历史记录,在下次打开页面的时候快速帮助我们定位到上次的位置,大家可以根据喜好开启和关闭,我的themes/next/_config.yml 配置如下:

1
2
3
4
5
6
7
bookmark:
enable: true
# Customize the color of the bookmark.
color: "#222"
# If auto, save the reading progress when closing the page or clicking the bookmark-icon.
# If manual, only save it by clicking the bookmark-icon.
save: auto

3.9. github_banner

在一些技术博客上,大家可能注意到在页面的右上角有个 GitHub 图标,点击之后可以跳转到其源码页面,可以为 GitHub Repository 引流,大家如果想显示的话可以自行选择打开,我的themes/next/_config.yml 配置如下:

1
2
3
4
5
# `Follow me on GitHub` banner in the top-right corner.
github_banner:
enable: true
permalink: https://github.com/kungs8/kungs8.github.io/tree/master
title: kungs GitHub

记得修改下链接 permalink 和标题 title,显示效果如下:

可以看到在页面右上角显示了 GitHub 的图标,点击可以进去到 Repository 页面。

3.10. gitalk

由于 Hexo 的博客是静态博客,而且也没有连接数据库的功能,所以它的评论功能是不能自行集成的,但可以集成第三方的服务。

Next 主题里面提供了多种评论插件的集成,有 changyan | disqus | disqusjs | facebook_comments_plugin | gitalk | livere | valine | vkontakte 这些。

作为一名程序员,我个人比较喜欢 gitalk,它是利用 GitHub 的 Issue 来当评论,样式也比较不错。

首先需要在 GitHub 上面注册一个 OAuth Application,链接为:https://github.com/settings/applications/new,注册完毕之后拿到 Client ID、Client Secret 就可以了。

首先需要在 _config.yml 文件的 comments 区域配置使用 gitalk:

1
2
3
4
5
6
7
# Multiple Comment System Support
comments:
# Available values: tabs | buttons
style: tabs
# Choose a comment system to be displayed by default.
# Available values: changyan | disqus | disqusjs | facebook_comments_plugin | gitalk | livere | valine | vkontakte
active: gitalk

主要是 comments.active 字段选择对应的名称即可。

然后找打 gitalk 配置,添加它的各项配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Gitalk
# Demo: https://gitalk.github.io
# For more information: https://github.com/gitalk/gitalk
gitalk:
enable: true
github_id: NightTeam
repo: nightteam.github.io # Repository name to store issues
client_id: {your client id} # GitHub Application Client ID
client_secret: {your client secret} # GitHub Application Client Secret
admin_user: germey # GitHub repo owner and collaborators, only these guys can initialize gitHub issues
distraction_free_mode: true # Facebook-like distraction free mode
# Gitalk's display language depends on user's browser or system environment
# If you want everyone visiting your site to see a uniform language, you can set a force language value
# Available values: en | es-ES | fr | ru | zh-CN | zh-TW
language: zh-CN

配置完成之后 gitalk 就可以使用了,点击进入文章页面。

GitHub 授权登录之后就可以使用了,评论的内容会自动出现在 Issue 里面。

3.11. pangu

我个人有个强迫症,那就是写中文和英文的时候中间必须要留有间距,一个简单直接的方法就是中间加个空格,但某些情况下可能习惯性不加或者忘记加了,这就导致中英文混排并不是那么美观。

pangu 就是来解决这个问题的,我们只需要在主题里面开启这个选项,在编译生成页面的时候,中英文之间就会自动添加空格,看起来更加美观。

具体的themes/next/_config.yml修改如下:

1
pangu: true

3.12. math

可能在一些情况下我们需要写一个公式,比如演示一个算法推导过程,MarkDown 是支持公式显示的,Hexo 的 Next 主题同样是支持的。

Next 主题提供了两个渲染引擎,分别是 mathjax 和 katex,后者相对前者来说渲染速度更快,而且不需要 JavaScript 的额外支持,但后者支持的功能现在还不如前者丰富,具体的对比可以看官方文档:https://theme-next.org/docs/third-party-services/math-equations。

所以我这里选择了 mathjax,通过修改配置即可启用:

1
2
3
4
5
6
7
8
9
10
11
12
13
math:
enable: true

# Default (true) will load mathjax / katex script on demand.
# That is it only render those page which has `mathjax: true` in Front-matter.
# If you set it to false, it will load mathjax / katex srcipt EVERY PAGE.
per_page: true

# hexo-renderer-pandoc (or hexo-renderer-kramed) required for full MathJax support.
mathjax:
enable: true
# See: https://mhchem.github.io/MathJax-mhchem/
mhchem: true

mathjax 的使用需要我们额外安装一个插件,叫做 hexo-renderer-kramed,另外也可以安装 hexo-renderer-pandoc,命令如下:

1
2
(base) kungs@kungsMac yanpenggong % npm un hexo-renderer-marked --save
(base) kungs@kungsMac yanpenggong % npm i hexo-renderer-kramed --save

另外还有其他的插件支持,大家可以到官方文档查看。

3.13. pjax

可能大家听说过 Ajax,没听说过 pjax,这个技术实际上就是利用 Ajax 技术实现了局部页面刷新,既可以实现 URL 的更换,有可以做到无刷新加载。

要开启这个功能需要先将 pjax 功能开启,然后安装对应的 pjax 依赖库,首先修改 themes/next/_config.yml 修改如下:

1
pjax: true

然后安装依赖库,切换到 next 主题下,然后安装依赖库:

1
2
(base) kungs@kungsMac yanpenggong % cd themes/next 
(base) kungs@kungsMac next % git clone https://github.com/theme-next/theme-next-pjax source/lib/pjax

这样 pjax 就开启了,页面就可以实现无刷新加载了。

另外关于 Next 主题的设置还有挺多的,这里就介绍到这里了,更多的主题设置大家可以参考官方文档:https://theme-next.org/docs/。

六、文章

现在整个站点只有一篇文章,那么我们怎样来增加其他的文章呢?

这个很简单,只需要调用 Hexo 提供的命令即可,比如我们要新建一篇「HelloWorld」的文章,命令如下:

1
(base) kungs@kungsMac yanpenggong % hexo new hello-world

创建的文章会出现在 source/_posts 文件夹下,是 MarkDown 格式。

在文章开头通过如下格式添加必要信息:

1
2
3
4
5
6
7
8
9
10
11
---
title: 标题 # 自动创建,如 hello-world
date: 日期 # 自动创建,如 2022-04-20 15:54:14
tags:
- 标签1
- 标签2
- 标签3
categories:
- 分类1
- 分类2
---

开头下方撰写正文,MarkDown 格式书写即可。

这样在下次编译的时候就会自动识别标题、时间、类别等等,另外还有其他的一些参数设置,可以参考文档:https://hexo.io/zh-cn/docs/writing.html。

1. 标签页

现在我们的博客只有首页、文章页,如果我们想要增加标签页,可以自行添加,这里 Hexo 也给我们提供了这个功能,在根目录执行命令如下:

1
(base) kungs@kungsMac yanpenggong % hexo new page tags

执行这个命令之后会自动帮我们生成一个 source/tags/index.md 文件,内容就只有这样子的:

1
2
3
4
---
title: tags
date: 2022-04-20 15:55:41
---

我们可以上面的后面自行添加一个 type 字段来指定页面的类型:

1
2
type: tags
comments: false

然后再在主题的 themes/next/_config.yml 文件将这个页面的链接添加到主菜单里面,修改 menu 字段如下:

1
2
3
4
5
6
7
8
9
menu:
home: / || home
#about: /about/ || user
tags: /tags/ || tags
#categories: /categories/ || th
archives: /archives/ || archive
#schedule: /schedule/ || calendar
#sitemap: /sitemap.xml || sitemap
#commonweal: /404/ || heartbeat

这样重新本地启动看下页面状态,效果如下:

可以看到左侧导航也出现了标签,点击之后右侧会显示标签的列表。

2. 分类页

分类功能和标签类似,一个文章可以对应某个分类,如果要增加分类页面可以使用如下命令创建:

1
(base) kungs@kungsMac yanpenggong % hexo new page categories

然后同样地,会生成一个 source/categories/index.md 文件。

我们可以自行添加一个 type 字段来指定页面的类型:

1
2
type: categories
comments: false

然后再在主题的 themes/next/_config.yml文件将这个页面的链接添加到主菜单里面,修改 menu 字段如下:

1
2
3
4
5
6
7
8
9
menu:  
home: / || home
#about: /about/ || user
tags: /tags/ || tags
categories: /categories/ || th
archives: /archives/ || archive
#schedule: /schedule/ || calendar
#sitemap: /sitemap.xml || sitemap
#commonweal: /404/ || heartbeat

这样页面就会增加分类的支持,效果如下:

3. 搜索页

很多情况下我们需要搜索全站的内容,所以一个搜索功能的支持也是很有必要的。

如果要添加搜索的支持,需要先安装一个插件,叫做 hexo-generator-searchdb,命令如下:

1
(base) kungs@kungsMac yanpenggong % npm install hexo-generator-searchdb --save

然后在项目的 _config.yml 里面添加搜索设置如下:

1
2
3
4
5
search:
path: search.xml
field: post
format: html
limit: 10000

然后在主题的 themes/next/_config.yml 里面修改如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
# Local search
# Dependencies: https://github.com/wzpan/hexo-generator-search
local_search:
enable: true
# If auto, trigger search by changing input.
# If manual, trigger search by pressing enter key or search button.
trigger: auto
# Show top n results per article, show all results by setting to -1
top_n_per_article: 5
# Unescape html strings to the readable one.
unescape: false
# Preload the search data when the page loads.
preload: false

这里用的是 Local Search,如果想启用其他是 Search Service 的话可以参考官方文档:https://theme-next.org/docs/third-party-services/search-services。

4. 404 页面

另外还需要添加一个 404 页面,直接在根目录 source 文件夹新建一个 404.md 文件即可,内容可以仿照如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
---
title: 404 Not Found
date: 2022-04-20 16:15:02
---


<center>
对不起,您所访问的页面不存在或者已删除。
您可以<a href="https://kungs8.github.io/archives/>">点击此处</a>返回首页。
</center>


<blockquote class="blockquote-center">
yanpenggong
</blockquote>

这里面的一些相关信息和链接可以替换成自己的。

增加了这个 404 页面之后就可以

完成了上面的配置基本就完成了大半了,其实 Hexo 还有很多很多功能,这里就介绍不过来了,大家可以直接参考官方文档:https://hexo.io/zh-cn/docs/ 查看更多的配置。

七、部署脚本

最后我这边还增加了一个简易版的部署脚本,其实就是重新 gererate 下文件,然后重新部署。在根目录下新建一个 deploy.sh 的脚本文件,内容如下:

1
2
3
hexo clean
hexo generate
hexo deploy

这样我们在部署发布的时候只需要执行:

1
(base) kungs@kungsMac yanpenggong % sh deploy.sh

就可以完成博客的更新了,非常简单。

八、自定义域名

将页面修改之后可以用上面的脚本重新部署下博客,其内容便会跟着更新。

另外我们也可以在 GitHub 的 Repository 里面设置域名,找到 Settings,拉到下面,可以看到有个 GitHub Pages 的配置项,如图所示:

如图所示:

下面有个 custom domain 的选项,输入你想自定义的域名地址,然后添加 CNAME 解析就好了。

另外下面还有一个 Enforce HTTPS 的选项,GitHub Pages 会在我们配置自定义域名之后自动帮我们配置 HTTPS 服务。刚配置完自定义域名的时候可能这个选项是不可用的,一段时间后等到其可以勾选了,直接勾选即可,这样整个博客就会变成 HTTPS 的协议的了。

另外有一个值得注意的地方,如果配置了自定义域名,在目前的情况下,每次部署的时候这个自定义域名的设置是会被自动清除的。所以为了避免这个情况,我们需要在项目目录下面新建一个 CNAME 文件,路径为 source/CNAME,内容就是自定义域名。

比如我就在 source 目录下新建了一个 CNAME 文件,内容为:

1
blog.nightteam.cn

这样避免了每次部署的时候自定义域名被清除的情况了。

以上就是从零搭建一个 Hexo 博客的流程,希望对大家有帮助。

[TOC]

1、假设检验

假设检验推论统计中用于检验统计假设的一种方法。而“统计假设”是可通过观察一组随机变量的模型进行检验的科学假说[1]一旦能估计未知参数,就会希望根据结果对未知的真正参数值做出适当的推论。

统计上对参数的假设,就是对一个或多个参数的论述。而其中欲检验其正确性的为零假设(null hypothesis),零假设通常由研究者决定,反映研究者对未知参数的看法。相对于零假设的其他有关参数之论述是备择假设(alternative hypothesis),它通常反映了执行检定的研究者对参数可能数值的另一种(对立的)看法(换句话说,备择假设通常才是研究者最想知道的)。

假设检验的种类包括:t检验Z检验卡方检验F检验等等。

1.1 基本思想

​ 假设检验的基本思想是小概率反证法思想。小概率思想是指小概率事件(P<0.01或P<0.05)在一次试验中基本上不会发生。[反证法](https://baike.baidu.com/item/反证法) 思想是先提出假设(检验假设H0</sub>),再用适当的统计方法确定假设成立的可能性大小,如可能性小,则认为假设不成立,若可能性大,则还不能认为假设不成立。

​ 假设是否正确,要用从总体中抽出的样本进行检验,与此有关的理论和方法,构成假设检验的内容。设A是关于总体分布的一项命题,所有使命题A成立的总体分布构成一个集合h0,称为原假设(常简称假设)。使命题A不成立的所有总体分布构成另一个集合h1,称为备择假设。如果h0可以通过有限个实参数来描述,则称为参数假设,否则称为非参数假设(见非参数统计)。如果h0(或h1)只包含一个分布,则称原假设(或备择假设)为简单假设,否则为复合假设。对一个假设h0进行检验,就是要制定一个规则,使得有了样本以后,根据这规则可以决定是接受它(承认命题A正确),还是拒绝它(否认命题A正确)。这样,所有可能的样本所组成的空间(称样本空间)被划分为两部分HA和HR(HA的补集),当样本x∈HA时,接受假设h0;当x∈HR时,拒绝h0。集合HR常称为检验的拒绝域,HA称为接受域。因此选定一个检验法,也就是选定一个拒绝域,故常把检验法本身与拒绝域HR等同起来。

1.2 基本方法

显著性检验 有时,根据一定的理论或经验,认为某一假设h0成立,例如,通常有理由认为特定的一群人的身高服从正态分布。当收集了一定数据后,可以评价实际数据与理论假设h0之间的偏离,如果偏离达到了“显著”的程度就拒绝h0,这样的检验方法称为显著性检验。偏离达到显著的程度通常是指定一个很小的正数α(如0.05,0.01),使当h0正确时,它被拒绝的概率不超过α,称α显著性水平。这种假设检验问题的特点是不考虑备择假设,考虑实验数据与理论之间拟合的程度如何,故此时又称为拟合优度检验。拟合优度检验是一类重要的显著性检验。 [1]

​ K.皮尔森在1900年提出的Ⅹ检验是一个重要的拟合优度检验。设原假设h0是:“总体分布等于某个已知的分布函数F(x)”。把(-∞,∞)分为若干个两两无公共点的区间I1,I2,…,Ik,对任一个区间,以vj记大小为n的样本X1,X2,…,Xn中落在Ij内的个数,称为区间Ij的观测频数,另外,求出Ij的理论频数(对j=1,2,…,k都这样做),再算出由下式定义的Ⅹ统计量,皮尔森证明了:若对j=1,2,…,k,则当n→∞时,Ⅹ的极限分布是自由度k-1的Ⅹ分布。于是在样本大小n相当大时,从Ⅹ分布表可查得Ⅹ分布的上α分位数(见概率分布)Ⅹ(k-1)。由此即得检验水平为α的拒绝域:{Ⅹ≥Ⅹα(k-1)}。如果原假设h0为:总体服从分布族{Fθ,θ∈嘷},式中θ为未知参数,嘷为θ的所有可能取值的集合(称参数空间),也可得到类似的拒绝域,只要在计算理论频数vj时,将所包含的未知参数θ用适当的点估计代替,即可计算 Ⅹ统计量。但此时极限分布的自由度为 k-Л-1,式中Л为θ中的独立参数的个数。柯尔莫哥洛夫检验(见非参数统计)也是一个重要的拟合优度检验方法。

奈曼-皮尔森理论  J.奈曼与 E.S.皮尔森合作,从1928年开始,对假设检验提出了一项系统的理论。他们认为,在检验一个假设h0时可能犯两类错误:

​ 第一类错误是真实情况为h0成立(即θ∈嘷0),但判断h0不成立,犯了“以真为假”的错误。第二类错误是h0实际不成立(即θ∈嘷1),但判断它成立,犯了“以假为真”的错误(见表)。这里嘷0,嘷1分别是使假设h0成立或不成立的θ的集合,显然嘷=嘷0+嘷1。当θ∈嘷0,样本X(即X1,X2,…,Xn组成的向量)∈HR,其概率Pθ(X∈HR)就是犯第一类错误的概率α;当θ∈嘷1,样本X∈HA,其概率就是犯第二类错误的概率β。通常人们不希望轻易拒绝h0,例如工厂的产品一般是合格的,出厂进行抽样检查时不希望轻易地被认为不合格,于是在限定犯第一类错误的概率不超过某个指定值α(称为检验水平)的条件下,寻求犯第二类错误的概率尽可能小的检验方法。为了描述检验的好坏,称θ的函数Pθ(X∈HR)为检验的功效函数。例如上述产品检验的例子中,所采用的检验可以是:当样品中的废品个数超过一定限度时,认为该批产品不合格,否则就认为合格。这个检验的功效函数有图示的形状,图中的 p0、p1、α、β根据需要选定。这种图形清楚地描述了犯两类错误的概率。

优良性准则  基于奈曼-皮尔森理论及统计决策理论,可以提出一些准则,来比较为检验同一假设而提出的各种检验。较重要的准则有:

一致最大功效(UMP)准则  欲检验h0:θ∈嘷0,h1:θ∈嘷1;当给定检验水平α后,在所有满足的可供选择的检验HR中,是否有一个最好的,亦即:是否存在拒绝域H,使得对于所有θ∈嘷1及一切检验水平为α的H皆有。若这样的检验存在,则称HR为检验水平α的一致最大功效检验,简称UMP检验。奈曼与皮尔森在1933年提出了著名的奈曼-皮尔森引理。这是对简单假设寻求UMP检验的一个构造性的结果,即此时似然比检验就是UMP检验。对某些复合假设也找到了 UMP检验,但并不是所有情况都存在 UMP检验。因此有必要在对检验作某些限制下寻找最大功效检验或建立另外一些优良性准则。

无偏性准则  要求检验在备择假设h1成立时作出正确判断的概率不小于检验水平α,这就是说在h0不成立时拒绝h0的概率要不小于在h0成立时拒绝h0的概率,这种性质称为无偏性,具有这种性质的检验称为无偏检验。显然,如果在无偏检验中存在一致最大功效检验就称为一致最大功效无偏检验(简称UMPU检验)。UMP检验不存在时,仍可能有UMPU检验存在。例如正态总体中方差未知时,为检验均值μ=μ0的t检验就是UMPU检验,但不是UMP检验。

​ 因为假设检验在统计决策理论中是一种特殊的统计决策问题,两类错误影响可用特殊损失来表示。例如选取特殊的损失函数,使正确判断时损失为零,错判时损失为1。它就可归结为犯第一类错误的概率α和犯第二类错误的概率β。这同用功效函数Pθ(X∈HR)来叙述是一致的。因此把统计决策理论中容许性、同变性、贝叶斯决策、最小化最大等概念引进来,而得到容许检验、同变检验、贝叶斯检验和最小化最大检验。在同变检验限制下,又可以建立一致最大功效同变检验的概念。这些准则又可作为假设检验的优良性准则,从而扩大了假设检验的内容。

​ 寻求在一定准则下的最优检验是很困难的,何况这种最优检验有时并不存在。于是提出了若干依据直观的推理法,其中最重要的是似然比法。

似然比检验 运用与最大似然估计(见点估计)类似的原理,可得到似然比检验法。设样本X的分布密度即似然函数l(尣,θ),θ∈嘷,欲检验的假设为h0:θ∈嘷0,称为似然比。显然0≤(尣)≤1,当(尣)太小时就拒绝h0,否则接受h0,其临界值λ0由检验水平α 和(尣)在h0成立时的分布确定,即。然而,在一般情况下,寻求(尣的精确分布并不容易。1938年S.S.威尔克斯证明了:在相当广泛的条件下,-2ln(尣)是渐近Ⅹ分布的, 这就为大样本的似然比检验提供了实行的可能。

用似然比法导出的重要检验有:

U检验  若总体遵从正态分布N(μσ),其中σ已知,X=(X1,X2,…,Xn)是从总体中抽取的简单随机样本,记,则遵从标准正态分布N(0,1),于是可考虑对μ的以下几种假设的检验,其中μ0是给定的常数,α为检验的水平,uα为标准正态分布的上α分位数。上述检验称为U 检验。

t检验  若总体服从正态分布N(μσ),但σ未知,记,,则t=遵从自由度为n-1的t分布,可对μ有以下的水平为α的检验,其中tα为自由度为n-1的t分布的上α分位数。这些检验称为t检验。

F检验X=(X1,X2,…,)及Y=(Y1,Y2,…,)分别为来自正态总体Nμ1,σ娝)及Nμ2,σ娤)的简单随机样本,记 ,,,,则遵从自由度为n1-1,n2-1的F分布,对比较σ娝与σ娤的假设有以下的水平为α的检验,其中Fα为自由度为(n1-1,n2-1)的F分布的上α分位数。这些检验称为F检验,在方差分析中有广泛的应用。

1.3 基本步骤

1、提出检验假设又称无效假设,符号是h0;备择假设的符号是H1

h0:样本与总体或样本与样本间的差异是由抽样误差引起的;

H1:样本与总体或样本与样本间存在本质差异;

预先设定的检验水准为0.05;当检验假设为真,但被错误地拒绝的概率,记作α,通常取α=0.05或α=0.01。

2、选定统计方法,由样本观察值按相应的公式计算出统计量的大小,如X2值、t值等。根据资料的类型和特点,可分别选用Z检验,T检验,秩和检验卡方检验等。

3、根据统计量的大小及其分布确定检验假设成立的可能性P的大小并判断结果。若P>α,结论为按α所取水准不显著,不拒绝h0,即认为差别很可能是由于抽样误差造成的,在统计上不成立;如果P≤α,结论为按所取α水准显著,拒绝h0,接受H1,则认为此差别不大可能仅由抽样误差所致,很可能是实验因素不同造成的,故在统计上成立。P值的大小一般可通过查阅相应的界值表得到。

教学中的做法:

1
2
3
4
5
1.根据实际情况提出原假设和备择假设;
2.根据假设的特征,选择合适的检验统计量;
3.根据样本观察值,计算检验统计量的观察值(obs);
4.选择许容显著性水平,并根据相应的统计量的统计分布表查出相应的临界值(ctrit);
5.根据检验统计量观察值的位置决定原假设取舍。

1.4 意义

假设检验是抽样推断中的一项重要内容。它是根据原资料作出一个总体指标是否等于某一个数值,某一随机变量是否服从某种概率分布的假设,然后利用样本资料采用一定的统计方法计算出有关检验的统计量,依据一定的概率原则,以较小的风险来判断估计数值与总体数值(或者估计分布与实际分布)是否存在显著差异,是否应当接受原假设选择的一种检验方法。

用样本指标估计总体指标,其结论有的完全可靠,有的只有不同程度的可靠性,需要进一步加以检验和证实。通过检验,对样本指标与假设的总体指标之间是否存在差别作出判断,是否接受原假设。这里必须明确,进行检验的目的不是怀疑样本指标本身是否计算正确,而是为了分析样本指标和总体指标之间是否存在显著差异。从这个意义上,假设检验又称为显著性检验。

进行假设检验,先要对假设进行陈述。通过下例加以说明。

例如,设某工厂制造某种产品的某种精度服从平均数为方差的正态分布,据过去的数据,已知平均数为75,方差为100。若经过技术革新,改进了制造方法,出现了平均数大于75,方差没有变更,但仍存在平均数不超过75的可能性。试陈述为统计假设。

根据上述情况,可有两种假设,(1) 平均数不超过75,(2)平均数大于75,即如果我们把(1)作为原假设,即被检验的假设,称作零假设,记作H0,如果其他假设相对于零假设来说,是约定的、补充的假设,则就是备择的,故称为备择假设或对立假设,记作H1

还须指出,哪个是零假设,哪个是备择假设,是无关紧要的。我们关心的问题,是要探索哪一个假设被接受的问题。被接受的假设是要作为推理的基础。在实际问题中,一般要考虑事情发生的逻辑顺序和关心的事件,来设立零假设和备择假设。

在作出了统计假设之后,就要采用适当的方法来决定是否应该接受零假设。由于运用统计方法所遇到的问题不同,因而解决问题的方法也不尽相同。但其解决方法的基本思想却是一致的,即都是“概率反证法”思想,即:

(1)为了检验一个零假设(即虚拟假设)是否成立, 先假定它是成立的,然后看接受这个假设之后,是否会导致不合理结果。如果结果是合理的,就接受它;如不合理,则否定原假设。

(2)所谓导致不合理结果,就是看是否在一次观察中, 出现小概率事件。通常把出现小概率事件的概率记为0,即显著性水平。 它在次数函数图形中是曲线两端或一端的面积。因此,从统计检验来说,就涉及到双侧检验和单侧检验问题。在实践中采用何类检验是由实际问题的性质来决定的。一般可以这样考虑:

双侧检验。如果检验的目的是检验抽样的样本统计量与假设参数的差数是否过大(无论是正方向还是负方向),就把风险平分在右侧和左侧。比如显著性水平为0.05,即概率曲线左右两侧各占,即0.025。

②单侧检验。这种检验只注意估计值是否偏高或偏低。如只注意偏低,则临界值在左侧,称左侧检验;如只注意偏高,则临界值在右侧,称右侧检验。

对总体的参数的检量,是通过由样本计算的统计量来实现的。所以检验统计量起着决策者的作用。

参数估计与假设检验

统计推断是由样本的信息来推测母体性能的一种方法,它又可以分为两类问题,即参数估计假设检验。实际生产和科学实验中,大量的问题是在获得一批数据后,要对母体的某一参数进行估计和检验。

例如,我们对45钢的断裂韧性作了测定,取得了一批数据,然后要求45钢断裂韧性的平均值,或要求45钢断裂韧性的单侧下限值,或要求45钢断裂韧性的分散度(即离散系数),这就是参数估计的问题。

又如,经过长期的积累,知道了某材料的断裂韧性的平均值和标准差,经改进热处理后,又测得一批数据,试问新工艺与老工艺相比是否有显著差异,这就是假设检验的问题。

这样可以看出,参数估计是假设检验的第一步,没有参数估计,也就无法完成假设检验。

1.5 应用

在雷达检测中,目标是产生假设的源,它可使用两个假设:H1和H0,分别表示目标存在(H1)和不存在(H0)。这是二元简单假设检验。二元数字通信问题也是简单假设检验。如果假设中含有目标未知参量,则是复合假设检验。m元通信问题也是复合假设检验。如果未知参量是随机变化的,则是随机参量信号的假设检验。

通信系统和雷达系统常用的最佳准则,是最小错误概率准则,即最大后验概率准则。以雷达检测为例:目标是源,它可使用的两个假设是H1和H0。接收端收到样本X(雷达回波)后,判定H1为真(目标存在),或判定H0为真(目标不存在概率可分别表示为p(H1|X)和p(H0|X),称为后验概率。最大后验概率准则的判决规则是,若

则判定H1为真(选择H1);否则判定H0为真。

2、显著性检验

显著性检验(significance test)就是事先对总体随机变量)的参数或总体分布形式做出一个假设,然后利用样本信息来判断这个假设(备择假设)是否合理,即判断总体的真实情况与原假设是否有显著性差异。或者说,显著性检验要判断样本与我们对总体所做的假设之间的差异是纯属机会变异,还是由我们所做的假设与总体真实情况之间不一致所引起的。 显著性检验是针对我们对总体所做的假设做检验,其原理就是“小概率事件实际不可能性原理”来接受或否定假设。

抽样实验会产生抽样误差,对实验资料进行比较分析时,不能仅凭两个结果(平均数或率)的不同就作出结论,而是要进行统计学分析,鉴别出两者差异是抽样误差引起的,还是由特定的实验处理引起的。

2.1 含义

显著性检验即用于实验处理组与对照组或两种不同处理的效应之间是否有差异,以及这种差异是否显著的方法。

常把一个要检验的假设记作H0,称为原假设(或零假设) (null hypothesis) ,与H0对立的假设记作H1,称为备择假设(alternative hypothesis) 。

⑴ 在原假设为真时,决定放弃原假设,称为第一类错误,其出现的概率通常记作α;

⑵ 在原假设不真时,决定不放弃原假设,称为第二类错误,其出现的概率通常记作β

(3)α+β 不一定等于1 [2]

通常只限定犯第一类错误的最大概率α, 不考虑犯第二类错误的概率β。这样的假设 检验又称为显著性检验,概率α称为显著性水平

最常用的α值为0.01、0.05、0.10等。一般情况下,根据研究的问题,如果放弃真假设损失大,为减少这类错误,α取值小些 ,反之,α取值大些。

2.2 目的

为什么要进行显著性检验进行显著性检验是为了消除第一类错误和第二类错误。通常情况下,α水平就是第一类错误。第一类错误是零假设为真却被错误拒绝的概率。第二类错误(β)是零假设为误却被错误接受的概率或是研究假设为真却被拒绝的概率。如果P值小于某个事先确定的水平,理论上则拒绝零假设,反之,如果P值大于某个事先确定的水平,理论上则不拒绝零假设。常用的显著性水平是0.05,0.01和0.001[2] 。不同的水平各有优缺点。水平越小,判定显著性的证据就越充分,但是不拒绝错误零假设的风险,犯第二类错误的可能性就越大,统计效力(就越低。选择水平不可避免地要在第一类错误和第二类错误之间做出权衡。如果犯第一类错误造成的后果不严重,比如在试探性研究中,我们可以将α水平定得高一些,如0.05或0.1。如果研究样本很小,为了提高统计效力,我们在某些研究中也不妨提高口水平。但是,如果犯第一类错误造成的后果很严重,比如我们要基于某项研究发现决定是否在全国推行某项教学改革,我们则需要将α水平定得低一些,如0.01或0.001。

2.3 常用的检验

2.3.1 t检验

T检验,亦称student t检验(Student’s t test),主要用于样本含量较小(例如n < 30),总体标准差σ未知的正态分布。 [2.1]

2.1. Fisher Box, Joan. Guinness, Gosset, Fisher, and Small Samples. Statistical Science. 1987, 2 (1): 45–52.

T检验是用t分布理论来推论差异发生的概率,从而比较两个平均数的差异是否显著。它与f检验、卡方检验并列。t检验是戈斯特为了观测酿酒质量而发明的,并于1908年在Biometrika上公布 [2.2] 。

2.2. 尹希果主编.计量经济学原理与操作:重庆大学出版社,2009.09:37

适用条件

(1) 已知一个总体均数;

(2) 可得到一个样本均数及该样本标准差

(3) 样本来自正态或近似正态总体 [2.3]。

主要分类

t检验可分为单总体检验和双总体检验,以及配对样本检验 [2.1]

1)单总体检验

单总体t检验是检验一个样本平均数与一个已知的总体平均数的差异是否显著。当总体分布是正态分布,如总体标准差未知且样本容量小于30,那么样本平均数与总体平均数的离差统计量呈t分布。

单总体t检验统计量为:

其中,$i = 1, …, n$, $\bar{x} = \frac{\sum{i=1}^{n}x{i}}{n}$ 为样本平均数,$\delta$ 、$s = \sqrt{\frac{\sum{i=1}^{n}(x{i}-\bar{x})^{2}}{n-1}}$ 为样本标准差,$n$为样本数。该统计量$t$在零假说:$\mu = \mu_{0}$ 为真的条件下服从自由度为 n-1 的 t分布。

2)双总体检验

双总体t检验是检验两个样本平均数与其各自所代表的总体的差异是否显著。双总体t检验又分为两种情况,一是独立样本t检验(各实验处理组之间毫无相关存在,即为独立样本),该检验用于检验两组非相关样本被试所获得的数据的差异性;一是配对样本t检验,用于检验匹配而成的两组被试获得的数据或同组被试在不同条件下所获得的数据的差异性,这两种情况组成的样本即为相关样本。

(1)独立样本t检验统计量为:

$S{1}^{2}$ 和$S{2}^{2}$为两样本方差;$n{1}$ 和 $n{2}$为两样本容量

(2)配对样本检验

配对样本t检验可视为单样本t检验的扩展,不过检验的对象由一群来自常态分配独立样本更改为二群配对样本之观测值之差。若二配对样本x1ix2i之差为d**i=x1ix2i独立,且来自常态分配,则d**i之母体期望值μ是否为μ0可利用以下统计量:

其中,$i = 1, …, n, \bar{d} = \frac{\sum{i=1}^{n}d{i}}{n}$ 为配对样本差值之平均数,$s{d} = \sqrt{\frac{\sum{i=1}^{n}(d{i}-\bar{d})^{2}}{n-1}}$ 为配对样本差值之标准偏差,$n$ 为配对样本数。该统计量 $t$ 在零假说:$\mu = \mu{0}$ 为真的条件下服从自由度为 $n−1$ 的t分布

检验步骤

下面以一个实例的单总体t检验对t检验做一说明: [2.4]

问题:难产儿出生数n = 35,体重均值 $\bar{x}=3.42, S = 0.40$, 一般婴儿出生体重 μ0= 3.30(大规模调查获得),问相同否?

解:

1.建立假设、确定检验水准α

​ H0:μ = μ0 (零假设null hypothesis)

​ H1:μ ≠ μ0(备择假设alternative hypothesis)

​ 双侧检验,检验水准:α=0.05

2.计算检验统计量

2.3.2 t 检验

2.3.3 U检验

2.3.4 方差分析

参考文献

[1] 邓奋发. MATLAB R2015b概率与数理统计[M]. 北京:清华大学出版社, 2017.01.第139页.

[2] 张厚粲, 徐建平. 现代心理与教育统计学[M]. 北京师范大学出版社, 2004.

[3] 张凤菊, 刘晓娟, 赵丽平,等. 数据差异显著性检验[J]. 农机使用与维修, 2012(4):51-52.