راهاندازی Replica Set در MongoDB با استفاده از Docker
دسترسی پذیری بالا (High Availability) و تحمل پذیری خطا (Fault Tolerance) در طراحی سیستمهای نرم افزاری، ضروری هستند. استفاده از راهکارهای همگامسازی مانند Replica Set در پایگاههای دادهای نظیر MongoDB، نقش کلیدی در تضمین پایداری سرویسها ایفا میکند. Replica Set با ایجاد چندین کپی همزمان از دادهها و خودکارسازی فرآیند بازیابی، نه تنها قابلیت اطمینان سیستم را افزایش میدهد، بلکه امکان توزیع بار پردازشی را نیز فراهم میسازد.
اما پیاده سازی چنین ساختاری در محیطهای توسعه و تولید، به ویژه هنگام کار با ابزارهای کانتینرسازی مانند Docker، نیازمند درک کامل مفاهیم و انجام تنظیماتی ظریف است. Docker با ارائه محیطهای ایزوله و قابل همگامسازی، بستری ایدهآل برای شبیهسازی یک Replica Set فراهم میکند و فرآیند راه اندازی، تست و توسعه را تسهیل میکند. در این مطلب به صورت گام به گام و عملی، چگونگی راهاندازی یک Replica Set ساده در MongoDB را با استفاده از Docker آموزش میدهیم.
فهرست مطالب
- خلاصه و مفید درباره Replica Set
- راه اندازی Replica Set در MongoDB با استفاده از Docker
- استفاده از Docker Compose
- نکات مهم
خلاصه و مفید درباره Replica Set
در دیتابیس هایی مثل MongoDB، وقتی از Replica Set حرف میزنیم، یعنی ایجاد یک گروه از دیتابیس ها که باهم هماهنگ کار میکنند تا هم اطلاعاتتان ایمن بماند و هم سیستم همیشه در دسترس باشد. در این گروه، یک دیتابیس به عنوان Primary (اصلی) انتخاب میشود که همه عملیات نوشتن (write) و تغییر دادهها (update) فقط از طریق آن صورت میگیرد. مثلاً وقتی کاربری در سایت ثبت نام میکند، این اطلاعات مستقیم به دیتابیس اصلی فرستاده میشود. اما بقیه ی دیتابیس ها که به آن ها Secondary میگوییم، دقیقاً از دیتابیس اصلی کپی برداری میکنند و داده هایشان همیشه با آن همگام است. این دیتابیسهای جانبی نمیتوانند دادهها را تغییر دهند، اما وقتی میخواهید اطلاعات را فقط بخوانید (مثلاً نمایش محصولات در یک فروشگاه آنلاین)، میتوانید برای کاهش تاخیر و سریعتر شدن این روند، از آنها کمک بگیرید.
این روش دو مزیت بزرگ دارد. اول این که بار کاری سیستم بهینه میشود. چون عملیات سنگین نوشتن، فقط روی دیتابیس اصلی انجام میشود و کارهای خواندن بین چندین دیتابیس ثانویه پخش میشود و سرعت پاسخگویی به کاربران بالاتر میرود. دوم اینکه اگر دیتابیس اصلی به هر دلیلی از کار بیفتد، سیستم به طور خودکار یکی از دیتابیس های Secondary را به عنوان جایگزین انتخاب میکند و کار بدون وقفه ادامه مییابد. این یعنی حتی در صورت بروز مشکل، کاربران متوجه اختلالی نمیشوند و دادهها هم از بین نمیروند.
در نهایت، Replica Set مثل یک تیم قوی است که همیشه از دادههای شما محافظت میکند. با این روش هم سرعت سیستم بالا میرود، هم خطاها مدیریت میشوند، و هم مدیران میتوانند با خیال راحتتر منابع را کنترل کنند. این قابلیت به خصوص در سرویسهای مهم که قطعی یا کندی در آن ها غیرقابل تحمل است، به یک ابزار حیاتی تبدیل میشود. اما اکنون که با این دو مفهوم آشنا شدید وقت آن است که اقدام به راهاندازی Replica Set در MongoDB با استفاده از Docker کنیم. برای این کار ابتدا از نصب داکر شروع می کنیم.
راه اندازی Replica Set در MongoDB با استفاده از Docker
برای راه اندازی Replica Set در MongoDB با Docker نیازی به نصب کامل MongoDB نیست و تنها کافیست داکر را نصب کنید. اگر از کامپیوتر شخصی استفاده میکنید، میتوانید Docker Desktop را نصب کنید. برای بررسی نصب Docker، دستور زیر را اجرا کنید:
docker -v
این دستور باید شماره نسخه را نمایش دهد. سپس، باید مطمئن شویم که سرویس Docker در حال اجرا است. برای این کار دستور زیر را اجرا کنید.
docker images
با اجرای این دستور میتوانید لیست image های موجود در سیستم خود را مشاهده کنید. در مرحله بعد، آخرین نسخه از MongoDB را با اجرای دستور زیر نصب میکنیم:
docker pull mongo
معماری مجموعه Replica
ما قصد داریم سه کانتینر از 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
پیکربندیReplication پایگاه داده
اکنون که تمام نمونههای 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
بیایید با مجموعه 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 خودکار سازی کنیم. برای این کار به کمک دستورات زیر ابتدا باید یک فایل 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 عالی است، اما قبل از انتقال آن به محیط عملیاتی باید برخی اقدامات احتیاطی انجام شود:
- هیچ یک از پایگاههای داده دارای اقدامات امنیتی مدیریتی نیستند. هنگام استقرار این راهحل در سرورهای عملیاتی، حتماً کاربران و رمزهای عبور را اضافه کنید.
- کانتینرهای replica مختلف باید در سرورهای فیزیکی مختلف نگهداری شوند. حداقل یک کانتینر را روی یک سرور متفاوت اجرا کنید و از طریق آدرس IP خارجی و پورت مربوطه به آن دسترسی پیدا کنید. (در مثال ما، پورتهای خارجی کانتینرها به ترتیب
30001
،30002
و30003
برایmongo1
،mongo2
وmongo3
بودند). - اگر یکی از کانتینرهای خود را به اشتباه حذف کنیم، دادهها نیز از بین میروند. استفاده از volumes در Docker و تنظیم
--dbpath
مناسب هنگام اجرای mongod از وقوع این اتفاق جلوگیری میکند. - در نهایت، به جای اجرای چندین اسکریپت shell، ممکن است خودکارسازی کل این فرایند با استفاده از ابزارهای خودکارسازی چندکانتینری مانند docker-compose راحتتر باشد.
منبع: sohamkamani.com