MinIO 复制最佳实践

MinIO Replication Best Practices

宝贵的数据必须受到保护,防止损坏和丢失,但数据量的增加——以及日益分布式的数据——使这项任务变得艰巨。MinIO 包含多种数据保护机制,这篇博文重点介绍复制最佳实践,这是软件定义对象存储的关键保护措施,有助于创建和维护多云数据湖,以便您可以在最适合的地方运行工作负载,并使用组织的最新数据。

我们将建立一个地理分布式基础设施,在其中我们在跨越广阔距离的多站点拥有一个多节点多驱动器 MinIO 集群。这将使我们能够真正体会到复制在规模化工作中的作用,从而帮助我们了解地理负载均衡和高可用性所需的基础设施。

MinIO 包含几种复制数据的方法,因此您可以选择最适合您需求的方法。我们之前已经发布了关于基于 Bucket 的主动-主动复制的博文,用于在 Bucket 级别复制对象,以及关于批量复制的博文,用于复制 Bucket 中的特定对象,这使您可以更精细地控制。

我们致力于灵活性的承诺意味着 MinIO 支持在站点和 Bucket 级别进行复制,使您能够根据应用程序的需求微调复制配置,并尽可能多地控制该过程。数据通过 IAM 在多个 MinIO 部署中使用 S3 样式策略和 PBAC 保护。复制同步对象的创建、删除和修改以及 Bucket。此外,它还同步元数据、加密设置和安全令牌服务 (STS)。请注意,您可以使用站点复制或 Bucket 复制,但不能同时使用两者。如果您已经在运行 Bucket 复制,则必须将其禁用才能使站点复制正常工作。

自从我们推出多站点主动-主动复制以来,我们的重点一直是性能,而不会对集群执行的现有操作造成任何额外的性能下降。这使您能够跨多个数据中心、云甚至灾难恢复需求复制数据,其中一个站点离线不会降低可用性。复制配置完全在服务器端处理,采用“设置并忘记”的理念,使用 MinIO 的应用程序无需以任何方式修改,所有操作都在服务器端处理。

数据保护远不止复制。MinIO 还包括

  • 加密:MinIO 支持静态传输中的加密。这确保了数据在从发出调用的那一刻到对象放置在 Bucket 中的所有交易方面都得到加密。
  • 比特腐烂保护:物理磁盘上的数据可能由于多种原因而损坏。这可能是由于电压尖峰、固件中的错误、错误的读取和写入等。MinIO 确保这些错误会被捕获并即时修复,以确保数据完整性。
  • 擦除编码:MinIO 使用此数据冗余和可用性功能即时重建对象,而无需任何额外的硬件或软件,而不是使用增加性能额外开销的 RAID 来确保数据的冗余。
  • 安全访问 ACL 和 PBAC:支持具有内置 IDP 的 IAM S3 样式策略,有关更多信息,请参阅MinIO 最佳实践 - 安全和访问控制
  • 分层:对于不经常访问的数据,您可以将其转移到运行 MinIO 的另一个冷存储中,以便您可以在最佳硬件上优化最新数据,而不会占用未使用的空间。
  • 对象锁定和保留:MinIO 支持对象锁定(保留),这强制执行一次写入和多次读取操作,以实现基于持续时间和无限期的法律保留。这允许关键数据保留合规性,并满足 SEC17a-4(f)、FINRA 4511(C) 和 CFTC 1.31(c)-(d) 的要求。

在本教程中,我们将把复制更进一步,以提供更多关于多站点复制的深度信息,并向您展示实施基于复制的存储体系结构的最佳实践。MinIO 的复制架构不会干扰集群的现有操作,确保不会降低性能。

基础设施概述

下面我们有一个图表,简要概述了我们的基础设施设置。

我们有三个不同的 MinIO 站点,每个站点在地理位置上彼此远离。在每个站点中,我们都有 NGINX 将请求代理到后端的三个 MinIO 服务器。如果其中一台 MinIO 服务器离线,NGINX 会确保请求被路由到其他 MinIO 节点。Unbound 是一种 DNS 服务,它将解析内部运行的 MinIO 服务器的 DNS 请求。我们可以使用外部 DNS(例如 Route53),但这需要一个专用域名。因此,我们将使用一个虚拟主机名(例如 minio.local),而不是编辑所有虚拟机上的 /etc/hosts 文件;我们只需要使用 Unbound 服务器的 IP 地址更新 /etc/resolv.conf

因此,问题出现了,为什么 MinIO 建议采用多站点设置作为最佳实践,而不是例如单站点、单节点和单驱动器配置?原因有几个。当您考虑数据完整性时,您不仅会考虑数据存储的安全位置,还会希望它具有冗余性和可扩展性,以便您的现有操作不受影响。在此设置中,我们正在考虑堆栈各个方面的冗余性。

首先让我们谈谈冗余性

  • 每个节点有多个磁盘,以防磁盘发生故障。使用擦除编码,MinIO 确保在发生磁盘故障时,数据会被复制到其他磁盘。
  • 我们将其设置为多个节点具有多个磁盘,以防整个节点离线,站点中的其他节点可以提供数据。
  • 在最坏的情况下,如果整个站点由于电源故障或网络问题而离线,则数据在另一个位置可用,可以从中提供服务。

但我们也需要考虑可扩展性和维护。在管理基础设施时,情况几乎是不稳定的。

  • 此设置允许您向池中添加更多服务器,以根据数据大小和需求的增加水平扩展您的基础设施。您甚至可以在维护期间从池中删除节点,以便在故障发生之前先发制人地避免故障。
  • 整个站点也是如此。您将能够添加一个全新的站点,而不会中断现有站点并在地理级别进行扩展。例如,假设您要使用 Anycast DNS,您可以将您的请求定向到地理位置更近的站点,以便您的最终用户能够尽快获取数据。如果您必须对特定站点进行维护,则可以使用 MinIO 多站点配置将其从处理流量中移除,直到它准备好再次处理流量。

基础设施设置

在本教程中,我们将以分布式方式设置软件定义的基础设施(MinIO、VPC、Unbound、NGINX),并共享用于启动它的代码。结果将是三个相同的 MinIO 部署,每个部署位于自己的区域中,并在所有三个部署之间进行主动-主动复制。这种设计的优势在于,如果特定站点中的一个 MinIO 节点出现故障,其他节点可以处理流量,因为 NGINX 会将流量重新路由到正常的节点。此外,如果整个站点离线,其他两个站点可以处理读写操作,而无需对应用程序进行任何更改,因为写入其他站点的任何数据都将在离线站点上线后复制到该站点。

它已准备好用于生产环境,并且可以根据您的需求进行自定义,基础设施即代码的设置如下。

MinIO 站点 1:https://github.com/minio/blog-assets/tree/main/replication-best-practices/terraform/infra/minio-1

MinIO 站点 2:https://github.com/minio/blog-assets/tree/main/replication-best-practices/terraform/infra/minio-2

MinIO 站点 3:https://github.com/minio/blog-assets/tree/main/replication-best-practices/terraform/infra/minio-3

通用模块:https://github.com/minio/blog-assets/tree/main/replication-best-practices/terraform/infra/modules

以下是将要部署的组件

  • VPC:这是我们在虚拟私有网络中启动所有资源的地方。可以将其想象为数据中心中您自己的笼子/机架。
  • Unbound:这是一项 DNS 服务,您可以在其中为节点本地添加区域记录以解析 MinIO 主机名。为什么我们需要这个?原因有两个:首先,我们需要确保 MinIO 服务器主机名在配置中按顺序排列。其次,在 /etc/hosts 中管理所有这些记录可能会变得难以管理,因为每次添加或删除节点时,都需要在所有节点上更新主机文件,这可能会变得很麻烦。这使我们能够在 Unbound 中更新它,并且我们将 /etc/resolv.conf 指向 Unbound 的 IP 以解析主机名。


  • NGINX:在之前的博文中,我们展示了如何使用 NGINX 作为反向代理,并将多个 MinIO 服务器作为后端。在配置站点间复制时,我们将提供 NGINX 端点而不是各个 MinIO 服务器,这样如果其中一个 MinIO 节点离线,请求将被路由到其他 MinIO 节点。
  • MinIO:最后但同样重要的是,我们将以多节点、多驱动器设置来设置 MinIO 集群。我们将在多个区域复制此配置,以便我们能够真正测试跨地理位置的站点间复制。

总共,我们将在 3 个不同的区域启动 3 个相同的基础设施配置。

VPC

我们将通过调用模块目录中的模块来启动 VPC。

这就是我们调用模块的方式

module "hello_minio_vpc" {
    source = "../modules/vpc"

    minio_cidr_block   = var.hello_minio_cidr_block
    minio_cidr_newbits = var.hello_minio_cidr_newbits

    minio_public_igw_cidr_blocks   	= var.hello_minio_public_igw_cidr_blocks
    minio_private_ngw_cidr_blocks  	= var.hello_minio_private_ngw_cidr_blocks
    minio_private_isolated_cidr_blocks = var.hello_minio_private_isolated_cidr_blocks

}

这是我们定义 VPC 模块的位置

https://github.com/minio/blog-assets/blob/main/replication-best-practices/terraform/infra/modules/vpc/main.tf

Unbound

使用我们在上一步中创建的 VPC 资源,我们将在该 VPC 的公共子网中启动 Unbound。这也可以在私有子网中,只要您不需要任何其他对 DNS 服务器的外部访问。

module "hello_minio_instance_unbound" {
    source = "../modules/instance"

    minio_vpc_security_group_ids = [module.hello_minio_security_group_unbound.minio_security_group_id]
    minio_subnet_id      	= module.hello_minio_vpc.minio_subnet_public_igw_map[local.common_public_subnet]

    minio_ami_filter_name_values = var.hello_minio_ami_filter_name_values
    minio_ami_owners         	= var.hello_minio_ami_owners
    minio_instance_type      	= var.hello_minio_instance_type
    minio_instance_key_name  	= var.hello_minio_instance_key_name

    minio_instance_user_data 	= templatefile("../templates/_user_data_unbound.sh.tftpl", {})

}

大多数 Unbound 配置是通过_user_data_unbound.sh.tftpl管理的。

但是为了配置 Unbound,我们需要我们将要启动的 MinIO 服务器的私有 IP,但此时 MinIO 服务器尚未启动。

一旦 MinIO 服务器启动并获得其私有 IP,请将以下配置添加到/etc/unbound/unbound.conf.d/myunbound.conf文件的第 2 行,位于server:指令下方。您需要将此添加到每个站点上运行的每个 Unbound 服务器,并使用每个 MinIO 节点的相应私有 IP。

local-zone: minio.local transparent
local-data: "server-1.minio.local A <MinIO Node 1 Private IP>"
local-data: "server-2.minio.local A <MinIO Node 2 Private IP>"
local-data: "server-3.minio.local A <MinIO Node 3 Private IP>"

更新上述配置后,请务必重新启动 Unbound,以使更改生效。

systemctl restart unbound

NGINX 集群

NGINX 博文中,我们使用了以下配置,我们在这里对其进行了稍微调整以匹配 MinIO 服务器主机名

upstream minio_server {
    server server-1.minio.local:9000;
    server server-2.minio.local:9000;
    server server-3.minio.local:9000;
}

server {
    listen   	80 default_server;

    ignore_invalid_headers off;
    client_max_body_size 0;
    proxy_buffering off;
    proxy_request_buffering off;

    location / {
        proxy_set_header Host $http_host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_connect_timeout 300;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        chunked_transfer_encoding off;

        proxy_pass http://minio_server;
    }
}

我们将使用此配置启动 NGINX 服务器

module "hello_minio_instance_nginx" {
    source = "../modules/instance"

    minio_vpc_security_group_ids = [module.hello_minio_security_group_nginx.minio_security_group_id]
    minio_subnet_id      	= module.hello_minio_vpc.minio_subnet_public_igw_map[local.common_public_subnet]

    minio_ami_filter_name_values = var.hello_minio_ami_filter_name_values
    minio_ami_owners         	= var.hello_minio_ami_owners
    minio_instance_type      	= var.hello_minio_instance_type
    minio_instance_key_name  	= var.hello_minio_instance_key_name

    minio_instance_user_data 	= templatefile("../templates/_user_data_nginx.sh.tftpl", {
    	unbound_ip = module.hello_minio_instance_unbound.minio_instance_private_ip
    })

    minio_instance_user_data_replace_on_change = false

    depends_on = [
    	module.hello_minio_instance_unbound
    ]

}

我们启动的 NGINX VM 将使用来自_user_data_nginx.sh.tftpl的用户数据,这有助于我们在 VM 启动后立即安装和配置 NGINX。

MinIO 集群

最后但并非最不重要的一点是,我们将使用以下配置启动 3 个 MinIO 节点,这不仅会启动 VM,还会附加一个将用于数据的辅助卷。

module "hello_minio_instance_minio" {
    source = "../modules/instance"

    for_each = var.hello_minio_private_ngw_cidr_blocks

    minio_vpc_security_group_ids = [module.hello_minio_security_group_minio.minio_security_group_id]
    minio_subnet_id      	= module.hello_minio_vpc.minio_subnet_private_ngw_map[each.key]

    minio_ami_filter_name_values = var.hello_minio_ami_filter_name_values
    minio_ami_owners         	= var.hello_minio_ami_owners
    minio_instance_type      	= var.hello_minio_instance_type
    minio_instance_key_name  	= var.hello_minio_instance_key_name

    minio_instance_user_data 	= templatefile("../templates/_user_data_minio.sh.tftpl", {
        minio_version = "20221207005637.0.0"
        unbound_ip = module.hello_minio_instance_unbound.minio_instance_private_ip
    })

}

resource "aws_ebs_volume" "ebs_volume_minio" {

    for_each = var.hello_minio_private_ngw_cidr_blocks

    availability_zone = each.key

    size = 10
}

resource "aws_volume_attachment" "volume_attachment_minio" {

    for_each = var.hello_minio_private_ngw_cidr_blocks

    device_name = "/dev/xvdb"
    volume_id = aws_ebs_volume.ebs_volume_minio[each.key].id
    instance_id = module.hello_minio_instance_minio[each.key].minio_instance_id

}

VM 启动并附加 HDD 后,我们将在_user_data_minio.sh.tftpl中对其进行格式化并挂载。它还包含在我们的多节点设置中位于/etc/default/minio中的 MinIO 配置。

理想情况下,您在此设置中唯一需要手动配置的是将 MinIO 服务器的私有 IP 作为 DNS A 记录添加到 Unbound,其余部分应根据我们预设的 DNS 名称自动配置。

在所有节点上启动 MinIO 服务。您可以使用 Ansible 之类的东西或手动执行。

systemctl start minio

站点复制配置

接下来,我们将实际启动我们在上一步中配置的基础设施。这涉及使用 Terraform 启动 VM,然后使用 MinIO mc客户端配置站点复制。

进入每个minio-1minio-2minio-3目录,并运行 terraform 命令以启动基础设施。

cd minio-1
terraform apply

cd minio-2
terraform apply

cd minio-3
terraform apply

一旦所有三个站点启动,输出将显示 Unbound 和 NGINX 的公共 IP 以及 3 个 MinIO 节点的私有 IP,类似于以下内容。

hello_minio_aws_instance_nginx = "<public_ip>"
hello_minio_aws_instance_unbound = "<public_ip>"
minio_hostname_ips_map = {
    "server-1.minio.local" = "<private_ip>"
    "server-2.minio.local" = "<private_ip>"
    "server-3.minio.local" = "<private_ip>"
}

不要忘记使用我们在前面配置 unbound 时显示的配置来配置 Unbound A 记录。

登录站点 1 中的 NGINX 节点之一以设置所有三个站点的mc alias。确保任何站点中都没有数据。

/opt/minio-binaries/mc alias set minio1 http://<nginx_public_ip> minioadmin minioadmin
/opt/minio-binaries/mc alias set minio2 http://<nginx_public_ip> minioadmin minioadmin
/opt/minio-binaries/mc alias set minio3 http://<nginx_public_ip> minioadmin minioadmin

让我们将其设置为跨所有 3 个站点进行复制

$ /opt/minio-binaries/mc admin replicate add minio1 minio2 minio3

Requested sites were configured for replication successfully.

验证 3 个站点是否已正确配置

/opt/minio-binaries/mc admin replicate info minio1

SiteReplication enabled for:

Deployment ID                    	| Site Name   	| Endpoint
f96a6675-ddc3-4c6e-907d-edccd9eae7a4 | minio1      	| http://<nginx_public_ip>
0dfce53f-e85b-48d0-91de-4d7564d5456f | minio2      	| http://<nginx_public_ip>
8527896f-0d4b-48fe-bddc-a3203dccd75f | minio3      	| http://<nginx_public_ip>

检查以确保复制正常工作

/opt/minio-binaries/mc admin replicate status minio1

Bucket replication status:
No Buckets present

Policy replication status:
●  5/5 Policies in sync

User replication status:
No Users present

Group replication status:
No Groups present

在 minio1 中创建一个存储桶

/opt/minio-binaries/mc mb minio1/testbucket

将任何对象添加到存储桶中

/opt/minio-binaries/mc cp my_object  minio1/testbucket

列出其他站点中的对象,在本例中是 minio2 和 minio3

/opt/minio-binaries/mc ls minio2/testbucket
[2022-12-19 18:52:09 UTC] 3.0KiB STANDARD my_object

/opt/minio-binaries/mc ls minio3/testbucket
[2022-12-19 18:52:09 UTC] 3.0KiB STANDARD my_object

如您所见,即使它们在地理上相距甚远,将数据复制到其他站点也几乎是即时的。

站点复制和自动化启用多云

云运营模型允许您运行相同的设置和配置,无论它是物理数据中心还是云上的虚拟资源。这是有效处理海量数据以及必须实时进行的 AI 和分析的唯一方法。您还必须设计一个多云架构,该架构收集和共享数据与计算资源/最佳服务(无论它们位于何处),以确保基础设施管理的开销尽可能低,以满足您的工程和 DevOps 团队的需求。

站点复制通过设置多个站点并在服务器端处理复制来强调多云架构的功能。这使您能够简化跨多个站点的 数据管理、元数据和配置,而无需在应用程序中添加任何额外开销以修改故障到一个节点甚至整个站点的情况。我们向您展示了一个关于如何部署到多个站点/区域以配置复制的工作示例,同时我们还部署了高可用性,将每个多站点 MinIO 集群放置在单独的区域中,以实现强大的业务连续性和灾难恢复策略

如果您对在您的环境中运行此设置有任何疑问,或者希望我们帮助您设置,请在Slack上与我们联系!