วิธีที่เหมาะสมในการซิงโครไนซ์ข้อมูลข้าม microservices คืออะไร


19

ฉันค่อนข้างใหม่กับสถาปัตยกรรมไมโครเซอร์วิส เรามีเว็บแอปพลิเคชันขนาดปานกลางและฉันชั่งน้ำหนักข้อดีและข้อเสียของการแบ่งมันออกเป็น microservices แทนระบบเสาหินที่เราได้ก้าวไปข้างหน้า

เท่าที่ฉันเข้าใจพิจารณา microservices AและBแต่ละรายการนั้นอาศัยชุดย่อยของข้อมูลที่อีกฝ่ายมี หากข้อความถูกโพสต์โดยAบอกว่ามีบางอย่างเปลี่ยนแปลงBสามารถใช้ข้อความนั้นและทำซ้ำสำเนาของAข้อมูลในเครื่องและใช้สิ่งนั้นเพื่อทำสิ่งที่Bต้องทำ

อย่างไรก็ตามจะเกิดอะไรขึ้นถ้าBลงไป / ล้มเหลวและหลังจากนั้นไม่นานก็กลับมาอีกครั้ง ในช่วงเวลาดังกล่าวAได้เผยแพร่ข้อความอีกสองข้อความ จะBทราบวิธีการอัปเดตAข้อมูลในเครื่องได้อย่างไร?

จริงอยู่ถ้าBเป็นผู้บริโภคAคิวเพียงคนเดียวก็สามารถเริ่มอ่านได้เมื่อกลับมาออนไลน์ แต่จะเกิดอะไรขึ้นถ้ามีผู้บริโภครายอื่นของคิวนั้นและข้อความเหล่านั้นถูกบริโภค?

เป็นตัวอย่างที่ชัดเจนยิ่งขึ้นถ้าUsersบริการมีการปรับปรุงที่อยู่อีเมลในขณะที่บริการBillingไมโครซอฟต์ล่มหากบริการBillingไมโครซอฟท์กลับมาอีกครั้งจะรู้ได้อย่างไรว่าอีเมลนั้นได้รับการปรับปรุงแล้ว?

เมื่อ microservices กลับมารายการออกอากาศจะพูดว่า "เฮ้ฉันสำรองข้อมูลเอาข้อมูลปัจจุบันของคุณทั้งหมดให้ฉันหรือเปล่า"

โดยทั่วไปแล้ววิธีปฏิบัติทางอุตสาหกรรมที่ดีที่สุดสำหรับการซิงโครไนซ์ข้อมูลคืออะไร


1
เพื่อหลีกเลี่ยงมันเมื่อทำได้
Telastyn

1
ทำไมOrdersต้องรู้อะไรเกี่ยวกับUsers?
kdgregory

มันเป็นเพียงตัวอย่าง แทนที่ทั้งสองด้วยสิ่งที่คุณต้องการที่เหมาะสม
28618 Noblelerare

การกำหนดเส้นทาง fan out จะช่วยแก้ปัญหาข้อความ 'ของคุณถูกใช้โดยคนอื่น' แต่จริงๆแล้วมันไม่ชัดเจนในสิ่งที่คุณพยายามที่จะบรรลุ
Ewan

@Ewan ฉันได้อัปเดตโพสต์ดั้งเดิมของฉันเพื่ออธิบายสิ่งที่ฉันพยายามถามได้ดีขึ้น
noblerare

คำตอบ:


5

ฉันจะท้าทายความคิดทั้งหมดของคุณในการ "ผลักดันข้อมูลไปยังไมโครไซต์อื่นทั้งหมด"

โดยปกติหากบริการเรียกเก็บเงินต้องการที่อยู่อีเมลก็จะถามบริการที่อยู่สำหรับที่อยู่อีเมลของลูกค้าที่เฉพาะเจาะจง มันไม่จำเป็นต้องเก็บสำเนาของข้อมูลที่อยู่ทั้งหมดและจะไม่ได้รับแจ้งหากมีการเปลี่ยนแปลงใด ๆ มันเพียงแค่ถามและรับคำตอบจากข้อมูลล่าสุด


ฉันคิดว่าคำตอบนี้ถูกต้องแน่นอน มันกำจัดปัญหามากมายที่เกี่ยวข้องกับการซิงโครไนซ์ อันที่จริงฉันกำลังดูรหัสในตอนนี้ที่มีปัญหาดังกล่าวเพราะบริการต่าง ๆ กำลังเก็บสำเนาข้อมูลและมีปัญหาการซิงค์
DaveG

2
ขอบคุณสำหรับคำตอบ. เหตุใดจึงมีความจำเป็นสำหรับรุ่นผับ / ย่อยและคิวข้อความ หากเราพยายามที่จะ "ดึง" แทนที่จะเป็นข้อมูล "ดัน" เรากังวลเกี่ยวกับความล่าช้าในการให้บริการ
noblerare

AFAIK บริการของคุณไม่จำเป็นต้องตอบสนองทันทีหากมีอะไรเปลี่ยนแปลง (เช่นในผับ / ย่อย) แต่บางครั้งก็ต้องการข้อมูล จากนั้นฉันก็จะดึงมัน หากคุณกังวลเกี่ยวกับเวลาแฝงคุณสามารถแคชข้อมูลได้ แต่สิ่งนี้จะเกิดขึ้นอีกครั้งโดยไม่รู้ว่าข้อมูลนั้นเป็นข้อมูลล่าสุดหรือไม่ หากไฟล์ของคุณมีขนาดใหญ่คุณสามารถถามว่ามีอะไรเปลี่ยนแปลงหรือไม่ก่อนที่จะดึงบางสิ่งบางอย่างอีกครั้ง
J. Fabian Meier

โปรดทราบว่าโซลูชันนี้มาพร้อมกับบริการเชื่อมต่อที่แน่นหนาซึ่งหมายความว่าที่อยู่อีเมลจะไม่สามารถใช้งานได้เมื่อบริการผู้ใช้ไม่พร้อมใช้งาน หนึ่งในแนวคิดเริ่มต้นของการแยกการบริการเพื่อเริ่มต้นเพื่อให้สามารถปรับใช้ได้อย่างอิสระปรับขนาดได้เป็นต้นหากบริการทั้งหมดสื่อสารโดยตรงกับกันและกันโดยไม่มีแคชหรือรับประกันความพร้อมใช้งานสูงเมื่อระบบหนึ่งหยุดทำงานพวกเขาทั้งหมด ลงข้างล่าง.
dukethrash

@dukethrash จากนั้นทำให้พร้อมใช้งานสูง
J. Fabian Meier

5

หลังจากทำบิตการวิจัยมากขึ้นฉัน stumbled เมื่อนี้บทความจากที่ผมได้ดึงคำพูดบางส่วนออกจากที่ฉันคิดว่าจะเป็นประโยชน์สำหรับสิ่งที่ฉันต้องการจะประสบความสำเร็จ (และสำหรับผู้อ่านใด ๆ ในอนาคต) นี่เป็นวิธีนำรูปแบบการเขียนโปรแกรมปฏิกิริยามาใช้กับรูปแบบการเขียนโปรแกรมที่จำเป็น

จัดกิจกรรมจัดหา

แนวคิดในที่นี้คือการนำเสนอการเปลี่ยนแปลงสถานะของแอปพลิเคชันทุกรูปแบบในเหตุการณ์ที่ไม่เปลี่ยนรูป กิจกรรมจะถูกจัดเก็บในรูปแบบบันทึกหรือบันทึกตามที่เกิดขึ้น (เรียกอีกอย่างว่า 'ที่จัดเก็บกิจกรรม') พวกเขายังสามารถสอบถามและจัดเก็บอย่างไม่มีกำหนดโดยมีวัตถุประสงค์เพื่อแสดงให้เห็นว่าสถานะของแอปพลิเคชันโดยรวมมีการพัฒนาอยู่ตลอดเวลา

สิ่งนี้จะช่วยให้ประสบความสำเร็จคือว่าถ้า MICROSERVICE ลงไปยังกิจกรรมอื่น ๆ ที่เกี่ยวข้องกับการที่มันจะได้รับการตีพิมพ์และเหตุการณ์ที่เกิดขึ้นมีการบริโภคโดยการพูด, กรณีอื่น ๆ ของ MICROSERVICE ว่าเมื่อ MICROSERVICE ที่กลับขึ้นมาก็สามารถอ้างถึงนี้event storeเพื่อดึงข้อมูลทั้งหมด เหตุการณ์ที่พลาดไปในช่วงเวลานั้นลดลง

Apache Kafka รับหน้าที่เป็นนายหน้า

พิจารณาการใช้ Apache Kafka ซึ่งสามารถจัดเก็บและส่งเหตุการณ์นับพันต่อวินาทีและมีกลไกการจำลองแบบและการยอมรับข้อบกพร่องในตัว มีที่เก็บถาวรของเหตุการณ์ที่สามารถเก็บไว้ในดิสก์ได้ตลอดเวลาและบริโภคได้ตลอดเวลา (แต่ไม่ได้ลบ) จากหัวข้อ (คิวแฟนซีของ Kafka) ถูกส่งไปยัง

จากนั้นเหตุการณ์จะถูกกำหนด offsets ที่ระบุอย่างไม่เจาะจงในหัวข้อ - Kafka สามารถจัดการ offsets เองได้อย่างง่ายดายให้ "อย่างมากที่สุดครั้งเดียว" หรือ "อย่างน้อยหนึ่งครั้ง" ความหมายของการจัดส่ง แต่พวกเขายังสามารถเจรจาเมื่อผู้บริโภคเหตุการณ์เข้าร่วมหัวข้อ อนุญาตให้ microservices เริ่มต้นการบริโภคกิจกรรมจากที่ใดก็ได้ตามเวลาที่กำหนด - โดยปกติแล้วผู้บริโภคจะออกไป หากการชดเชยเหตุการณ์ที่ใช้ล่าสุดถูกเก็บรักษาไว้เป็นธุรกรรมในหน่วยเก็บข้อมูลภายในของเซอร์วิสเมื่อการดำเนินการเสร็จสมบูรณ์แล้วการชดเชยนั้นสามารถนำมาใช้เพื่อให้เกิดความหมายของการจัดส่งเหตุการณ์

ในความเป็นจริงเมื่อผู้บริโภคระบุตัวตนให้คาฟคาคาฟคาจะบันทึกข้อความที่ส่งไปยังผู้บริโภครายใดเพื่อที่จะไม่ให้บริการมันอีก

โศกนาฏกรรม

สำหรับ usecases ที่ซับซ้อนมากขึ้นซึ่งการสื่อสารระหว่างบริการต่าง ๆ เป็นสิ่งจำเป็นจริง ๆ ความรับผิดชอบในการทำให้เสร็จสิ้น usecase จะต้องได้รับการยอมรับอย่างดี - usecase นั้นจะกระจายอำนาจและเสร็จสิ้นก็ต่อเมื่อบริการทั้งหมดที่เกี่ยวข้องยอมรับว่างานของพวกเขาสำเร็จ และมาตรการแก้ไขต้องถูกกระตุ้นให้ย้อนกลับสถานะท้องถิ่นที่ไม่ถูกต้องใด ๆ

นี่คือเมื่อเทพนิยายเข้ามาเล่น Saga คือลำดับของธุรกรรมในท้องถิ่น ธุรกรรมในท้องถิ่นแต่ละรายการจะอัพเดตฐานข้อมูลและเผยแพร่ข้อความหรือเหตุการณ์เพื่อกระตุ้นการทำธุรกรรมในท้องถิ่นครั้งต่อไปใน saga หากการทำธุรกรรมในท้องถิ่นล้มเหลวเนื่องจากเป็นการฝ่าฝืนกฎทางธุรกิจ Saga จะดำเนินการตามลำดับของการชดเชยธุรกรรมที่ยกเลิกการเปลี่ยนแปลงที่เกิดขึ้นจากการทำธุรกรรมในท้องถิ่นก่อนหน้านี้ อ่านนี้สำหรับข้อมูลเพิ่มเติม


ฉันยังไม่เข้าใจว่าทำไมคุณต้องการสร้างโครงสร้างที่ซับซ้อนเช่นนี้ โดยทั่วไปแล้วจะง่ายกว่ามากหากบริการแต่ละอย่างเก็บข้อมูลของตนเองและมอบให้กับบริการอื่น ๆ เมื่อมีการร้องขอ
J. Fabian Meier

^ แต่มันจะลดความพร้อมใช้งานของระบบ โครงสร้างที่ซับซ้อนอาจได้รับการรับประกันหากต้องการความยืดหยุ่นสูง
avmohan

1

แม้ว่าฉันจะมาสายฉันก็จะเอา 2 เซ็นต์มาโต้แย้งเพราะฉันคิดว่ามันเป็นประเด็นสำคัญเมื่อคุณต้องการประเมิน e ออกแบบสถาปัตยกรรม microservices ที่ขับเคลื่อนด้วยเหตุการณ์ ไมโครเซอร์วิสแต่ละคนรู้อย่างแน่นอนว่าเหตุการณ์ใดส่งผลกระทบต่อสถานะของมันและสามารถรอได้ เมื่อ microservice ไม่สามารถใช้ได้ควรมีส่วนประกอบที่เก็บข้อความที่ต้องการจาก microservice ที่ล้มเหลวจนกว่าจะไม่สามารถ "กิน" ข้อความเหล่านั้น นี่คือรูปแบบ "ผู้ผลิต / ผู้บริโภค" และไม่ใช่ "เผยแพร่ / สมัครสมาชิก" โบรกเกอร์ข้อความ (เช่น Kafka, RabbitMQ, ActiveMQ และอื่น ๆ ) มักเป็นวิธีที่ดีที่สุดในการบรรลุพฤติกรรมนี้ (เว้นแต่ว่าคุณไม่ได้ดำเนินการบางอย่างที่แตกต่างกันเช่นการจัดหากิจกรรม) โดยมีการจัดคิวแบบถาวรและกลไก ack / nack

ตอนนี้ microservice รู้ว่ามีการส่งข้อความในที่สุด แต่ไม่เพียงพอ: วิธีใดที่คาดว่าจะส่งข้อความเดียว มันสามารถจัดการการส่งมอบสำเนาหลายชุดของการแจ้งเตือนเหตุการณ์เดียวกันได้หรือไม่ นี่เป็นเรื่องของความหมายของการจัดส่ง (อย่างน้อยหนึ่งครั้งหนึ่งครั้ง)

ความคิดสุดท้าย):

  1. เมื่อคุณเพิ่มบริการไมโครสโคปในสถาปัตยกรรมของคุณที่ต้องใช้กิจกรรมจากผู้อื่นคุณต้องทำการซิงค์ครั้งแรก

  2. แม้นายหน้าจะล้มเหลวในกรณีนี้ข้อความจะหายไป

สำหรับทั้งสองสถานการณ์มันจะมีประโยชน์ที่จะมีกลไกง่าย ๆ ในการเติมความชุ่มชื้นให้คุณอีกครั้ง อาจเป็น REST API หรือสคริปต์ที่ส่ง messsages แต่สิ่งที่สำคัญที่สุดคือการมีงานบำรุงรักษา


0

คุณสามารถแทนที่คิวเหตุการณ์ปกติด้วยโมเดลผู้เผยแพร่ / ผู้สมัครสมาชิกโดยที่Aเซอร์วิสเผยแพร่ข้อความใหม่ของหัวข้อTและBประเภทของ microservices ที่จะสมัครสมาชิกในหัวข้อเดียวกัน

Bจะเป็นการดีเลิศที่จะเป็นผู้ไร้สัญชาติบริการและมันจะใช้ประโยชน์จากการคงอยู่บริการเช่นว่าBบริการที่ล้มเหลวจะถูกแทนที่ด้วยการวางไข่หนึ่งหรือหลายBกรณีบริการอินสแตนซ์เพื่อดำเนินการต่อการทำงานของมัน


0

หากข้อความถูกโพสต์โดย A โดยบอกว่ามีบางอย่างเปลี่ยนแปลง B สามารถใช้ข้อความนั้นและทำซ้ำข้อมูลท้องถิ่นของ A และใช้สิ่งนั้นเพื่อทำสิ่งที่ B ต้องการทำ

หากคุณต้องการให้ B สามารถเข้าถึงข้อมูลภายในของ A คุณควรให้สิทธิ์เข้าถึงฐานข้อมูลภายในของ A

อย่างไรก็ตามคุณไม่ควรทำเช่นนั้นจุดรวมของสถาปัตยกรรมเชิงบริการคือเซอร์วิส B ไม่สามารถมองเห็นสถานะภายในของเซอร์วิส A และถูก จำกัด ให้ทำการร้องขอผ่าน REST API (และในทางกลับกัน)

ในกรณีของคุณคุณอาจมีบริการข้อมูลผู้ใช้ซึ่งมีหน้าที่จัดเก็บข้อมูลผู้ใช้ทั้งหมด บริการอื่น ๆ ที่ต้องการใช้ข้อมูลนั้นร้องขอเฉพาะเมื่อพวกเขาต้องการและไม่เก็บสำเนาเฉพาะที่ (btw. ซึ่งมีประโยชน์จริง ๆ ถ้าคุณคิดเกี่ยวกับการปฏิบัติตาม GDPR) บริการข้อมูลผู้ใช้สามารถรองรับการทำงาน CRUD อย่างง่ายเช่น "สร้างผู้ใช้ใหม่" หรือ "เปลี่ยนชื่อสำหรับ user_id 23" หรืออาจมีการดำเนินการที่ซับซ้อนยิ่งขึ้น "ค้นหาผู้ใช้มาตรฐานทั้งหมดที่มีวันเกิดขึ้นในอีก 2 สัปดาห์ข้างหน้า สถานะการทดลองใช้ระดับพรีเมียม " ตอนนี้เมื่อบริการการเรียกเก็บเงินของคุณต้องการส่งอีเมลไปยังผู้ใช้ 42 ก็จะถามบริการข้อมูลผู้ใช้ "ที่อยู่อีเมลสำหรับ user_id 42" คืออะไรใช้ข้อมูลภายในที่มีข้อมูลการเรียกเก็บเงินทั้งหมดเพื่อสร้างอีเมลแล้วอาจส่ง ที่อยู่อีเมลและเนื้อหาไปยังเซิร์ฟเวอร์อีเมล

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.