ترجمه و اقتباس از Microservices جاوا: راهنمای عملی . بخش های قبلی راهنما:
بیایید به مشکلات ذاتی میکروسرویس ها در جاوا نگاه کنیم، از چیزهای انتزاعی شروع کنیم و با کتابخانه های انضمامی پایان دهیم.
چگونه یک میکروسرویس جاوا را مقاوم کنیم؟
به یاد بیاورید که وقتی میکروسرویس ایجاد میکنید، اساساً تماسهای روش JVM را برای تماسهای HTTP همزمان یا پیامهای ناهمزمان معامله میکنید. در حالی که یک فراخوانی روش عمدتاً تضمین شده است که تکمیل شود (به استثنای خاموش شدن غیرمنتظره JVM)، تماس شبکه به طور پیش فرض غیرقابل اعتماد است. ممکن است کار کند، اما ممکن است به دلایل مختلف کار نکند: شبکه بیش از حد بارگذاری شده است، یک قانون فایروال جدید اجرا شده است، و غیره. برای اینکه بفهمیم چگونه این تفاوت ایجاد می کند، اجازه دهید نگاهی به مثال BillingService بیندازیم.الگوهای انعطاف پذیری HTTP/REST
فرض کنید مشتریان می توانند کتاب های الکترونیکی را در وب سایت شرکت شما خریداری کنند. برای انجام این کار، شما به تازگی یک میکروسرویس صورتحساب را پیاده سازی کرده اید که می تواند با فروشگاه آنلاین شما تماس بگیرد تا فاکتورهای واقعی PDF را ایجاد کند. در حال حاضر، ما این تماس را به صورت همزمان و از طریق HTTP انجام خواهیم داد (اگرچه تماس ناهمزمان با این سرویس منطقی تر است، زیرا تولید PDF از دیدگاه کاربر نباید آنی باشد. از همین مثال در موارد بعدی استفاده خواهیم کرد. بخش و به تفاوت ها نگاه کنید).@Service
class BillingService {
@Autowired
private HttpClient client;
public void bill(User user, Plan plan) {
Invoice invoice = createInvoice(user, plan);
httpClient.send(invoiceRequest(user.getEmail(), invoice), responseHandler());
// ...
}
}
به طور خلاصه، در اینجا سه نتیجه ممکن از این تماس HTTP وجود دارد.
- خوب: تماس انجام شد، حساب با موفقیت ایجاد شد.
- تأخیر: تماس انجام شد، اما تکمیل آن خیلی طول کشید.
- خطا. تماس ناموفق بود، ممکن است درخواستی ناسازگار ارسال کرده باشید، یا ممکن است سیستم کار نکند.
الگوهای انعطاف پذیری پیام
بیایید نگاهی دقیق تر به ارتباطات ناهمزمان بیندازیم. برنامه BillingService ما اکنون ممکن است چیزی شبیه به این باشد، با فرض اینکه از Spring و RabbitMQ برای پیام رسانی استفاده می کنیم. برای ایجاد یک حساب کاربری، اکنون یک پیام به کارگزار پیام RabbitMQ خود ارسال می کنیم، جایی که چندین کارگر منتظر پیام های جدید هستند. این کارگران فاکتورهای PDF را ایجاد کرده و برای کاربران مناسب ارسال می کنند.@Service
class BillingService {
@Autowired
private RabbitTemplate rabbitTemplate;
public void bill(User user, Plan plan) {
Invoice invoice = createInvoice(user, plan);
// преобразует счет, например, в json и использует его How тело messages
rabbitTemplate.convertAndSend(exchange, routingkey, invoice);
// ...
}
}
خطاهای احتمالی اکنون کمی متفاوت به نظر می رسند، زیرا دیگر پاسخ های OK یا ERROR فوری مانند اتصال HTTP همزمان دریافت نمی کنید. در عوض، ممکن است سه سناریوی بالقوه داشته باشیم که ممکن است اشتباه پیش برود، که می تواند سوالات زیر را ایجاد کند:
- آیا پیام من توسط کارمند تحویل و استفاده شد؟ یا گم شده است؟ (کاربر فاکتوری دریافت نمی کند).
- آیا پیام من فقط یک بار تحویل داده شد؟ یا بیش از یک بار تحویل داده شده و فقط یک بار پردازش شده است؟ (کاربر چندین فاکتور دریافت خواهد کرد).
- پیکربندی: از "آیا از کلیدهای مسیریابی/نام های صحیح برای تبادل استفاده کردم" تا "آیا کارگزار پیام من به درستی پیکربندی و نگهداری می شود یا صف های آن پر است؟" (کاربر فاکتوری دریافت نمی کند).
- اگر از پیاده سازی های JMS مانند ActiveMQ استفاده می کنید، می توانید سرعت را با تضمین تعهدات دو فازی (XA) مبادله کنید.
- اگر از RabbitMQ استفاده می کنید، ابتدا این راهنما را بخوانید و سپس به دقت در مورد تأیید، تحمل خطا و به طور کلی قابلیت اطمینان پیام فکر کنید.
- شاید کسی در پیکربندی سرورهای Active یا RabbitMQ، به خصوص در ترکیب با کلاسترینگ و Docker (هر کسی؟ ;)) مهارت کافی داشته باشد.
کدام فریم ورک بهترین راه حل برای میکروسرویس های جاوا خواهد بود؟
از یک طرف، می توانید یک گزینه بسیار محبوب مانند Spring Boot را نصب کنید . ایجاد فایلهای jar را بسیار آسان میکند، دارای یک وب سرور داخلی مانند Tomcat یا Jetty است و میتواند به سرعت و در هر مکانی اجرا شود. ایده آل برای ساخت برنامه های میکروسرویس. اخیراً، چند فریم ورک میکروسرویس تخصصی، Kubernetes یا GraalVM ظاهر شدند که تا حدی از برنامه نویسی واکنشی الهام گرفته شده بودند. در اینجا چند رقیب جالب دیگر وجود دارد: Quarkus ، Micronaut ، Vert.x ، Helidon . در پایان، باید خودتان انتخاب کنید، اما ما میتوانیم چند توصیه به شما بدهیم که ممکن است کاملاً استاندارد نباشند: به استثنای Spring Boot، همه فریمورکهای میکروسرویس معمولاً با سرعتی باورنکردنی و با راهاندازی تقریباً آنی به بازار عرضه میشوند. ، استفاده از حافظه کم، مقیاس پذیری تا بی نهایت. مواد بازاریابی معمولاً دارای گرافیک های چشمگیر هستند که پلتفرم را در کنار غول آستین چکمه یا روی یکدیگر نشان می دهند. این، در تئوری، اعصاب توسعهدهندگانی را که از پروژههای قدیمی حمایت میکنند، که گاهی چندین دقیقه طول میکشد تا بارگذاری کنند، کاهش میدهد. یا توسعهدهندگانی که در فضای ابری کار میکنند و میخواهند به تعداد ریز کانتینرهایی که در حال حاضر نیاز دارند در عرض 50 میلیثانیه راهاندازی/توقف کنند. با این حال، مشکل این است که این زمانهای راهاندازی فلزی (مصنوعی) و زمانهای استقرار مجدد به سختی به موفقیت کلی پروژه کمک میکند. حداقل آنها تأثیر بسیار کمتری نسبت به یک زیرساخت چارچوب قوی، اسناد قوی، جامعه و مهارت های توسعه دهنده قوی دارند. پس بهتر است اینگونه به قضیه نگاه کنیم: اگر تاکنون:- شما اجازه میدهید ORMهای شما بیسرعت اجرا شوند و صدها پرسش برای گردشهای کاری ساده ایجاد میکنند.
- برای اجرای یکپارچه نسبتاً پیچیده خود به گیگابایت بی پایان نیاز دارید.
- شما آنقدر کد دارید و پیچیدگی آن به قدری زیاد است (حالا در مورد استارتهای بالقوه کند مانند Hibernate صحبت نمیکنیم) که بارگیری برنامه شما چندین دقیقه طول میکشد.
کدام کتابخانه ها برای تماس های REST همگام جاوا بهتر هستند؟
در بخش فنی سطح پایین، احتمالاً با یکی از کتابخانه های سرویس گیرنده HTTP زیر مواجه خواهید شد: HttpClient بومی جاوا (از جاوا 11)، HttpClient آپاچی یا OkHttp . توجه داشته باشید که من در اینجا میگویم "احتمالا" زیرا گزینههای دیگری نیز وجود دارد، از کلاینتهای خوب قدیمی JAX-RS تا کلاینتهای مدرن WebSocket . در هر صورت، گرایش به سمت ایجاد یک کلاینت HTTP است، و از دست و پنجه نرم کردن با تماسهای HTTP خودداری میکنید. برای انجام این کار، باید نگاهی به پروژه OpenFeign و مستندات آن به عنوان نقطه شروعی برای مطالعه بیشتر بیندازید.بهترین کارگزاران برای پیام رسانی ناهمزمان جاوا کدامند؟
به احتمال زیاد، با ActiveMQ محبوب (کلاسیک یا آرتمیس) ، RabbitMQ یا کافکا مواجه خواهید شد .- ActiveMQ و RabbitMQ کارگزاران پیام سنتی و تمام عیار هستند. آنها شامل تعامل یک "کارگزار باهوش" و "کاربران احمق" هستند.
- از لحاظ تاریخی، ActiveMQ از مزایای درونسازی آسان (برای آزمایش) برخوردار بوده است که میتوان آن را با تنظیمات RabbitMQ/Docker/TestContainer کاهش داد.
- کافکا را نمی توان یک دلال سنتی «هوشمند» نامید. در عوض، این یک فروشگاه پیام نسبتاً "گنگ" (فایل لاگ) است که برای پردازش به مصرف کنندگان هوشمند نیاز دارد.
از چه کتابخانه هایی می توانم برای آزمایش میکروسرویس ها استفاده کنم؟
این بستگی به پشته شما دارد. اگر اکوسیستم Spring را مستقر کرده اید، عاقلانه است که از ابزارهای خاص این چارچوب استفاده کنید . اگر JavaEE چیزی شبیه به Arquillian باشد . شاید ارزش آن را داشته باشد که به Docker و کتابخانه واقعاً خوب Testcontainers نگاهی بیندازید ، که به ویژه به راهاندازی آسان و سریع پایگاه داده Oracle برای آزمایشهای توسعه محلی یا ادغام کمک میکند. برای آزمایش ساختگی کل سرورهای HTTP، Wiremock را بررسی کنید . برای آزمایش پیامهای ناهمزمان، ActiveMQ یا RabbitMQ را پیادهسازی کنید و سپس تستها را با استفاده از Awaitility DSL بنویسید . علاوه بر این، تمام ابزارهای معمول شما استفاده می شود - Junit ، TestNG برای AssertJ و Mockito . لطفا توجه داشته باشید که این یک لیست کامل نیست. اگر ابزار مورد علاقه خود را در اینجا پیدا نکردید، لطفاً آن را در بخش نظرات ارسال کنید.چگونه لاگ را برای همه میکروسرویس های جاوا فعال کنیم؟
ورود به سیستم در مورد میکروسرویس ها موضوعی جالب و نسبتاً پیچیده است. به جای داشتن یک فایل log که می توانید با دستورات کمتر یا grep آن را دستکاری کنید، اکنون n فایل log دارید و می خواهید که آنها خیلی پراکنده نباشند. ویژگیهای اکوسیستم چوبگیری در این مقاله (به زبان انگلیسی) به خوبی توضیح داده شده است. حتما آن را بخوانید و به بخش ثبت مرکزی از دیدگاه میکروسرویس توجه کنید . در عمل، با رویکردهای مختلفی روبرو خواهید شد: مدیر سیستم اسکریپت های خاصی را می نویسد که فایل های گزارش را از سرورهای مختلف در یک فایل گزارش جمع آوری و ترکیب می کند و آنها را برای دانلود روی سرورهای FTP قرار می دهد. اجرای ترکیبات cat/grep/unig/ sort در جلسات SSH موازی. این دقیقاً همان کاری است که Amazon AWS انجام می دهد و می توانید به مدیر خود اطلاع دهید. از ابزاری مانند Graylog یا ELK Stack (Elasticsearch، Logstash، Kibana) استفاده کنید.میکروسرویس های من چگونه یکدیگر را پیدا می کنند؟
تا به حال، ما فرض میکردیم که میکروسرویسهای ما از یکدیگر اطلاع دارند و IPS مربوطه را میدانند. بیایید در مورد پیکربندی استاتیک صحبت کنیم. بنابراین، یکپارچه بانکی ما [ip = 192.168.200.1] می داند که باید با سرور ریسک [ip = 192.168.200.2] صحبت کند، که در فایل ویژگی ها کدگذاری شده است. با این حال، می توانید همه چیز را پویاتر کنید:- از یک سرور پیکربندی مبتنی بر ابر استفاده کنید که همه میکروسرویسها به جای استقرار فایلهای application.properties روی میکروسرویسهای خود، تنظیمات خود را از آن استخراج میکنند.
- از آنجایی که نمونههای سرویس شما میتوانند به صورت پویا مکان خود را تغییر دهند، ارزش دارد به سرویسهایی نگاه کنید که میدانند سرویسهای شما در کجا زندگی میکنند، IP آنها چیست و چگونه آنها را مسیریابی کنند.
- اکنون که همه چیز پویا است، مشکلات جدیدی مانند انتخاب خودکار یک رهبر به وجود می آید: استاد کیست که روی برخی وظایف کار می کند تا مثلاً دو بار آنها را پردازش نکند؟ چه کسی وقتی رهبر شکست می خورد جایگزین او می شود؟ تعویض بر چه اساسی انجام می شود؟
چگونه با استفاده از میکروسرویس جاوا مجوز و احراز هویت را سازماندهی کنیم؟
این مبحث نیز شایسته یک داستان جداگانه است. باز هم، گزینهها از احراز هویت اولیه HTTPS با کد سخت با چارچوبهای امنیتی سفارشی گرفته تا اجرای نصب Oauth2 با سرور مجوز خود را شامل میشود.چگونه می توانم مطمئن شوم که همه محیط های من یکسان هستند؟
آنچه برای استقرار بدون میکروسرویس صادق است برای استقرار با یک نیز صادق است. ترکیبی از Docker/Testcontainers و Scripting/Ansible را امتحان کنید.بدون سوال: به طور خلاصه در مورد YAML
بیایید لحظه ای از کتابخانه ها و مسائل مربوط به آن فاصله بگیریم و نگاهی گذرا به یامل بیندازیم. این فرمت فایل به طور واقعی به عنوان فرمتی برای "پیکربندی نوشتن به عنوان کد" استفاده می شود. همچنین توسط ابزارهای ساده ای مانند Ansible و غول هایی مانند Kubernetes استفاده می شود. برای اینکه درد تورفتگی YAML را تجربه کنید، سعی کنید یک فایل Ansible ساده بنویسید و ببینید چقدر باید فایل را ویرایش کنید قبل از اینکه مطابق انتظار کار کند. و این با وجود پشتیبانی از فرمت توسط همه IDE های اصلی! پس از آن، برای پایان خواندن این راهنما بازگردید.Yaml:
- is:
- so
- great
در مورد معاملات توزیع شده چطور؟ ازمایش عملکرد؟ موضوعات دیگر؟
شاید روزی، در نسخه های بعدی کتابچه راهنما. در حال حاضر، این همه است. با ما بمان!مسائل مفهومی با میکروسرویس ها
علاوه بر مشکلات خاص میکروسرویس ها در جاوا، مشکلات دیگری نیز وجود دارد، مثلاً مشکلاتی که در هر پروژه میکروسرویس ظاهر می شوند. آنها بیشتر به سازمان، تیم و مدیریت مربوط می شوند.عدم تطابق Frontend و Backend
عدم تطابق Frontend و Backend یک مشکل بسیار رایج در بسیاری از پروژه های میکروسرویس است. چه مفهومی داره؟ فقط در مونولیت های خوب قدیمی، توسعه دهندگان رابط وب یک منبع خاص برای به دست آوردن داده ها داشتند. در پروژههای میکروسرویس، توسعهدهندگان فرانتاند ناگهان n منبع برای بهدست آوردن دادهها دارند. تصور کنید که در حال ایجاد نوعی پروژه میکروسرویس IoT (اینترنت اشیا) در جاوا هستید. فرض کنید ماشینهای ژئودتیک و کورههای صنعتی را در سراسر اروپا مدیریت میکنید. و این اجاق ها با دمای خود و مواردی از این دست به روز رسانی های منظم را برای شما ارسال می کنند. دیر یا زود ممکن است بخواهید کورهها را در رابط کاربری مدیریت پیدا کنید، شاید با استفاده از میکروسرویسهای "جستجوی کوره". بسته به اینکه همتایان پشتیبان شما چقدر قوانین طراحی مبتنی بر دامنه یا ریزسرویس را به شدت اعمال میکنند، یک میکروسرویس «فهرست را پیدا کن» ممکن است فقط شناسههای فر را برگرداند و نه دادههای دیگری مانند نوع، مدل یا مکان. برای انجام این کار، توسعه دهندگان فرانت اند باید یک یا n تماس اضافی (بسته به پیاده سازی صفحه بندی) در میکروسرویس «دریافت اطلاعات کوره» با شناسه هایی که از اولین میکروسرویس دریافت کرده اند، انجام دهند. و اگرچه این فقط یک مثال ساده است، اگرچه از یک پروژه واقعی (!) گرفته شده است، حتی مشکل زیر را نشان می دهد: سوپرمارکت ها بسیار محبوب شده اند. دلیلش این است که با آنها مجبور نیستید برای خرید سبزیجات، لیموناد، پیتزا یخ زده و دستمال توالت به 10 مکان مختلف بروید. در عوض، به یک مکان می روید، آسان تر و سریع تر است. همین امر در مورد توسعه دهندگان فرانت اند و میکروسرویس نیز صدق می کند.انتظارات مدیریت
مدیریت در این تصور اشتباه است که اکنون باید تعداد بی نهایت توسعه دهنده را برای یک پروژه (کلی) استخدام کند، زیرا توسعه دهندگان اکنون می توانند کاملاً مستقل از یکدیگر کار کنند و هر کدام بر روی میکروسرویس خود کار کنند. فقط کمی کار یکپارچه سازی در پایان (کمی قبل از راه اندازی) مورد نیاز است. در واقع، این رویکرد بسیار مشکل ساز است. در پاراگراف های بعدی سعی می کنیم دلیل آن را توضیح دهیم."قطعه های کوچکتر" با "قطعه های بهتر" برابری نمی کند
این یک اشتباه بزرگ است که فرض کنیم کد تقسیم شده به 20 قسمت لزوماً کیفیت بالاتری نسبت به یک قطعه کامل دارد. حتی اگر کیفیت را صرفاً از نقطه نظر فنی در نظر بگیریم، سرویسهای فردی ما ممکن است همچنان 400 کوئری Hibernate را برای انتخاب کاربر از پایگاه داده اجرا کنند و لایههایی از کدهای پشتیبانی نشده را طی کنند. یک بار دیگر به نقل قول سایمون براون باز می گردیم: اگر نتوانید یکپارچه ها را به درستی بسازید، ساخت میکروسرویس های مناسب دشوار خواهد بود. صحبت در مورد تحمل خطا در پروژه های میکروسرویس اغلب بسیار دیر است. به حدی که گاهی اوقات دیدن نحوه عملکرد میکروسرویس ها در پروژه های واقعی ترسناک است. دلیل این امر این است که توسعه دهندگان جاوا همیشه آماده مطالعه تحمل خطا، شبکه و سایر موضوعات مرتبط در سطح مناسب نیستند. "قطعات" خود کوچکتر هستند، اما "قطعات فنی" بزرگتر هستند. تصور کنید از تیم میکروسرویس شما خواسته می شود که یک میکروسرویس فنی برای ورود به سیستم پایگاه داده بنویسد، چیزی شبیه به این:@Controller
class LoginController {
// ...
@PostMapping("/login")
public boolean login(String username, String password) {
User user = userDao.findByUserName(username);
if (user == null) {
// обработка варианта с несуществующим пользователем
return false;
}
if (!user.getPassword().equals(hashed(password))) {
// обработка неверного пароля
return false;
}
// 'Ю-ху, залогинorсь!';
// установите cookies, делайте, что угодно
return true;
}
}
اکنون تیم شما ممکن است تصمیم بگیرد (و شاید حتی افراد تجاری را متقاعد کند) که این بسیار ساده و خسته کننده است، به جای نوشتن یک سرویس ورود به سیستم، بهتر است یک میکروسرویس واقعا مفید UserStateChanged بدون هیچ گونه الزامات تجاری واقعی و ملموس بنویسید. و از آنجایی که برخی از مردم در حال حاضر با جاوا مانند یک دایناسور رفتار می کنند، بیایید میکروسرویس UserStateChanged خود را در Erlang مد روز بنویسیم. و بیایید در جایی از درختان قرمز-مشکی استفاده کنیم، زیرا استیو یگ نوشته است که باید آنها را از درون بشناسید تا در گوگل درخواست دهید. از منظر یکپارچه سازی، تعمیر و نگهداری و طراحی کلی، این به همان اندازه بد است که لایه هایی از کد اسپاگتی را در داخل یک تک سنگ بنویسید. یک نمونه مصنوعی و معمولی؟ درست است. با این حال، این می تواند در واقعیت رخ دهد.
قطعات کمتر - درک کمتر
سپس این سؤال به طور طبیعی در مورد درک سیستم به عنوان یک کل، فرآیندها و جریان های کاری آن مطرح می شود، اما در عین حال شما به عنوان یک توسعه دهنده، تنها مسئول کار بر روی میکروسرویس ایزوله خود هستید [95: login-101: updateUserProfile]. با پاراگراف قبلی هماهنگ است، اما بسته به سازمان، سطح اعتماد و ارتباطات شما، این امر میتواند منجر به سردرگمی، بالا انداختن و سرزنش زیادی در صورت خرابی تصادفی در زنجیره میکروسرویس شود. و هیچ کس نیست که مسئولیت کامل این اتفاق را بپذیرد. و اصلاً بحث بی صداقتی نیست. در واقع، اتصال قطعات مختلف و درک جایگاه آنها در تصویر کلی پروژه بسیار دشوار است.ارتباطات و خدمات
سطح ارتباطات و خدمات بسته به اندازه شرکت بسیار متفاوت است. با این حال، رابطه کلی واضح است: هر چه بیشتر، مشکل ساز تر.- چه کسی میکروسرویس شماره 47 را اجرا می کند؟
- آیا آنها فقط یک نسخه جدید و ناسازگار از یک میکروسرویس را مستقر کردند؟ این کجا مستند بود؟
- برای درخواست ویژگی جدید باید با چه کسی صحبت کنم؟
- بعد از اینکه تنها کسی که این زبان را بلد بود شرکت را ترک کرد، چه کسی از آن میکروسرویس در ارلنگ پشتیبانی خواهد کرد؟
- همه تیم های میکروسرویس ما نه تنها در زبان های برنامه نویسی مختلف، بلکه در مناطق زمانی مختلف نیز کار می کنند! چگونه همه اینها را به درستی هماهنگ کنیم؟
GO TO FULL VERSION