Microservices چیست؟ آموزش کامل معماری میکروسرویس با Python، FastAPI و Docker
Microservices معماری نرمافزاری مبتنی بر سرویسهای مستقل و قابلاستقرار جداگانه است. در این آموزش، اصول طراحی میکروسرویس و ساخت یک پروژه عملی با Python، FastAPI، Docker Compose و API درواره را یاد میگیرید.
بسیاری از پروژههای نرمافزاری با یک Backend ساده شروع میشوند. احراز هویت، کاربران، سفارشها، پرداخت، گزارشها، Notification و قابلیتهای هوش مصنوعی همگی در یک پروژه قرار میگیرند و با یک فرایند Deploy منتشر میشوند.
این ساختار در مراحل اولیه معمولاً انتخاب خوبی است. توسعه سریعتر انجام میشود، Debug سادهتر است و تیم برای اجرای پروژه به زیرساخت پیچیدهای نیاز ندارد.
اما با بزرگشدن محصول ممکن است مشکلاتی ظاهر شوند:
- تغییر یک بخش به Deploy کل Backend نیاز دارد.
- خطای یک Module میتواند کل برنامه را مختل کند.
- چند تیم روی یک Codebase بزرگ با هم تداخل پیدا میکنند.
- مقیاسکردن یک قابلیت باعث Scale شدن تمام برنامه میشود.
- Releaseها کند و پرریسک میشوند.
- وابستگی میان Moduleها افزایش پیدا میکند.
- تغییر تکنولوژی یک بخش دشوار میشود.
- تست کامل برنامه زمان زیادی میگیرد.
معماری Microservices یا میکروسرویس تلاش میکند سیستم را به سرویسهای مستقل و دارای مرز مشخص تقسیم کند. هر سرویس مسئول یک قابلیت کسبوکار است، Codebase و چرخه Deploy خود را دارد و معمولاً دادههایش را نیز مستقل مدیریت میکند.
اما Microservices فقط تقسیم یک پروژه به چند API کوچک نیست. اگر مرز سرویسها اشتباه انتخاب شود یا زیرساخت مناسب وجود نداشته باشد، نتیجه میتواند از یک Monolith پیچیدهتر، کندتر و پرهزینهتر باشد.
در این مقاله ابتدا معماری Microservices را دقیق بررسی میکنیم، آن را با Monolith و Modular Monolith مقایسه میکنیم و سپس یک پروژه عملی با سه سرویس مستقل، Python، FastAPI، Docker Compose و API هوش مصنوعی درواره میسازیم.
Microservices چیست؟
Microservices یک سبک معماری نرمافزار است که برنامه را به مجموعهای از سرویسهای کوچک، مستقل و Loosely Coupled تقسیم میکند. هر سرویس معمولاً یک قابلیت مشخص کسبوکار را پیادهسازی میکند و میتواند مستقل توسعه، تست، Deploy و Scale شود.
برای مثال، یک فروشگاه اینترنتی میتواند شامل سرویسهای زیر باشد:
User Service
Product Service
Order Service
Payment Service
Inventory Service
Notification Service
Search Service
AI Service
هر سرویس API یا Message Contract مشخصی دارد و جزئیات داخلی خود را از سایر سرویسها پنهان میکند.
براساس راهنمای معماری Microservices مایکروسافت، میکروسرویسها Componentهای کوچک، مستقل و دارای اتصال ضعیف هستند که هرکدام باید یک قابلیت مشخص را در یک Bounded Context پیادهسازی کنند.
ویژگیهای اصلی Microservice
یک Microservice مناسب معمولاً این ویژگیها را دارد:
- مسئول یک قابلیت مشخص کسبوکار است.
- مرز داده مشخص دارد.
- API یا Event Contract واضح دارد.
- مستقل Deploy میشود.
- مستقل Scale میشود.
- خرابی آن تا حد امکان از سایر سرویسها جداست.
- پیادهسازی داخلی خود را پنهان میکند.
- توسط یک تیم مشخص نگهداری میشود.
- Monitoring و Health Check مستقل دارد.
- نسخه و چرخه انتشار خود را دارد.
کوچکبودن سرویس فقط به تعداد Lineهای Code مربوط نیست. مهمتر از اندازه، Cohesion و استقلال قابلیت کسبوکار است.
Monolith چیست؟
در معماری Monolith، بیشتر قابلیتهای برنامه داخل یک واحد اجرایی قرار دارند:
Application
├── Users
├── Products
├── Orders
├── Payments
├── Reports
└── AI Features
این برنامه معمولاً:
- یک Codebase دارد.
- یک فرایند Build دارد.
- یک واحد Deploy دارد.
- اغلب از یک Database مشترک استفاده میکند.
- همه Moduleها داخل یک Process اجرا میشوند.
Monolith لزوماً معماری بدی نیست. برای بسیاری از MVPها، Startupها، پنلهای مدیریتی و پروژههای دارای تیم کوچک، یک Monolith ماژولار بهترین نقطه شروع است.
Modular Monolith چیست؟
Modular Monolith یک برنامه واحد است که داخل آن مرز Moduleها جدی گرفته میشود:
Application
├── user_module
├── article_module
├── billing_module
├── notification_module
└── ai_module
همه Moduleها با هم Deploy میشوند، اما:
- وابستگیها کنترلشدهاند.
- هر Module Interface مشخص دارد.
- دسترسی مستقیم و نامحدود به اجزای داخلی Moduleها وجود ندارد.
- منطق Domain از Framework جدا نگه داشته میشود.
- امکان استخراج آینده یک Module به Microservice وجود دارد.
برای بسیاری از پروژهها، Modular Monolith قبل از Microservices انتخاب منطقیتری است.
مقایسه Monolith، Modular Monolith و Microservices
| معیار | Monolith | Modular Monolith | Microservices |
|---|---|---|---|
| تعداد واحد Deploy | یک | یک | چند |
| پیچیدگی اولیه | کم | متوسط | زیاد |
| ارتباط داخلی | فراخوانی مستقیم | Interface داخلی | شبکه یا Message Broker |
| Database | معمولاً مشترک | مشترک با مرز منطقی | ترجیحاً مستقل |
| Scale مستقل | دشوار | دشوار | امکانپذیر |
| Deploy مستقل | ندارد | ندارد | دارد |
| Debug | سادهتر | نسبتاً ساده | پیچیدهتر |
| تراکنش | سادهتر | سادهتر | توزیعشده و دشوارتر |
| نیاز به DevOps | کم | متوسط | زیاد |
| مناسب تیم کوچک | بله | بله | معمولاً نه |
| تحمل خرابی | محدود | محدود | با طراحی مناسب بیشتر |
| هزینه عملیاتی | کمتر | کمتر | بیشتر |
چه زمانی از Microservices استفاده کنیم؟
Microservices زمانی ارزش بیشتری ایجاد میکند که مسئله واقعی برای حلکردن داشته باشید.
نشانههای مناسب:
- چند تیم مستقل روی Domainهای متفاوت کار میکنند.
- بخشهای مختلف سیستم نرخ Scale متفاوتی دارند.
- Release یک Module نباید به Release کل برنامه وابسته باشد.
- خرابی یک قابلیت باید از سایر قابلیتها جدا شود.
- بعضی سرویسها به تکنولوژی یا Storage متفاوت نیاز دارند.
- حجم ترافیک بالا یا الگوی بار نامتوازن است.
- Domain پیچیده و دارای مرزهای روشن است.
- CI/CD، Monitoring و عملیات Production قابلاتکا دارید.
- هزینه زیرساخت توزیعشده قابلقبول است.
مثال:
یک سرویس تولید تصویر ممکن است منابع و مقیاس متفاوتی از سرویس مدیریت حساب کاربری داشته باشد. جداکردن این دو سرویس میتواند منطقی باشد.
چه زمانی Microservices انتخاب مناسبی نیست؟
در شرایط زیر بهتر است ابتدا Monolith یا Modular Monolith را بررسی کنید:
- محصول هنوز به Product-Market Fit نرسیده است.
- تیم فنی کوچک است.
- Domain هنوز مرتب تغییر میکند.
- مرز قابلیتها مشخص نیست.
- ترافیک محدود است.
- Deploy برنامه فعلی مشکل جدی ندارد.
- Monitoring متمرکز ندارید.
- تیم تجربه سیستمهای توزیعشده ندارد.
- هزینه نگهداری چند سرویس قابلتوجیه نیست.
- فقط برای استفاده از Docker یا Kubernetes به Microservices فکر میکنید.
Microservices نباید هدف پروژه باشد. هدف باید حل مسئله کسبوکار و کاهش محدودیت معماری موجود باشد.
تفاوت SOA و Microservices
Service-Oriented Architecture یا SOA نیز سیستم را به سرویسها تقسیم میکند، اما معمولاً در مقیاس سازمانی و با Integration مرکزیتر استفاده میشود.
| ویژگی | SOA | Microservices |
|---|---|---|
| اندازه سرویس | معمولاً بزرگتر | معمولاً کوچکتر و متمرکز |
| Integration | گاهی ESB مرکزی | API و Eventهای سبکتر |
| Deploy | ممکن است وابسته باشد | ترجیحاً مستقل |
| Governance | متمرکزتر | غیرمتمرکزتر |
| مالکیت داده | ممکن است مشترک باشد | ترجیحاً مستقل |
| تمرکز اصلی | Integration سازمانی | استقلال تیم و قابلیت |
این مرز همیشه قطعی نیست و معماری واقعی ممکن است ویژگیهایی از هر دو داشته باشد.
Bounded Context چیست؟
یکی از مهمترین مفاهیم طراحی Microservices، Bounded Context در Domain-Driven Design است.
Bounded Context محدودهای است که در آن یک مدل و اصطلاحات Domain معنی مشخصی دارند.
برای مثال واژه «کاربر» میتواند در بخشهای مختلف معنی متفاوتی داشته باشد:
- در Identity Service: حساب، رمز، Session و دسترسی
- در Billing Service: مشتری، کیف پول و صورتحساب
- در Support Service: تیکت و سابقه پشتیبانی
- در Analytics Service: Segment و رفتار استفاده
قرار دادن تمام این مفاهیم در یک مدل مشترک بزرگ، Coupling ایجاد میکند. هر سرویس باید فقط بخشی از اطلاعات را که برای Domain خودش لازم است مدیریت کند.
چگونه مرز Microservice را انتخاب کنیم؟
مرز سرویس نباید فقط براساس Tableهای Database یا نام Entityها انتخاب شود.
روش مناسبتر:
- قابلیتهای کسبوکار را شناسایی کنید.
- Workflowهای اصلی را ترسیم کنید.
- دادهها و قوانین هر Workflow را مشخص کنید.
- تغییراتی را که معمولاً با هم رخ میدهند پیدا کنید.
- مالکیت تیم را بررسی کنید.
- نیاز Scale هر بخش را بسنجید.
- وابستگیهای Sync را اندازهگیری کنید.
- Bounded Contextها را مشخص کنید.
- قبل از جداسازی فیزیکی، مرزها را در Modular Monolith آزمایش کنید.
نمونه مرزبندی نامناسب:
Name Service
Address Service
Phone Service
Email Service
این سرویسها بیشازحد ریز هستند و برای انجام یک عملیات ساده به تعداد زیادی Request نیاز دارند.
نمونه منطقیتر:
Customer Profile Service
Microservice چقدر باید کوچک باشد؟
عدد ثابتی برای تعداد Endpoint، Table یا Line Code وجود ندارد.
یک سرویس زمانی بیشازحد بزرگ است که:
- چند قابلیت مستقل کسبوکار را مدیریت میکند.
- چند تیم مرتب روی آن تداخل دارند.
- بخشهایش نیاز Scale متفاوت دارند.
- Release یک قابلیت به سایر قابلیتها وابسته است.
یک سرویس زمانی بیشازحد کوچک است که:
- بهتنهایی ارزش کسبوکاری ندارد.
- برای هر Request باید چند سرویس دیگر را فراخوانی کند.
- مدل و داده مستقلی ندارد.
- Deployment مستقل آن مزیتی ایجاد نمیکند.
- بیشتر وقت تیم صرف مدیریت ارتباط سرویسها میشود.
Database per Service
یکی از اصول متداول Microservices این است که هر سرویس مالک دادههای خودش باشد:
User Service → User Database
Order Service → Order Database
AI Service → AI Job Database
سرویس دیگر نباید مستقیماً Tableهای داخلی سرویس را Query کند. ارتباط باید از طریق API یا Event انجام شود.
این اصل به معنی آن نیست که هر سرویس الزاماً به یک Server فیزیکی Database جدا نیاز دارد. ممکن است چند Database منطقی روی یک Cluster قرار داشته باشند، اما مالکیت Schema و دسترسی باید جدا باشد.
چرا Database مشترک مشکل ایجاد میکند؟
اگر همه سرویسها مستقیماً از یک Schema مشترک استفاده کنند:
- تغییر Schema چند سرویس را همزمان تحتتأثیر قرار میدهد.
- سرویسها جزئیات داخلی یکدیگر را میشناسند.
- Deploy مستقل دشوار میشود.
- مالکیت داده نامشخص میشود.
- یک Query سنگین میتواند سایر سرویسها را مختل کند.
- استخراج یا تغییر Storage یک سرویس دشوار میشود.
آیا هر سرویس میتواند Database متفاوت داشته باشد؟
بله. این مفهوم Polyglot Persistence نامیده میشود:
Identity Service → PostgreSQL
Cache Service → Redis
Search Service → Elasticsearch
Document Service → MongoDB
Analytics Service → ClickHouse
اما استفاده از تکنولوژی متفاوت برای هر سرویس هزینه نگهداری زیادی دارد. فقط زمانی Storage متفاوت انتخاب کنید که نیاز واقعی وجود داشته باشد.
ارتباط Synchronous بین Microservices
در ارتباط Synchronous، سرویس A درخواست را ارسال و منتظر پاسخ سرویس B میماند.
ابزارهای رایج:
- REST API
- gRPC
- GraphQL در لایه Composition
مثال:
API Gateway
→ Article Service
→ AI Service
→ Response
مزایا:
- پیادهسازی و درک سادهتر
- پاسخ فوری
- Debug راحتتر در Workflowهای کوتاه
- مناسب Query و عملیات تعاملی
معایب:
- افزایش Latency در زنجیره
- وابستگی زمانی سرویسها
- انتشار خطا به سرویس بالادستی
- احتمال Cascading Failure
- نیاز به Timeout و Circuit Breaker
ارتباط Asynchronous
در ارتباط Asynchronous، Producer یک Event یا Message منتشر میکند و منتظر پایان Consumer نمیماند.
ابزارهای رایج:
- RabbitMQ
- Apache Kafka
- Redis Streams
- سرویسهای مدیریتشده Queue
مثال:
Article Service
→ article.created Event
→ AI Worker
→ Summary Created Event
مزایا:
- Coupling زمانی کمتر
- تحمل بهتر اختلال موقت
- مناسب Jobهای سنگین
- قابلیت Scale مستقل Consumer
- امکان Retry و Queue کردن بار
معایب:
- نتیجه فوری نیست.
- Debug پیچیدهتر میشود.
- Eventual Consistency ایجاد میشود.
- Idempotency ضروری است.
- مدیریت Retry و DLQ لازم است.
چه زمانی Sync و چه زمانی Async؟
| سناریو | روش پیشنهادی |
|---|---|
| دریافت اطلاعات پروفایل | Sync |
| بررسی موجودی لحظهای | Sync |
| ارسال ایمیل | Async |
| تولید گزارش سنگین | Async |
| پردازش متن با مدل | بسته به UX |
| ایجاد Thumbnail | Async |
| دریافت وضعیت Job | Sync |
| انتشار رویداد سفارش | Async |
| Validation فوری | Sync |
| Analytics | Async |
معماری واقعی معمولاً ترکیبی از هر دو روش است.
API Gateway در معماری Microservices
API Gateway ورودی مرکزی Clientهاست:
Client
→ API Gateway
├── Identity Service
├── Article Service
├── Billing Service
└── AI Service
وظایف احتمالی Gateway:
- Routing
- Authentication
- Rate Limiting
- Request ID
- Response Aggregation
- Protocol Translation
- محدودکردن دسترسی مستقیم به سرویسهای داخلی
Gateway نباید به یک Monolith جدید تبدیل شود. منطق اصلی کسبوکار باید در سرویسهای Domain باقی بماند.
Service Discovery
در محیط Docker Compose، سرویسها میتوانند با نام Service یکدیگر را پیدا کنند:
http://article-service:8000
http://ai-service:8000
در Kubernetes معمولاً DNS داخلی Service Discovery را انجام میدهد.
آدرس IP یک Container یا Pod نباید در Code هاردکد شود؛ زیرا Instanceها ممکن است جایگزین شوند.
داده و تراکنش در Microservices
در Monolith میتوان چند Table را در یک Transaction تغییر داد. در Microservices، دادهها ممکن است در Databaseهای مختلف باشند.
فرض کنید ثبت سفارش شامل این مراحل است:
- ایجاد سفارش
- کاهش موجودی
- ثبت پرداخت
- ارسال Notification
اجرای یک Transaction سنتی روی همه سرویسها معمولاً دشوار یا نامناسب است.
روشهای رایج:
- Saga Pattern
- Transactional Outbox
- Eventual Consistency
- Compensating Action
- Idempotent Consumer
Saga Pattern
Saga یک Workflow را به چند Transaction محلی تقسیم میکند.
مثال:
Order Created
→ Inventory Reserved
→ Payment Completed
→ Order Confirmed
اگر پرداخت شکست بخورد:
Payment Failed
→ Inventory Released
→ Order Cancelled
عملیات جبرانی دقیقاً Rollback فنی Transaction قبلی نیست؛ بلکه یک عملیات کسبوکاری برای جبران نتیجه است.
Transactional Outbox
Outbox Pattern برای هماهنگی تغییر Database و انتشار Event استفاده میشود.
در یک Transaction محلی:
ثبت داده اصلی
+
ثبت Event در جدول Outbox
Worker جداگانه Eventهای Outbox را منتشر و پس از موفقیت علامتگذاری میکند.
این روش احتمال گمشدن Event میان Commit دیتابیس و انتشار Message را کاهش میدهد.
مشکلات سیستمهای توزیعشده
در Microservices باید بپذیرید که شبکه قابلاعتماد نیست.
ممکن است:
- سرویس مقصد Down باشد.
- Request Timeout شود.
- پاسخ دیر برسد.
- Request انجام شود اما پاسخ گم شود.
- Message دوباره تحویل داده شود.
- سرویسها نسخه متفاوت داشته باشند.
- Clock سرورها دقیقاً هماهنگ نباشد.
- دادهها موقتاً ناسازگار باشند.
بنابراین کدنویسی Microservices فقط ساخت چند Endpoint نیست.
Timeout
هر فراخوانی شبکه باید Timeout مشخص داشته باشد:
timeout = httpx.Timeout(
connect=3.0,
read=60.0,
write=10.0,
pool=5.0,
)
نبود Timeout میتواند Connectionها را برای مدت نامحدود اشغال کند.
Retry
Retry فقط برای خطاهای موقت و عملیات قابلتکرار مناسب است.
نمونه خطاهای قابل Retry:
- Timeout
- خطای موقت 502 یا 503
- Rate Limit با زمان انتظار مشخص
- قطع کوتاه شبکه
Retry برای همه خطاها مناسب نیست. درخواست نامعتبر با Retry درست نمیشود.
Retry باید:
- محدود باشد.
- Backoff داشته باشد.
- Jitter داشته باشد.
- با Idempotency هماهنگ باشد.
- Metric و Log داشته باشد.
Circuit Breaker
Circuit Breaker پس از افزایش خطا، برای مدتی فراخوانی سرویس ناسالم را متوقف میکند.
حالتهای مفهومی:
Closed → درخواستها عبور میکنند
Open → درخواستها موقتاً متوقف میشوند
Half-Open → چند درخواست آزمایشی ارسال میشود
Circuit Breaker از فشار بیشتر روی سرویس مختل جلوگیری میکند.
Bulkhead
Bulkhead منابع سرویسها یا عملیات مختلف را جدا میکند.
برای مثال، اگر همه Connectionهای HTTP توسط تولید گزارش مصرف شوند، درخواستهای ساده نیز مختل میشوند. با Pool یا محدودیت Concurrency جداگانه میتوان خرابی را محدود کرد.
Idempotency
درخواست Idempotent با اجرای چندباره اثر نهایی ناخواسته ایجاد نمیکند.
برای عملیات مهم از Idempotency Key استفاده کنید:
Idempotency-Key: 7bc69fdd-daf2-4a8f-9658-16cd92419c16
سرویس مقصد نتیجه درخواست قبلی را برای همان Key بازیابی میکند و عملیات را دوباره انجام نمیدهد.
Observability در Microservices
در Monolith معمولاً یک Log برای دنبالکردن Request کافی است. در Microservices یک Request ممکن است از چند سرویس عبور کند.
سه ستون اصلی Observability:
- Logs
- Metrics
- Traces
Correlation ID و Trace ID
هر Request باید یک شناسه قابلردیابی داشته باشد:
X-Request-ID: 2b3f3750-f50e-414d-a5c5-f21998ea7ae3
Gateway این شناسه را ایجاد و به سرویسهای بعدی ارسال میکند.
Log نمونه:
{
"service": "ai-service",
"request_id": "2b3f3750-f50e-414d-a5c5-f21998ea7ae3",
"operation": "summarize",
"duration_ms": 2480,
"status": "success"
}
Health Check
هر سرویس بهتر است حداقل دو مفهوم سلامت داشته باشد:
- Liveness: Process زنده است؟
- Readiness: سرویس آماده دریافت ترافیک است؟
Endpoint ساده:
GET /health
در پروژه واقعی Readiness باید وابستگیهای ضروری مانند Database را نیز بررسی کند؛ اما نباید هر Health Check باعث اجرای عملیات سنگین شود.
پروژه عملی: ساخت Microservices با FastAPI و Docker Compose
در این پروژه سه سرویس میسازیم:
Article Service
وظایف:
- ایجاد مقاله
- ذخیره مقاله در Database مستقل
- بازیابی مقاله
AI Service
وظایف:
- دریافت متن
- اتصال به API درواره
- تولید خلاصه
API Gateway
وظایف:
- ورودی Client
- ایجاد Correlation ID
- فراخوانی Article Service
- فراخوانی AI Service
- مدیریت Timeout و خطا
- برگرداندن پاسخ نهایی
معماری پروژه:
Client
→ API Gateway
→ Article Service
→ SQLite اختصاصی Article Service
API Gateway
→ AI Service
→ API درواره
این پروژه برای آموزش از SQLite استفاده میکند. در Production میتوانید PostgreSQL اختصاصی Article Service را جایگزین کنید.
ساختار پروژه
fastapi-microservices/
├── .env
├── docker-compose.yml
├── gateway/
│ ├── Dockerfile
│ ├── requirements.txt
│ └── main.py
├── article-service/
│ ├── Dockerfile
│ ├── requirements.txt
│ └── main.py
└── ai-service/
├── Dockerfile
├── requirements.txt
└── main.py
تنظیم متغیرهای محیطی
فایل .env:
DARVAREH_API_KEY=YOUR_DARVAREH_API_KEY
DARVAREH_MODEL_ID=YOUR_MODEL_ID
فایل .env را به .gitignore اضافه کنید:
.env
__pycache__/
*.pyc
ساخت Article Service
فایل article-service/requirements.txt:
fastapi>=0.115,<1
uvicorn[standard]>=0.34,<1
aiosqlite>=0.21,<1
pydantic>=2.10,<3
فایل article-service/main.py:
import os
from contextlib import asynccontextmanager
from datetime import datetime, timezone
from uuid import uuid4
import aiosqlite
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, Field
DATABASE_PATH = os.getenv(
"DATABASE_PATH",
"/data/articles.db",
)
class ArticleCreate(BaseModel):
title: str = Field(
min_length=3,
max_length=300,
)
content: str = Field(
min_length=10,
max_length=100_000,
)
class ArticleResponse(BaseModel):
id: str
title: str
content: str
created_at: str
async def init_database() -> None:
directory = os.path.dirname(DATABASE_PATH)
if directory:
os.makedirs(
directory,
exist_ok=True,
)
async with aiosqlite.connect(
DATABASE_PATH
) as database:
await database.execute(
"""
CREATE TABLE IF NOT EXISTS articles (
id TEXT PRIMARY KEY,
title TEXT NOT NULL,
content TEXT NOT NULL,
created_at TEXT NOT NULL
)
"""
)
await database.commit()
@asynccontextmanager
async def lifespan(app: FastAPI):
await init_database()
yield
app = FastAPI(
title="Article Service",
version="1.0.0",
lifespan=lifespan,
)
@app.get("/health")
async def health():
try:
async with aiosqlite.connect(
DATABASE_PATH
) as database:
await database.execute(
"SELECT 1"
)
return {
"status": "ready",
"service": "article-service",
}
except Exception as exc:
raise HTTPException(
status_code=503,
detail="Database is unavailable",
) from exc
@app.post(
"/articles",
response_model=ArticleResponse,
status_code=201,
)
async def create_article(
payload: ArticleCreate,
):
article_id = str(uuid4())
created_at = datetime.now(
timezone.utc
).isoformat()
async with aiosqlite.connect(
DATABASE_PATH
) as database:
await database.execute(
"""
INSERT INTO articles (
id,
title,
content,
created_at
)
VALUES (?, ?, ?, ?)
""",
(
article_id,
payload.title,
payload.content,
created_at,
),
)
await database.commit()
return ArticleResponse(
id=article_id,
title=payload.title,
content=payload.content,
created_at=created_at,
)
@app.get(
"/articles/{article_id}",
response_model=ArticleResponse,
)
async def get_article(
article_id: str,
):
async with aiosqlite.connect(
DATABASE_PATH
) as database:
database.row_factory = (
aiosqlite.Row
)
cursor = await database.execute(
"""
SELECT
id,
title,
content,
created_at
FROM articles
WHERE id = ?
""",
(article_id,),
)
row = await cursor.fetchone()
if row is None:
raise HTTPException(
status_code=404,
detail="Article not found",
)
return ArticleResponse(
id=row["id"],
title=row["title"],
content=row["content"],
created_at=row["created_at"],
)
Article Service تنها سرویس دارای دسترسی مستقیم به Database مقالههاست. Gateway و AI Service نباید فایل SQLite یا Tableهای آن را مستقیماً بخوانند.
Dockerfile مربوط به Article Service
فایل article-service/Dockerfile:
FROM python:3.13-slim
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
WORKDIR /app
COPY requirements.txt .
RUN pip install \
--no-cache-dir \
-r requirements.txt
COPY main.py .
CMD [
"uvicorn",
"main:app",
"--host",
"0.0.0.0",
"--port",
"8000"
]
ساخت AI Service
فایل ai-service/requirements.txt:
fastapi>=0.115,<1
uvicorn[standard]>=0.34,<1
openai>=1.100,<2
pydantic>=2.10,<3
فایل ai-service/main.py:
import os
from contextlib import asynccontextmanager
from fastapi import FastAPI, HTTPException
from openai import AsyncOpenAI
from pydantic import BaseModel, Field
DARVAREH_API_KEY = os.getenv(
"DARVAREH_API_KEY",
"",
)
DARVAREH_MODEL_ID = os.getenv(
"DARVAREH_MODEL_ID",
"YOUR_MODEL_ID",
)
DARVAREH_BASE_URL = (
"https://api.darvareh.ir/v1"
)
class SummaryRequest(BaseModel):
text: str = Field(
min_length=10,
max_length=100_000,
)
class SummaryResponse(BaseModel):
summary: str
model: str
@asynccontextmanager
async def lifespan(app: FastAPI):
if not DARVAREH_API_KEY:
raise RuntimeError(
"DARVAREH_API_KEY is missing"
)
client = AsyncOpenAI(
api_key=DARVAREH_API_KEY,
base_url=DARVAREH_BASE_URL,
timeout=60,
max_retries=2,
)
app.state.ai_client = client
try:
yield
finally:
await client.close()
app = FastAPI(
title="AI Service",
version="1.0.0",
lifespan=lifespan,
)
@app.get("/health")
async def health():
return {
"status": "ready",
"service": "ai-service",
}
@app.post(
"/summaries",
response_model=SummaryResponse,
)
async def create_summary(
payload: SummaryRequest,
):
try:
response = (
await app.state.ai_client
.chat.completions.create(
model=DARVAREH_MODEL_ID,
temperature=0.2,
max_tokens=800,
messages=[
{
"role": "system",
"content": (
"متن ورودی را دقیق، روان "
"و بدون افزودن اطلاعات جدید "
"خلاصه کن."
),
},
{
"role": "user",
"content": payload.text,
},
],
)
)
summary = response.choices[
0
].message.content
if not summary:
raise ValueError(
"Model returned empty content"
)
return SummaryResponse(
summary=summary,
model=DARVAREH_MODEL_ID,
)
except Exception as exc:
raise HTTPException(
status_code=502,
detail=(
"AI provider request failed"
),
) from exc
AI Service تنها سرویس دارای دسترسی به کلید API درواره است. Article Service و Gateway نیازی به مشاهده کلید ندارند.
آدرس پایه API:
https://api.darvareh.ir/v1
Endpoint فراخوانیشده توسط SDK:
https://api.darvareh.ir/v1/chat/completions
برای دریافت کلید API و مشاهده مدلهای قابلاستفاده میتوانید به درواره مراجعه کنید. شناسه مدلها و قیمت بهروز آنها در صفحه مدلهای درواره قرار دارد.
Dockerfile مربوط به AI Service
فایل ai-service/Dockerfile:
FROM python:3.13-slim
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
WORKDIR /app
COPY requirements.txt .
RUN pip install \
--no-cache-dir \
-r requirements.txt
COPY main.py .
CMD [
"uvicorn",
"main:app",
"--host",
"0.0.0.0",
"--port",
"8000"
]
ساخت API Gateway
فایل gateway/requirements.txt:
fastapi>=0.115,<1
uvicorn[standard]>=0.34,<1
httpx>=0.28,<1
pydantic>=2.10,<3
فایل gateway/main.py:
import os
from contextlib import asynccontextmanager
from uuid import uuid4
import httpx
from fastapi import (
FastAPI,
Header,
HTTPException,
Request,
Response,
)
from pydantic import BaseModel, Field
ARTICLE_SERVICE_URL = os.getenv(
"ARTICLE_SERVICE_URL",
"http://article-service:8000",
)
AI_SERVICE_URL = os.getenv(
"AI_SERVICE_URL",
"http://ai-service:8000",
)
class ArticleCreate(BaseModel):
title: str = Field(
min_length=3,
max_length=300,
)
content: str = Field(
min_length=10,
max_length=100_000,
)
@asynccontextmanager
async def lifespan(app: FastAPI):
timeout = httpx.Timeout(
connect=3.0,
read=60.0,
write=10.0,
pool=5.0,
)
limits = httpx.Limits(
max_connections=100,
max_keepalive_connections=20,
)
client = httpx.AsyncClient(
timeout=timeout,
limits=limits,
)
app.state.http_client = client
try:
yield
finally:
await client.aclose()
app = FastAPI(
title="Microservices API Gateway",
version="1.0.0",
lifespan=lifespan,
)
def get_request_id(
incoming_request_id: str | None,
) -> str:
return (
incoming_request_id
or str(uuid4())
)
@app.get("/health")
async def health():
return {
"status": "ready",
"service": "api-gateway",
}
@app.post(
"/articles",
status_code=201,
)
async def create_article(
payload: ArticleCreate,
request: Request,
response: Response,
x_request_id: str | None = Header(
default=None,
),
):
request_id = get_request_id(
x_request_id
)
response.headers[
"X-Request-ID"
] = request_id
try:
upstream = (
await request.app.state.http_client.post(
f"{ARTICLE_SERVICE_URL}/articles",
json=payload.model_dump(),
headers={
"X-Request-ID": request_id,
},
timeout=10.0,
)
)
except httpx.RequestError as exc:
raise HTTPException(
status_code=503,
detail=(
"Article service is unavailable"
),
) from exc
if upstream.status_code == 422:
raise HTTPException(
status_code=422,
detail=upstream.json(),
)
if upstream.status_code >= 400:
raise HTTPException(
status_code=502,
detail=(
"Article service returned "
"an unexpected response"
),
)
return upstream.json()
@app.get(
"/articles/{article_id}/summary",
)
async def summarize_article(
article_id: str,
request: Request,
response: Response,
x_request_id: str | None = Header(
default=None,
),
):
request_id = get_request_id(
x_request_id
)
response.headers[
"X-Request-ID"
] = request_id
client: httpx.AsyncClient = (
request.app.state.http_client
)
headers = {
"X-Request-ID": request_id,
}
try:
article_response = await client.get(
(
f"{ARTICLE_SERVICE_URL}"
f"/articles/{article_id}"
),
headers=headers,
timeout=5.0,
)
except httpx.RequestError as exc:
raise HTTPException(
status_code=503,
detail=(
"Article service is unavailable"
),
) from exc
if article_response.status_code == 404:
raise HTTPException(
status_code=404,
detail="Article not found",
)
if article_response.status_code >= 400:
raise HTTPException(
status_code=502,
detail=(
"Article service returned "
"an unexpected response"
),
)
article = article_response.json()
try:
summary_response = await client.post(
f"{AI_SERVICE_URL}/summaries",
json={
"text": article["content"],
},
headers=headers,
timeout=60.0,
)
except httpx.RequestError as exc:
raise HTTPException(
status_code=503,
detail="AI service is unavailable",
) from exc
if summary_response.status_code >= 400:
raise HTTPException(
status_code=502,
detail=(
"AI service could not "
"generate the summary"
),
)
summary_data = summary_response.json()
return {
"request_id": request_id,
"article": {
"id": article["id"],
"title": article["title"],
},
"summary": summary_data["summary"],
"model": summary_data["model"],
}
در این Gateway:
- Client فقط Gateway را میشناسد.
- آدرس داخلی سرویسها در Environment Variable قرار دارد.
- Connection Pool برای HTTP Client استفاده میشود.
- برای فراخوانی سرویسها Timeout داریم.
- خطای داخلی بدون نمایش جزئیات حساس به Client تبدیل میشود.
X-Request-IDبرای ردیابی زنجیره Request استفاده میشود.
Dockerfile مربوط به Gateway
فایل gateway/Dockerfile:
FROM python:3.13-slim
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
WORKDIR /app
COPY requirements.txt .
RUN pip install \
--no-cache-dir \
-r requirements.txt
COPY main.py .
CMD [
"uvicorn",
"main:app",
"--host",
"0.0.0.0",
"--port",
"8000"
]
ساخت Docker Compose
فایل docker-compose.yml:
services:
gateway:
build:
context: ./gateway
container_name: microservices-gateway
environment:
ARTICLE_SERVICE_URL: http://article-service:8000
AI_SERVICE_URL: http://ai-service:8000
ports:
- "127.0.0.1:8080:8000"
depends_on:
article-service:
condition: service_healthy
ai-service:
condition: service_healthy
restart: unless-stopped
article-service:
build:
context: ./article-service
container_name: microservices-article
environment:
DATABASE_PATH: /data/articles.db
volumes:
- article_data:/data
healthcheck:
test:
[
"CMD",
"python",
"-c",
"import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health')"
]
interval: 10s
timeout: 5s
retries: 10
restart: unless-stopped
ai-service:
build:
context: ./ai-service
container_name: microservices-ai
environment:
DARVAREH_API_KEY: ${DARVAREH_API_KEY}
DARVAREH_MODEL_ID: ${DARVAREH_MODEL_ID}
healthcheck:
test:
[
"CMD",
"python",
"-c",
"import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health')"
]
interval: 10s
timeout: 5s
retries: 10
restart: unless-stopped
volumes:
article_data:
فقط Gateway روی Host منتشر شده است:
127.0.0.1:8080
Article Service و AI Service فقط از شبکه داخلی Docker Compose قابل دسترسیاند.
اجرای پروژه
ساخت و اجرای سرویسها:
docker compose up \
--build \
-d
مشاهده وضعیت:
docker compose ps
مشاهده Log همه سرویسها:
docker compose logs -f
مشاهده Log یک سرویس:
docker compose logs \
-f \
ai-service
مستندات Gateway:
http://127.0.0.1:8080/docs
ایجاد مقاله
curl -X POST \
"http://127.0.0.1:8080/articles" \
-H "Content-Type: application/json" \
-H "X-Request-ID: test-request-001" \
-d '{
"title": "کاربرد هوش مصنوعی در توسعه نرمافزار",
"content": "هوش مصنوعی میتواند در توضیح کد، تولید تست، مستندسازی، تحلیل خطا و بازنویسی بخشهای مشخص نرمافزار به توسعهدهندگان کمک کند. بااینحال، خروجی مدل باید بررسی و آزمایش شود و نباید بدون بازبینی وارد محیط Production شود."
}'
پاسخ:
{
"id": "ARTICLE_ID",
"title": "کاربرد هوش مصنوعی در توسعه نرمافزار",
"content": "هوش مصنوعی میتواند...",
"created_at": "2026-08-09T10:00:00+00:00"
}
مقدار id را برای مرحله بعد نگه دارید.
تولید خلاصه مقاله
curl \
"http://127.0.0.1:8080/articles/ARTICLE_ID/summary" \
-H "X-Request-ID: test-request-002"
جریان داخلی:
Client
→ Gateway
→ Article Service
→ Gateway
→ AI Service
→ API درواره
→ AI Service
→ Gateway
→ Client
پاسخ نمونه:
{
"request_id": "test-request-002",
"article": {
"id": "ARTICLE_ID",
"title": "کاربرد هوش مصنوعی در توسعه نرمافزار"
},
"summary": "هوش مصنوعی میتواند به توسعهدهندگان در تحلیل، تست و مستندسازی کد کمک کند، اما خروجی آن باید پیش از استفاده در Production بررسی شود.",
"model": "YOUR_MODEL_ID"
}
چرا AI Service را جدا کردیم؟
جداکردن AI Service میتواند این مزایا را داشته باشد:
- کلید API فقط در یک سرویس نگهداری میشود.
- انتخاب مدل متمرکز مدیریت میشود.
- Rate Limit در یک نقطه اعمال میشود.
- Retry و Timeout یکپارچه میشود.
- چند سرویس داخلی میتوانند از AI Service استفاده کنند.
- Usage و هزینه متمرکز اندازهگیری میشود.
- تغییر مدل به تغییر همه سرویسها نیاز ندارد.
- AI Service میتواند مستقل Scale شود.
اما اگر فقط یک قابلیت کوچک هوش مصنوعی دارید، ایجاد Microservice مستقل ممکن است پیچیدگی غیرضروری باشد. در آن حالت یک Module مشخص داخل Modular Monolith میتواند کافی باشد.
اضافهکردن Job غیرهمزمان
در پروژه فعلی Gateway تا دریافت پاسخ AI Service منتظر میماند. برای متن کوتاه و UX تعاملی، این روش قابلقبول است.
برای فایلهای بزرگ یا Jobهای طولانی بهتر است معماری Async شود:
Gateway
→ Job Service
→ Message Broker
→ AI Worker
→ Result Database
Client وضعیت را بررسی میکند:
POST /jobs
GET /jobs/{job_id}
یا پس از تکمیل Job یک Webhook دریافت میکند.
API Versioning
تغییر ناسازگار API میتواند Consumerهای دیگر را خراب کند.
روش متداول:
/v1/articles
/v2/articles
قواعد مناسب:
- Field جدید را تا حد امکان Optional اضافه کنید.
- Field قبلی را ناگهانی حذف نکنید.
- رفتار یک Endpoint را بدون Version تغییر ندهید.
- زمان Deprecation مشخص کنید.
- Contract Test داشته باشید.
- Clientهای وابسته را شناسایی کنید.
Contract Testing
در Microservices فقط Unit Test کافی نیست. سرویسها باید روی شکل Request و Response توافق داشته باشند.
نمونه Contract:
{
"id": "string",
"title": "string",
"content": "string",
"created_at": "ISO-8601 string"
}
Contract Test بررسی میکند Provider تغییری ایجاد نکرده باشد که Consumer را خراب کند.
تست Microservices
Unit Test
منطق هر سرویس را مستقل تست کنید:
- Validation
- Domain Rules
- تبدیل داده
- مدیریت خطا
- ساخت Prompt
- Idempotency
Integration Test
ارتباط واقعی با Database یا Message Broker آزمایشی را بررسی کنید.
Contract Test
سازگاری API میان Provider و Consumer را بسنجید.
End-to-End Test
مسیر اصلی کاربر را از Gateway تا سرویسهای داخلی اجرا کنید.
Failure Test
این خطاها را آزمایش کنید:
- Article Service خاموش است.
- AI Service خاموش است.
- API درواره Timeout میشود.
- مدل نامعتبر است.
- پاسخ AI خالی است.
- Database در دسترس نیست.
- Request تکراری است.
- شبکه کند است.
- یک سرویس نسخه قدیمی دارد.
Deployment مستقل
هدف مهم Microservices استقلال Deploy است. اگر همه سرویسها همیشه باید همزمان Deploy شوند، احتمالاً Coupling زیادی وجود دارد.
هر سرویس بهتر است:
- Repository یا مسیر Build مشخص داشته باشد.
- Docker Image نسخهبندیشده بسازد.
- تست مستقل داشته باشد.
- Migration مستقل داشته باشد.
- Health Check داشته باشد.
- Rollback مستقل داشته باشد.
- Release Notes داشته باشد.
نمونه Tag:
article-service:1.4.2
ai-service:2.1.0
gateway:1.8.3
از Tag مبهم latest برای Deploy قابلتکرار Production استفاده نکنید.
Kubernetes برای Microservices ضروری است؟
خیر. Microservices یک سبک معماری است و Kubernetes یک پلتفرم Orchestration محسوب میشود.
برای تعداد محدود سرویس میتوان از این گزینهها استفاده کرد:
- Docker Compose روی یک Server
- Container Service مدیریتشده
- Platform as a Service
- Kubernetes
- Nomad
Kubernetes زمانی ارزش بیشتری دارد که به Scheduling، Auto Scaling، Self-Healing، Service Discovery و مدیریت تعداد زیادی Workload نیاز داشته باشید.
شروع مستقیم با Kubernetes برای یک پروژه کوچک میتواند هزینه یادگیری و عملیات را افزایش دهد.
اشتباههای رایج در Microservices
تقسیم سرویسها براساس Table
ساخت یک سرویس برای هر Table معمولاً باعث سرویسهای بسیار ریز و Chatty Communication میشود.
مرز را براساس قابلیت کسبوکار انتخاب کنید، نه صرفاً Entityهای Database.
Database مشترک بدون مرز
اگر همه سرویسها آزادانه Tableهای یکدیگر را تغییر دهند، استقلال واقعی وجود ندارد.
زنجیره طولانی Requestهای Sync
این زنجیره شکننده است:
Gateway
→ Service A
→ Service B
→ Service C
→ Service D
Latency و احتمال شکست در هر مرحله افزایش پیدا میکند. Workflow را بازطراحی یا بعضی بخشها را Async کنید.
Shared Library بزرگ
کتابخانه مشترکی که مدل Domain و منطق همه سرویسها را نگه دارد، Coupling ایجاد میکند. Library مشترک را به موارد پایدار و فنی محدود کنید.
Deploy هماهنگ همه سرویسها
اگر هر تغییر به Release همزمان همه سرویسها نیاز دارد، Contractها یا مرزها بهاندازه کافی مستقل نیستند.
نبود Observability
بدون Log ساختاریافته، Metrics و Trace، Debug سیستم توزیعشده بسیار دشوار میشود.
Retry بدون محدودیت
Retry نامحدود میتواند اختلال کوچک را به فشار گسترده روی سیستم تبدیل کند.
استفاده از Microservices برای تیم کوچک
اگر یک یا دو توسعهدهنده مسئول دهها سرویس باشند، هزینه نگهداری میتواند از مزایا بیشتر شود.
Distributed Monolith
Distributed Monolith سیستمی است که از چند سرویس تشکیل شده، اما سرویسها استقلال واقعی ندارند:
- Database مشترک دارند.
- همیشه با هم Deploy میشوند.
- فراخوانیهای Sync زیادی دارند.
- تغییر یک سرویس چند سرویس را میشکند.
- مدل Domain مشترک بزرگی دارند.
- تست مستقل دشوار است.
این معماری پیچیدگی شبکه را دارد، بدون آنکه مزایای اصلی Microservices را به دست آورد.
مهاجرت از Monolith به Microservices
همه سیستم را یکباره بازنویسی نکنید.
روش تدریجی:
- Monolith را ماژولار کنید.
- وابستگی Moduleها را اندازهگیری کنید.
- مرزهای Domain را مشخص کنید.
- یک قابلیت دارای ارزش مستقل انتخاب کنید.
- API یا Event Contract تعریف کنید.
- داده آن قابلیت را بهتدریج جدا کنید.
- ترافیک را به سرویس جدید Route کنید.
- Monitoring و Rollback داشته باشید.
- نتیجه را ارزیابی کنید.
- فقط در صورت موفقیت، قابلیت بعدی را جدا کنید.
این رویکرد با Strangler Fig Pattern همراستاست.
چکلیست طراحی Microservices
پیش از جداکردن هر سرویس بررسی کنید:
- قابلیت کسبوکار مشخصی دارد.
- Bounded Context روشن است.
- تیم یا مالک مشخص دارد.
- داده تحت مالکیت سرویس مشخص است.
- API یا Event Contract تعریف شده است.
- دلیل Deploy مستقل روشن است.
- نیاز Scale مستقل وجود دارد.
- وابستگیهای Sync محدود هستند.
- Timeout برای همه درخواستها تعیین شده است.
- Retry محدود و هدفمند است.
- Idempotency بررسی شده است.
- Failure Modeها طراحی شدهاند.
- Health Check وجود دارد.
- Log ساختاریافته وجود دارد.
- Request ID میان سرویسها منتقل میشود.
- Metrics و Trace قابل جمعآوری هستند.
- Versioning API مشخص است.
- Contract Test وجود دارد.
- Migration Database مستقل است.
- Rollback سرویس آزمایش شده است.
- هزینه زیرساخت قابلتوجیه است.
- Modular Monolith بهعنوان گزینه سادهتر بررسی شده است.
پرسشهای متداول
Microservices چیست؟
Microservices سبک معماری نرمافزار است که برنامه را به سرویسهای مستقل، دارای مرز مشخص و قابلاستقرار جداگانه تقسیم میکند.
میکروسرویس چه تفاوتی با Monolith دارد؟
در Monolith همه قابلیتها در یک واحد Deploy قرار دارند. در Microservices هر سرویس میتواند Codebase، Database، Scale و چرخه Deploy مستقل داشته باشد.
آیا Monolith معماری بدی است؟
خیر. Monolith برای بسیاری از پروژههای کوچک و متوسط انتخاب مناسبی است. مشکل اصلی معمولاً Monolith بدون مرز و ساختار است، نه خود Monolith.
Modular Monolith چیست؟
Modular Monolith یک برنامه واحد با Moduleهای دارای مرز و وابستگی کنترلشده است. همه Moduleها با هم Deploy میشوند، اما ساختار داخلی منظم باقی میماند.
هر Microservice باید Database جدا داشته باشد؟
هر سرویس بهتر است مالک داده خودش باشد. این جداسازی میتواند منطقی یا فیزیکی باشد. سرویسهای دیگر نباید مستقیماً Schema داخلی آن را تغییر دهند.
آیا هر Microservice باید زبان برنامهنویسی متفاوتی داشته باشد؟
خیر. امکان استفاده از زبانهای متفاوت وجود دارد، اما تنوع بیدلیل تکنولوژی هزینه نگهداری را افزایش میدهد.
REST بهتر است یا gRPC؟
REST برای APIهای عمومی، Debug ساده و سازگاری گسترده مناسب است. gRPC برای ارتباط داخلی Typed و کمLatency قابل بررسی است. انتخاب به نیاز پروژه بستگی دارد.
چه زمانی از Message Broker استفاده کنیم؟
برای Jobهای طولانی، Eventها، Notification، پردازش فایل و Workflowهایی که نیاز به پاسخ فوری ندارند، ارتباط Async با Message Broker مناسب است.
API Gateway چیست؟
API Gateway ورودی مرکزی Clientهاست و میتواند Routing، Authentication، Rate Limit، Request ID و Aggregation را مدیریت کند.
آیا Kubernetes برای Microservices لازم است؟
خیر. Microservices را میتوان با Docker Compose یا سایر پلتفرمها Deploy کرد. Kubernetes برای Orchestration در مقیاس بزرگتر مفید است.
مهمترین مشکل Microservices چیست؟
پیچیدگی سیستم توزیعشده، Consistency داده، ارتباط شبکه، Monitoring، تست Integration و عملیات Production از مهمترین چالشها هستند.
آیا میتوان API هوش مصنوعی را بهصورت Microservice ساخت؟
بله. یک AI Service میتواند انتخاب مدل، فراخوانی API، Rate Limit، Retry، Usage و هزینه را متمرکز مدیریت کند. این جداسازی زمانی مفید است که چند سرویس داخلی به قابلیتهای هوش مصنوعی نیاز داشته باشند.
هزینه استفاده از AI Service چگونه محاسبه میشود؟
هزینه به مدل انتخابی، تعداد Tokenهای ورودی و خروجی و تعداد Requestها وابسته است. اطلاعات بهروز در صفحه مدلها و قیمتهای درواره قابل مشاهده است.
جمعبندی
Microservices فقط تقسیم یک Backend به چند پروژه کوچک نیست. یک معماری میکروسرویس واقعی به مرزهای Domain، مالکیت داده، Deploy مستقل، ارتباط قابلاتکا، Observability، Versioning، Idempotency و مدیریت خطا نیاز دارد.
در این مقاله تفاوت Monolith، Modular Monolith و Microservices را بررسی کردیم و دیدیم که Microservices همیشه بهترین نقطه شروع نیست. برای بسیاری از محصولات، آغاز با Modular Monolith و استخراج تدریجی سرویسها تصمیم کمریسکتری است.
در پروژه عملی، سه سرویس مستقل با Python، FastAPI و Docker Compose ساختیم:
- Article Service برای مدیریت داده مقاله
- AI Service برای اتصال به API درواره
- API Gateway برای ارتباط با Client و Orchestration درخواست
این ساختار یک نمونه آموزشی از Service Discovery، Database Ownership، ارتباط Synchronous، Timeout، Connection Pool، Health Check و Correlation ID ارائه میدهد و میتواند در مراحل بعد با PostgreSQL، Message Broker، Distributed Tracing و Orchestration تکمیل شود.
اگر میخواهید یک AI Service مستقل برای نرمافزار یا معماری Microservices خود بسازید، در درواره ثبتنام کنید، کلید API بگیرید و مدل مناسب هر Workflow را از صفحه مدلها انتخاب کنید.
منابع پیشنهادی
- راهنمای معماری Microservices مایکروسافت
- طراحی معماری Microservices
- Architecture Styles در Azure Architecture Center
- مستندات FastAPI برای اجرای Container
- مستندات Docker Compose
- مستندات HTTPX
مقالات مرتبط
- API Gateway چیست؟ راهنمای جامع معماری، کاربرد و پیادهسازی
- AI Gateway چیست و چه کاربردی دارد؟
- ساخت API هوش مصنوعی آماده Production
- مانیتورینگ و Observability در سیستمهای هوش مصنوعی
- پردازش غیرهمزمان API هوش مصنوعی با Job Queue، Worker و Webhook
- معماری Multi-Model و Multi-Provider برای هوش مصنوعی
- آموزش اتصال API هوش مصنوعی به اپلیکیشن
برای مطالعه شرایط استفاده و محدودیتهای مسئولیت، صفحه «سلب مسئولیت» را مشاهده کنید.