تکنولوژی

راه‌اندازی Replica Set در MongoDB با استفاده از Docker

دسترسی پذیری بالا (High Availability) و تحمل پذیری خطا (Fault Tolerance) در طراحی سیستم‌های نرم افزاری، ضروری هستند. استفاده از راهکارهای همگام‌سازی مانند Replica Set در پایگاه‌های داده‌ای نظیر MongoDB، نقش کلیدی در تضمین پایداری سرویس‌ها ایفا می‌کند. Replica Set با ایجاد چندین کپی همزمان از داده‌‌ها و خودکارسازی فرآیند بازیابی، نه تنها قابلیت اطمینان سیستم را افزایش می‌دهد، بلکه امکان توزیع بار پردازشی را نیز فراهم می‌سازد.

اما پیاده سازی چنین ساختاری در محیط‌های توسعه و تولید، به ویژه هنگام کار با ابزارهای کانتینرسازی مانند Docker، نیازمند درک کامل مفاهیم و انجام تنظیماتی ظریف است. Docker با ارائه محیط‌های ایزوله و قابل همگام‌سازی، بستری ایده‌آل برای شبیه‌سازی یک Replica Set فراهم می‌کند و فرآیند راه اندازی، تست و توسعه را تسهیل می‌کند. در این مطلب به صورت گام به گام و عملی، چگونگی راه‌اندازی یک Replica Set ساده در MongoDB را با استفاده از Docker آموزش می‌دهیم.

فهرست مطالب

در دیتابیس هایی مثل MongoDB، وقتی از Replica Set حرف می‌زنیم، یعنی ایجاد یک گروه از دیتابیس ها که باهم هماهنگ کار می‌کنند تا هم اطلاعاتتان ایمن بماند و هم سیستم همیشه در دسترس باشد. در این گروه، یک دیتابیس به عنوان Primary (اصلی) انتخاب می‌شود که همه عملیات نوشتن (write) و تغییر داده‌ها (update) فقط از طریق آن صورت می‌گیرد. مثلاً وقتی کاربری در سایت ثبت نام می‌کند، این اطلاعات مستقیم به دیتابیس اصلی فرستاده می‌شود. اما بقیه ی دیتابیس ها که به آن ها Secondary می‌گوییم، دقیقاً از دیتابیس اصلی کپی برداری می‌کنند و داده هایشان همیشه با آن همگام است. این دیتابیس‌های جانبی نمی‌توانند داده‌ها را تغییر دهند، اما وقتی می‌خواهید اطلاعات را فقط بخوانید (مثلاً نمایش محصولات در یک فروشگاه آنلاین)، می‌توانید برای کاهش تاخیر و سریع‌تر شدن این روند، از آن‌ها کمک بگیرید.

این روش دو مزیت بزرگ دارد. اول این که بار کاری سیستم بهینه می‌شود. چون عملیات سنگین نوشتن، فقط روی دیتابیس اصلی انجام می‌شود و کارهای خواندن بین چندین دیتابیس ثانویه پخش می‌شود و سرعت پاسخگویی به کاربران بالاتر می‌رود. دوم اینکه اگر دیتابیس اصلی به هر دلیلی از کار بیفتد، سیستم به طور خودکار یکی از دیتابیس های Secondary را به عنوان جایگزین انتخاب می‌کند و کار بدون وقفه ادامه می‌یابد. این یعنی حتی در صورت بروز مشکل، کاربران متوجه اختلالی نمی‌شوند و داده‌ها هم از بین نمی‌روند.

در نهایت، Replica Set مثل یک تیم قوی است که همیشه از داده‌های شما محافظت می‌کند. با این روش هم سرعت سیستم بالا می‌رود، هم خطاها مدیریت می‌شوند، و هم مدیران می‌توانند با خیال راحت‌تر منابع را کنترل کنند. این قابلیت به خصوص در سرویس‌های مهم که قطعی یا کندی در آن ها غیرقابل تحمل است، به یک ابزار حیاتی تبدیل می‌شود. اما اکنون که با این دو مفهوم آشنا شدید وقت آن است که اقدام به راه‌اندازی Replica Set در MongoDB با استفاده از Docker کنیم. برای این کار ابتدا از نصب داکر شروع می کنیم.

برای راه اندازی Replica Set در MongoDB با Docker نیازی به نصب کامل MongoDB نیست و تنها کافیست داکر را نصب کنید. اگر از کامپیوتر شخصی استفاده می‌کنید، می‌توانید Docker Desktop را نصب کنید. برای بررسی نصب Docker، دستور زیر را اجرا کنید:

docker -v

این دستور باید شماره نسخه را نمایش دهد. سپس، باید مطمئن شویم که سرویس Docker در حال اجرا است. برای این کار دستور زیر را اجرا کنید.

docker images

با اجرای این دستور می‌توانید لیست image های موجود در سیستم خود را مشاهده کنید. در مرحله بعد، آخرین نسخه از MongoDB را با اجرای دستور زیر نصب می‌کنیم:

docker pull mongo
راه اندازی Replica Set در MongoDB با Docker

ما قصد داریم سه کانتینر از Mongo image ایجاد کنیم که همگی در شبکه مخصوص کانتینرهای Docker قرار دارند. این کانتینرها را mongo1، mongo2 و mongo3 نامگذاری می‌کنیم. این‌ها سه نمونه Mongo از مجموعه Replica ما خواهند بود.

همچنین هر یک از آن‌ها را به ماشین لوکال خود متصل می‌کنیم تا بتوانیم از طریق رابط Mongo shell از ماشین لوکال به آن‌ها دسترسی داشته باشیم. هر یک از سه کانتینر Mongo باید بتوانند با تمام کانتینرهای دیگر در شبکه ارتباط برقرار کنند.

برای مشاهده تمام شبکه‌های موجود در سیستم، دستور زیر را اجرا کنید:

docker network ls

با اجرای این دستور خروجی مشابه زیر نمایش داده می‌شود:

NETWORK ID          NAME                DRIVER              SCOPE
2a4e341c6039        bridge              bridge              local
4fbef5286425        host                host                local
8062e4e7cdca        none                null                local

حال به کمک دستور زیر یک شبکه جدید به نام my-mongo-cluster ایجاد می‌کنیم:

docker network create my-mongo-cluster

شبکه جدید اکنون باید به لیست شبکه‌های شما اضافه شده باشد. برای بررسی این موضوع دستور زیر را اجرا کنید:

docker network ls

برای راه‌اندازی اولین کانتینر (mongo1)، دستور زیر را اجرا کنید:

docker run \
-p 30001:27017 \
--name mongo1 \
--net my-mongo-cluster \
mongo mongod --replSet my-mongo-set

اجزای این دستور:

  • docker run: شروع یک کانتینر از یک image
  • -p 30001:27017: قرار دادن پورت 27017 در کانتینر به عنوان پورت 30001 روی localhost
  • --name mongo1: نام این کانتینر را “mongo1” بگذار
  • --net my-mongo-cluster: این کانتینر را به شبکه “my-mongo-cluster” اضافه کن.
  • mongo: نام image که از آن کانتینر ایجاد می‌کنیم.
  • mongod --replSet my-mongo-set: mongod را اجرا کن در حالی که این نمونه mongod را به مجموعه replica با نام “my-mongo-set” اضافه می‌کنی.

حال دو کانتینر دیگر را با اجرای دستورات زیر راه‌اندازی می‌کنیم:

docker run \
-p 30002:27017 \
--name mongo2 \
--net my-mongo-cluster \
mongo mongod --replSet my-mongo-set
docker run \
-p 30003:27017 \
--name mongo3 \
--net my-mongo-cluster \
mongo mongod --replSet my-mongo-set

اکنون که تمام نمونه‌های Mongo ما در حال اجرا هستند، بیایید آن‌ها را به یک مجموعه replica تبدیل کنیم.

به کمک دستور زیر به Mongo shell در هر یک از کانتینرها متصل شوید:

docker exec -it mongo1 mongo

این دستور Mongo shell را در کانتینر در حال اجرای mongo1 باز می‌کند (اما می‌توانید آن را از کانتینرهای mongo2 یا mongo3 نیز اجرا کنید).

در داخل Mongo shell، ابتدا پیکربندی خود را به کمک دستور زیر ایجاد می‌کنیم:

> db = (new Mongo('localhost:27017')).getDB('test')
test
> config = {
      "_id" : "my-mongo-set",
      "members" : [
          {
              "_id" : 0,
              "host" : "mongo1:27017"
          },
          {
              "_id" : 1,
              "host" : "mongo2:27017"
          },
          {
              "_id" : 2,
              "host" : "mongo3:27017"
          }
      ]
  }

کلید _id اول در پیکربندی باید با Flag (فلگ) --replSet که برای نمونه های mongod تعیین کرده ایم، یکسان باشد. در مثال ما، این مقدار برابر با my-mongo-set است. سپس، تمام اعضایی که باید در مجموعه رپلیکا (Replica Set) حضور داشته باشند را فهرست می‌کنیم.

از آنجایی که تمام نمونه های Mongo خود را به شبکه داکر (Docker) اضافه کرده‌ایم، نام هر نمونه در مرجع نام (resolver) کانتینرها، به آدرس IP مربوطه در شبکه my-mongo-cluster تبدیل می‌شود.

در نهایت، مجموعه رپلیکا (Replica Set) را با اجرای دستور زیر در Mongo shell راه‌اندازی کنید:

در نهایت، مجموعه replica را با اجرای دستور زیر در Mongo shell راه‌اندازی کنید:

> rs.initiate(config)
{ "ok" : 1 }

اگر دستور موفقیت‌آمیز باشد، prompt شما باید تغییر کند تا نشان دهد که پایگاه داده فعلی بخشی از یک مجموعه replica است:

my-mongo-set:PRIMARY>

این بدان معناست که shell در حال حاضر با پایگاه داده PRIMARY در خوشه my-mongo-set ما مرتبط است.

بیایید با مجموعه replica جدید خود کار کنیم تا مطمئن شویم که همانطور که انتظار می‌رود کار می‌کند. ابتدا یک سند را در پایگاه داده اصلی خود وارد می‌کنیم:

> db.mycollection.insert({name : 'sample'})
WriteResult({ "nInserted" : 1 })
> db.mycollection.find()
{ "_id" : ObjectId("57761827767433de37ff95ee"), "name" : "sample" }

سپس یک اتصال جدید به یکی از پایگاه‌های داده secondary خود (واقع در mongo2) ایجاد می‌کنیم و بررسی می‌کنیم که آیا سند ما رپلیکیت (همگام) شده است یا خیر:

> db2 = (new Mongo('mongo2:27017')).getDB('test')
test
> db2.setSecondaryOk()
> db2.mycollection.find()
{ "_id" : ObjectId("57761827767433de37ff95ee"), "name" : "sample" }

دستور db2.setSecondaryOk() به شل اطلاع می‌دهد که ما عمداً از یک پایگاه داده secondary پرس‌وجو می‌کنیم. به نظر می‌رسد همان سند در پایگاه داده secondary نیز وجود دارد.

می‌توانیم مراحل شرح داده شده در بالا را با استفاده از Docker compose خودکار سازی کنیم. برای این کار به کمک دستورات زیر ابتدا باید یک فایل docker-compose.yml ایجاد کنیم که سه سرور replica و همچنین یک سرور مقداردهی اولیه که کد پیکربندی مجموعه‌های replica را اجرا می‌کند، اعلام کند:

services:
  mongo1:
    hostname: mongo1
    image: mongo
    expose:
      - 27017
    ports:
      - 30001:27017 
    restart: always
    command: mongod --replSet my-mongo-set
  mongo2:
    hostname: mongo2
    image: mongo
    expose:
      - 27017
    ports:
      - 30002:27017
    restart: always
    command: mongod --replSet my-mongo-set
  mongo3:
    hostname: mongo3
    image: mongo
    expose:
      - 27017
    ports:
      - 30003:27017
    restart: always
    command: mongod --replSet my-mongo-set

  mongoinit:
    image: mongo
    restart: "no"
    depends_on:
      - mongo1
      - mongo2
      - mongo3
    command: >
      mongo --host mongo1:27017 --eval 
      '
      db = (new Mongo("localhost:27017")).getDB("test");
      config = {
      "_id" : "my-mongo-set",
      "members" : [
        {
          "_id" : 0,
          "host" : "mongo1:27017"
        },
        {
          "_id" : 1,
          "host" : "mongo2:27017"
        },
        {
          "_id" : 2,
          "host" : "mongo3:27017"
        }
      ]
      };
      rs.initiate(config);
      '      

برای راه‌اندازی این مجموعه، می‌توانید دستور زیر را اجرا کنید:

docker compose up

پس از راه‌اندازی کانتینرها، باید پیام‌ “Connection Accepted” را مشاهده کنید که به شکل زیر هستند:

mongo1_1     | {"t":{"$date":"2022-05-12T10:42:15.604+00:00"},"s":"I",  "c":"NETWORK",  "id":22943,   "ctx":"listener","msg":"Connection accepted","attr":{"remote":"172.19.0.3:37384","uuid":"53c10057-50bb-4055-8e1c-b3709b168b09","connectionId":19,"connectionCount":13}}
mongo2_1     | {"t":{"$date":"2022-05-12T10:42:15.605+00:00"},"s":"I",  "c":"NETWORK",  "id":22943,   "ctx":"listener","msg":"Connection accepted","attr":{"remote":"172.19.0.2:45566","uuid":"20c69c7a-384c-4d3f-bf47-210030d8151f","connectionId":21,"connectionCount":6}}
mongo3_1     | {"t":{"$date":"2022-05-12T10:42:15.607+00:00"},"s":"I",  "c":"NETWORK",  "id":22943,   "ctx":"listener","msg":"Connection accepted","attr":{"remote":"172.19.0.3:47582","uuid":"bcc4f252-3471-43b1-9834-7f13a369caa7","connectionId":23,"connectionCount":6}}

پس از این، می‌توانید کانتینرهای فعال را با اجرای دستور زیر فهرست کنید:

docker ps

CONTAINER ID   IMAGE          COMMAND                  CREATED              STATUS              PORTS                                           NAMES
60fea8228806   1b7803cb64be   "docker-entrypoint.s…"   About a minute ago   Up About a minute   0.0.0.0:30001->27017/tcp, :::30001->27017/tcp   example_mongo1_1
9bfce9c09fc7   1b7803cb64be   "docker-entrypoint.s…"   About a minute ago   Up About a minute   0.0.0.0:30002->27017/tcp, :::30002->27017/tcp   example_mongo2_1
bbc6c97094b6   1b7803cb64be   "docker-entrypoint.s…"   About a minute ago   Up About a minute   0.0.0.0:30003->27017/tcp, :::30003->27017/tcp   example_mongo3_1

نام کانتینرها ممکن است بسته به نام دایرکتوری فعلی شما تغییر کند. می‌توانید هر یک از کانتینرهای mongo را انتخاب کرده و با اجرای دستور زیر، Mongo shell را راه‌اندازی کنید:

docker exec -it example_mongo1_1 mongo

(‍example_mongo1_1 را با نام کانتینر خود جایگزین کنید)

با استفاده از Docker، توانستیم یک مجموعه Replica در MongoD را در حدود 5 دقیقه راه‌اندازی و اجرا کنیم. اگرچه این تنظیمات برای تست مجموعه‌های replica عالی است، اما قبل از انتقال آن به محیط عملیاتی باید برخی اقدامات احتیاطی انجام شود:

  1. هیچ یک از پایگاه‌های داده دارای اقدامات امنیتی مدیریتی نیستند. هنگام استقرار این راه‌حل در سرورهای عملیاتی، حتماً کاربران و رمزهای عبور را اضافه کنید.
  2. کانتینرهای replica مختلف باید در سرورهای فیزیکی مختلف نگهداری شوند. حداقل یک کانتینر را روی یک سرور متفاوت اجرا کنید و از طریق آدرس IP خارجی و پورت مربوطه به آن دسترسی پیدا کنید. (در مثال ما، پورت‌های خارجی کانتینرها به ترتیب 30001، 30002 و 30003 برای mongo1، mongo2 و mongo3 بودند).
  3. اگر یکی از کانتینرهای خود را به اشتباه حذف کنیم، داده‌ها نیز از بین می‌روند. استفاده از volumes در Docker و تنظیم --dbpath مناسب هنگام اجرای mongod از وقوع این اتفاق جلوگیری می‌کند.
  4. در نهایت، به جای اجرای چندین اسکریپت shell، ممکن است خودکارسازی کل این فرایند با استفاده از ابزارهای خودکارسازی چندکانتینری مانند docker-compose راحت‌تر باشد.

منبع: sohamkamani.com

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا