מבוא לדובבו

1. הקדמה

דובבו הוא מסגרת RPC ומערכת מיקרו-שירות קוד פתוח מבית עליבאבא.

בין היתר, זה עוזר בשיפור הממשל בשירות ומאפשר לשחזר בצורה חלקה יישומים מונוליטים מסורתיים לאדריכלות מבוזרת ניתנת להרחבה.

במאמר זה נביא מבוא לדובבו ולמאפיינים החשובים ביותר שלו.

2. אדריכלות

דובבו מבחין בכמה תפקידים:

  1. ספק - היכן שנחשף השירות; ספק ירשום את השירות שלו לרישום
  2. מיכל - היכן השירות יוזם, נטען ומופעל
  3. צרכן - הפונה לשירותים מרחוק; צרכן יירשם כמנוי לשירות הדרוש ברישום
  4. רישום - שם השירות יירשם ויתגלה
  5. צג - רשמו נתונים סטטיסטיים עבור שירותים, למשל, תדירות הפעלת השירות בפרק זמן נתון

(מקור: //dubbo.io/images/dubbo-architecture.png)

החיבורים בין ספק, צרכן ורישום הם מתמשכים, כך שבכל פעם שספק שירות לא נמצא, הרישום יכול לאתר את הכשל ולהודיע ​​לצרכנים.

הרישום והצג הם אופציונליים. הצרכנים יכולים להתחבר ישירות לספקי השירות, אך יציבות המערכת כולה תושפע.

3. תלות של Maven

לפני שנצלול פנימה, בואו נוסיף את התלות הבאה שלנו pom.xml:

 com.alibaba dubbo 2.5.7 

הגרסה האחרונה תוכל למצוא כאן.

4. Bootstrapping

עכשיו בואו ננסה את התכונות הבסיסיות של דובבו.

זוהי מסגרת פולשנית מינימלית, והרבה מהתכונות שלה תלויות בתצורות או ביאורים חיצוניים.

מוצע באופן רשמי שנשתמש בקובץ תצורה של XML מכיוון שהוא תלוי במיכל Spring (כרגע באביב 4.3.10).

נדגים את רוב התכונות שלו באמצעות תצורת XML.

4.1. רישום שידורי שידור - ספק שירות

כהתחלה מהירה, נצטרך רק נותן שירותים, צרכן ורישום "בלתי נראה". הרישום אינו נראה כי אנו משתמשים ברשת שידור מולטי-קול.

בדוגמה הבאה, הספק אומר רק "היי" לצרכניו:

ממשק ציבורי GreetingsService {String sayHi (שם מחרוזת); } מעמד ציבורי GreetingsServiceImpl מיישם GreetingsService {@Override public String sayHi (שם מחרוזת) {להחזיר "היי," + שם; }}

כדי לבצע שיחת הליך מרחוק, על הצרכן לשתף ממשק משותף עם ספק השירות, ובכך הממשק GreetingsService חייבים להיות משותפים עם הצרכן.

4.2. רישום Multicast - רישום שירות

בואו נרשם עכשיו GreetingsService לרישום. דרך נוחה מאוד היא להשתמש ברישום ריבוי שידורים אם הן הספקים והן הצרכנים נמצאים באותה רשת מקומית:

עם תצורת השעועית לעיל, רק חשפנו את שלנו GreetingsService לכתובת אתר תחת dubbo: //127.0.0.1: 20880 ורשם את השירות לכתובת שידור שצוינה ב .

בתצורת הספק, הכרזנו גם על מטא נתונים של היישום שלנו, על הממשק לפרסום ויישומו בהתאמה , ו .

ה דובבו פרוטוקול הוא אחד מפרוטוקולים רבים שמסגרת התומכת בו. הוא בנוי על גבי התכונה הלא חוסמת של Java NIO וזה פרוטוקול ברירת המחדל המשמש.

נדון בזה ביתר פירוט בהמשך מאמר זה.

4.3. רישום שידורי שידור - צרכן שירותים

באופן כללי, הצרכן צריך לציין את הממשק שיוזעק וכתובת השירות המרוחק, וזה בדיוק מה שנדרש לצרכן:

עכשיו הכל מוגדר, בואו נראה איך הם עובדים בפעולה:

מחלקה ציבורית MulticastRegistryTest {@ לפני ריקה initRemote פומבית () {ClassPathXmlApplicationContext remoteContext = חדש ClassPathXmlApplicationContext ("multicast / provider-app.xml"); remoteContext.start (); } @Test הציבור בטל givenProvider_whenConsumerSaysHi_thenGotResponse () {ClassPathXmlApplicationContext localContext = ClassPathXmlApplicationContext חדש ("multicast / consumer-app.xml"); localContext.start (); GreetingsService greetingsService = (GreetingsService) localContext.getBean ("greetingsService"); מחרוזת hiMessage = greetingsService.sayHi ("baeldung"); assertNotNull (hiMessage); assertEquals ("היי, באלדונג", hiMessage); }}

כאשר הספק remoteContext מתחיל, Dubbo יטען אוטומטית GreetingsService ולרשום אותו לרישום נתון. במקרה זה, זהו רישום שידור לקבוצה.

הצרכן מנוי לרישום שידור הקלט ויוצר פרוקסי של GreetingsService בהקשר. כאשר הלקוח המקומי שלנו מזמין את להגיד שלום שיטה, זה קורא בשקיפות שירות מרוחק.

הזכרנו כי הרישום הוא אופציונלי, כלומר הצרכן יכול להתחבר ישירות לספק, דרך הנמל החשוף:

בעיקרון, ההליך דומה לשירות אתרים מסורתי, אך דובבו פשוט הופך אותו לפשוט, פשוט וקל משקל.

4.4. רישום פשוט

שים לב שבעת השימוש ברישום ריבוי שידורים "בלתי נראה", שירות הרישום אינו עצמאי. עם זאת, זה חל רק על רשת מקומית מוגבלת.

כדי להגדיר במפורש רישום לניהול, אנו יכולים להשתמש ב- SimpleRegistryService.

לאחר טעינת תצורת השעועית הבאה בהקשר האביב, מתחיל שירות רישום פשוט:

שים לב שה- SimpleRegistryService המחלקה אינה כלולה בחפץ, ולכן העתקנו את קוד המקור ישירות ממאגר Github.

לאחר מכן נתאים את תצורת הרישום של הספק והצרכן:

SimpleRegistryService יכול לשמש כרישום עצמאי בעת הבדיקה, אך לא מומלץ להשתמש בו בסביבת הייצור.

4.5. תצורת Java

תצורה באמצעות Java API, קובץ מאפיין והערות נתמכים גם כן. עם זאת, קובצי נכסים והערות חלים רק אם הארכיטקטורה שלנו אינה מורכבת במיוחד.

בואו נראה כיצד ניתן לתרגם את תצורות ה- XML ​​הקודמות שלנו לרישום ריבוי שידורים לתצורת API. ראשית, הספק מוגדר באופן הבא:

ApplicationConfig יישום = ApplicationConfig חדש (); application.setName ("ספק הדגמה"); application.setVersion ("1.0"); RegistryConfig registryConfig = RegistryConfig חדש (); registryConfig.setAddress ("multicast: //224.1.1.1: 9090"); ServiceConfig service = ServiceConfig חדש (); service.setApplication (יישום); service.setRegistry (registryConfig); service.setInterface (GreetingsService.class); service.setRef (GreetingsServiceImpl חדש ()); service.export ();

כעת, לאחר שהשירות כבר נחשף באמצעות רישום המולטי-קול, בואו נצרוך אותו בלקוח מקומי:

ApplicationConfig יישום = ApplicationConfig חדש (); application.setName ("צרכן הדגמה"); application.setVersion ("1.0"); RegistryConfig registryConfig = RegistryConfig חדש (); registryConfig.setAddress ("multicast: //224.1.1.1: 9090"); ReferenceConfig reference = חדש ReferenceConfig (); reference.setApplication (יישום); reference.setRegistry (registryConfig); reference.setInterface (GreetingsService.class); GreetingsService greetingsService = reference.get (); מחרוזת hiMessage = greetingsService.sayHi ("baeldung");

למרות שקטע הקוד לעיל עובד כמו קסם כדוגמת תצורת ה- XML ​​הקודמת, הוא קצת יותר טריוויאלי. לעת עתה, תצורת XML צריכה להיות הבחירה הראשונה אם אנו מתכוונים לעשות שימוש מלא בדובבו.

5. תמיכה בפרוטוקולים

המסגרת תומכת במספר פרוטוקולים, כולל דובבו, RMI, הסינית, HTTP, שירות רשת, חִסָכוֹן, memcached ו redis. רוב הפרוטוקולים נראים מוכרים, למעט דובבו. בואו נראה מה חדש בפרוטוקול זה.

ה דובבו פרוטוקול שומר על קשר מתמשך בין ספקים לצרכנים. החיבור הארוך ותקשורת הרשת הלא חוסמת של NIO מביאים לביצועים נהדרים למדי בעת העברת מנות נתונים בקנה מידה קטן (<100K).

ישנם מספר מאפיינים הניתנים להגדרה, כגון יציאה, מספר חיבורים לצרכן, חיבורים מקובלים מקסימליים וכו '.

דובבו תומך גם בחשיפת שירותים באמצעות פרוטוקולים שונים בבת אחת:

וכן, אנו יכולים לחשוף שירותים שונים באמצעות פרוטוקולים שונים, כפי שמוצג בקטע לעיל. ניתן להגדיר גם את המובילים הבסיסיים, יישומי הסידור ותכונות נפוצות אחרות הקשורות לרשת.

6. מטמון תוצאה

אחסון במטמון של תוצאות מרחוק נתמך באופן מאובטח כדי להאיץ את הגישה לנתונים חמים. זה פשוט כמו להוסיף מאפיין מטמון להפניה לשעועית:

כאן הגדרנו מטמון שהשתמשו בו לאחרונה. כדי לאמת את התנהגות המטמון, נשנה מעט ביישום הסטנדרטי הקודם (נקרא לזה "יישום מיוחד"):

מחלקה ציבורית GreetingsServiceSpecialImpl מיישמת GreetingsService {@Override public String sayHi (שם מחרוזת) {נסה {SECONDS.sleep (5); } לתפוס (התעלם מהחרגה) {} להחזיר "היי" + שם; }}

לאחר הפעלת הספק, אנו יכולים לוודא מצד הצרכן, שהתוצאה נשמרת במטמון בעת ​​הפעלת יותר מפעם אחת:

@Test הציבור בטל givenProvider_whenConsumerSaysHi_thenGotResponse () {ClassPathXmlApplicationContext localContext = ClassPathXmlApplicationContext חדש ("multicast / consumer-app.xml"); localContext.start (); GreetingsService greetingsService = (GreetingsService) localContext.getBean ("greetingsService"); הרבה לפני = System.currentTimeMillis (); מחרוזת hiMessage = greetingsService.sayHi ("baeldung"); long timeElapsed = System.currentTimeMillis () - לפני; assertTrue (timeElapsed> 5000); assertNotNull (hiMessage); assertEquals ("היי, באלדונג", hiMessage); לפני = System.currentTimeMillis (); hiMessage = greetingsService.sayHi ("baeldung"); timeElapsed = System.currentTimeMillis () - לפני; assertTrue (timeElapsed <1000); assertNotNull (hiMessage); assertEquals ("היי, באלדונג", hiMessage); }

כאן הצרכן מגיש את יישום השירות המיוחד, ולכן נדרשו יותר מ -5 שניות עד שההפעלה הושלמה בפעם הראשונה. כאשר אנו קוראים שוב, להגיד שלום השיטה הושלמה כמעט באופן מיידי, מכיוון שהתוצאה מוחזרת מהמטמון.

שים לב כי מטמון מקומי חוטים ו- JCache נתמכים גם הם.

7. תמיכה באשכול

דובבו עוזר לנו להגדיל את השירותים שלנו באופן חופשי בעזרת יכולתו של איזון עומסים ומספר אסטרטגיות לסובלנות תקלות. הנה, נניח שיש לנו את Zookeeper כרישום שלנו לניהול שירותים באשכול. ספקים יכולים לרשום את שירותיהם ב- Zookeeper כך:

שים לב כי אנו זקוקים לתלות נוספות אלה ב- POM:

 org.apache.zookeeper zookeeper 3.4.11 com.101tec zkclient 0.10 

הגרסאות האחרונות של שומר חיות תלות ו zkclient ניתן למצוא כאן וכאן.

7.1. איזון עומסים

נכון לעכשיו, המסגרת תומכת בכמה אסטרטגיות לאיזון עומסים:

  • אַקרַאִי
  • רובין העגול
  • הכי פחות פעיל
  • עקבי-חשיש.

בדוגמה הבאה, יש לנו שתי יישומי שירות כספקים באשכול. הבקשות מנותבות באמצעות גישת הרובין.

ראשית, בוא נקים ספקי שירות:

@ לפני החלל הריק initRemote () {ExecutorService executorService = Executors.newFixedThreadPool (2); executorService.submit (() -> {ClassPathXmlApplicationContext remoteContext = new ClassPathXmlApplicationContext ("אשכול / ספק-אפליקציית ברירת מחדל. xml"); remoteContext.start ();}); executorService.submit (() -> {ClassPathXmlApplicationContext backupRemoteContext = new ClassPathXmlApplicationContext ("אשכול / ספק-אפליקציה מיוחדת.קסמל"); backupRemoteContext.start ();}); }

עכשיו יש לנו "ספק מהיר" סטנדרטי שמגיב מייד, ו"ספק איטי "מיוחד שישן 5 שניות בכל בקשה.

לאחר ריצה 6 פעמים עם אסטרטגיית הרובין, אנו מצפים שזמן התגובה הממוצע יהיה לפחות 2.5 שניות:

@Test הציבור בטל givenProviderCluster_whenConsumerSaysHi_thenResponseBalanced () {ClassPathXmlApplicationContext localContext = חדש ClassPathXmlApplicationContext ("אשכול / צריכה-אפליקציה-lb.xml"); localContext.start (); GreetingsService greetingsService = (GreetingsService) localContext.getBean ("greetingsService"); רשימה elapseList = ArrayList חדש (6); עבור (int i = 0; i e). ממוצע (); assertTrue (avgElapse.isPresent ()); assertTrue (avgElapse.getAsDouble ()> 2500.0); }

יתר על כן, מאומץ על איזון עומסים דינמי. הדוגמה הבאה מדגימה כי, עם אסטרטגיית סבב-רובין, הצרכן בוחר אוטומטית את ספק השירות החדש כמועמד כאשר הספק החדש יעלה לרשת.

"הספק האיטי" נרשם כעבור שניות לאחר הפעלת המערכת:

@ לפני החלל הריק initRemote () {ExecutorService executorService = Executors.newFixedThreadPool (2); executorService.submit (() -> {ClassPathXmlApplicationContext remoteContext = new ClassPathXmlApplicationContext ("אשכול / ספק-אפליקציית ברירת מחדל. xml"); remoteContext.start ();}); executorService.submit (() -> {SECONDS.sleep (2); ClassPathXmlApplicationContext backupRemoteContext = new ClassPathXmlApplicationContext ("cluster / provider-app-special.xml"); backupRemoteContext.start (); return null;}); }

הצרכן מזמין את השירות מרחוק פעם בשנייה. לאחר ריצה 6 פעמים, אנו מצפים שזמן התגובה הממוצע יהיה גדול מ- 1.6 שניות:

@Test הציבור בטל givenProviderCluster_whenConsumerSaysHi_thenResponseBalanced () זורק InterruptedException {ClassPathXmlApplicationContext localContext = חדש ClassPathXmlApplicationContext ("אשכול / צריכה-אפליקציה-lb.xml"); localContext.start (); GreetingsService greetingsService = (GreetingsService) localContext.getBean ("greetingsService"); רשימה elapseList = ArrayList חדש (6); עבור (int i = 0; i e). ממוצע (); assertTrue (avgElapse.isPresent ()); assertTrue (avgElapse.getAsDouble ()> 1666.0); }

שים לב שניתן להגדיר את איזון העומס הן בצד הצרכן והן בצד הספק. הנה דוגמה לתצורה בצד הצרכן:

7.2. סובלנות תקלות

מספר אסטרטגיות לסובלנות תקלות נתמכות בדובבו, כולל:

  • כישלון
  • אל כשל
  • כישלון מהיר
  • כישלון-חזרה
  • מזלג.

במקרה של כישלון, כשספק אחד נכשל, הצרכן יכול לנסות עם ספקי שירות אחרים באשכול.

אסטרטגיות סובלנות התקלות מוגדרות כדלקמן עבור נותני שירותים:

כדי להדגים כישלון שירות בפעולה, בואו ליצור יישום כישלון GreetingsService:

מחלקה ציבורית GreetingsFailoverServiceImpl מיישמת GreetingsService {@Override public String sayHi (שם מחרוזת) {להחזיר "היי, failover" + שם; }}

אנו יכולים לזכור כי יישום השירות המיוחד שלנו GreetingsServiceSpecialImpl ישן 5 שניות לכל בקשה.

כאשר כל תגובה שלוקחת יותר משתי שניות נתפסת ככישלון בקשה עבור הצרכן, יש לנו תרחיש כישלון:

לאחר הפעלת שני ספקים, אנו יכולים לאמת את התנהגות הכישלון באמצעות הטקסט הבא:

@ מבחן ציבורי בטל כאשר ConsumerSaysHi_thenGotFailoverResponse () {ClassPathXmlApplicationContext localContext = ClassPathXmlApplicationContext חדש ("אשכול / צרכן-אפליקציה- failtest.xml"); localContext.start (); GreetingsService greetingsService = (GreetingsService) localContext.getBean ("greetingsService"); מחרוזת hiMessage = greetingsService.sayHi ("baeldung"); assertNotNull (hiMessage); assertEquals ("היי, baeldung כישלון", hiMessage); }

8. סיכום

במדריך זה לקחנו נגיסה קטנה בדובבו. רוב המשתמשים נמשכים מפשטותו ומתכונותיו העשירות והחזקות.

מלבד מה שהצגנו במאמר זה, למסגרת יש מספר תכונות שטרם נחקרו, כמו אימות פרמטרים, התראות והתקשרות חוזרת, יישום והפניה כללית, קיבוץ ומיזוג תוצאות מרחוק, שדרוג שירות ותאימות לאחור, אם לציין רק כמה.

כמו תמיד, ניתן למצוא את היישום המלא ב- Github.