ในคู่มือนี้ คุณจะได้เรียนรู้ว่าไมโครเซอร์วิส Java คืออะไร รวมถึงวิธีการออกแบบและสร้างไมโครเซอร์วิสเหล่านั้น นอกจากนี้ยังครอบคลุมคำถามเกี่ยวกับไลบรารีไมโครเซอร์วิส Java และความเป็นไปได้ในการใช้ไมโครเซอร์วิส การแปลและการปรับJava Microservices: A Practical Guide
Java Microservices: พื้นฐาน
หากต้องการทำความเข้าใจไมโครเซอร์วิส คุณต้องกำหนดก่อนว่าไมโครเซอร์วิสคืออะไร ไม่ใช่ "เสาหิน" - Java monolith: มันคืออะไรและมีข้อดีหรือข้อเสียอย่างไรJava monolith คืออะไร?
ลองนึกภาพคุณทำงานให้กับธนาคารหรือบริษัทสตาร์ทอัพฟินเทค คุณให้แอปบนมือถือแก่ผู้ใช้ที่พวกเขาสามารถใช้เพื่อเปิดบัญชีธนาคารใหม่ ในโค้ด Java สิ่งนี้จะส่งผลให้มีคลาสคอนโทรลเลอร์อยู่ อย่างง่ายดูเหมือนว่านี้:@Controller
class BankController {
@PostMapping("/users/register")
public void register(RegistrationForm form) {
validate(form);
riskCheck(form);
openBankAccount(form);
// etc..
}
}
คุณต้องมีคอนโทรลเลอร์เพื่อ:
- ยืนยันแบบฟอร์มการลงทะเบียน
- ตรวจสอบความเสี่ยงของที่อยู่ของผู้ใช้เพื่อตัดสินใจว่าจะให้บัญชีธนาคารแก่เขาหรือไม่
- เปิดบัญชีธนาคารแล้ว
BankController
จะถูกรวมแพ็กเกจพร้อมกับซอร์สที่เหลือของคุณลงในไฟล์ bank.jar หรือ bank.war สำหรับการนำไปใช้งาน - นี่เป็นโมโนลิธเก่าที่ดีที่มีโค้ดทั้งหมดที่จำเป็นในการรันธนาคารของคุณ จากการประมาณการคร่าวๆ ขนาดเริ่มต้นของไฟล์ .jar (หรือ .war) จะมีขนาดตั้งแต่ 1 ถึง 100 MB ตอนนี้คุณสามารถเรียกใช้ไฟล์ .jar บนเซิร์ฟเวอร์ของคุณได้... และนั่นคือทั้งหมดที่คุณต้องทำเพื่อปรับใช้แอปพลิเคชัน Java ของคุณ รูปภาพ สี่เหลี่ยมผืนผ้าซ้ายบน: การปรับใช้ mono(lithic) bank java -jar bank.jar (cp .war/.ear ใน appserver) สี่เหลี่ยมด้านขวา: เปิดเบราว์เซอร์
ปัญหาของ Java Monoliths คืออะไร
ไม่มีอะไรผิดปกติกับ Java monoliths อย่างไรก็ตาม ประสบการณ์ได้แสดงให้เห็นว่าหากอยู่ในโครงการของคุณ:- มีโปรแกรมเมอร์/ทีม/ที่ปรึกษาจำนวนมากที่ทำงาน...
- ...บนเสาหินเดียวกันภายใต้แรงกดดันจากลูกค้าที่มีข้อกำหนดที่คลุมเครือมาก...
- ภายในสองสามปี...
จะลดขนาดของ Monolith Java ได้อย่างไร?
คำถามที่เป็นธรรมชาติเกิดขึ้น: จะทำให้เสาหินเล็กลงได้อย่างไร? ขณะนี้ bank.jar ของคุณกำลังทำงานบน JVM หนึ่งกระบวนการบนเซิร์ฟเวอร์เดียว ไม่มากไม่น้อย. และตอนนี้ความคิดเชิงตรรกะอาจเข้ามาในใจ: “แต่แผนกอื่นในบริษัทของฉันสามารถใช้บริการตรวจสอบความเสี่ยงได้! มันไม่เกี่ยวข้องโดยตรงกับใบสมัครธนาคารขนาดใหญ่ของฉัน! บางทีมันควรจะถูกตัดออกจากเสาหินและปรับใช้เป็นผลิตภัณฑ์แยกต่างหาก กล่าวคือ ในทางเทคนิคแล้ว ให้รันมันเป็นกระบวนการ Java ที่แยกจากกัน”ไมโครเซอร์วิส Java คืออะไร?
ในทางปฏิบัติ วลีนี้หมายความว่าขณะนี้การเรียกเมธอดriskCheck()
จะไม่ถูกสร้างจาก BankController: เมธอดหรือส่วนประกอบ bean ที่มีคลาสเสริมทั้งหมดจะถูกย้ายไปยังโปรเจ็กต์ Maven หรือ Gradle ของตัวเอง นอกจากนี้ยังจะถูกปรับใช้และวางไว้ภายใต้การควบคุมเวอร์ชันโดยไม่ขึ้นอยู่กับระบบธนาคารขนาดใหญ่ อย่างไรก็ตาม กระบวนการแยกข้อมูลทั้งหมดนี้ไม่ได้เปลี่ยนโมดูล RiskCheck ใหม่ของคุณให้เป็นไมโครเซอร์วิสต่อตัว เนื่องจากคำจำกัดความของไมโครเซอร์วิสเปิดให้ตีความได้ สิ่งนี้นำไปสู่การพูดคุยกันบ่อยครั้งภายในทีมและบริษัท
- มี 5-7 คลาสในโปรเจ็กต์ไมโครหรืออะไร
- 100 หรือ 1,000 คลาส... ยังไมโครอยู่หรือเปล่า?
- โดยทั่วไปแล้วไมโครเซอร์วิสเกี่ยวข้องกับจำนวนคลาสหรือไม่?
- มาเรียกไมโครเซอร์วิสบริการที่ใช้งานแยกกันทั้งหมด โดยไม่คำนึงถึงขนาดหรือขอบเขตโดเมน
- ลองคิดถึงวิธีจัดเตรียมการสื่อสารระหว่างกัน ไมโครเซอร์วิสของเราต้องการวิธีในการสื่อสารระหว่างกัน
จะสร้างการสื่อสารระหว่างไมโครเซอร์วิส Java ได้อย่างไร
โดยทั่วไปมีสองตัวเลือก - การสื่อสารแบบซิงโครนัสและแบบอะซิงโครนัสการสื่อสารแบบซิงโครนัส: (HTTP)/REST
โดยทั่วไปแล้ว การสื่อสารแบบซิงโครไนซ์ระหว่างไมโครเซอร์วิสจะเกิดขึ้นผ่านบริการที่คล้ายกับ HTTP และ REST ที่ส่งคืน XML หรือ JSON แน่นอนว่าอาจมีตัวเลือกอื่น - ใช้Google Protocol Buffers เป็นอย่างน้อย หากคุณต้องการการตอบสนองทันที ควรใช้การสื่อสาร REST จะดีกว่า ในตัวอย่างของเรา นี่คือสิ่งที่ต้องทำ เนื่องจากต้องมีการตรวจสอบความเสี่ยงก่อนเปิดบัญชี หากไม่มีการตรวจสอบความเสี่ยง ก็ไม่มีบัญชี เราจะพูดถึงเครื่องมือด้านล่าง ในส่วน “ ไลบรารีใดดีที่สุดสำหรับการเรียก Java REST แบบซิงโครนัส ”การส่งข้อความ - การสื่อสารแบบอะซิงโครนัส
โดยทั่วไปการสื่อสารไมโครเซอร์วิส แบบอะซิงโครนัสทำได้โดยการแลกเปลี่ยนข้อความด้วยการนำ JMS ไปใช้ และ/หรือการใช้โปรโตคอล เช่นAMQP เราเขียนว่า "ปกติ" ที่นี่ด้วยเหตุผล: สมมติว่าจำนวนการรวมอีเมล/SMTP ไม่สามารถประเมินต่ำไปได้ ใช้มันเมื่อคุณไม่ต้องการคำตอบทันที ตัวอย่างเช่น ผู้ใช้คลิกปุ่ม "ซื้อเลย" และคุณก็จะต้องการสร้างใบแจ้งหนี้ในทางกลับกัน กระบวนการนี้ไม่ควรเกิดขึ้นภายในรอบการตอบกลับคำขอซื้อของผู้ใช้อย่างแน่นอน ด้านล่างนี้เราจะอธิบายว่าเครื่องมือใดดีที่สุดสำหรับการส่งข้อความ Java แบบอะซิงโครนัสตัวอย่าง: การเรียก REST API ใน Java
สมมติว่าเราเลือกการสื่อสารไมโครเซอร์วิสแบบซิงโครนัส ในกรณีนี้ โค้ด Java ของเรา (โค้ดที่เรานำเสนอด้านบน) ในระดับต่ำจะมีลักษณะดังนี้ (โดยระดับต่ำในที่นี้ เราหมายถึงความจริงที่ว่าสำหรับการสื่อสารแบบไมโครเซอร์วิส ไลบรารีไคลเอนต์มักจะถูกสร้างขึ้นเพื่อดึงคุณออกจากการเรียก HTTP จริง)@Controller
class BankController {
@Autowired
private HttpClient httpClient;
@PostMapping("/users/register")
public void register(RegistrationForm form) {
validate(form);
httpClient.send(riskRequest, responseHandler());
setupAccount(form);
// etc..
}
}
จากโค้ดดังกล่าว เห็นได้ชัดว่าตอนนี้เราจำเป็นต้องปรับใช้บริการ Java (micro) สองรายการ ได้แก่ Bank และ RiskCheck ด้วยเหตุนี้ เราจะมีกระบวนการ JVM สองกระบวนการที่ทำงานอยู่ นั่นคือทั้งหมดที่คุณต้องมีในการพัฒนาโปรเจ็กต์ไมโครเซอร์วิส Java เพียงสร้างและปรับใช้ไฟล์ที่มีขนาดเล็กกว่า (ไฟล์ .jar หรือ .war) แทนที่จะเป็นไฟล์ขนาดใหญ่ชิ้นเดียว คำตอบสำหรับคำถามนี้ยังไม่ชัดเจน: เราจะตัด Monolith ให้เป็นไมโครเซอร์วิสได้อย่างไร ชิ้นส่วนเหล่านี้ควรมีขนาดเล็กแค่ไหนจะกำหนดขนาดที่ถูกต้องได้อย่างไร? มาตรวจสอบกัน
สถาปัตยกรรมไมโครเซอร์วิส Java
ในทางปฏิบัติ บริษัทต่างๆ พัฒนาโครงการไมโครเซอร์วิสในรูปแบบต่างๆ วิธีการนี้ขึ้นอยู่กับว่าคุณกำลังพยายามเปลี่ยนเสาหินที่มีอยู่ให้เป็นโปรเจ็กต์ไมโครเซอร์วิสหรือเริ่มโปรเจ็กต์ตั้งแต่ต้นจากเสาหินไปจนถึงไมโครเซอร์วิส
แนวคิดที่สมเหตุสมผลที่สุดประการหนึ่งคือการแยกไมโครเซอร์วิสออกจากเสาหินที่มีอยู่ โปรดทราบว่าคำนำหน้า "micro" ในที่นี้ไม่ได้หมายความว่าบริการที่แยกออกมาจะมีขนาดเล็กจริงๆ ซึ่งไม่จำเป็นต้องเป็นเช่นนั้นเสมอไป ลองดูที่พื้นหลังทางทฤษฎีแนวคิด: แบ่งโมโนลิธออกเป็นไมโครเซอร์วิส
แนวทางไมโครเซอร์วิสสามารถนำไปใช้กับโปรเจ็กต์เดิมได้ และนั่นคือเหตุผล:- ส่วนใหญ่แล้วโครงการดังกล่าวจะรักษา/เปลี่ยนแปลง/ขยายได้ยาก
- ทุกคนตั้งแต่นักพัฒนาไปจนถึงผู้บริหารต่างก็ต้องการความเรียบง่าย
- คุณมีขอบเขตโดเมนที่ชัดเจน (ค่อนข้าง) ซึ่งหมายความว่าคุณทราบแน่ชัดว่าซอฟต์แวร์ของคุณควรทำอะไร
- ดังนั้นจึงสมเหตุสมผลที่จะแยกการประมวลผลข้อมูลผู้ใช้ (เช่น ชื่อ ที่อยู่ หมายเลขโทรศัพท์) ออกเป็นไมโครเซอร์วิส “การจัดการบัญชี” ที่แยกต่างหาก
- หรือ "Risk Checker Module" ที่กล่าวมาข้างต้นซึ่งจะตรวจสอบระดับความเสี่ยงของผู้ใช้และสามารถนำมาใช้กับโครงการอื่นๆ มากมาย หรือแม้แต่หน่วยงานของบริษัทก็ได้
- หรือโมดูลการออกใบแจ้งหนี้ที่ส่งใบแจ้งหนี้ในรูปแบบ PDF หรือทางไปรษณีย์
การนำแนวคิดไปปฏิบัติ: ให้คนอื่นทำ
วิธีการที่อธิบายไว้ข้างต้นดูดีบนกระดาษและไดอะแกรมคล้าย UML อย่างไรก็ตามทุกอย่างไม่ง่ายนัก การนำไปปฏิบัติจริงจำเป็นต้องมีการเตรียมการทางเทคนิคอย่างจริงจัง: ช่องว่างระหว่างความเข้าใจของเราว่าอะไรดีที่จะสกัดจากหินใหญ่ก้อนเดียวและกระบวนการสกัดนั้นมีมหาศาล โครงการระดับองค์กรส่วนใหญ่มาถึงขั้นที่นักพัฒนากลัวที่จะอัพเกรด Hibernate เวอร์ชัน 7 ปีเป็นรุ่นใหม่ ไลบรารีจะได้รับการอัปเดตตามไปด้วย แต่มีอันตรายอย่างแท้จริงที่จะทำลายบางสิ่ง ดังนั้นตอนนี้นักพัฒนาคนเดียวกันเหล่านั้นจึงต้องขุดค้นโค้ดรุ่นเก่าที่มีขอบเขตธุรกรรมฐานข้อมูลที่ไม่ชัดเจนและแยกไมโครเซอร์วิสที่มีการกำหนดไว้อย่างดี บ่อยครั้งปัญหานี้ซับซ้อนมากและไม่สามารถ "แก้ไข" บนไวท์บอร์ดหรือในการประชุมทางสถาปัตยกรรมได้ หากต้องการอ้างอิงถึงนักพัฒนา Twitter @simonbrown: ฉันจะพูดสิ่งนี้ซ้ำแล้วซ้ำเล่า... หากผู้คนไม่สามารถสร้างเสาหินได้อย่างถูกต้อง ไมโครเซอร์วิสก็ไม่ช่วยอะไร ไซมอน บราวน์โปรเจ็กต์ตั้งแต่เริ่มต้นโดยใช้สถาปัตยกรรมไมโครเซอร์วิส
ในกรณีของโปรเจ็กต์ Java ใหม่ จุดที่มีหมายเลขสามจุดจากส่วนก่อนหน้าจะดูแตกต่างออกไปเล็กน้อย:- คุณเริ่มต้นด้วยกระดานชนวนที่สะอาด ดังนั้นจึงไม่มี "สัมภาระ" ที่ต้องดูแลรักษา
- นักพัฒนาต้องการให้ทุกอย่างง่ายขึ้นในอนาคต
- ปัญหา: คุณมีภาพขอบเขตโดเมนที่คลุมเครือกว่ามาก: คุณไม่รู้ว่าซอฟต์แวร์ของคุณควรจะทำอะไร (คำใบ้: agile ;))
สถาปัตยกรรมไมโครเซอร์วิสทางเทคนิค
ประเด็นแรกดูเหมือนจะชัดเจนที่สุดสำหรับนักพัฒนา แต่ก็มีผู้ที่ท้อแท้อย่างยิ่งเช่นกัน Hadi Hariri แนะนำการปรับโครงสร้าง "Extract Microservice" ใน IntelliJ และถึงแม้ว่าตัวอย่างต่อไปนี้จะง่ายกว่ามาก แต่การใช้งานที่สังเกตได้ในโครงการจริง แต่น่าเสียดายที่ไม่ไกลเกินไป ก่อนไมโครเซอร์วิส@Service
class UserService {
public void register(User user) {
String email = user.getEmail();
String username = email.substring(0, email.indexOf("@"));
// ...
}
}
ด้วยไมโครเซอร์วิส Java สตริงย่อย
@Service
class UserService {
@Autowired
private HttpClient client;
public void register(User user) {
String email = user.getEmail();
//теперь вызываем substring microservice via http
String username = httpClient.send(substringRequest(email), responseHandler());
// ...
}
}
ดังนั้นคุณจึงสรุปการเรียกเมธอด Java ในการเรียก HTTP โดยไม่มีเหตุผลที่ชัดเจนในการทำเช่นนั้น อย่างไรก็ตาม เหตุผลหนึ่งก็คือ: ขาดประสบการณ์และพยายามบังคับใช้แนวทางไมโครเซอร์วิส Java คำแนะนำ: อย่าทำเช่นนี้.
สถาปัตยกรรมไมโครเซอร์วิสที่เน้นเวิร์กโฟลว์
แนวทางทั่วไปถัดไปคือการแบ่งไมโครเซอร์วิส Java ออกเป็นโมดูลตามเวิร์กโฟลว์ ตัวอย่างชีวิตจริง: ในเยอรมนี เมื่อคุณไปพบแพทย์ (สาธารณะ) เขาจะต้องบันทึกการมาของคุณในระบบ CRM ทางการแพทย์ของเขา ในการรับเงินจากการประกัน เขาจะส่งข้อมูลเกี่ยวกับการรักษาของคุณ (และการรักษาผู้ป่วยรายอื่น) ไปยังตัวกลางผ่าน XML นายหน้าจะดูไฟล์ XML นี้และ (แบบง่าย):- จะตรวจสอบว่าได้รับไฟล์ XML ที่ถูกต้องหรือไม่
- มันจะตรวจสอบความน่าเชื่อถือของขั้นตอน: เช่นเด็กอายุ 1 ขวบที่ได้รับการทำความสะอาดฟันสามครั้งจากนรีแพทย์ในวันเดียวดูค่อนข้างน่าสงสัย
- จะรวม XML เข้ากับข้อมูลราชการอื่นๆ
- จะส่งต่อไฟล์ XML ไปยังบริษัทประกันภัยเพื่อเริ่มการชำระเงิน
- และจะส่งผลการตรวจไปให้แพทย์โดยระบุข้อความว่า “ความสำเร็จ” หรือ “โปรดส่งบันทึกนี้อีกครั้งทันทีที่เหมาะสม”
- จำเป็นต้องปรับใช้หกแอปพลิเคชันเพื่อประมวลผลไฟล์ XML หนึ่งไฟล์หรือไม่
- ไมโครเซอร์วิสเหล่านี้เป็นอิสระจากกันจริง ๆ หรือไม่? สามารถใช้งานแยกจากกันได้หรือไม่? ด้วยเวอร์ชันและรูปแบบ API ที่แตกต่างกัน
- ไมโครเซอร์วิสด้านความน่าเชื่อถือจะทำอย่างไรหากไมโครเซอร์วิสการยืนยันไม่ทำงาน ระบบยังทำงานอยู่หรือไม่?
- ไมโครเซอร์วิสเหล่านี้ใช้ฐานข้อมูลเดียวกันหรือไม่ (แน่นอนว่าพวกเขาต้องการข้อมูลทั่วไปในตาราง DB) หรือแต่ละบริการมีของตัวเองหรือไม่
- …และอีกมากมาย
- คุณไม่จำเป็นต้องปรับใช้แอปพลิเคชันเดียว แต่ต้องมีอย่างน้อยหกแอปพลิเคชัน
- คุณอาจต้องปรับใช้หลายฐานข้อมูล ขึ้นอยู่กับว่าคุณต้องการเจาะลึกสถาปัตยกรรมไมโครเซอร์วิสไปไกลแค่ไหน
- คุณต้องตรวจสอบให้แน่ใจว่าแต่ละระบบออนไลน์และทำงานอย่างถูกต้อง
- คุณต้องตรวจสอบให้แน่ใจว่าการโทรระหว่างไมโครเซอร์วิสมีความยืดหยุ่นอย่างแท้จริง (ดูวิธีทำให้ไมโครเซอร์วิส Java มีความยืดหยุ่น)
- และทุกอย่างอื่นๆ ที่การตั้งค่านี้บอกเป็นนัย ตั้งแต่การตั้งค่าการพัฒนาท้องถิ่นไปจนถึงการทดสอบการรวมระบบ
- หากคุณไม่ใช่ Netflix (อาจเป็นไปได้ว่าคุณไม่ใช่ Netflix)...
- เว้นแต่ว่าคุณมีทักษะการทำงานที่แข็งแกร่งเป็นพิเศษโดยที่คุณเปิดสภาพแวดล้อมการพัฒนาและมันเรียกลิงแห่งความโกลาหลที่จะทำลายฐานข้อมูลการผลิตของคุณซึ่งสามารถกู้คืนได้อย่างง่ายดายใน 5 วินาที
- หรือคุณรู้สึกเหมือน @monzo และเต็มใจที่จะลองใช้ไมโครเซอร์วิส 1,500 รายการเพียงเพราะคุณทำได้
GO TO FULL VERSION