操屁眼的视频在线免费看,日本在线综合一区二区,久久在线观看免费视频,欧美日韩精品久久综

新聞資訊

    安裝(Ubuntu)使用(常用命令)容器數(shù)據(jù)卷創(chuàng)建自定義鏡像DockerFile容器內(nèi)自定義鏡像源自定義網(wǎng)絡(luò)保存鏡像導(dǎo)入鏡像推送鏡像到hub Docker常用命令

    Docker常用命令

    • 官方下載安裝
    • 官方文檔
    • Docker倉庫搜索

    安裝(Ubuntu)

    • 更多內(nèi)容請查考官方文檔
    • 依次執(zhí)行下列代碼即可!
    #卸載舊版本
    sudo apt-get remove docker docker-engine docker.io containerd runc
    
    #使用 Docker 倉庫進(jìn)行安裝
    #更新 apt 包索引
    sudo apt-get update
    
    #安裝 apt 依賴包,用于通過HTTPS來獲取倉庫
    sudo apt-get install \
        apt-transport-https \
        ca-certificates \
        curl \
        gnupg \
        lsb-release \
        software-properties-common
        
    #添加Docker官方的GPG密鑰(使用鏡像)
     curl -fsSL https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/gpg | sudo apt-key add -
     
    #設(shè)置穩(wěn)定版?zhèn)}庫
    sudo add-apt-repository \
       "deb [arch=amd64] https://mirrors.ustc.edu.cn/docker-ce/linux/ubuntu/ \
      $(lsb_release -cs) \
      stable"
      
    #安裝 Docker 引擎
    sudo apt-get update
    sudo apt-get install docker-ce docker-ce-cli containerd.io
    
    • 測試是否安裝成功
    sudo docker run hello-world
    
    xiaoqiang@xiaoqiangclub:~/桌面$ sudo docker run hello-world
    Unable to find image 'hello-world:latest' locally
    latest: Pulling from library/hello-world
    b8dfde127a29: Already exists 
    Digest: sha256:9f6ad537c5132bcce57f7a0a20e317228d382c3cd61edae14650eec68b2b345c
    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/
    
    
    • 更多內(nèi)容請查考官方文檔

    使用(常用命令)

    • 下面是一些常用命令
    #萬能的幫助命令
    docker 命令 --help   #docker images --help
    
    #搜索鏡像
    docker search 鏡像  #docker search ubuntu
    
    #拉取鏡像
    docker pull 鏡像:版本 #docker pull ubuntu:18.04
    
    #查看本地所有鏡像
    docker images
    docker images -aq  #顯示所有鏡像的id 
    
    #刪除鏡像
    docker rmi -f 鏡像名/id  #-f強(qiáng)制刪除鏡像
    docker rmi -f $(docker images -aq)  #刪除所有鏡像
    
    #啟動容器,可以使用 鏡像名:版本號 啟動,如果是最新版可以省略版本號;也可以使用 鏡像id
    docker run -i -t 鏡像名:版本號 /bin/bash  
    docker run -i -t id /bin/bash
    docker run -it --rm id /bin/bash  #添加 --rm參數(shù) 可以實(shí)現(xiàn)在退出容器后就刪除容器(一般用于測試)
    參數(shù)說明:
    -i: 交互式操作。
    -t: 終端。
    ubuntu: ubuntu 鏡像。
    /bin/bash:放在鏡像名后的是命令,這里我們希望有個(gè)交互式 Shell,因此用的是 /bin/bash。
    要退出終端,直接輸入 exit 這個(gè)命令會停止容器!可以使用 ctrl + p + q 組合鍵退出,不會退出容器
    
    #退出容器
    exit      #這個(gè)命令會停止容器!
    ctrl + p + q    #組合鍵退出,不會退出容器
    
    #查看當(dāng)前運(yùn)行的容器
    docker ps
    docker ps -a     #顯示所有容器
    #啟動一個(gè)已停止的容器
    docker start 容器id #通過docker ps -a可以查看
    #重啟一個(gè)容器
    docker restart 容器id 
    #停止容器
    docker stop 容器id
    docker kill 容器id   #當(dāng)使用 stop 無法正常停止的時(shí)候使用 kill
    
    #后臺運(yùn)行容器:-d 后臺運(yùn)行 --name 設(shè)定容器的別名
    docker run -i -t -d -p 外網(wǎng)端口:容器端口 --name 容器別名 鏡像 /bin/bash  #docker run -i -t -d -p 6666:80 --name ubuntu-test ubuntu /bin/bash
    
    #在使用 -d 參數(shù)時(shí),容器啟動后會進(jìn)入后臺,此時(shí)想要進(jìn)入容器,可以通過以下指令進(jìn)入
    docker attach 容器id  #重新進(jìn)入容器當(dāng)前正在運(yùn)行的命令終端,使用exit會停止容器!
    docker exec -i -t 容器id /bin/bash #進(jìn)入容器并開啟一個(gè)新的終端,使用exit不會停止容器(常用)
    
    #刪除容器
    docker rm -f 容器別名/容器id  #docker rm -f test_ubuntu
    
    #拷貝容器文件到宿主機(jī)(復(fù)制文件)
    docker cp 容器id/容器id:容器內(nèi)文件路徑 要拷貝到的路徑  #docker cp test-ubuntu:/home/test.txt /home
    
    #查看容器的cpu內(nèi)存狀態(tài)
    docker stats
    
    # 從容器創(chuàng)建一個(gè)新的鏡像
    docker commit -a 作者 -m 說明信息 容器id 容器名稱:版本號 #docker commit -a "xiaoqiangclub" -m "this is a test!" a404c6c174a2  mymysql:v1 
    OPTIONS說明:
    
    -a :提交鏡像的作者;
    
    -c :使用Dockerfile指令來創(chuàng)建鏡像;
    
    -m :提交時(shí)的說明文字;
    
    -p :在commit時(shí),將容器暫停。
    
    • docker run -it --rm id /bin/bash 添加參數(shù) --rm 可以實(shí)現(xiàn)在退出容器后就刪除容器(一般用于測試)
    • 直接輸入exit 這個(gè)命令會停止容器!可以使用ctrl + p + q 組合鍵退出,不會退出容器
    • 我們常用docker exec -i -t 容器id /bin/bash命令進(jìn)入容器并開啟一個(gè)新的終端,這個(gè)命令進(jìn)入容器后使用exit不會停止容器
    • 后臺啟動容器使用docker run -i -t -d --name ubuntu-test ubuntu /bin/bash
    • 復(fù)制文件命令docker cp test-ubuntu:/home/test.txt /home
    • docker run -m設(shè)置容器使用內(nèi)存最大值

    容器數(shù)據(jù)卷

    為了容器內(nèi)數(shù)據(jù)的持久化&與宿主機(jī)的數(shù)據(jù)同步,我們可以使用容器的數(shù)據(jù)卷。

    • 添加-v參數(shù)來映射目錄,命令docker run -it -v 主機(jī)目錄:容器目錄 鏡像 /bin/bash
    • 具名掛載:- 添加-v參數(shù)來映射目錄,命令docker run -it -v 卷名:主機(jī)目錄:容器目錄 鏡像 /bin/bash;使用docker volume ls查看卷
    docker 容器內(nèi)路徑    # 匿名掛載
    docker 卷名:容器內(nèi)路徑   # 具名掛載
    docker /宿主機(jī)路徑:容器內(nèi)路徑 # 指定路徑掛載
    docker 卷名:容器內(nèi)路徑:ro/rw  # 使用ro/rw來設(shè)置讀寫權(quán)限:ro:readonly;rw:readwrite;默認(rèn)為:rw;如果設(shè)置為ro:說明這個(gè)路徑只能通過宿主機(jī)改變,容器內(nèi)無法改變!
    
    • docker inspect獲取容器/鏡像的元數(shù)據(jù)(詳情)

    創(chuàng)建自定義鏡像

    • 使用Docker commit 命令從容器創(chuàng)建一個(gè)新的鏡像,下面是他的用法
    xiaoqiang@xiaoqiangclub:~/studyArea/dockerStudy$ docker commit --help
    
    Usage:  docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]] # 用法
    
    Create a new image from a container's changes
    
    Options:
      -a, --author string    作者(e.g., "John Hannibal Smith <hannibal@a-team.com>")
      -c, --change list      使用Dockerfile指令來創(chuàng)建鏡像
      -m, --message string   提交時(shí)的說明文字
      -p, --pause            在commit時(shí),將容器暫停 (默認(rèn):true)
    
    • 我們運(yùn)行容器并且在容器中安裝了ipython,現(xiàn)在使用commit來創(chuàng)建一個(gè)行的鏡像
    xiaoqiang@xiaoqiangclub:~/studyArea/dockerStudy$ docker commit -m 'add ipython' -a 'xiaoqiangclub<xiaoqiangclub@hotmail.com>' image-test image-commit-test
    sha256:b6819ae4531e548c7ff400017d302da82601f931eed7c1edf765465556601d64
    
    • docker images查看鏡像
    xiaoqiang@xiaoqiangclub:~/studyArea/dockerStudy$ docker images
    REPOSITORY          TAG       IMAGE ID       CREATED         SIZE
    image-commit-test   latest    b6819ae4531e   2 minutes ago   234MB  # 這個(gè)就是我們安裝ipython后新創(chuàng)建的鏡像
    my-ubuntu           latest    beb3e79259ee   10 hours ago    134MB
    

    DockerFile

    Dockerfile就是用來構(gòu)建docker鏡像的構(gòu)建文件

    • DockerFile常用命令
    FROM    # 基礎(chǔ)鏡像
    MAINTAINER   # 作者,姓名 + 郵箱
    RUN     # 鏡像構(gòu)建的時(shí)候需要運(yùn)行的命令
    ADD     # 添加內(nèi)容(COPY文件,會自動解壓)
    WORKDIR    # 設(shè)置工作目錄(相當(dāng)于cd)
    VOLUME    # 目錄掛載
    EXPOST    # 暴露端口
    CMD     # 指定容器啟動的時(shí)候需要運(yùn)行的命令,只有最后一個(gè)會生效,可被替代!
    ENTRYPOINT   # 指定容器啟動的時(shí)候需要運(yùn)行的命令,可以追加命令
    ONBUILD    # 當(dāng)構(gòu)建一個(gè)被繼承時(shí),DockerFile 就會運(yùn)行 ONBUILD 的指令,是一個(gè)觸發(fā)指令。
    COPY    # 類似ADD,將文件拷貝到鏡像中
    ENV     # 構(gòu)建的時(shí)候設(shè)置環(huán)境變量
    

    DockerFile常用命令

    容器內(nèi)自定義鏡像源

    • 簡單示例
    xiaoqiang@xiaoqiangclub:~/桌面/docker-study/DockerFile$ vim myDockFile-ubuntu
    xiaoqiang@xiaoqiangclub:~/桌面/docker-study/DockerFile$ cat myDockFile-ubuntu 
    FROM ubuntu
    MAINTAINER xiaoqiangclub<xiaoqiangclub@hotmail.com>
    
    ENV MYPATH /usr/local
    WORKDIR $MYPATH
    
    # 設(shè)置鏡像源
    COPY sources.list /etc/apt/sources.list  
    # 使用&&連接構(gòu)建為一層,最后清理緩存
    RUN apt update \
    &&apt-get install -y vim net-tools \
    && rm -rf /var/lib/apt/lists/*
    
    EXPOSE 80
    
    CMD echo $MYPATH
    CMD ECHO "----end----"
    CMD /bin/bash
    
    • 報(bào)錯(cuò)解決方案
    • sources.list文件
    deb http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
    deb-src http://mirrors.aliyun.com/ubuntu/ bionic main restricted universe multiverse
    
    deb http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
    deb-src http://mirrors.aliyun.com/ubuntu/ bionic-security main restricted universe multiverse
    
    deb http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
    deb-src http://mirrors.aliyun.com/ubuntu/ bionic-updates main restricted universe multiverse
    
    deb http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
    deb-src http://mirrors.aliyun.com/ubuntu/ bionic-proposed main restricted universe multiverse
    
    deb http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
    deb-src http://mirrors.aliyun.com/ubuntu/ bionic-backports main restricted universe multiverse
    
    • 使用docker history 容器id/容器名:版本可以查看容器的構(gòu)建過程
    • 容器內(nèi)更換鏡像源后使用apt update可能會提示以下錯(cuò)誤(NO_PUBKEY缺少公鑰):

    • 依次運(yùn)行gpg --keyserver keyserver.ubuntu.com --recv 公鑰gpg --export --armor 公鑰 | apt-key add -即可(非docker容器中運(yùn)行的話需要添加sudo
    root@eee3e5c095f6:/# gpg --keyserver keyserver.ubuntu.com --recv 3B4FE6ACC0B21F32 # 報(bào)錯(cuò)的時(shí)候提供的公鑰
    gpg: directory '/root/.gnupg' created
    gpg: keybox '/root/.gnupg/pubring.kbx' created
    gpg: /root/.gnupg/trustdb.gpg: trustdb created
    gpg: key 3B4FE6ACC0B21F32: public key "Ubuntu Archive Automatic Signing Key (2012) <ftpmaster@ubuntu.com>" imported
    gpg: Total number processed: 1
    gpg:               imported: 1
    root@eee3e5c095f6:/# gpg --export --armor 3B4FE6ACC0B21F32 | apt-key add -
    OK
    
    • 現(xiàn)在在運(yùn)行apt update就正常了!
    • 使用build生成鏡像,先看看參數(shù)說明
    xiaoqiang@xiaoqiangclub:~/桌面/myProjects/myDockerFile$ docker build --help
    
    Usage:  docker build [OPTIONS] PATH | URL | -
    
    Build an image from a Dockerfile
    
    Options:
          --add-host list           Add a custom host-to-IP mapping (host:ip)
          --build-arg list          Set build-time variables
          --cache-from strings      Images to consider as cache sources
          --cgroup-parent string    Optional parent cgroup for the container
          --compress                Compress the build context using gzip
          --cpu-period int          Limit the CPU CFS (Completely Fair Scheduler) period
          --cpu-quota int           Limit the CPU CFS (Completely Fair Scheduler) quota
      -c, --cpu-shares int          CPU shares (relative weight)
          --cpuset-cpus string      CPUs in which to allow execution (0-3, 0,1)
          --cpuset-mems string      MEMs in which to allow execution (0-3, 0,1)
          --disable-content-trust   Skip image verification (default true)
      -f, --file string             Name of the Dockerfile (Default is 'PATH/Dockerfile')
          --force-rm                Always remove intermediate containers
          --iidfile string          Write the image ID to the file
          --isolation string        Container isolation technology
          --label list              Set metadata for an image
      -m, --memory bytes            Memory limit
          --memory-swap bytes       Swap limit equal to memory plus swap: '-1' to enable unlimited swap
          --network string          Set the networking mode for the RUN instructions during build (default "default")
          --no-cache                Do not use cache when building the image
          --pull                    Always attempt to pull a newer version of the image
      -q, --quiet                   Suppress the build output and print image ID on success
          --rm                      Remove intermediate containers after a successful build (default true)
          --security-opt strings    Security options
          --shm-size bytes          Size of /dev/shm
      -t, --tag list                Name and optionally a tag in the 'name:tag' format
          --target string           Set the target build stage to build.
          --ulimit ulimit           Ulimit options (default [])
    
    • 如果你的文件名為Dockerfile,可以直接使用docker build -t 鏡像名:版本號 .(注意最后有一個(gè)點(diǎn),如果是其他文件名,請使用-f參數(shù)指定文件路徑)

    自定義網(wǎng)絡(luò)

    • 我們可以使用docker network自定義網(wǎng)絡(luò),使用說明
    Usage:  docker network COMMAND
    
    Manage networks
    
    Commands:
      connect     # 將一個(gè)容器連接到網(wǎng)絡(luò)
      create      # 創(chuàng)建一個(gè)自定義網(wǎng)絡(luò)
      disconnect  # 將一個(gè)容器從自定義網(wǎng)絡(luò)斷開
      inspect     # 顯示自定義網(wǎng)絡(luò)的詳細(xì)信息
      ls          # 列出所有網(wǎng)絡(luò)
      prune       # 刪除所有未使用的網(wǎng)絡(luò)
      rm          # 刪除一個(gè)或多個(gè)網(wǎng)絡(luò)
    
    • 下面是docker默認(rèn)的網(wǎng)絡(luò)
    xiaoqiang@xiaoqiangclub:~/studyArea/dockerStudy$ docker network ls
    NETWORK ID     NAME                DRIVER    SCOPE
    b3c47254c1ce   bridge              bridge    local
    205f46f5b907   host                host      local
    8d0210334194   none                null      local
    
    • 我們可以使用--net 網(wǎng)絡(luò)的方式指定容器使用的網(wǎng)絡(luò),如docker run -it --net host my-ubuntu
    • 有時(shí)候在docker中使用Ubuntu鏡像無法聯(lián)網(wǎng),我們可以嘗試使用命令docker run -it --net host ubuntu即可解決!(有些情況下重啟一下主機(jī)就解決了!)
    • 自己創(chuàng)建一個(gè)docker network create參數(shù)
    xiaoqiang@xiaoqiangclub:~/studyArea/dockerStudy$ docker network create --help
    
    Usage:  docker network create [OPTIONS] NETWORK
    
    Create a network
    
    Options:
          --attachable           Enable manual container attachment
          --aux-address map      Auxiliary IPv4 or IPv6 addresses used by Network driver (default map[])
          --config-from string   The network from which to copy the configuration
          --config-only          Create a configuration only network
      -d, --driver string        創(chuàng)建一個(gè)網(wǎng)絡(luò),默認(rèn):bridge
          --gateway strings      網(wǎng)關(guān)
          --ingress              Create swarm routing-mesh network
          --internal             Restrict external access to the network
          --ip-range strings     Allocate container ip from a sub-range
          --ipam-driver string   IP Address Management Driver (default "default")
          --ipam-opt map         Set IPAM driver specific options (default map[])
          --ipv6                 Enable IPv6 networking
          --label list           Set metadata on a network
      -o, --opt map              Set driver specific options (default map[])
          --scope string         Control the network's scope
          --subnet strings       子網(wǎng)掩碼
    
    • --drive類型
    bridge:多由于獨(dú)立container之間的通信
    host: 直接使用宿主機(jī)的網(wǎng)絡(luò),端口也使用宿主機(jī)的
    overlay:當(dāng)有多個(gè)docker主機(jī)時(shí),跨主機(jī)的container通信
    macvlan:每個(gè)container都有一個(gè)虛擬的MAC地址
    none: 禁用網(wǎng)絡(luò)
    
    • 根據(jù)上面的使用說明,我們可以嘗試使用命令docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet來創(chuàng)建一個(gè)網(wǎng)絡(luò)(也可以直接簡寫docker network create test-net):
    xiaoqiang@xiaoqiangclub:~/studyArea/dockerStudy$ docker network create --driver bridge --subnet 192.168.0.0/16 --gateway 192.168.0.1 mynet
    856ac8b90e9b76be642751446de170d6400b9a9c96f896f1ee71de8db7f4d8f0
    
    • 現(xiàn)在查看一下docker下的網(wǎng)絡(luò)docker network ls
    xiaoqiang@xiaoqiangclub:~/studyArea/dockerStudy$ docker network ls
    NETWORK ID     NAME                DRIVER    SCOPE
    2087a9b3522d   bridge              bridge    local
    205f46f5b907   host                host      local
    856ac8b90e9b   mynet               bridge    local  # 這就是我們剛創(chuàng)建的網(wǎng)絡(luò)
    8d0210334194   none                null      local
    9cad2d367255   proxypool_default   bridge    local
    
    • 現(xiàn)在我們就可以使用剛剛創(chuàng)建的網(wǎng)絡(luò)運(yùn)行容器試試了!
    xiaoqiang@xiaoqiangclub:~/studyArea/dockerStudy$ docker run -it --net=mynet my-ubuntu
    root@59052c9eca94:/usr/local# ifconfig
    eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
            inet 192.168.0.2  netmask 255.255.0.0  broadcast 192.168.255.255 # 使用了我們剛創(chuàng)建的網(wǎng)絡(luò)
            ether 02:42:c0:a8:00:02  txqueuelen 0  (Ethernet)
            RX packets 23  bytes 4216 (4.2 KB)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 0  bytes 0 (0.0 B)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    
    • 可以添加--ip指定容器的ip(在網(wǎng)卡的網(wǎng)段內(nèi)),例如:docker run -it --net mynet --ip 192.168.0.66 my-ubuntu

    保存鏡像

    • 使用docker save將指定鏡像保存成 tar 歸檔文件,來看一下它的參數(shù)
    xiaoqiang@xiaoqiangclub:~/桌面$ docker save --help
    
    Usage:  docker save [OPTIONS] IMAGE [IMAGE...]
    
    Save one or more images to a tar archive (streamed to STDOUT by default)
    
    Options:
      -o, --output string   輸入文件
    
    • 例如docker save -o /home/xiaoqiang/桌面/myProjects/my-django-web-image.tar xiaoqiangclub/django-web:v1.0

    導(dǎo)入鏡像

    • 使用docker load 導(dǎo)入docker save 命令導(dǎo)出的鏡像,參數(shù)
    xiaoqiang@xiaoqiangclub:~/桌面$ docker load --help
    
    Usage:  docker load [OPTIONS]
    
    Load an image from a tar archive or STDIN
    
    Options:
      -i, --input string   # 指定導(dǎo)入的文件,代替 STDIN
      -q, --quiet          # 精簡輸出信息
    
    • 例如docker load --input my-django-web-image.tar,也可以docker load < my-django-web-image.tar

    推送鏡像到hub

    • docker login docker logout登入登出
    • 參考文章

    • 阿里云復(fù)制下來的操作指南

    1. 登錄阿里云Docker Registry
    $ docker login --username=xiaoqiang**** registry.cn-hangzhou.aliyuncs.com
    用于登錄的用戶名為阿里云賬號全名,密碼為開通服務(wù)時(shí)設(shè)置的密碼。

    您可以在訪問憑證頁面修改憑證密碼。

    2. 從Registry中拉取鏡像
    $ docker pull registry.cn-hangzhou.aliyuncs.com/xiaoqiangclub/xiaoqiangclub:[鏡像版本號]
    3. 將鏡像推送到Registry
    $ docker login --username=xiaoqiang**** registry.cn-hangzhou.aliyuncs.com
    $ docker tag [ImageId] registry.cn-hangzhou.aliyuncs.com/xiaoqiangclub/xiaoqiangclub:[鏡像版本號]
    $ docker push registry.cn-hangzhou.aliyuncs.com/xiaoqiangclub/xiaoqiangclub:[鏡像版本號]
    請根據(jù)實(shí)際鏡像信息替換示例中的[ImageId]和[鏡像版本號]參數(shù)。

    4. 選擇合適的鏡像倉庫地址
    從ECS推送鏡像時(shí),可以選擇使用鏡像倉庫內(nèi)網(wǎng)地址。推送速度將得到提升并且將不會損耗您的公網(wǎng)流量。

    如果您使用的機(jī)器位于VPC網(wǎng)絡(luò),請使用 registry-vpc.cn-hangzhou.aliyuncs.com 作為Registry的域名登錄。

    5. 示例
    使用"docker tag"命令重命名鏡像,并將它通過專有網(wǎng)絡(luò)地址推送至Registry。

    $
    docker images
    REPOSITORY TAG IMAGE ID CREATED VIRTUAL SIZE
    registry.aliyuncs.com/acs/agent 0.7-dfb6816 37bb9c63c8b2 7 days ago 37.89 MB
    $ docker tag 37bb9c63c8b2 registry-vpc.cn-hangzhou.aliyuncs.com/acs/agent:0.7-dfb6816
    使用 "docker push" 命令將該鏡像推送至遠(yuǎn)程。

    $
    docker push registry-vpc.cn-hangzhou.aliyuncs.com/acs/agent:0.7-dfb6816

    本文深度參考了以下這些文章的真知灼見!特此說明,并表示感謝:

    • ? The Dynamo Paper[1]

    • ? The DynamoDB paper[2]

    • ? Key Takeaways from the DynamoDB Paper[3]

    • ? DynamoDB 2022 論文解讀[4]

    Dynamo 前傳

    2004 年,Amazon.com 發(fā)展迅速,并開始達(dá)到其 Oracle 數(shù)據(jù)庫的擴(kuò)展上限。它開始考慮在內(nèi)部構(gòu)建自己的數(shù)據(jù)庫。在這個(gè)實(shí)驗(yàn)中,工程師創(chuàng)建了 Amazon Dynamo 數(shù)據(jù)庫,該數(shù)據(jù)庫支持主要的內(nèi)部基礎(chǔ)設(shè)施,包括 Amazon.com 網(wǎng)站上的購物車。

    Amazon Dynamo 數(shù)據(jù)庫背后的一群工程師于 2007 年發(fā)表了Dynamo 論文[5]。它描述了構(gòu)建內(nèi)部高可用鍵值存儲的經(jīng)驗(yàn)教訓(xùn),旨在滿足 Amazon.com 網(wǎng)站的苛刻要求。

    該論文極具影響力并啟發(fā)了許多 NoSQL 數(shù)據(jù)庫,包括 Apache Cassandra(最初在 Facebook 開發(fā))和 AWS 產(chǎn)品 SimpleDB 和 DynamoDB。2012 年,Amazon Web Services 推出了 DynamoDB,這是一種以 Dynamo 背后的原理為藍(lán)本的托管數(shù)據(jù)庫服務(wù)。

    Dynamo 的核心設(shè)計(jì)理念

    沒有關(guān)系模型

    關(guān)系數(shù)據(jù)模型是對許多類型的數(shù)據(jù)進(jìn)行建模的有用方法。通常,對關(guān)系數(shù)據(jù)進(jìn)行規(guī)范化以提高數(shù)據(jù)的完整性。您可以將其存儲在一個(gè)位置并使用從一個(gè)表到另一個(gè)表的 JOIN 操作來引用它,而不是在多行中復(fù)制一條特定的數(shù)據(jù)。你可以更新單個(gè)位置,并且引用該數(shù)據(jù)的所有的item也將獲得更新的收益。

    然而,Amazon.com 工程師在收集數(shù)據(jù)庫需求時(shí)最有趣的發(fā)現(xiàn)之一是他們的工程師如何使用他們的關(guān)系數(shù)據(jù)庫:

    大約 70% 的操作屬于鍵值類型,僅使用主鍵并返回單行。大約 20% 會返回一組行,但仍然只對單個(gè)表進(jìn)行操作。——沃納·沃格爾斯

    90% 的操作沒有使用關(guān)系數(shù)據(jù)庫的核心 JOIN 功能!

    JOIN 操作很昂貴。在足夠大的規(guī)模上,工程師經(jīng)常對他們的數(shù)據(jù)進(jìn)行非規(guī)范化,以避免進(jìn)行昂貴的join和減慢響應(yīng)時(shí)間。這種響應(yīng)時(shí)間的減少伴隨著應(yīng)用程序復(fù)雜性的增加——現(xiàn)在您需要在代碼中而不是在數(shù)據(jù)庫中管理更多的數(shù)據(jù)完整性問題。

    Amazon.com工程師已經(jīng)在權(quán)衡非規(guī)范化以縮短響應(yīng)時(shí)間。意識到亞馬遜工程師不需要關(guān)系模型,Dynamo 設(shè)計(jì)人員可以重新評估關(guān)系數(shù)據(jù)庫的其他方面。

    可用性 > 一致性

    大多數(shù)關(guān)系數(shù)據(jù)庫對其數(shù)據(jù)使用高度一致的模型。簡而言之,這意味著如果同時(shí)查詢,服務(wù)器的所有客戶端將看到相同的數(shù)據(jù)。

    讓我們以 Twitter 為例。想象一下,弗吉尼亞州的 Bob 在下午 2:30 發(fā)布了一張貓的照片。在 Bob 發(fā)布照片后,有兩個(gè)用戶查看了 Bob 的個(gè)人資料:他的鄰居 Cheryl 和住在新加坡的叔叔 Jeffrey。如果 Twitter 使用強(qiáng)一致性模型,那么 Cheryl 和 Jeffrey 都應(yīng)該在 Bob 的操作提交到數(shù)據(jù)庫后立即看到 Bob 的最新推文。

    由于幾個(gè)原因,這可能并不理想。首先,考慮一下這個(gè)場景所涉及的地理環(huán)境。Twitter 可以選擇使用單個(gè)數(shù)據(jù)庫實(shí)例來實(shí)現(xiàn)這種強(qiáng)一致性。此數(shù)據(jù)庫實(shí)例可能位于弗吉尼亞州,靠近 Bob 和 Cheryl。這會導(dǎo)致對 Bob 和 Cheryl 的快速響應(yīng),但對 Jeffrey 的響應(yīng)非常緩慢,因?yàn)槊總€(gè)請求都必須從新加坡穿越海洋到弗吉尼亞州以請求數(shù)據(jù),然后從弗吉尼亞州返回新加坡以將其返回給 Jeffrey。這會導(dǎo)致某些用戶的讀取時(shí)間變慢。

    與維護(hù)單個(gè)數(shù)據(jù)庫實(shí)例不同,Twitter 可能希望擁有兩個(gè)完全相同的實(shí)例——一個(gè)在弗吉尼亞州,一個(gè)在新加坡。如果我們?nèi)匀幌氡3謴?qiáng)一致性,這意味著如果她同時(shí)查詢弗吉尼亞實(shí)例或新加坡實(shí)例,用戶必須得到相同的答案。這可以通過一個(gè)更復(fù)雜的數(shù)據(jù)庫寫入系統(tǒng)來實(shí)現(xiàn)——在 Bob 的推文提交到數(shù)據(jù)庫之前,它必須同時(shí)提交給弗吉尼亞實(shí)例和新加坡實(shí)例。現(xiàn)在 Bob 的請求需要跨越大洋并返回。這會導(dǎo)致某些用戶的寫入時(shí)間變慢。

    在 Dynamo 論文中,亞馬遜指出,強(qiáng)一致性并非在所有場景中都很重要。在我們的示例中,如果 Jeffrey 和 Cheryl 看到我的個(gè)人資料的版本略有不同,即使他們同時(shí)查詢也是可以的。有時(shí)您可以滿足于最終的一致性,這意味著不同的用戶最終會看到相同的數(shù)據(jù)視圖。Jeffrey 最終會在新加坡看到 Bob 的推文,但可能是下午 2:32 而不是 2:30。

    強(qiáng)一致性對于某些用例很重要——想想銀行賬戶余額——但對于其他用例來說則不太重要,例如我們的 Twitter 示例或亞馬遜購物車,這是 Dynamo 的推動力。對于這些用例,速度和可用性比一致更重要。通過削弱關(guān)系數(shù)據(jù)庫的一致性模型,Dynamo 工程師能夠提供更符合 Amazon.com 需求的數(shù)據(jù)庫。

    無限可擴(kuò)展

    Dynamo 的最后一個(gè)關(guān)鍵方面是它可以無限擴(kuò)展,不會對性能產(chǎn)生任何負(fù)面影響。這方面是放寬先前數(shù)據(jù)庫的關(guān)系和一致性約束的結(jié)果。

    當(dāng)擴(kuò)展系統(tǒng)時(shí),您可以垂直擴(kuò)展(使用具有更多 CPU 或 RAM 更大的服務(wù)器實(shí)例),也可以通過將數(shù)據(jù)拆分到多臺機(jī)器來水平擴(kuò)展,每臺機(jī)器都有完整數(shù)據(jù)集的一個(gè)子集。垂直擴(kuò)展很昂貴,并最終達(dá)到硬件的上限瓶頸。水平縮放更便宜但更難實(shí)現(xiàn)。

    要考慮水平擴(kuò)展,假設(shè)您有一個(gè)用戶數(shù)據(jù)集,您希望將其分布在三臺機(jī)器上。您可以選擇根據(jù)用戶的姓氏將它們拆分到機(jī)器上——A 到 H 進(jìn)入機(jī)器 1,I 到 Q 進(jìn)入機(jī)器 2,R 到 Z 進(jìn)入機(jī)器 3。

    如果您只有一個(gè)用戶,這很好——檢索 Linda Duffy 的調(diào)用可以直接轉(zhuǎn)到機(jī)器 1——但如果您的查詢跨越多臺機(jī)器,則可能會很慢。獲取所有 18 歲以上用戶的查詢將必須訪問所有三臺機(jī)器,從而導(dǎo)致響應(yīng)速度變慢。

    同樣,我們在上一節(jié)中看到了強(qiáng)一致性要求如何使其難以橫向擴(kuò)展。我們將在寫入期間引入延遲,以確保在返回寫入用戶之前將寫入提交給所有節(jié)點(diǎn)。

    放寬這些要求可以讓 Dynamo 在不犧牲性能的情況下更輕松地進(jìn)行水平擴(kuò)展。DynamoDB 使用一致的散列將item分布在多個(gè)節(jié)點(diǎn)上。隨著 DynamoDB 表中數(shù)據(jù)量的增加,AWS 可以在后臺添加額外的節(jié)點(diǎn)來處理這些數(shù)據(jù)。

    DynamoDB 通過本質(zhì)上要求所有讀取操作使用主鍵(掃描除外)來避免多機(jī)問題。在我們之前的用戶示例中,我們的主鍵可以是姓氏,亞馬遜會相應(yīng)地分發(fā)數(shù)據(jù)。如果確實(shí)需要通過 Age 進(jìn)行查詢,則可以使用二級索引通過不同的鍵應(yīng)用相同的分布策略。

    最后,由于 DynamoDB 允許最終一致性,它允許更輕松的數(shù)據(jù)復(fù)制策略。您可以將您的item復(fù)制到三臺不同的機(jī)器上并查詢其中任何一臺以提高吞吐量。由于最終一致性模型,其中一臺機(jī)器在不同時(shí)間對item的視圖可能略有不同,但對于許多用例來說,這是一個(gè)值得接受的權(quán)衡。此外,如果您的應(yīng)用程序需要,您可以顯式指定強(qiáng)一致性讀取。

    這些變化使 DynamoDB 能夠?yàn)閹缀鯚o限量的數(shù)據(jù)提供幾毫秒的查詢延遲——100TB+。

    十五年后又以一篇論文回顧

    十五年后(也就是前不久),亞馬遜的人發(fā)布了一篇關(guān)于 DynamoDB 的新論文[6]。大多數(shù)作者都發(fā)生了變化(除了AWS VP Swami Sivasubramanian ,他同時(shí)出現(xiàn)在兩篇上),但令人好奇的是 Dynamo 的核心概念是如何更新和更改以提供完全托管、高度可擴(kuò)展的多租戶云數(shù)據(jù)庫服務(wù)。

    論文公開了一些數(shù)據(jù):

    2021 年,在 66 小時(shí)的 Amazon Prime Day 購物活動中,亞馬遜系統(tǒng)……對 DynamoDB 進(jìn)行了數(shù)萬億次 API 調(diào)用,峰值達(dá)到每秒 8920 萬次請求

    從任何標(biāo)準(zhǔn)來看,每秒 8900 萬個(gè)請求都是一個(gè)大型數(shù)據(jù)庫(這只是 Amazon 對 DynamoDB 的使用)!

    在這篇文章中,我想討論我從新的 DynamoDB 論文中獲得的主要收獲:

    • ? DynamoDB 服務(wù)的產(chǎn)品級“用戶需求”學(xué)習(xí);和

    • ? 多年來的技術(shù)改進(jìn)使服務(wù)得到進(jìn)一步發(fā)展。

    DynamoDB 論文中的產(chǎn)品級要點(diǎn)

    Dynamo 論文和 DynamoDB 論文都描述了一些令人難以置信的技術(shù)概念,但對用戶需求的討論同樣給我留下了深刻的印象。在這兩篇論文中,都對現(xiàn)有實(shí)踐進(jìn)行了深入調(diào)查,以了解什么是重要的,以及應(yīng)該圍繞核心用戶需求重新考慮什么。

    在 Dynamo 論文中,我們清楚地看到了這一點(diǎn):即 RDBMS 提供的許多高級查詢功能并未被 Amazon 的服務(wù)使用。70% 的數(shù)據(jù)庫操作是使用主鍵的單記錄查找,另外 20% 讀取一組行但只訪問一個(gè)表

    Dynamo 論文還指出,傳統(tǒng)的強(qiáng)一致性保證雖然在某些情況下至關(guān)重要,但并非所有應(yīng)用程序都需要。在許多情況下,通過放寬一致性要求來提高可用性和減少寫入延遲是非常值得的。

    正如 Dynamo 論文重新審視了傳統(tǒng)數(shù)據(jù)庫系統(tǒng)中的一些陳詞濫調(diào)一樣,DynamoDB 論文圍繞使 Dynamo 學(xué)習(xí)更廣泛適用的用戶需求。通過這樣做,DynamoDB 能夠制定一組明確的產(chǎn)品優(yōu)先級,將 DynamoDB 與許多其他數(shù)據(jù)庫產(chǎn)品區(qū)分開來。

    我從論文中獲得了關(guān)于用戶需求的三個(gè)重要說明:

    • ? 恒定可預(yù)測性能的重要性

    • ? 完全托管優(yōu)于自管理

    • ? 用戶數(shù)據(jù)分布不均

    恒定可預(yù)測性能的重要性

    DynamoDB 論文反復(fù)強(qiáng)調(diào)的一點(diǎn)是,對于許多用戶來說,“任何規(guī)模的一致性能通常比中值請求服務(wù)時(shí)間更重要。” 換句話說,最好在中值和尾部延遲之間設(shè)置更窄的范圍,而不是減少中值(甚至 p90 或 p95)延遲。

    對于一些認(rèn)為“DynamoDB 超級快”的人來說,這是一個(gè)令人驚訝的觀點(diǎn)。以下是DynamoDB 跟 RDBMS 在數(shù)據(jù)規(guī)模與性能之間關(guān)系的對比圖:

    在此圖表中,我們看到 RDBMS 延遲會隨著數(shù)據(jù)庫中數(shù)據(jù)量的增加而變差,而 DynamoDB 會隨著數(shù)據(jù)的增加提供一致的性能。隨著并發(fā)請求數(shù)量的增加,同樣的關(guān)系也成立。

    上面的圖表是一個(gè)粗略的草圖,但總體而言是站得住腳的。在特定級別的數(shù)據(jù)和事務(wù)量下,RDBMS 將比 DynamoDB 具有更快的響應(yīng)時(shí)間。從概念上講,這很容易理解。對 DynamoDB 的請求將通過多個(gè)系統(tǒng)(請求路由器、元數(shù)據(jù)系統(tǒng)、身份驗(yàn)證系統(tǒng)),然后再到達(dá)保存請求數(shù)據(jù)的底層物理存儲節(jié)點(diǎn)。雖然這些系統(tǒng)都經(jīng)過了高度優(yōu)化,但它們中的每一個(gè)都為整體請求增加了延遲。相反,單節(jié)點(diǎn) RDBMS 可以跳過很多工作,直接對本地?cái)?shù)據(jù)進(jìn)行操作。

    所以 MySQL 可能會在中位數(shù)上擊敗 DynamoDB,但這還不是全部。出于兩個(gè)原因,您還應(yīng)該全面考慮數(shù)據(jù)庫的性能。

    首先,尾部延遲很重要,尤其是在具有大量組件和子組件的架構(gòu)中。如果對后端的一次調(diào)用導(dǎo)致對底層服務(wù)的大量調(diào)用,那么每個(gè)請求更有可能經(jīng)歷來自某些服務(wù)的尾部延遲,從而導(dǎo)致響應(yīng)速度變慢。

    其次,DynamoDB 性能的一致性和可預(yù)測性可減少您的服務(wù)的長期維護(hù)負(fù)擔(dān)。由于您的應(yīng)用性能不可避免地下降,您不必回來進(jìn)行調(diào)查、調(diào)整和重構(gòu)。您知道您將在測試環(huán)境中獲得與發(fā)布五年后相同的性能,從而使您能夠?qū)W⒂跒橛脩魟?chuàng)造更多價(jià)值的功能。

    總結(jié)一下,DynamoDB 的可預(yù)測性能的核心在于:

    • ? 對 Workload 準(zhǔn)確抽象(WCU/RCU)

    • ? 對 Partition 預(yù)分配配額,并嚴(yán)格限流

    • ? 在 Node 上留出余量作為應(yīng)對突發(fā)場景的臨時(shí)資源池(Burst)

    • ? 使用全局信息進(jìn)行流量調(diào)度,在各個(gè)層面上都流控

    完全托管優(yōu)于自管理

    在無服務(wù)器世界中,我們盡可能專注于構(gòu)建我們業(yè)務(wù)的關(guān)鍵差異化因素,同時(shí)將無差異的繁重工作卸載給其他人。但是亞馬遜的內(nèi)部經(jīng)驗(yàn)和 Dynamo(不是 DynamoDB)的創(chuàng)造者真正推動了它的發(fā)展。

    回想一下,Dynamo 論文在業(yè)界具有巨大的影響力,而亞馬遜的內(nèi)部 Dynamo 系統(tǒng)在可用性和可擴(kuò)展性方面對亞馬遜的巨大運(yùn)營規(guī)模來說是一個(gè)巨大的改進(jìn)。

    盡管有這種改進(jìn),許多內(nèi)部工程師還是選擇避開運(yùn)行 Dynamo,轉(zhuǎn)而使用Amazon SimpleDB,這是 AWS 首次涉足托管 NoSQL 數(shù)據(jù)庫市場。

    如果你從未聽說過 Amazon SimpleDB,那么你并不孤單。DynamoDB 本質(zhì)上是 SimpleDB 的繼任者,幾乎在各個(gè)方面都更勝一籌,AWS 很少再推銷它。

    SimpleDB 有一些真正令人驚訝的缺點(diǎn),例如整個(gè)數(shù)據(jù)庫的大小不能超過 10GB。對于大多數(shù)應(yīng)用程序來說,這是一個(gè)巨大的限制,對于擁有如此龐大的應(yīng)用程序以至于不得不設(shè)計(jì)一個(gè)全新的數(shù)據(jù)庫的公司(Amazom)來說尤其如此。然而工程師選擇使用多個(gè) SimpleDB 表批量處理他們的需求,可能在應(yīng)用程序?qū)舆M(jìn)行分片以將每個(gè)數(shù)據(jù)庫保持在 10GB 以下。這不得不大大增加應(yīng)用程序邏輯的復(fù)雜性。盡管如此,工程師仍然選擇使用 SimpleDB 而不是操作自己的 Dynamo 實(shí)例。

    Amazon 工程師的這種偏好刺激并促進(jìn)了 Amazon DynamoDB 的開發(fā),這是一個(gè)將 Dynamo 的可擴(kuò)展性與 SimpleDB 的完全托管性質(zhì)相結(jié)合的數(shù)據(jù)庫。

    用戶數(shù)據(jù)分布不均

    最后的用戶要點(diǎn)是,您必須與給定的用戶合作,而不是與您想要的用戶合作。在理想情況下,用戶將擁有穩(wěn)定、可預(yù)測的流量,將數(shù)據(jù)訪問均勻地分布在表的鍵空間中。實(shí)際情況大不相同。

    最初的 Dynamo 論文使用一致性哈希的概念將數(shù)據(jù)分布在大約 10GB 大小的獨(dú)立分區(qū)中。(分區(qū)將在下面更深入地討論)。它使用item的分區(qū)鍵跨分區(qū)放置數(shù)據(jù),從而實(shí)現(xiàn)可預(yù)測的性能和線性水平擴(kuò)展。

    此外,與原始 Dynamo 系統(tǒng)不同,DynamoDB 是一個(gè)多租戶系統(tǒng)。你的分區(qū)可能與其他 DynamoDB 用戶表中的分區(qū)位于同一位置。

    最初,DynamoDB 團(tuán)隊(duì)構(gòu)建了一個(gè)系統(tǒng)來避免嘈雜的租戶干擾問題,即一個(gè)分區(qū)的高流量會導(dǎo)致同一存儲節(jié)點(diǎn)上不相關(guān)分區(qū)的體驗(yàn)降低。然而,隨著系統(tǒng)的發(fā)展,他們意識到管理這個(gè)問題的初始系統(tǒng)會導(dǎo)致那些工作量激增、不平衡的workload。

    隨著 AWS 團(tuán)隊(duì)構(gòu)建 DynamoDB,他們意識到他們需要改進(jìn)訪問控制系統(tǒng),以管理是否允許分區(qū)為請求提供服務(wù)。下面我們將更多地研究這種演變的技術(shù)方面。

    DynamoDB 論文的技術(shù)要點(diǎn)

    產(chǎn)品級的學(xué)習(xí)很吸引人,但這最終是一篇技術(shù)論文。DynamoDB 團(tuán)隊(duì)正在大規(guī)模開展的工作令人印象深刻,許多技術(shù)知識甚至適用于那些沒有 DynamoDB 規(guī)模的人。

    我從這篇論文中獲得了三個(gè)最有趣的技術(shù)要點(diǎn):

    • ? 使用日志副本來提高持久性和可用性;

    • ? 為改善對不平衡工作負(fù)載的服務(wù)而采取的增量步驟;

    • ? 使用異步緩存機(jī)制來提高底層服務(wù)的性能、可用性和彈性

    使用日志副本提高持久性和可用性

    更有趣的一點(diǎn)是 DynamoDB 如何使用稱為日志副本的設(shè)計(jì)在實(shí)例故障期間提供幫助。要了解日志副本,我們首先需要了解 DynamoDB 存儲的底層架構(gòu)的一些背景知識。

    DynamoDB 存儲背景部分的開始

    在后臺,DynamoDB 將您的數(shù)據(jù)拆分為分區(qū),這些分區(qū)是大小約為 10GB 的獨(dú)立存儲段。DynamoDB 使用分區(qū)鍵將您的item分配給給定的分區(qū),這允許 DynamoDB 隨著數(shù)據(jù)庫的增長水平擴(kuò)展,同時(shí)仍將相關(guān)item保持在一起。DynamoDB 運(yùn)行大量存儲節(jié)點(diǎn),這些節(jié)點(diǎn)處理來自許多不同用戶表的分區(qū)。

    單個(gè)分區(qū)實(shí)際上是一組位于不同可用區(qū)的三個(gè)分區(qū)實(shí)例,它們形成一個(gè)復(fù)制組。其中一個(gè)實(shí)例是該分區(qū)的leader,負(fù)責(zé)處理所有寫入。當(dāng)有數(shù)據(jù)寫入時(shí),leader將其寫入本地,并確保在返回給客戶端之前將其提交到至少一個(gè)額外的副本。這增加了發(fā)生故障時(shí)的持久性,因?yàn)閬G失一個(gè)節(jié)點(diǎn)不會導(dǎo)致數(shù)據(jù)丟失。

    一個(gè)分區(qū)的副本構(gòu)成一個(gè)復(fù)制組。復(fù)制組使用 Multi-Paxos 進(jìn)行領(lǐng)導(dǎo)者選舉和共識。只有領(lǐng)導(dǎo)者副本可以服務(wù)寫入和強(qiáng)一致性讀取請求。收到寫入請求后,正在寫入的密鑰的復(fù)制組的領(lǐng)導(dǎo)者會生成一個(gè)預(yù)寫日志記錄并將其發(fā)送給其對等方(副本)。...復(fù)制組的任何副本都可以提供最終一致的讀取。

    每個(gè)存儲分區(qū)上都有兩個(gè)數(shù)據(jù)結(jié)構(gòu) - B-Tree 包含分區(qū)上的索引數(shù)據(jù)以及預(yù)寫日志 (WAL),其中包含應(yīng)用于該分區(qū)的更新的有序列表。預(yù)寫日志是數(shù)據(jù)庫中常用的策略,用于提高寫入操作的持久性和延遲。更新 B-Tree 比較慢,因?yàn)樗婕半S機(jī) I/O,并且可能涉及在磁盤上重寫多個(gè)頁面,而更新預(yù)寫日志是一個(gè)僅追加的操作,速度要快得多。

    請注意,除了針對這些結(jié)構(gòu)的單個(gè)操作的性能差異之外,這兩個(gè)結(jié)構(gòu)的大小也存在巨大差異。B-Tree的大小可以超過 10 GB(考慮到分區(qū)的 10 GB 大小以及索引開銷),而預(yù)寫日志只有幾百兆字節(jié)(預(yù)寫日志的完整歷史記錄是定期同步到 S3,用于支持時(shí)間點(diǎn)恢復(fù)和其他功能)。

    DynamoDB 存儲背景部分結(jié)束

    當(dāng)您運(yùn)行像 DynamoDB 這樣大的系統(tǒng)時(shí),實(shí)例總是會失敗。當(dāng)存儲節(jié)點(diǎn)發(fā)生故障時(shí),您現(xiàn)在可能有數(shù)千個(gè)分區(qū)副本需要重新定位到非故障節(jié)點(diǎn)。在此故障期間,在該節(jié)點(diǎn)上具有副本的每個(gè)復(fù)制組現(xiàn)在都減少到兩個(gè)副本。因?yàn)樾枰獌蓚€(gè)副本來確認(rèn)給定的寫入,所以您現(xiàn)在正在增加寫入的延遲分布以及如果另一個(gè)副本發(fā)生故障時(shí)降低可用性的概率。

    為了減少只有兩個(gè)副本處于活動狀態(tài)的時(shí)間,DynamoDB 使用日志副本。日志副本是僅包含預(yù)寫日志的復(fù)制組的成員。通過跳過分區(qū)的 B-Tree,DynamoDB 子系統(tǒng)可以通過復(fù)制最后幾百 MB 的日志來快速啟動日志副本。此日志副本可用于確認(rèn)寫入,但不能用于讀取。

    當(dāng)此日志副本在幫助復(fù)制組時(shí),DynamoDB 子系統(tǒng)可以在后臺運(yùn)行以啟動一個(gè)完整的副本成員來替換失敗的成員。

    看到團(tuán)隊(duì)為不斷突破持久性、可用性和延遲的極限而進(jìn)行的增量調(diào)整非常有趣。其中大部分都不會改變系統(tǒng)做出的核心承諾,例如在 CAP 定理上做出不同的選擇。相反,它們是對數(shù)據(jù)庫可靠性和性能的穩(wěn)定改進(jìn)。

    首先,DynamoDB 使用預(yù)寫日志與索引存儲的標(biāo)準(zhǔn)組合來提高持久性并減少寫入請求的延遲。

    其次,DynamoDB 放棄了 RDBMS 的典型單節(jié)點(diǎn)設(shè)置,并轉(zhuǎn)移到分區(qū)系統(tǒng)。這減少了恢復(fù)時(shí)間(這意味著可用性的提升),因?yàn)榛謴?fù) 10GB 分區(qū)比恢復(fù) 200GB 表要快得多。此外,此復(fù)制跨越三個(gè)不同的可用區(qū) (AZ),因此整個(gè) AZ 可以不可用而不會影響系統(tǒng)的可用性。

    然后,DynamoDB 放寬了一致性要求,要求復(fù)制組中的三個(gè)節(jié)點(diǎn)中只有兩個(gè)節(jié)點(diǎn)確認(rèn)寫入。以一些偶爾過時(shí)的數(shù)據(jù)為代價(jià),DynamoDB 能夠提高可用性并減少寫入延遲。

    最后,DynamoDB 使用日志副本來提高節(jié)點(diǎn)故障期間的可用性。

    將分區(qū)與吞吐量解耦

    在上一節(jié)中,我們討論了如何使用分區(qū)來分割表中的數(shù)據(jù)并允許水平擴(kuò)展。此外,我們還看到了 DynamoDB 如何將來自不同客戶的分區(qū)放在同一存儲節(jié)點(diǎn)上,以提高 DynamoDB 服務(wù)的效率。

    第二個(gè)有趣的技術(shù)要點(diǎn)是對這些分區(qū)的“準(zhǔn)入控制”系統(tǒng)進(jìn)行緩慢而穩(wěn)定的改進(jìn)。準(zhǔn)入控制是指 DynamoDB 根據(jù)可用容量確定請求是否可以成功的過程。在確定這一點(diǎn)時(shí),DynamoDB 正在檢查兩個(gè)軸的容量:

    • ? 根據(jù)為表預(yù)置的容量,是否有可供客戶使用的容量?

    • ? 根據(jù)分區(qū)所在存儲節(jié)點(diǎn)的總?cè)萘浚謪^(qū)是否有可用容量?

    第一個(gè)是成本決策,因?yàn)?DynamoDB 希望確保您為他們提供的服務(wù)付費(fèi)。第二個(gè)是性能決策,因?yàn)樗麄兿M苊鈦碜酝环謪^(qū)的嘈雜鄰居問題。

    跨分區(qū)的吞吐量均勻分布是基于這樣的假設(shè):應(yīng)用程序一致地訪問表中的鍵,并且根據(jù)大小劃分分區(qū)會平均分配性能。

    準(zhǔn)入控制的第一次迭代純粹是在分區(qū)級別。DynamoDB 會將預(yù)配置的總吞吐量除以分區(qū)數(shù),然后將該數(shù)量平均分配給每個(gè)分區(qū)。這是最簡單的系統(tǒng),因?yàn)槟槐刂鹈雲(yún)f(xié)調(diào)大量分區(qū)。但是,它導(dǎo)致了工作負(fù)載不平衡和“吞吐量稀釋”[7]問題。這可能會導(dǎo)致對熱分區(qū)的請求受到限制。

    但是,我們發(fā)現(xiàn)應(yīng)用程序工作負(fù)載經(jīng)常具有隨時(shí)間和鍵范圍的非統(tǒng)一訪問模式。當(dāng)表中的請求率不均勻時(shí),拆分分區(qū)并按比例劃分性能分配會導(dǎo)致分區(qū)的熱點(diǎn)部分具有比拆分前更少的可用性能。由于吞吐量是靜態(tài)分配的并在分區(qū)級別強(qiáng)制執(zhí)行,這些非統(tǒng)一的工作負(fù)載偶爾會導(dǎo)致應(yīng)用程序的讀取和寫入被拒絕,稱為限制。

    為了解決這個(gè)問題,DynamoDB 想要將準(zhǔn)入控制與分區(qū)解耦,但意識到這將是一個(gè)很大的提升。為了解決這個(gè)問題,他們分階段進(jìn)行。

    一是完善分區(qū)級準(zhǔn)入控制系統(tǒng)。雖然每個(gè)分區(qū)都受到限制以防止過度消耗單個(gè)節(jié)點(diǎn)上的資源,但他們也意識到存儲節(jié)點(diǎn)經(jīng)常在滿負(fù)荷下運(yùn)行。為了幫助解決各個(gè)分區(qū)的臨時(shí)流量高峰,DynamoDB 添加了短期突發(fā),如果它可用于給定的存儲節(jié)點(diǎn),則可以讓分區(qū)使用額外的吞吐量。這種改進(jìn)主要集中在訪問控制的第二個(gè)軸上——防止嘈雜的鄰居。

    Burst 思路很簡單,在分配配額的時(shí)候, DynamoDB 會給各個(gè) Partition 預(yù)留一部分 Capacity,就是在短期流量 spike 的時(shí)候,用這些預(yù)留的 Capacity 扛一扛;

    第二個(gè)初始改進(jìn)有助于訪問控制的另一個(gè)軸——單個(gè)表的預(yù)置吞吐量。如前所述,具有傾斜訪問模式的表可能會消耗一個(gè)分區(qū)的所有吞吐量,但仍低于表的總預(yù)置吞吐量。為了解決這個(gè)問題,DynamoDB 增加了自適應(yīng)容量,Adaptive Capacity[8],可以將稀疏使用分區(qū)的吞吐量轉(zhuǎn)移到高度使用的分區(qū)。

    Adaptive Capacity 就是在用戶的 Workload 在其 Partitions 上出現(xiàn)傾斜后,動態(tài)的調(diào)整不同 Partition 的配額(但是總量不能超過原來的總配額)。

    這兩個(gè)變化在保持通用的基于分區(qū)的訪問控制方案的同時(shí),減輕了基于數(shù)據(jù)訪問模式不均勻的大量痛苦。

    后來,DynamoDB 遷移到全局訪問控制系統(tǒng),將吞吐量與分區(qū)完全解耦。這將自適應(yīng)容量從較慢的“盡力而為”系統(tǒng)更改為幾乎即時(shí)的系統(tǒng),以將吞吐量分散到各個(gè)分區(qū)。這種靈活性帶來了驚人的其他改進(jìn),包括能夠?qū)⑻貏e熱點(diǎn)的item分離到它們自己的分區(qū)上、提供按需計(jì)費(fèi)、以及根據(jù)底層分區(qū)的可預(yù)測工作負(fù)載“超載”存儲節(jié)點(diǎn)。

    所有這些都在論文的第 4 節(jié)中進(jìn)行了更詳細(xì)的敘述,值得您自己閱讀以了解詳細(xì)信息。

    使用異步緩存

    最后一個(gè)技術(shù)要點(diǎn)是 DynamoDB 對異步緩存的使用。我所說的“異步緩存”是指一個(gè)系統(tǒng)在本地緩存數(shù)據(jù),然后在后臺異步對緩存進(jìn)行再更新,以確保其保持最新狀態(tài)。

    我們都知道緩存是一種通過存儲高昂調(diào)用的結(jié)果來減少延遲的方法。在論文中提及,單個(gè)請求路由器實(shí)例都在本地存儲外部調(diào)用的結(jié)果,以避免緩慢的網(wǎng)絡(luò)請求。在回顧這些時(shí),我們應(yīng)該注意 DynamoDB 如何從“內(nèi)部”系統(tǒng)處理“外部”系統(tǒng)(也稱為“依賴項(xiàng)”)。

    DynamoDB 使用其他 AWS 服務(wù),例如 IAM 來驗(yàn)證請求或使用 KMS 來加密和解密數(shù)據(jù)。這兩項(xiàng)服務(wù)都是外部依賴項(xiàng),因?yàn)樗鼈儾皇?DynamoDB 團(tuán)隊(duì)的控制。在這里,DynamoDB 將緩存對這些服務(wù)的調(diào)用結(jié)果,作為提高可用性的一種方式。這些結(jié)果會定期異步刷新以確保新鮮度。即使這些外部服務(wù)本身存在問題,這也允許 DynamoDB 繼續(xù)工作(在某種程度上)。如果沒有這個(gè),DynamoDB 的可用性必然低于 IAM 和 KMS。

    DynamoDB 還為“內(nèi)部”系統(tǒng)使用異步緩存。DynamoDB 有一個(gè)元數(shù)據(jù)系統(tǒng),用于跟蹤每個(gè) DynamoDB 分區(qū)的表信息和位置。當(dāng)請求到達(dá) DynamoDB 請求路由器時(shí),它需要找到給定item的相關(guān)分區(qū)以將請求轉(zhuǎn)發(fā)到存儲節(jié)點(diǎn)。

    此元數(shù)據(jù)信息不會經(jīng)常更改,因此請求路由器會大量緩存此數(shù)據(jù)。論文指出,緩存命中率為99.75%(!!),相當(dāng)不錯(cuò)。但是,高緩存命中率也可能導(dǎo)致一個(gè)問題[9]:流量輕微減少可能導(dǎo)致底層服務(wù)負(fù)載顯著增加。將元數(shù)據(jù)緩存命中率從 99.75% 降低到仍然驚人的 99.5% 會導(dǎo)致對底層元數(shù)據(jù)服務(wù)的請求數(shù)量增加一倍。

    DynamoDB 團(tuán)隊(duì)發(fā)現(xiàn)元數(shù)據(jù)服務(wù)必須根據(jù)請求路由器服務(wù)進(jìn)行擴(kuò)展,因?yàn)樾碌恼埱舐酚善饔锌站彺妫瑢?dǎo)致對元數(shù)據(jù)服務(wù)的大量調(diào)用。這導(dǎo)致了整個(gè)系統(tǒng)的不穩(wěn)定。

    在 Request Router 和 Metadata Service 中間加了一級分布式內(nèi)存緩存 MemDS,Router 的本地緩存失效后,并不直接訪問 Meta Service,而是先訪問 MemDS,然后 MemDS 在后臺批量的訪問 Metadata Service 填充數(shù)據(jù)。通過添加一層緩存進(jìn)行削峰操作,相當(dāng)于再加一層保險(xiǎn),屬于常見的手段。

    為了提高其內(nèi)部系統(tǒng)的彈性,DynamoDB 使用異步緩存刷新來為底層元數(shù)據(jù)系統(tǒng)提供恒定負(fù)載。雖然請求路由器將以高命中率在本地緩存,但每次命中都會導(dǎo)致對元數(shù)據(jù)服務(wù)的關(guān)聯(lián)請求以刷新緩存的數(shù)據(jù)。

    第二個(gè)手段比較巧妙,剛才提到 Router 事實(shí)上是通過 MemDS 獲取元信息,當(dāng)請求在 MemDS 的時(shí)候沒命中的時(shí)候好理解,但是 MemDS 巧妙地方在于:即使緩存命中,MemDS 也會異步訪問 Meta Service。1) 盡可能保證 MemDS 中已有緩存能被及時(shí)更新; 2) 給 MetaService 帶來一個(gè)’穩(wěn)定‘的流量;

    通過將本地緩存命中與對元數(shù)據(jù)服務(wù)的異步請求配對,它可以確保元數(shù)據(jù)服務(wù)的流量更加一致。緩存命中和緩存未命中都會導(dǎo)致對元數(shù)據(jù)服務(wù)的請求,因此增加具有冷緩存的請求路由器的數(shù)量不會導(dǎo)致元數(shù)據(jù)服務(wù)的新流量激增。

    完結(jié)

    亞馬遜再次幫助推動了我們對深層技術(shù)主題的理解。正如 Dynamo 論文在設(shè)計(jì)新的數(shù)據(jù)庫架構(gòu)方面具有革命性意義一樣,DynamoDB 論文是運(yùn)行和發(fā)展大規(guī)模托管系統(tǒng)的重要課程。

    在這篇文章中,我們從 DynamoDB 論文中的用戶需求角度研究了核心設(shè)計(jì)要素。然后,我們研究了論文中的一些技術(shù)設(shè)計(jì)點(diǎn)。

    該論文還有許多沒有涉及的其他有趣點(diǎn),例如Serverless、存儲的 GC 策略、分布式事務(wù)等、DynamoDB 如何通過檢測內(nèi)部 Amazon 服務(wù)來監(jiān)控客戶端可用性、用于針對大量實(shí)例部署新版本 DynamoDB 的策略以及用于防止數(shù)據(jù)錯(cuò)誤機(jī)制,無論是在inflight還是在靜止時(shí)。讓我們對未來保持期待!

    引用鏈接

    [1] The Dynamo Paper: https://www.dynamodbguide.com/the-dynamo-paper
    [2] The DynamoDB paper: https://brooker.co.za/blog/2022/07/12/dynamodb.html
    [3] Key Takeaways from the DynamoDB Paper: https://www.alexdebrie.com/posts/dynamodb-paper/
    [4] DynamoDB 2022 論文解讀: http://blog.0xffff.me/posts/dynamodb-2022/
    [5] Dynamo 論文: http://www.allthingsdistributed.com/files/amazon-dynamo-sosp2007.pdf
    [6] 關(guān)于 DynamoDB 的新論文: https://www.usenix.org/system/files/atc22-elhemali.pdf
    [7] “吞吐量稀釋”: https://hackernoon.com/beware-of-dilution-of-dynamodb-throughput-due-to-excessive-scaling-4df51063edae
    [8] 自適應(yīng)容量,Adaptive Capacity: https://aws.amazon.com/blogs/database/how-amazon-dynamodb-adaptive-capacity-accommodates-uneven-data-access-patterns-or-why-what-you-know-about-dynamodb-might-be-outdated/
    [9] 高緩存命中率也可能導(dǎo)致一個(gè)問題: https://www.gomomento.com/blog/the-biggest-miss-in-your-cache-hit-rate

網(wǎng)站首頁   |    關(guān)于我們   |    公司新聞   |    產(chǎn)品方案   |    用戶案例   |    售后服務(wù)   |    合作伙伴   |    人才招聘   |   

友情鏈接: 餐飲加盟

地址:北京市海淀區(qū)    電話:010-     郵箱:@126.com

備案號:冀ICP備2024067069號-3 北京科技有限公司版權(quán)所有