راهنمای جامع Ceph
Englishشروع کنید
در این صفحه
فصل ۴

ذخیره‌سازی شیء با ‏RADOS Gateway‏

۵۱ دقیقه مطالعهویرایش این صفحه
حوصله ندارم این فصل در چند خط
  • ‏RGW‏ یک سرور ‏HTTP‏ بی‌حالت است که ‏S3‏ و ‏Swift‏ را روی ‏RADOS‏ پیاده می‌کند؛ چند نمونه از آن را پشت سرویس ‏ingress‏ در ‏cephadm‏ اجرا کنید.
  • هر شیء ‏S3‏ به یک ‏head‏، چند ‏tail‏ و یک مدخل در ‏bucket index‏ تبدیل می‌شود؛ ‏pool‏ ایندکس را ‏replicated‏ و روی ‏SSD‏ نگه دارید.
  • ‏user‏، ‏subuser‏، ‏tenant‏ و ‏account‏ سطوح متفاوت هویت‌اند؛ برای طراحی تازه ‏account‏ را (از ‏Squid‏ به بعد) در نظر بگیرید.
  • ‏versioning‏، ‏object lock‏، ‏lifecycle‏، ‏storage class‏، ‏policy‏، ‏SSE‏ و اعلان رویداد، ‏RGW‏ را به سرویس کامل ‏S3‏ تبدیل کرده‌اند؛ قانون ‏lifecycle‏ برای ‏multipart‏های ناتمام را فراموش نکنید و بدانید ‏gc‏ فضا را بعداً آزاد می‌کند.

۴-۱ پیش از شروع#

۴-۱-۱ این فصل به چه سؤال‌هایی جواب می‌دهد؟#

ذخیره‌سازی شیء سریع‌ترین بخش در حال رشد دنیای ذخیره‌سازی است: پشتیبان‌ها، آرشیو رسانه، لاگ‌ها، دیتاست‌های یادگیری ماشین، ‏artifact‏های ‏CI‏ و حتی «دریاچه‌ی داده». ‏API‏ عملاً استاندارد این حوزه ‏Amazon S3‏ است و ‏RADOS Gateway‏ (‏RGW‏) پیاده‌سازی ‏Ceph‏ از آن است. در این فصل:

  • ذخیره‌سازی شیء چه فرقی با بلوک و فایل دارد و ‏RGW‏ چطور آن را روی ‏RADOS‏ پیاده می‌کند؟
  • چطور ‏RGW‏ را با ‏cephadm‏ مستقر و پشت ‏load balancer‏ قرار دهیم؟
  • کاربر، کلید، ‏subuser‏، ‏tenant‏ و ‏account‏ چیست و کدام را کی به کار ببریم؟
  • چطور با ‏S3‏ (s۳cmd و ‏aws-cli‏) و ‏Swift‏ به ‏RGW‏ دسترسی داشته باشیم و ‏DNS‏ مجازی ‏bucket‏ را پیکربندی کنیم؟
  • ‏RGW‏ را چطور با ‏Keystone‏ و ‏Hadoop S3A‏ یکپارچه کنیم؟
  • قابلیت‌های امروزی مثل نسخه‌بندی، ‏lifecycle‏، ‏object lock‏، سیاست ‏bucket‏ و اعلان رویداد چطور کار می‌کنند؟

۴-۱-۲ پیش‌نیاز#

کلاستر فصل ۱ و میزبان ‏ceph-node4‏ با برچسب ‏rgw‏، به‌علاوه‌ی ‏client-node1‏ برای ابزارهای کلاینت.

۴-۲ آشنایی با ذخیره‌سازی شیء در ‏Ceph‏#

۴-۲-۱ شیء، ‏bucket‏ و ‏API‏#

در ذخیره‌سازی شیء، هیچ درخت پوشه یا بلوک قابل‌بازنویسی وجود ندارد. داده در قالب شیء ذخیره می‌شود: یک کلید (نام)، محتوای باینری و فراداده. اشیاء در ‏bucket‏ها (در اصطلاح ‏Swift: container‏) دسته‌بندی می‌شوند و از طریق ‏HTTP‏ با فعل‌هایی مثل ‏PUT‏، ‏GET‏، ‏HEAD‏ و ‏DELETE‏ دسترسی پیدا می‌کنند. شیء معمولاً یک‌جا نوشته و یک‌جا خوانده می‌شود؛ تغییر بخشی از شیء یعنی بازنویسی کل آن. همین سادگی است که مقیاس عظیم و دسترسی از هر جای اینترنت را ممکن می‌کند.

ویژگیبلوک (‏RBD‏)فایل (‏CephFS‏)شیء (‏RGW‏)
رابطدستگاه بلوکی‏POSIX‏‏HTTP‏ (S۳/Swift)
واحد دسترسیبلوکبایت در فایلکل شیء (با ‏range read‏)
فرادادهنداردمجوزها، زمان‌هادلخواه، به‌همراه برچسب‌ها
مقیاس معمولترابایت در هر دیسکمیلیون‌ها فایلمیلیاردها شیء
کاربرد‏VM‏، پایگاه دادهاشتراک فایل، ‏HPC‏پشتیبان، رسانه، داده‌ی تحلیلی

۴-۲-۲ ‏RGW‏ روی ‏RADOS‏#

‏radosgw‏ یک سرور ‏HTTP‏ بدون حالت است (‏frontend‏ پیش‌فرض آن از ‏Nautilus‏ به بعد ‏Beast‏ مبتنی بر ‏Boost.Asio‏ است و ‏frontend‏ قدیمی ‏civetweb‏ کنار گذاشته شده). هر درخواست ‏S3‏ یا ‏Swift‏ را به مجموعه‌ای از عملیات ‏RADOS‏ ترجمه می‌کند. چون حالتی در خود ‏RGW‏ نگه داشته نمی‌شود، هر تعداد نمونه را می‌توان پشت ‏load balancer‏ قرار داد.

شکل ۴-۱: معماری RGW : نمونه‌های بدون حالت پشت load balancer و pool های جداگانه برای index ، داده و فراداده
شکل ۴-۱: معماری ‏RGW‏: نمونه‌های بدون حالت پشت ‏load balancer‏ و ‏pool‏های جداگانه برای ‏index‏، داده و فراداده

۴-۲-۳ ‏pool‏های ‏RGW‏#

‏RGW‏ در یک استقرار ساده (‏zone‏ پیش‌فرض) این ‏pool‏ها را می‌سازد:

‏pool‏محتواتوصیه
‏.rgw.root‏تعریف ‏realm‏، ‏zonegroup‏ و ‏zone‏کوچک؛ تکثیری
‏default.rgw.control‏اشیای ‏watch/notify‏ برای هماهنگی ‏cache‏ بین نمونه‌هاکوچک
‏default.rgw.meta‏فراداده‌ی کاربران و ‏bucket‏هاروی ‏SSD‏ در صورت امکان
‏default.rgw.log‏لاگ‌های همگام‌سازی، ‏lifecycle‏، ‏usage‏کوچک تا متوسط
‏default.rgw.buckets.index‏‏index‏ هر ‏bucket‏ در ‏omap‏حتماً روی ‏SSD/NVMe‏ و تکثیری
‏default.rgw.buckets.data‏داده‌ی اشیاءتکثیری یا ‏EC‏؛ بزرگ‌ترین ‏pool‏
‏default.rgw.buckets.non-ec‏فراداده‌ی بارگذاری چندبخشیتکثیری
⚠ هشدار

‏pool index‏ را هرگز ‏erasure-coded‏ نکنید (‏EC‏ از ‏omap‏ پشتیبانی نمی‌کند) و آن را روی ‏HDD‏ نگذارید. هر ‏PUT‏ و ‏DELETE‏ یک به‌روزرسانی ‏omap‏ در ‏index‏ است و ‏index‏ کند یعنی کل ‏RGW‏ کند. یک قاعده‌ی ‏CRUSH‏ مبتنی بر ‏device class‏ برای ‏index‏ روی ‏NVMe‏ یکی از مؤثرترین بهینه‌سازی‌های ‏RGW‏ است.

۴-۲-۴ شیء ‏S3‏ در ‏RADOS‏#

شکل ۴-۲: یک شیء S3 بیست‌مگابایتی در RADOS : شیء head با فراداده و manifest ، اشیای tail برای بقیه‌ی داده، و یک ورودی در shard مربوط به index
شکل ۴-۲: یک شیء ‏S3‏ بیست‌مگابایتی در ‏RADOS‏: شیء ‏head‏ با فراداده و ‏manifest‏، اشیای ‏tail‏ برای بقیه‌ی داده، و یک ورودی در ‏shard‏ مربوط به ‏index‏
  • ‏head object‏: نخستین بخش داده (به‌طور پیش‌فرض تا ۴ مگابایت؛ ‏rgw_max_chunk_size‏) به‌همراه فراداده‌ی شیء در ‏xattr‏ و یک ‏manifest‏ که فهرست بقیه‌ی قطعات را دارد.
  • ‏tail objects‏: بقیه‌ی داده در اشیای جداگانه (نام‌هایی با پیشوند ‏__shadow_‏ یا در بارگذاری چندبخشی ‏__multipart_‏).
  • ورودی ‏index‏: یک کلید در ‏omap‏ یکی از ‏shard‏های ‏index bucket‏؛ برای فهرست‌گیری (‏ListObjects‏) استفاده می‌شود.
◆ عمیق‌تر

چون ‏index‏ هر ‏bucket‏ در ‏omap‏ اشیای ‏RADOS‏ است، یک ‏bucket‏ با صدها میلیون شیء اگر ‏shard‏ نشود، یک شیء ‏omap‏ غول‌پیکر می‌سازد که ‏scrub‏، بازیابی و حتی عملیات عادی را کند می‌کند و هشدار ‏LARGE_OMAP_OBJECTS‏ می‌دهد. ‏resharding‏ پویا (پیش‌فرض از ‏Luminous‏) با رسیدن تعداد اشیاء هر ‏shard‏ به آستانه‌ی ‏rgw_max_objs_per_shard‏ (پیش‌فرض ۱۰۰٬۰۰۰) تعداد ‏shard‏ها را خودکار افزایش می‌دهد. در ‏Tentacle‏ بیشتر پردازش ‏reshard‏ پیش از قفل کردن نوشتن‌ها انجام می‌شود تا اثرش بر کلاینت‌ها کمتر شود.

۴-۳ استقرار و پیکربندی ‏RADOS Gateway‏#

۴-۳-۱ استقرار با ‏cephadm‏#

در گذشته ‏RGW‏ را دستی با بسته‌ها و ‏ceph-deploy‏ روی یک ‏node‏ جداگانه نصب می‌کردند. با ‏cephadm‏ یک دستور کافی است:

bashReef+
ceph orch host label add ceph-node4 rgw
ceph orch host label add ceph-node3 rgw
ceph orch apply rgw objstore --placement="label:rgw count-per-host:1" --port=8080
ceph orch ls rgw
ceph orch ps --daemon-type rgw
curl http://ceph-node4:8080

پاسخ خالی ‏ListAllMyBucketsResult‏ با کاربر ‏anonymous‏ یعنی ‏RGW‏ بالاست. برای کنترل بیشتر، از ‏spec‏ به زبان ‏YAML‏ استفاده کنید:

yaml
service_type: rgw
service_id: objstore
placement:
  label: rgw
  count_per_host: 2
networks:
  - 192.168.56.0/24
spec:
  rgw_frontend_port: 8080
  rgw_frontend_type: beast

۴-۳-۲ ‏load balancer‏ با سرویس ‏ingress‏#

‏cephadm‏ یک سرویس ‏ingress‏ دارد که ‏HAProxy‏ و ‏keepalived‏ را مستقر می‌کند و یک ‏IP‏ مجازی جلوی نمونه‌های ‏RGW‏ قرار می‌دهد:

yaml
service_type: ingress
service_id: rgw.objstore
placement:
  hosts: [ceph-node3, ceph-node4]
spec:
  backend_service: rgw.objstore
  virtual_ip: 192.168.56.100/24
  frontend_port: 443
  monitor_port: 1967
  ssl: true
bashReef+
ceph orch apply -i ingress.yaml
ceph orch ls ingress

در نسخه‌های جدید (‏Tentacle‏ و ‏Umbrella‏) زیرسیستم ‏certmgr‏ در ‏cephadm‏ گواهی‌های امضاشده توسط ‏cephadm‏ را برای چنین سرویس‌هایی خودکار تولید و تمدید می‌کند، یا گواهی شما را می‌پذیرد و برای گواهی‌های در آستانه‌ی انقضا هشدار سلامت می‌دهد.

💡 نکته

در ‏production‏، ‏TLS‏ را یا در ‏load balancer‏ پایان دهید یا در خود ‏Beast‏ (با ‏rgw_frontend_ssl_certificate‏). اگر در ‏HAProxy‏ پایان می‌دهید، مطمئن شوید ‏RGW‏ نشانی واقعی کلاینت را از هدر ‏X-Forwarded-For‏ می‌خواند (‏rgw_remote_addr_param = http_x_forwarded_for‏)؛ وگرنه سیاست‌های مبتنی بر ‏IP‏ و لاگ‌ها نشانی ‏load balancer‏ را می‌بینند.

✚ عیب‌یابی

اگر پس از ‏apply‏ نمونه‌ای از ‏RGW‏ بالا نیامد، ‏ceph orch ps --daemon-type rgw‏ و ‏ceph health detail‏ را ببینید. شایع‌ترین دلیل در کلاسترهای کوچک، هشدار ‏TOO_MANY_PGS‏ یا خطای ساخت ‏pool‏ به دلیل رسیدن به ‏mon_max_pg_per_osd‏ است، چون ‏RGW‏ چند ‏pool‏ تازه می‌سازد. راه دیگر بررسی، ‏cephadm logs --name rgw.objstore.ceph-node4.xxxx‏ روی میزبان است.

۴-۴ کاربران، کلیدها و مستاجرها#

۴-۴-۱ ساختن کاربر ‏radosgw‏#

کاربران ‏RGW‏ مستقل از کاربران ‏cephx‏ هستند و در ‏pool‏ فراداده‌ی ‏RGW‏ نگه داشته می‌شوند. ابزار مدیریت آن‌ها ‏radosgw-admin‏ است:

bashReef+
radosgw-admin user create --uid=alice --display-name="Alice" --email=alice@example.com
radosgw-admin user info --uid=alice
radosgw-admin user list
radosgw-admin key create --uid=alice --key-type=s3 --gen-access-key --gen-secret
radosgw-admin user suspend --uid=alice
radosgw-admin user enable --uid=alice

خروجی ‏user create‏ یک جفت ‏access_key‏ و ‏secret_key‏ دارد که کلاینت ‏S3‏ برای امضای درخواست‌ها (‏AWS Signature v4‏) استفاده می‌کند.

⚠ هشدار

خروجی ‏radosgw-admin user info‏ کلید محرمانه را به‌صورت متن ساده نشان می‌دهد. آن را در تیکت، چت یا لاگ ‏CI‏ کپی نکنید. برای تحویل کلید به تیم‌ها از یک سامانه‌ی مدیریت رمز (مثلاً ‏Vault‏) استفاده کنید و کلیدهای قدیمی را دوره‌ای چرخش دهید (‏key create‏ و سپس ‏key rm‏).

۴-۴-۲ سهمیه و محدودیت نرخ#

bashReef+
radosgw-admin quota set --quota-scope=user --uid=alice --max-size=500G --max-objects=10000000
radosgw-admin quota enable --quota-scope=user --uid=alice
radosgw-admin quota set --quota-scope=bucket --uid=alice --max-objects=5000000
radosgw-admin quota enable --quota-scope=bucket --uid=alice
radosgw-admin ratelimit set --ratelimit-scope=user --uid=alice --max-read-ops=1000 --max-write-ops=200
radosgw-admin ratelimit enable --ratelimit-scope=user --uid=alice

محدودیت نرخ از ‏Quincy‏ اضافه شده است و در ‏Umbrella‏ پاسخ محدودیت نرخ هدر ‏Retry-After‏ هم دارد که کلاینت‌های خوش‌رفتار برای عقب‌نشینی از آن استفاده می‌کنند.

۴-۴-۳ ‏subuser‏ و کلید ‏Swift‏#

‏API Swift‏ از مفهوم ‏subuser‏ استفاده می‌کند: هویتی زیرمجموعه‌ی یک کاربر با سطح دسترسی مشخص و کلید مخصوص ‏Swift‏.

bashReef+
radosgw-admin subuser create --uid=alice --subuser=alice:swift --access=full
radosgw-admin key create --subuser=alice:swift --key-type=swift --gen-secret

۴-۴-۴ ‏tenant‏ و ‏account‏#

شکل ۴-۳: دو سازوکار چندمستاجری: tenant برای جداسازی فضای نام bucket ها و account (از Squid ) برای مدیریت سلف‌سرویس کاربران و سیاست‌ها به سبک IAM
شکل ۴-۳: دو سازوکار چندمستاجری: ‏tenant‏ برای جداسازی فضای نام ‏bucket‏ها و ‏account‏ (از ‏Squid‏) برای مدیریت سلف‌سرویس کاربران و سیاست‌ها به سبک ‏IAM‏

در ‏RGW‏ نام ‏bucket‏ها به‌طور پیش‌فرض در کل کلاستر یکتاست. ‏tenant‏ یک فضای نام جداگانه می‌سازد تا دو مشتری بتوانند ‏bucket‏ هم‌نام داشته باشند:

bashReef+
radosgw-admin user create --tenant=acme --uid=bob --display-name="Bob at ACME"
# نام کامل کاربر: acme$bob ، و bucketها در فضای acme

از ‏Squid‏، ‏account‏ مفهومی شبیه حساب ‏AWS‏ اضافه کرده است: یک ‏account‏ مالک کاربران، گروه‌ها، نقش‌ها و سیاست‌هاست و «کاربر ریشه»ی آن می‌تواند از طریق ‏API‏های سازگار با ‏IAM‏، بدون دخالت مدیر کلاستر، کاربران و کلیدها را مدیریت کند.

bashSquid+
radosgw-admin account create --account-name=acme --email=ops@acme.example
radosgw-admin user create --uid=acme-root --display-name="ACME root" \
  --account-id=<account-id> --account-root --gen-secret --gen-access-key
radosgw-admin quota set --quota-scope=account --account-id=<account-id> --max-size=10T
radosgw-admin quota enable --quota-scope=account --account-id=<account-id>
✎ یادداشت

یادداشت‌های انتشار ‏Tentacle‏ اعلام می‌کنند که قابلیت‌های ‏IAM‏ مبتنی بر ‏tenant‏ (مانند ‏CreateRole‏ و ‏PutUserPolicy‏ در سطح ‏tenant‏ و ‏STS Lite‏) به نفع ‏account‏ منسوخ شده‌اند و زودتر از نسخه‌ی ‏V‏ حذف نخواهند شد. خود ‏tenant‏ برای جداسازی فضای نام باقی می‌ماند. برای طراحی تازه‌ی چندمستاجری، از ‏account‏ شروع کنید.

۴-۵ دسترسی با ‏API‏ سازگار با ‏S3‏#

۴-۵-۱ ‏DNS‏ و دسترسی ‏virtual-host‏#

‏S3‏ دو سبک نشانی‌دهی دارد: ‏path-style‏ (‏https://s3.example.com/bucket/key‏) و ‏virtual-hosted-style‏ (‏https://bucket.s3.example.com/key‏). بسیاری از ‏SDK‏های جدید پیش‌فرض را سبک دوم گذاشته‌اند. برای پشتیبانی از آن:

  1. ۱. یک رکورد ‏wildcard‏ در ‏DNS‏ بسازید: ‏*.s3.example.com‏ به ‏IP‏ مجازی ‏load balancer‏.
  2. ۲. به ‏RGW‏ بگویید نام دامنه‌اش چیست:
bashReef+
ceph config set client.rgw rgw_dns_name s3.example.com
ceph orch restart rgw.objstore

در استقرار چند ‏zonegroup‏، نام‌های میزبان در فیلد ‏hostnames‏ تعریف ‏zonegroup‏ قرار می‌گیرند (فصل ۵). گواهی ‏TLS‏ هم باید ‏wildcard‏ (‏*.s3.example.com‏) باشد.

۴-۵-۲ ‏s3cmd‏#

bash
sudo dnf install -y s3cmd      # یا pip install s3cmd
s3cmd --configure              # access key، secret key و endpoint
# یا مستقیم در ~/.s3cfg:
cat > ~/.s3cfg <<'C'
[default]
access_key = <ACCESS>
secret_key = <SECRET>
host_base = s3.example.com
host_bucket = %(bucket)s.s3.example.com
use_https = True
C
s3cmd mb s3://photos
s3cmd put cat.jpg s3://photos/
s3cmd ls s3://photos
s3cmd get s3://photos/cat.jpg /tmp/cat.jpg
s3cmd info s3://photos/cat.jpg

۴-۵-۳ ‏aws-cli‏ و ‏SDK‏ها#

bash
aws configure --profile ceph                      # کلیدها
aws --profile ceph --endpoint-url https://s3.example.com s3 mb s3://backups
aws --profile ceph --endpoint-url https://s3.example.com s3 cp ./db.dump s3://backups/
aws --profile ceph --endpoint-url https://s3.example.com s3api list-objects-v2 --bucket backups
aws --profile ceph --endpoint-url https://s3.example.com s3 presign s3://backups/db.dump --expires-in 3600
⚠ هشدار

برخی نسخه‌های جدید ‏SDK‏های ‏AWS‏ به‌طور پیش‌فرض ‏checksum‏های جدید یکپارچگی داده (مثل ‏CRC32‏ در هدرهای ‏x-amz-checksum-*‏) را برای هر ‏PUT‏ می‌فرستند. پشتیبانی ‏RGW‏ از این قابلیت‌ها در نسخه‌های مختلف متفاوت است؛ اگر پس از ارتقای ‏SDK‏ خطای امضا یا «‏InvalidArgument‏» دیدید، یادداشت‌های انتشار نسخه‌ی ‏RGW‏ خود را بررسی کنید و در صورت لزوم در پیکربندی کلاینت، ارسال ‏checksum‏ را به حالت «فقط وقتی لازم است» برگردانید. یادداشت‌های ‏Umbrella‏ هم یک رگرسیون ‏SigV4‏ در نسخه‌های ۱۹.۲.۶ و ۲۰.۲.۴ را گزارش می‌کنند که بارگذاری‌های ‏presigned PUT‏ با ‏Content-Type‏ امضانشده را رد می‌کرد و اصلاح شده است.

۴-۵-۴ بارگذاری چندبخشی#

برای اشیای بزرگ (معمولاً بالای ۱۰۰ مگابایت) از ‏multipart upload‏ استفاده کنید؛ ‏aws-cli‏ و ‏s3cmd‏ خودکار این کار را انجام می‌دهند. بارگذاری‌های نیمه‌کاره فضا اشغال می‌کنند و در فهرست اشیاء دیده نمی‌شوند. یک قاعده‌ی ‏lifecycle‏ برای پاک کردنشان اضافه کنید (‏AbortIncompleteMultipartUpload‏) و گاهی با ‏radosgw-admin bucket list --bucket=<b>‏ یا ‏aws s3api list-multipart-uploads‏ بررسی‌شان کنید.

۴-۶ دسترسی با ‏API Swift‏#

bash
pip install python-swiftclient
swift -A http://s3.example.com:8080/auth/1.0 -U alice:swift -K '<SWIFT_SECRET>' stat
swift -A http://s3.example.com:8080/auth/1.0 -U alice:swift -K '<SWIFT_SECRET>' post container01
swift -A http://s3.example.com:8080/auth/1.0 -U alice:swift -K '<SWIFT_SECRET>' upload container01 report.pdf
swift -A http://s3.example.com:8080/auth/1.0 -U alice:swift -K '<SWIFT_SECRET>' list container01

‏bucket‏ها در ‏S3‏ و ‏container‏ها در ‏Swift‏ یک چیزند: فایلی که با ‏Swift‏ بارگذاری شده با ‏S3‏ هم دیده می‌شود (به شرطی که کاربر یکی باشد).

۴-۷ یکپارچه‌سازی با ‏OpenStack Keystone‏#

در ابرهای ‏OpenStack‏ معمولاً می‌خواهیم کاربران با همان هویت ‏Keystone‏ به ذخیره‌سازی شیء دسترسی داشته باشند و ‏RGW‏ در ‏catalog‏ به‌عنوان سرویس ‏object-store‏ ثبت شود.

شکل ۴-۴: جریان احراز هویت Swift با Keystone: RGW توکن را نزد Keystone اعتبارسنجی می‌کند و برای هر پروژه خودکار کاربر می‌سازد
شکل ۴-۴: جریان احراز هویت ‏Swift‏ با ‏Keystone: RGW‏ توکن را نزد ‏Keystone‏ اعتبارسنجی می‌کند و برای هر پروژه خودکار کاربر می‌سازد
bashReef+
# در Keystone
openstack service create --name swift --description "Ceph RGW" object-store
openstack endpoint create --region RegionOne object-store public \
  "https://s3.example.com/swift/v1/AUTH_%(project_id)s"
# در Ceph
ceph config set client.rgw rgw_keystone_url https://keystone.example.com:5000
ceph config set client.rgw rgw_keystone_api_version 3
ceph config set client.rgw rgw_keystone_admin_user rgw
ceph config set client.rgw rgw_keystone_admin_password_path /etc/ceph/keystone.pass
ceph config set client.rgw rgw_keystone_admin_domain Default
ceph config set client.rgw rgw_keystone_admin_project service
ceph config set client.rgw rgw_keystone_accepted_roles "member,admin"
ceph config set client.rgw rgw_keystone_implicit_tenants true
ceph config set client.rgw rgw_swift_account_in_url true
ceph config set client.rgw rgw_s3_auth_use_keystone true
💡 نکته

مستندات ‏RGW‏ گزینه‌ی ‏rgw_keystone_admin_password_path‏ را به گذاشتن رمز به‌صورت متن ساده در پیکربندی ترجیح می‌دهند. با ‏cephadm‏ می‌توانید فایل را از طریق ‏extra_container_args‏/‏mount‏ یا ‏ceph config-key‏ در اختیار کانتینر بگذارید. ‏rgw_s3_auth_use_keystone‏ امکان استفاده از اعتبارنامه‌های ‏EC2‏ در ‏Keystone‏ (‏openstack ec2 credentials create‏) برای ‏S3‏ را فراهم می‌کند. در ‏Umbrella‏، الزام قدیمی ‏admin token‏ برای ‏Keystone‏ حذف شده و نقش‌های ‏Keystone‏ به محیط ارزیابی سیاست ‏IAM‏ تزریق می‌شوند.

۴-۸ یکپارچه‌سازی با ‏Hadoop‏ و ‏Spark‏ از طریق ‏S3A‏#

اکوسیستم ‏Hadoop‏ از طریق کانکتور ‏S3A‏ به هر سرویس سازگار با ‏S3‏ وصل می‌شود. این یعنی می‌توانید ‏HDFS‏ را برای ذخیره‌سازی سرد یا حتی اصلی با ‏RGW‏ جایگزین کنید و محاسبه و ذخیره‌سازی را از هم جدا مقیاس دهید.

xml
<!-- core-site.xml -->
<property><name>fs.s3a.endpoint</name><value>https://s3.example.com</value></property>
<property><name>fs.s3a.path.style.access</name><value>true</value></property>
<property><name>fs.s3a.access.key</name><value>ACCESS</value></property>
<property><name>fs.s3a.secret.key</name><value>SECRET</value></property>
<property><name>fs.s3a.connection.ssl.enabled</name><value>true</value></property>
<property><name>fs.s3a.committer.name</name><value>magic</value></property>
bash
hadoop fs -mkdir s3a://analytics/raw
hadoop fs -put events.parquet s3a://analytics/raw/
spark-submit --conf spark.hadoop.fs.s3a.endpoint=https://s3.example.com job.py
◆ عمیق‌تر

نوشتن خروجی کارهای ‏Spark‏ روی ذخیره‌سازی شیء چالش «‏rename‏» دارد: ‏commit‏ سنتی ‏Hadoop‏ پوشه‌ی موقت را ‏rename‏ می‌کند که در ‏S3‏ یعنی کپی و حذف همه‌ی اشیاء. ‏S3A committers‏ (مثل ‏directory‏ و ‏magic‏) این مشکل را با بارگذاری چندبخشی که فقط در لحظه‌ی ‏commit‏ نهایی می‌شود حل می‌کنند. برای بارهای سنگین تحلیلی روی ‏RGW‏ حتماً یکی از این ‏committer‏ها را فعال کنید. اسناد خود ‏Hadoop‏ درباره‌ی پیش‌نیازهای سازگاری (مثلاً پشتیبانی از ‏multipart‏ و فهرست‌گیری سازگار) راهنمای خوبی است؛ ‏RGW‏ سازگاری قوی ‏read-after-write‏ دارد.

۴-۹ از درون کد: ‏bucket index‏، ‏manifest‏ و مسیر ‏PUT‏ در ‏RGW‏#

۴-۹-۱ دو جای جدا برای یک شیء ‏S3‏#

‏RGW‏ هر شیء ‏S3‏ را در دو مکان مستقل ثبت می‌کند. یکی ورودی ‏bucket index‏ است که در ‏omap‏ اشیای شارد در ‏pool index‏ قرار دارد و برای ‏List‏ و آمار ‏bucket‏ استفاده می‌شود. دیگری خود داده است که در ‏pool‏ داده به شکل یک ‏head‏ و صفر یا چند ‏tail‏ ذخیره می‌شود. هماهنگ نگه داشتن این دو، بدون تراکنش توزیع‌شده، با یک پروتکل دومرحله‌ای سبک روی کلاس ‏cls_rgw‏ انجام می‌شود.

شکل ۴-۵: مسیر PUT یک شیء. radosgw شماره‌ی شارد را از hash نام شیء محاسبه می‌کند. ابتدا متد cls به نام bucket_prepare_op یک ورودی با حالت PENDING_MODIFY و یک tag یکتا در شارد ثبت می‌کند. سپس head (شامل حداکثر ۴ MiB اول داده و xattr های manifest ، ACL و etag ) و stripe های tail نوشته می‌شوند. در پایان bucket_complete_op ورودی را با اندازه، etag و mtime به حالت COMPLETE می‌برد و یک رکورد bilog برای همگام‌سازی multisite می‌سازد. اگر RGW بین این دو مرحله از کار بیفتد، ورودی pending باقی می‌ماند و بعداً با dir_suggest_changes (هنگام list ) یا radosgw-admin bucket check اصلاح می‌شود
شکل ۴-۵: مسیر ‏PUT‏ یک شیء. ‏radosgw‏ شماره‌ی شارد را از ‏hash‏ نام شیء محاسبه می‌کند. ابتدا متد ‏cls‏ به نام ‏bucket_prepare_op‏ یک ورودی با حالت ‏PENDING_MODIFY‏ و یک ‏tag‏ یکتا در شارد ثبت می‌کند. سپس ‏head‏ (شامل حداکثر ۴‏MiB‏ اول داده و ‏xattr‏های ‏manifest‏، ‏ACL‏ و ‏etag‏) و ‏stripe‏های ‏tail‏ نوشته می‌شوند. در پایان ‏bucket_complete_op‏ ورودی را با اندازه، ‏etag‏ و ‏mtime‏ به حالت ‏COMPLETE‏ می‌برد و یک رکورد ‏bilog‏ برای همگام‌سازی ‏multisite‏ می‌سازد. اگر ‏RGW‏ بین این دو مرحله از کار بیفتد، ورودی ‏pending‏ باقی می‌ماند و بعداً با ‏dir_suggest_changes‏ (هنگام ‏list‏) یا ‏radosgw-admin bucket check‏ اصلاح می‌شود
ثابت/گزینهمقدار (‏main‏)منبع
پیشوند شیء شارد ‏index‏‏.dir.‏‏rgw/services/svc_bi_rados.cc‏
تعداد شارد پیش‌فرض ‏bucket‏ جدید۱۱‏default_bucket_index_max_shards‏ در ‏rgw_zone_types.h‏
‏rgw_override_bucket_index_max_shards‏۰ (یعنی مقدار ‏zonegroup‏)‏rgw.yaml.in‏
‏rgw_dynamic_resharding‏‏true‏‏rgw.yaml.in‏
‏rgw_max_objs_per_shard‏۱۰۰۰۰۰آستانه‌ی ‏resharding‏ پویا
‏rgw_safe_max_objects_per_shard‏۱۰۲۴۰۰آستانه‌ی هشدار ‏bucket limit check‏
‏rgw_max_chunk_size‏۴_‏M‏بیشینه‌ی داده در ‏head‏
‏rgw_obj_stripe_size‏۴_‏M‏اندازه‌ی هر ‏stripe‏ در ‏tail‏
‏rgw_bucket_index_max_aio‏۱۲۸موازی‌سازی عملیات روی شاردها

حالت‌های ورودی ‏index‏ در ‏cls_rgw_types.h‏: ‏CLS_RGW_STATE_PENDING_MODIFY = 0‏، ‏CLS_RGW_STATE_COMPLETE = 1‏، ‏CLS_RGW_STATE_UNKNOWN = 2‏.

شکل ۴-۶: چیدمان فیزیکی. در pool index ، هر bucket به N شیء . dir.<marker>.<shard> تقسیم می‌شود و ورودی‌ها در omap آن‌ها نگهداری می‌شوند. در pool داده، head با نام < marker>_<key> و tail ها با پیشوند __ shadow_ ذخیره می‌شوند. در multipart هر part یک شیء __ multipart_ جداست و CompleteMultipartUpload فقط manifest را می‌سازد و داده را کپی نمی‌کند. tail اشیای حذف‌شده یا بازنویسی‌شده به‌صورت ناهمگام در صف GC (کلاس rgw_gc ) پاک می‌شوند
شکل ۴-۶: چیدمان فیزیکی. در ‏pool index‏، هر ‏bucket‏ به ‏N‏ شیء .‏dir.<marker>.<shard>‏ تقسیم می‌شود و ورودی‌ها در ‏omap‏ آن‌ها نگهداری می‌شوند. در ‏pool‏ داده، ‏head‏ با نام <‏marker>_<key>‏ و ‏tail‏ها با پیشوند __‏shadow_‏ ذخیره می‌شوند. در ‏multipart‏ هر ‏part‏ یک شیء __‏multipart_‏ جداست و ‏CompleteMultipartUpload‏ فقط ‏manifest‏ را می‌سازد و داده را کپی نمی‌کند. ‏tail‏ اشیای حذف‌شده یا بازنویسی‌شده به‌صورت ناهمگام در صف ‏GC‏ (کلاس ‏rgw_gc‏) پاک می‌شوند
text
pseudocode: put_obj (خلاصه‌ی این کتاب از rgw_rados.cc و cls_rgw.cc)
  shard = hash(key) % num_shards
  tag   = unique_op_tag()
  cls_call(index[shard], "rgw.bucket_prepare_op", {key, tag, op=ADD})
  write head  oid="<marker>_<key>"   data[0:4MiB], xattrs{manifest, acl, etag}
  for i, chunk in stripes(data[4MiB:], 4MiB):
      write tail oid="<marker>__shadow_<prefix>_<i>"
  cls_call(index[shard], "rgw.bucket_complete_op", {key, tag, size, etag, mtime})
      # درون OSD: ورودی COMPLETE + به‌روزرسانی header آمار + bilog entry
  if old version existed: enqueue old tail to GC
◆ عمیق‌تر

چرا ‏bucket‏های بسیار بزرگ کند می‌شوند: ‏List‏ با ترتیب الفبایی باید از همه‌ی شاردها بخواند و نتایج را ‏merge‏ کند؛ هزینه‌ی آن با تعداد شارد رشد می‌کند. از طرف دیگر، شارد بیش از حد بزرگ (میلیون‌ها کلید ‏omap‏) باعث کندی ‏compaction‏ در ‏RocksDB‏، ‏scrub‏ طولانی و هشدار ‏LARGE_OMAP_OBJECTS‏ می‌شود. ‏dynamic resharding‏ تعادل این دو را خودکار برقرار می‌کند، ولی در ‏multisite‏ فقط وقتی کار می‌کند که ‏zone feature‏ به نام ‏resharding‏ در ‏zonegroup‏ فعال باشد (ثابت آن در ‏rgw/rgw_zone_features.h‏ تعریف شده است؛ بررسی: ‏radosgw-admin zonegroup get | jq .enabled_features‏).

✚ عیب‌یابی

فرمان‌های بررسی:

bashReef+
radosgw-admin bucket stats --bucket=photos | jq '.num_shards, .usage'
radosgw-admin bucket limit check | jq '.[].buckets[] | select(.fill_status!="OK")'
radosgw-admin reshard list ; radosgw-admin reshard status --bucket=photos
radosgw-admin object stat --bucket=photos --object=a.jpg | jq '.manifest'
radosgw-admin bucket check --bucket=photos --check-objects   # بدون --fix فقط گزارش
radosgw-admin gc list --include-all | jq length
ceph health detail | grep -A3 LARGE_OMAP
آزمایشگاه

PUT و multipart در RGW

یک کلید و اندازه بدهید و یک PUT ی S3 را از radosgw تا bucket index و data pool، همراه با شیءهای RADOS که می‌سازد، دنبال کنید.

۳شیء RADOS
.dir.MARKER.5shard ی bucket index
۱۰ MiBاندازهٔ شیء
ceph_str_hash_linux("photos/2026/11/img_0001.jpg") = 2668161921 → sid ^ ((sid & 0xff) << 24) → % 7877 % 11 = 5
clientradosgwauthindex pooldata pool۱. PUT۲. احراز هویت۳. stripeهای دُم۴. آماده‌سازی index۵. نوشتن head۶. تکمیل index۷. 200 OK
  1. PUT کلاینت PUT /bucket/photos/2026/11/img_0001.jpg را با ۱۰ MiB داده می‌فرستد؛ RGWPutObj::execute آغاز می‌شود. RGWPutObj::execute (rgw_op.cc)
  2. احراز هویت امضای AWS (این‌جا v4) بررسی و مجوزهای کاربر روی bucket ارزیابی می‌شود. rgw::auth::s3::AWSAuthStrategy, AWSv4ComplSingle (rgw_auth_s3.cc)
  3. stripeهای دُم هم‌زمان با رسیدن بدنه، processor تعداد ۲ شیء دُم ۴ MiB در data pool می‌نویسد. AtomicObjectProcessor::process, RadosWriter::process
  4. آماده‌سازی index rgw_bucket_prepare_op یک ورودی معلق برای photos/2026/11/img_0001.jpg روی shard ۵ از ۱۱ می‌گذارد تا اگر همین حالا crash رخ دهد ردی برای پاک‌سازی بماند. RGWRados::Bucket::UpdateIndex::prepare, cls_rgw rgw_bucket_prepare_op
  5. نوشتن head شیء head با یک write_full همراه ۴ MiB نخست، manifest و attributeها (ETag، ACL و content type) نوشته می‌شود. RGWRados::Object::Write::_do_write_meta (write_full + xattrs)
  6. تکمیل index rgw_bucket_complete_op ورودی معلق را به شیئی فهرست‌شده روی shard ۵ تبدیل می‌کند و برای همگام‌سازی به bucket index log می‌افزاید. UpdateIndex::complete, rgw_bucket_complete_op (+ bilog)
  7. 200 OK radosgw با 200 و ETag پاسخ می‌دهد؛ شیء حالا در فهرست‌ها دیده می‌شود. RGWPutObj_ObjStore_S3::send_response (rgw_rest_s3.cc)
شیءهای RADOS این بارگذاری
  1. MARKER_photos/2026/11/img_0001.jpg۴ MiB + xattrs
  2. MARKER__shadow_.RAND32_1۴ MiB
  3. MARKER__shadow_.RAND32_2۲ MiB

اندازه‌های پیش‌فرض: head تا ۴ MiB (rgw_max_chunk_size)، stripeها ۴ MiB (rgw_obj_stripe_size) و هر part دست‌کم ۵ MiB (rgw_multipart_min_part_size).

مطابق با:

  • src/rgw/rgw_op.cc :: RGWPutObj::execute, RGWCompleteMultipart::execute عملیات PUT و تکمیل multipart
  • src/rgw/driver/rados/rgw_putobj_processor.cc :: AtomicObjectProcessor, MultipartObjectProcessor نوشتن head، stripeها و partها
  • src/rgw/driver/rados/rgw_rados.cc :: Object::Write::_do_write_meta, Bucket::UpdateIndex::prepare / complete نوشتن head و به‌روزرسانی index
  • src/cls/rgw/cls_rgw.cc :: rgw_bucket_prepare_op, rgw_bucket_complete_op دو عملیات index روی OSD
  • src/rgw/services/svc_bi_rados.h :: bucket_shard_index; src/common/ceph_hash.cc :: ceph_str_hash_linux هر کلید به کدام shard ی bucket index می‌رود
  • src/rgw/driver/rados/rgw_obj_manifest.cc :: RGWObjManifest (head, stripes, rgw_obj_stripe_size 4M) چیدمان شیء در RADOS
تصویری ثابت از شبیه‌ساز؛ نسخهٔ تعاملی در آزمایشگاه نسخهٔ وب است. آزمایشگاه تعاملی: PUT و multipart در RGW

۴-۱۰ ‏RGW‏ با عدد: ‏shard‏ ایندکس، ‏reshard‏، فهرست‌گیری و ‏manifest‏#

چهار الگوریتم این بخش تعیین می‌کنند یک شیء ‏S3‏ در کدام شیء ایندکس ثبت شود، ‏bucket‏ کی و به چند ‏shard‏ تقسیم شود، فهرست‌گیری مرتب از ‏bucket‏ چقدر داده از ‏OSD‏ها می‌خواند و بایت‌های خود شیء در چه شیءهای ‏RADOS‏ با چه نامی ذخیره شوند. همه‌ی ارجاع‌ها به ‏main‏ در نوامبر ۲۰۲۶ است و عددها با بازپیاده‌سازی پایتونی همان توابع حساب شده‌اند. منطق کاهش ‏shard‏ در ‏reshard‏ پویا و جزئیات چند ضریب در نسخه‌های اخیر اضافه یا عوض شده‌اند. پیش از تکیه بر آن‌ها، کد نسخه‌ی خود را بررسی کنید.

۴-۱۰-۱ انتخاب ‏shard‏ ایندکس#

∑ الگوریتم: نگاشت کلید شیء به ‏shard‏ ایندکس ‏bucket‏

منبع در کد: src/rgw/services/svc_bi_rados.h :: RGWSI_BucketIndex_RADOS::bucket_shard_index؛ src/rgw/driver/rados/rgw_tools.h :: rgw_shards_mod؛ src/common/ceph_hash.cc :: ceph_str_hash_linux

پیچیدگی: ‏O‏(طول کلید)

text
pseudocode
key = نام شیء   (برای قطعه‌های multipart: کلید شیء نهایی، تا همه‌ی قطعه‌ها در یک shard باشند)
sid  = ceph_str_hash_linux(key)                         # hash = (hash + (c<<4) + (c>>4)) × 11 برای هر بایت
sid2 = sid XOR ((sid AND 0xFF) << 24)                    # بیت‌های کم‌ارزش را به بالا می‌برد
shard = n ≤ 7877 ? sid2 mod 7877 mod n : sid2 mod 65521 mod n
oid ایندکس = ".dir." + bucket_marker + "." + shard   (با نسل لایه، ".dir.<marker>.<gen>.<shard>")

مثال عددی. برای کلید ‏photos/2026/11/img_0001.jpg‏، مقدار ‏ceph_str_hash_linux‏ عدد ۲۶۶۸۱۶۱۹۲۱ است. بایت پایین آن ۰‏x81‏ است و پس از ‏XOR‏ با ۰‏x81000000‏ عدد ۵۰۳۹۰۱۰۵۷ به دست می‌آید. ۵۰۳۹۰۱۰۵۷ ‏mod 7877 mod 11‏ = ۵، پس با ۱۱ ‏shard‏ (پیش‌فرض ‏zonegroup‏ برای ‏bucket‏ تازه) ورودی در ‏.dir.<marker>.5‏ می‌نشیند. کلید بعدی، ‏img_0002.jpg‏، به ‏shard‏ ‏۱۰ می‌رود و ‏logs/app.log‏ به ‏shard‏ ‏۹. اگر ‏bucket‏ به ۲۳ ‏shard‏ برود، همین سه کلید به ‏shard‏های ۱۸، ۲۱ و ۲ جابه‌جا می‌شوند. به همین دلیل ‏reshard‏ باید همه‌ی ورودی‌ها را بازنویسی کند. برای ۱۰۰۰۰۰ کلید پشت‌سرهم با الگوی ‏img_NNNNNN.jpg‏، کمترین ‏shard‏ ‏۹۰۳۱ و بیشترین ۹۱۶۲ ورودی گرفت، یعنی ±۱ درصد حول میانگین ۹۰۹۱. این ‏hash‏ ضعیف است، اما برای نام‌های معمولی پخش خوبی می‌دهد.

شکل ۴-۷: سمت چپ: پخش ۱۰۰۰۰۰ کلید پشت‌سرهم میان ۱۱ shard ایندکس. خط‌چین میانگین است و همه‌ی shard ها در حدود یک درصد آن هستند. سمت راست: سه کلید نمونه گام‌به‌گام از hash تا شماره‌ی shard ، هم برای ۱۱ و هم برای ۲۳ shard . مرحله‌ی XOR بایت پایین hash را به بایت بالا می‌برد، چون باقی‌مانده‌ی تقسیم بر عدد اول کوچک بیشتر به بیت‌های پایین حساس است
شکل ۴-۷: سمت چپ: پخش ۱۰۰۰۰۰ کلید پشت‌سرهم میان ۱۱ ‏shard‏ ایندکس. خط‌چین میانگین است و همه‌ی ‏shard‏ها در حدود یک درصد آن هستند. سمت راست: سه کلید نمونه گام‌به‌گام از ‏hash‏ تا شماره‌ی ‏shard‏، هم برای ۱۱ و هم برای ۲۳ ‏shard‏. مرحله‌ی ‏XOR‏ بایت پایین ‏hash‏ را به بایت بالا می‌برد، چون باقی‌مانده‌ی تقسیم بر عدد اول کوچک بیشتر به بیت‌های پایین حساس است

۴-۱۰-۲ ‏reshard‏ پویا: کی و به چند ‏shard‏؟#

∑ الگوریتم: محاسبه‌ی تعداد ‏shard‏ پیشنهادی

منبع در کد: src/rgw/driver/rados/rgw_reshard.cc :: RGWBucketReshard::calculate_preferred_shards، nearest_prime

پیچیدگی: ‏O‏(log P) برای جست‌وجو در فهرست ۳۰۴ عدد اول تا ۱۹۹۹

text
pseudocode
max_objs = rgw_max_objs_per_shard (100000) ; max_dyn = rgw_max_dynamic_shards (1999) ; min_dyn = 11
min_objs = min(10000, ceil(max_objs / 100))           # آستانه‌ی کاهش: 1000
if cur < max_dyn and objs > cur × max_objs: افزایش
elif cur > min_dyn and objs < cur × min_objs: کاهش   (اگر rgw_dynamic_resharding_may_reduce، با تأخیر)
else: کاری نکن
m = multisite ? 8 : 2
new = clamp(objs × m / max_objs, min_dyn, max_dyn) ; new = کوچک‌ترین عدد اول ≥ new در فهرست
new = min(max_dyn, max(new, min_dyn, min_layout_shards))

مثال عددی. ‏bucket‏ با ۱۱ ‏shard‏ شروع می‌کند. فرض کنید هر ۱۰۰۰۰۰ شیء یک بار بررسی شود. در ۱.۲ میلیون شیء، شرط ۱۲۰۰۰۰۰ > ۱۱ × ۱۰۰۰۰۰ برقرار است. ‏new‏ = ۱۲۰۰۰۰۰ × ۲ / ۱۰۰۰۰۰ = ۲۴ و نزدیک‌ترین عدد اول بزرگ‌تر یا مساوی ۲۹ است. مسیر رشد در یک ‏zone‏ این است: ۱۱ → ۲۹ (۱.۲ میلیون) → ۶۱ (۳ میلیون) → ۱۲۷ (۶.۲ میلیون) → ۲۵۷ (۱۲.۸ میلیون) → ۵۲۱ (۲۵.۸ میلیون) → ۱۰۴۹ (۵۲.۲ میلیون) → ۱۹۹۹ (۱۰۵ میلیون). در ‏multisite‏ با ضریب ۸ فقط سه ‏reshard‏ لازم است: ۱۱ → ۹۷ → ۷۸۷ → ۱۹۹۹. هدف ضریب بزرگ‌تر کاهش تعداد ‏reshard‏ها است، چون هر ‏reshard‏ در ‏multisite‏ یک نسل تازه‌ی ‏bilog‏ می‌سازد و همگام‌سازی باید از آن عبور کند. کاهش هم ممکن است. اگر ‏bucket‏ی با ۱۰۱ ‏shard‏ به ۹۰۰۰۰ شیء برسد، ۹۰۰۰۰ < ۱۰۱ × ۱۰۰۰ است و پیشنهاد ۱۱ ‏shard‏ داده می‌شود. پیش‌فرض ‏rgw_dynamic_resharding_reduction_wait‏ در ‏main‏ ‏۱۲۰ ساعت است، تا ‏bucket‏ی که موقتاً خالی شده بلافاصله کوچک نشود.

شکل ۴-۸: تعداد shard ایندکس برحسب تعداد شیء در bucket ، روی محورهای لگاریتمی. آبی مسیر یک zone با ضریب ۲ است و قرمز مسیر multisite با ضریب ۸. هر پله یک reshard است و عدد کنار آن تعداد shard تازه (عدد اول) است. خط نقطه‌چین سقف ۱۰۰۰۰۰ شیء در هر shard است. هر بار که bucket از آن عبور کند، reshard صف می‌شود. سقف ۱۹۹۹ در هر دو مسیر به تعداد شیء متفاوتی می‌رسد
شکل ۴-۸: تعداد ‏shard‏ ایندکس برحسب تعداد شیء در ‏bucket‏، روی محورهای لگاریتمی. آبی مسیر یک ‏zone‏ با ضریب ۲ است و قرمز مسیر ‏multisite‏ با ضریب ۸. هر پله یک ‏reshard‏ است و عدد کنار آن تعداد ‏shard‏ تازه (عدد اول) است. خط نقطه‌چین سقف ۱۰۰۰۰۰ شیء در هر ‏shard‏ است. هر بار که ‏bucket‏ از آن عبور کند، ‏reshard‏ صف می‌شود. سقف ۱۹۹۹ در هر دو مسیر به تعداد شیء متفاوتی می‌رسد

۴-۱۰-۳ فهرست‌گیری مرتب: چند ورودی از هر ‏shard‏؟#

∑ الگوریتم: تعداد ورودی درخواستی از هر ‏shard‏ در ‏ListObjects‏ مرتب

منبع در کد: src/rgw/driver/rados/rgw_rados.cc :: RGWRados::calc_ordered_bucket_list_per_shard، cls_bucket_list_ordered

پیچیدگی: هر صفحه ‏O‏(s × ‏k‏) ورودی از ‏s shard‏ و ادغام ‏O‏(n log s)

text
pseudocode
per_shard(n, s) = max(8, 1 + ⌊n / s⌋ + sqrt(2 n ln s / s))     # تحلیل «توپ در سطل» Raab و Steger
k = per_shard(max_keys, shards)
از هر shard تا k ورودی بعد از marker بخوان (به‌صورت موازی)
ادغام مرتب ؛ اگر یک shard زودتر تمام شد و n ورودی نرسید: تلاش دوباره با k × 2^(expansion − 1) (حداکثر 1024 برابر)

مثال عددی. صفحه‌ی پیش‌فرض ‏S3‏ هزار کلید است (‏max-keys‏ = ۱۰۰۰). با ۱۱ ‏shard‏: ⌊۱۰۰۰ / ۱۱⌋ = ۹۰ و ‏sqrt‏(۲۰۰۰ × ‏ln 11‏ / ۱۱) ≈ ۲۰.۹، پس ‏k‏ = ۱۱۱ و کل ورودی‌های خوانده‌شده ۱۲۲۱ است، یعنی ۲۲ درصد اضافه. با ۱۰۱ ‏shard: k‏ = ۱ + ۹ + ۹.۶ ≈ ۱۹ و کل ۱۹۱۹. با ۱۹۹۹ ‏shard‏، ⌊۱۰۰۰ / ۱۹۹۹⌋ = ۰ و ریشه حدود ۲.۸ است، اما حداقل ۸ اعمال می‌شود و کل ۱۵۹۹۲ ورودی، یعنی ۱۶ برابر نیاز، از ۱۹۹۹ شیء ایندکس خوانده می‌شود. هر ‏shard‏ هم یک فراخوانی ‏cls‏ جداگانه است. پس ‏bucket‏ با ۱۹۹۹ ‏shard‏ برای هر صفحه‌ی ۱۰۰۰ کلیدی ۱۹۹۹ عملیات ‏cls‏ به ‏OSD‏ها می‌فرستد. اگر برنامه فقط به فهرست نامرتب نیاز دارد (مثلاً پاک‌سازی یا پشتیبان‌گیری)، ‏allow-unordered=true‏ در ‏API‏ یا ‏--allow-unordered‏ در ‏radosgw-admin‏ این هزینه را حذف می‌کند.

شکل ۴-۹: تعداد کل ورودی‌های ایندکسی که برای ساختن یک صفحه‌ی فهرست مرتب درخواست می‌شود، برحسب تعداد shard ، برای max-keys برابر ۱۰۰۰ و ۱۰۰. خط نقطه‌چین هم‌رنگ تعداد واقعی کلیدهای صفحه است. با shard کم، اضافه‌خوانی کم است. از جایی که n / s زیر ۸ می‌رود، حداقل ۸ غالب می‌شود، دو منحنی بر هم منطبق می‌شوند و هزینه با تعداد shard خطی بالا می‌رود. عددها فقط تلاش اول را نشان می‌دهند، پیش از گسترش ضریب
شکل ۴-۹: تعداد کل ورودی‌های ایندکسی که برای ساختن یک صفحه‌ی فهرست مرتب درخواست می‌شود، برحسب تعداد ‏shard‏، برای ‏max-keys‏ برابر ۱۰۰۰ و ۱۰۰. خط نقطه‌چین هم‌رنگ تعداد واقعی کلیدهای صفحه است. با ‏shard‏ کم، اضافه‌خوانی کم است. از جایی که ‏n‏ / ‏s‏ زیر ۸ می‌رود، حداقل ۸ غالب می‌شود، دو منحنی بر هم منطبق می‌شوند و هزینه با تعداد ‏shard‏ خطی بالا می‌رود. عددها فقط تلاش اول را نشان می‌دهند، پیش از گسترش ضریب

۴-۱۰-۴ نام شیءهای ‏RADOS: head‏، ‏tail‏ و ‏multipart‏#

∑ الگوریتم: چیدمان یک شیء ‏S3‏ در ‏RADOS‏

منبع در کد: src/rgw/rgw_obj_manifest.cc :: RGWObjManifest::get_implicit_location؛ src/rgw/driver/rados/rgw_putobj_processor.cc :: AtomicObjectProcessor::prepare؛ src/rgw/driver/rados/rgw_obj_manifest.cc :: RGWObjManifest::generator::create_begin

پیچیدگی: ‏O‏(size / ‏stripe‏) شیء برای هر ‏PUT‏

text
pseudocode
head_max = rgw_max_chunk_size (4 MiB)   # اگر placement داده‌ی inline دارد و tail در همان pool است، وگرنه 0
stripe   = rgw_obj_stripe_size (4 MiB، هم‌تراز با alignment pool)
prefix   = "." + rand_alnum(32) + "_"    (PUT عادی) ؛ name + "." + upload_id   (multipart)
location(part, stripe_no, ofs):
    part == 0 and ofs < head_max: شیء head = "<marker>_<name>"
    part == 0:                     ns shadow    "<marker>__shadow_" + prefix + stripe_no
    part > 0 and stripe_no == 0:   ns multipart "<marker>__multipart_" + prefix + "." + part
    part > 0:                      ns shadow    "<marker>__shadow_" + prefix + "." + part + "_" + stripe_no

مثال عددی. ‏PUT‏ یک فایل ۱۰ ‏MiB‏ به نام ‏photo.jpg‏ در ‏pool‏ پیش‌فرض سه شیء ‏RADOS‏ می‌سازد. ‏head‏ با نام ‏<marker>_photo.jpg‏ چهار مگابایت اول داده را همراه ‏xattr‏های ‏manifest‏، ‏ACL‏ و ‏ETag‏ نگه می‌دارد. دو شیء ‏tail‏ با نام‌های ‏<marker>__shadow_.<rand32>_1‏ (۴ ‏MiB‏) و ‏..._2‏ (۲ ‏MiB‏) بقیه را دارند. یک آپلود ‏multipart‏ با دو قطعه‌ی ۱۰ مگابایتی برای ‏big.iso‏ این‌ها را می‌سازد: ‏head‏ بدون داده با ‏manifest‏، و برای هر قطعه یک شیء ‏__multipart_big.iso.<upload>.N‏ با ۴ ‏MiB‏ اول آن قطعه و دو ‏stripe‏ در ‏ns shadow‏ با نام‌های ‏big.iso.<upload>.N_1‏ و ‏.N_2‏. کل یک شیء ‏S3‏ بیست مگابایتی هفت شیء ‏RADOS‏ است. ‏ETag‏ چنین شیئی ‏md5‏ الحاق ‏md5‏ دودویی قطعه‌ها و پسوند «‎-۲» است، نه ‏md5‏ کل فایل. حذف شیء فوری فقط ‏head‏ را پاک می‌کند. ‏tail‏ها به صف ‏GC‏ (‏radosgw-admin gc list‏) می‌روند و بعد از ‏rgw_gc_obj_min_wait‏ پاک می‌شوند. به همین دلیل فضای ‏pool‏ پس از حذف انبوه بلافاصله آزاد نمی‌شود.

شکل ۴-۱۰: بالا: یک PUT ساده‌ی ۱۰ مگابایتی. head (زرد) چهار مگابایت اول و فراداده را دارد و دو stripe در namespace shadow (آبی) با پیشوند تصادفی ۳۲ نویسه‌ای بقیه را دارند. پایین: آپلود multipart با دو قطعه‌ی ۱۰ مگابایتی. head بدون داده است و فقط manifest را دارد. هر قطعه یک شیء در namespace multipart (قرمز) برای ۴ مگابایت اول خود و دو stripe در namespace shadow دارد. نام‌ها از get_implicit_location گرفته شده‌اند. marker و upload id نمادین هستند
شکل ۴-۱۰: بالا: یک ‏PUT‏ ساده‌ی ۱۰ مگابایتی. ‏head‏ (زرد) چهار مگابایت اول و فراداده را دارد و دو ‏stripe‏ در ‏namespace‏ ‏‏shadow‏ (آبی) با پیشوند تصادفی ۳۲ نویسه‌ای بقیه را دارند. پایین: آپلود ‏multipart‏ با دو قطعه‌ی ۱۰ مگابایتی. ‏head‏ بدون داده است و فقط ‏manifest‏ را دارد. هر قطعه یک شیء در ‏namespace‏ ‏‏multipart‏ (قرمز) برای ۴ مگابایت اول خود و دو ‏stripe‏ در ‏namespace‏ ‏‏shadow‏ دارد. نام‌ها از ‏get_implicit_location‏ گرفته شده‌اند. ‏marker‏ و ‏upload id‏ نمادین هستند

۴-۱۱ قابلیت‌های پیشرفته‌ی ‏S3‏ در ‏RGW‏#

۴-۱۱-۱ نسخه‌بندی و ‏object lock‏#

با فعال کردن ‏versioning‏ روی ‏bucket‏، هر بازنویسی یا حذف یک نسخه‌ی تازه می‌سازد و نسخه‌های قبلی قابل بازیابی‌اند. ‏object lock‏ یک گام جلوتر می‌رود: نسخه‌ها را برای مدت مشخص غیرقابل‌حذف و غیرقابل‌تغییر (‏WORM‏) می‌کند؛ قابلیتی کلیدی برای حفاظت پشتیبان‌ها در برابر باج‌افزار و الزامات قانونی نگه‌داری داده.

bash
EP="--endpoint-url https://s3.example.com --profile ceph"
aws $EP s3api create-bucket --bucket vault --object-lock-enabled-for-bucket
aws $EP s3api put-object-lock-configuration --bucket vault \
  --object-lock-configuration '{"ObjectLockEnabled":"Enabled","Rule":{"DefaultRetention":{"Mode":"COMPLIANCE","Days":30}}}'
aws $EP s3 cp backup-2026-11-15.tar s3://vault/
aws $EP s3api list-object-versions --bucket vault
aws $EP s3api get-object-retention --bucket vault --key backup-2026-11-15.tar
حالترفتارچه کسی می‌تواند زودتر حذف کند؟
‏GOVERNANCE‏نسخه تا پایان مهلت قفل استکاربری با مجوز ‏s3:BypassGovernanceRetention‏
‏COMPLIANCE‏نسخه تا پایان مهلت قفل استهیچ کاربر ‏S3‏ای، حتی مالک
‏Legal Hold‏قفل بدون تاریخ پایانتا وقتی برداشته نشود
⚠ هشدار

‏object lock‏ در حالت ‏COMPLIANCE‏ از دید ‏API S3‏ قطعی است، اما مدیر کلاستر با دسترسی ‏radosgw-admin‏ یا ‏RADOS‏ هنوز از نظر فنی می‌تواند داده را حذف کند. حفاظت واقعی در برابر مهاجمی که به اعتبارنامه‌ی مدیر کلاستر رسیده، نیازمند جداسازی دسترسی‌ها، پایش و نسخه‌ی خارج از سایت است. همچنین ‏bucket‏ی که با ‏object lock‏ ساخته شده را نمی‌توان بعداً بدون آن کرد؛ مدت پیش‌فرض را با دقت انتخاب کنید.

۴-۱۱-۲ ‏lifecycle‏، ‏storage class‏ و ‏placement‏#

‏placement target‏ تعیین می‌کند داده و ‏index‏ یک ‏bucket‏ در کدام ‏pool‏ها باشند. هر ‏placement‏ می‌تواند چند ‏storage class‏ داشته باشد که هر کدام به ‏pool‏ داده‌ی متفاوتی اشاره می‌کند. قاعده‌های ‏lifecycle‏ اشیاء را پس از مدتی به کلاس دیگر منتقل یا حذف می‌کنند.

شکل ۴-۱۱: placement و storage class : داده‌ی تازه در کلاس STANDARD و پس از مدتی با lifecycle به کلاس سرد EC یا ذخیره‌سازی ابری بیرونی منتقل می‌شود
شکل ۴-۱۱: ‏placement‏ و ‏storage class‏: داده‌ی تازه در کلاس ‏STANDARD‏ و پس از مدتی با ‏lifecycle‏ به کلاس سرد ‏EC‏ یا ذخیره‌سازی ابری بیرونی منتقل می‌شود
bashReef+
# تعریف کلاس COLD در zonegroup و zone پیش‌فرض
radosgw-admin zonegroup placement add --rgw-zonegroup default \
  --placement-id default-placement --storage-class COLD
radosgw-admin zone placement add --rgw-zone default \
  --placement-id default-placement --storage-class COLD \
  --data-pool default.rgw.cold.data --compression lz4
radosgw-admin period update --commit     # فقط اگر realm تعریف شده باشد
json
{"Rules":[{"ID":"tiering","Status":"Enabled","Filter":{"Prefix":"logs/"},
  "Transitions":[{"Days":30,"StorageClass":"COLD"}],
  "Expiration":{"Days":365},
  "AbortIncompleteMultipartUpload":{"DaysAfterInitiation":7}}]}
bashReef+
aws $EP s3api put-bucket-lifecycle-configuration --bucket logs-bucket --lifecycle-configuration file://lc.json
radosgw-admin lc list
radosgw-admin lc process --bucket logs-bucket    # اجرای دستی برای آزمایش
💡 نکته

در آزمایشگاه برای دیدن اثر ‏lifecycle‏ بدون صبر چندروزه، ‏rgw_lc_debug_interval‏ را مثلاً ۶۰ بگذارید تا هر «روز» ‏lifecycle‏ شصت ثانیه حساب شود. این گزینه را هرگز در ‏production‏ روشن نگذارید.

در نسخه‌های جدید، ‏lifecycle‏ می‌تواند اشیاء را به یک ذخیره‌سازی ابری سازگار با ‏S3‏ هم منتقل کند (‏cloud transition‏) و در ‏Umbrella‏ بازگرداندن از ‏Glacier‏ یا نوار (‏cloud restore‏) با ابزارهای مدیریتی و اعلان رویداد کامل‌تر شده است.

۴-۱۱-۳ سیاست ‏bucket‏ و ‏IAM‏#

‏RGW‏ زبان سیاست ‏AWS‏ را پشتیبانی می‌کند. نمونه‌ی زیر به کاربر ‏ci-bot‏ اجازه می‌دهد فقط در پیشوند ‏artifacts/‏ بنویسد:

json
{"Version":"2012-10-17","Statement":[{
  "Effect":"Allow",
  "Principal":{"AWS":["arn:aws:iam:::user/ci-bot"]},
  "Action":["s3:PutObject","s3:GetObject"],
  "Resource":["arn:aws:s3:::builds/artifacts/*"]}]}
bash
aws $EP s3api put-bucket-policy --bucket builds --policy file://policy.json

با ‏account‏ (از ‏Squid‏) می‌توان همین سیاست‌ها را روی کاربران و گروه‌ها هم با ‏API‏های ‏IAM‏ گذاشت و از ‏STS‏ برای اعتبارنامه‌ی موقت و ‏AssumeRoleWithWebIdentity‏ (OIDC) استفاده کرد.

۴-۱۱-۴ رمزنگاری سمت سرور#

‏RGW‏ از ‏SSE-C‏ (کلید از کلاینت)، ‏SSE-KMS‏ (کلید از ‏Vault‏ یا ‏KMIP‏ یا ‏Barbican‏) و ‏SSE-S3‏ پشتیبانی می‌کند. در ‏Umbrella‏ رمزنگاری ‏AES-256-GCM‏ اضافه شده و ‏CopyObject‏ برای اشیای رمزشده هم کار می‌کند.

⚠ هشدار

‏SSE-C‏ و ‏SSE-KMS‏ فقط روی اتصال ‏HTTPS‏ مجازند. اگر ‏TLS‏ را در ‏load balancer‏ پایان می‌دهید، به ‏RGW‏ بگویید درخواست‌ها امن رسیده‌اند (‏rgw_trust_forwarded_https = true‏) و فقط وقتی این را روشن کنید که مطمئنید ‏load balancer‏ همیشه این هدر را خودش تنظیم یا پاک می‌کند.

۴-۱۱-۵ اعلان رویداد و لاگ ‏bucket‏#

‏RGW‏ می‌تواند رویدادهایی مثل ساخت یا حذف شیء را به ‏Kafka‏، ‏AMQP‏ (RabbitMQ) یا ‏HTTP‏ بفرستد؛ پایه‌ای برای پردازش رویدادمحور (مثلاً تولید ‏thumbnail‏ پس از آپلود عکس):

bash
aws $EP sns create-topic --name uploads \
  --attributes '{"push-endpoint":"kafka://kafka.example.com:9092","persistent":"true"}'
aws $EP s3api put-bucket-notification-configuration --bucket photos \
  --notification-configuration '{"TopicConfigurations":[{"Id":"n1","TopicArn":"arn:aws:sns:default::uploads","Events":["s3:ObjectCreated:*"]}]}'

‏Bucket logging‏ (ثبت درخواست‌های هر ‏bucket‏ در ‏bucket‏ دیگر) طبق مستندات از ‏Tentacle‏ اضافه شده و در ‏Umbrella‏ حالت ‏journal‏، پشتیبانی از ‏pool EC‏ و دستورهای مدیریتی گرفته است.

۴-۱۲ عملیات روزمره‌ی ‏RGW‏#

۴-۱۲-۱ دستورهای پرکاربرد#

bashReef+
radosgw-admin bucket list
radosgw-admin bucket stats --bucket=photos
radosgw-admin bucket limit check            # shardهای نزدیک آستانه
radosgw-admin reshard list
radosgw-admin reshard add --bucket=photos --num-shards=101
radosgw-admin gc list --include-all | head
radosgw-admin gc process
radosgw-admin usage show --uid=alice --start-date=2026-11-01
radosgw-admin bucket check --bucket=photos --check-objects --fix
◆ عمیق‌تر

حذف شیء در ‏RGW‏ فوری فضا آزاد نمی‌کند. ‏head object‏ حذف می‌شود اما اشیای ‏tail‏ به ‏garbage collector‏ سپرده می‌شوند و پس از ‏rgw_gc_obj_min_wait‏ (پیش‌فرض دو ساعت) پاک می‌شوند. اگر حذف انبوه انجام دادید و ‏ceph df‏ تغییری نکرد، صف ‏gc‏ را ببینید. در کلاسترهای پرتراکنش ممکن است نیاز باشد پارامترهای ‏rgw_gc_max_concurrent_io‏ و ‏rgw_gc_processor_period‏ را تنظیم کنید.

۴-۱۲-۲ عیب‌یابی#

✚ عیب‌یابی

نشانه‌ها و راه بررسی:

خطای ‏SignatureDoesNotMatch‏: اختلاف ساعت کلاینت و سرور بیش از ۱۵ دقیقه، یا ‏load balancer‏ که هدر ‏Host‏ را تغییر می‌دهد، یا ‏path-style‏ در برابر ‏virtual-host‏ اشتباه.

خطای ‏NoSuchBucket‏ با وجود ‏bucket‏: کلاینت ‏virtual-host‏ استفاده می‌کند ولی ‏rgw_dns_name‏ یا ‏hostnames‏ در ‏zonegroup‏ تنظیم نشده و ‏RGW‏ نام ‏bucket‏ را از ‏Host‏ تشخیص نمی‌دهد.

فهرست‌گیری بسیار کند: ‏index‏ روی ‏HDD‏، ‏bucket‏ بدون ‏shard‏ کافی، یا میلیون‌ها نسخه‌ی حذف‌شده در ‏bucket‏ نسخه‌بندی‌شده.

هشدار ‏LARGE_OMAP_OBJECTS‏: ‏shard‏های ‏index‏ بزرگ؛ با ‏radosgw-admin bucket limit check‏ ‏bucket‏ مقصر را پیدا کنید.

برای دیدن جزئیات یک درخواست، موقتاً ‏debug_rgw‏ را بالا ببرید: ‏ceph config set client.rgw debug_rgw 20‏ و پس از بازتولید مشکل، برگردانید.

۴-۱۳ تکمیلی و به‌روز#

  • ‏ingress‏ و ‏certmgr‏ در ‏cephadm‏: ‏load balancer‏ و گواهی‌ها حالا بخشی از ارکستراتورند.
  • ‏account‏ و ‏IAM‏ (Squid به بعد): مدیریت سلف‌سرویس کاربران، گروه‌ها، نقش‌ها و سیاست‌ها؛ در ‏Umbrella GetAccountSummary‏، ‏PublicAccessBlock‏ در سطح ‏account‏، ‏API‏های مدیریتی سهمیه‌ی ‏account‏ و ‏S3 Object Ownership‏ (غیرفعال‌سازی ‏ACL‏) اضافه شده‌اند.
  • ‏S3 GetObjectAttributes‏ در ‏Tentacle‏ اضافه شده و برای سازگاری با ‏AWS‏، زمان ‏LastModified‏ به ثانیه گرد می‌شود.
  • ‏dedup‏ کامل اشیاء در ‏Umbrella‏ به‌صورت پیش‌نمایش فنی آمده است.
  • ‏cache D4N‏ مبتنی بر ‏Redis‏ در حال توسعه است.
  • اسکریپت ‏Lua‏: ‏RGW‏ اجازه می‌دهد در مراحل مختلف پردازش درخواست، اسکریپت ‏Lua‏ اجرا شود (مثلاً برای لاگ سفارشی یا تغییر رفتار)؛ ‏Umbrella hook‏ جدید ‏postAuth‏ را اضافه کرده است.

۴-۱۴ جمع‌بندی و مرور#

۴-۱۴-۱ خلاصه‌ی فصل#

نکته‌های کلیدی
  • ‏RGW‏ سرور ‏HTTP‏ بدون حالت است که ‏S3‏ و ‏Swift‏ را روی ‏RADOS‏ پیاده می‌کند؛ با ‏cephadm‏ و سرویس ‏ingress‏ به‌سادگی مقیاس افقی می‌گیرد.
  • هر شیء ‏S3‏ یک ‏head object‏، تعدادی ‏tail‏ و یک ورودی در ‏index bucket‏ دارد؛ ‏index‏ باید روی ‏SSD‏ و تکثیری باشد.
  • کاربر، ‏subuser‏، ‏tenant‏ و ‏account‏ سطوح مختلف هویت و چندمستاجری‌اند؛ برای طراحی تازه ‏account‏ را در نظر بگیرید.
  • ‏virtual-host‏ نیازمند ‏DNS wildcard‏، ‏rgw_dns_name‏ و گواهی ‏wildcard‏ است.
  • ‏Keystone‏ و ‏S3A‏ اتصال ‏RGW‏ به ‏OpenStack‏ و اکوسیستم داده را ممکن می‌کنند.
  • ‏versioning‏، ‏object lock‏، ‏lifecycle‏، ‏storage class‏، سیاست‌ها، ‏SSE‏ و اعلان رویداد ‏RGW‏ را به یک سرویس ‏S3‏ کامل تبدیل کرده‌اند.

۴-۱۴-۲ اشتباهات رایج#

  • ‏pool index‏ روی ‏HDD‏ یا ‏EC‏.
  • اجرای یک نمونه‌ی ‏RGW‏ بدون ‏load balancer‏.
  • فراموش کردن ‏lifecycle‏ برای بارگذاری‌های چندبخشی نیمه‌کاره.
  • انتظار آزاد شدن فوری فضا پس از حذف (بی‌اطلاعی از ‏gc‏).
  • ساخت ‏bucket‏ با ‏object lock‏ در حالت ‏COMPLIANCE‏ با مدت طولانی برای آزمایش.
  • اختلاف ساعت بین کلاینت‌ها و ‏RGW‏.

۴-۱۴-۳ تمرین عملی#

  1. ۱. ‏RGW‏ را با دو نمونه و یک سرویس ‏ingress‏ مستقر کنید و با متوقف کردن یک نمونه نشان دهید سرویس قطع نمی‌شود.
  2. ۲. یک کاربر با سهمیه‌ی ۱ گیگابایت بسازید و رفتار ‏RGW‏ را هنگام عبور از سهمیه ببینید.
  3. ۳. یک ‏bucket‏ با ‏versioning‏ بسازید، فایلی را سه بار بازنویسی و سپس حذف کنید و با ‏list-object-versions‏ همه‌ی نسخه‌ها و ‏delete marker‏ را ببینید. نسخه‌ی دوم را بازیابی کنید.
  4. ۴. یک ‏storage class‏ سرد روی ‏pool EC‏ بسازید و با ‏lifecycle‏ و ‏rgw_lc_debug_interval‏ انتقال اشیاء را در آزمایشگاه مشاهده کنید.
  5. ۵. ۱۰۰٬۰۰۰ شیء کوچک در یک ‏bucket‏ بنویسید (مثلاً با ‏s3-benchmark‏ یا یک اسکریپت موازی) و با ‏bucket limit check‏ و ‏reshard list‏ رفتار ‏resharding‏ پویا را ببینید.

۴-۱۴-۴ پرسش‌های مرور#

  1. ۱. چرا ‏RGW‏ را «بدون حالت» می‌نامیم و این چه اثری بر طراحی دسترس‌پذیری بالا دارد؟
  2. ۲. یک شیء ‏S3‏ بیست‌مگابایتی در ‏RADOS‏ به چه اشیایی تبدیل می‌شود؟
  3. ۳. چرا ‏pool index‏ نباید ‏EC‏ یا روی ‏HDD‏ باشد؟
  4. ۴. ‏resharding‏ پویا چه مشکلی را حل می‌کند و آستانه‌ی پیش‌فرض آن چیست؟
  5. ۵. تفاوت ‏tenant‏ و ‏account‏ چیست؟
  6. ۶. برای دسترسی ‏virtual-hosted-style‏ چه پیکربندی‌هایی لازم است؟
  7. ۷. دو حالت ‏GOVERNANCE‏ و ‏COMPLIANCE‏ در ‏object lock‏ چه فرقی دارند؟
  8. ۸. چرا پس از حذف انبوه اشیاء، فضای کلاستر فوراً آزاد نمی‌شود؟
  9. ۹. گزینه‌ی ‏rgw_s3_auth_use_keystone‏ چه امکانی فراهم می‌کند؟
  10. ۱۰. چرا ‏S3A committers‏ برای ‏Spark‏ روی ‏RGW‏ مهم‌اند؟

پاسخ این پرسش‌ها در پیوست ه: پاسخ پرسش‌ها آمده است. پاسخ پرسش‌های این فصل →

۴-۱۴-۵ منابع این فصل#

راهنمای جامع Ceph · ۱٫۶ · آبان ۱۴۰۵
© 2026 Ramin Najarbashi · CC BY-NC-SA 4.0

حریم خصوصی: این سایت کوکی نمی‌گذارد. برای شمارش بازدیدها از Cloudflare Web Analytics استفاده می‌شود که کوکی ندارد و افراد را دنبال نمی‌کند.