ย้ายข้อมูลไปยังโซลูชัน XMPP ที่กำหนดเองได้สำเร็จ
เผยแพร่แล้ว: 2019-04-08ฉันจะคุยกับคุณเกี่ยวกับความท้าทายที่เราเผชิญในการย้ายจากการแชทของบุคคลที่สามไปยังโซลูชันการส่งข้อความตาม XMPP แบบกำหนดเองสำหรับลูกค้าของเรา Forward Health ซึ่งเป็นโซลูชันการดูแลสุขภาพการส่งข้อความในสหราชอาณาจักร บทความนี้จะกล่าวถึงเหตุผลในการโยกย้าย ความคาดหวังของเรากับความเป็นจริงของการใช้งาน และความท้าทายในการสร้างฟังก์ชันเพิ่มเติม
ที่เราเริ่มต้น
ลูกค้าของเรา Forward Health ต้องการสร้างแอปพลิเคชันการสื่อสารเคลื่อนที่สำหรับเจ้าหน้าที่ทางการแพทย์ในสหราชอาณาจักร รวมถึงฟังก์ชันการแชท ในการเริ่มต้นพวกเขาต้องการแสดงผลิตภัณฑ์ที่ใช้งานได้อย่างรวดเร็ว ในขณะเดียวกัน การส่งข้อความจะต้องมีความน่าเชื่อถือ แข็งแกร่ง และสามารถส่งข้อมูลผู้ป่วยที่ละเอียดอ่อนได้อย่างปลอดภัย เพื่อให้บรรลุสิ่งนี้ เราจึงตัดสินใจใช้หนึ่งในโซลูชันของบุคคลที่สามที่มีให้สำหรับฟังก์ชันการแชท
ฟังก์ชันแชทไม่ใช่เรื่องเล็กน้อย โดยเฉพาะอย่างยิ่งเมื่อมีวัตถุประสงค์เพื่อสนับสนุนอุตสาหกรรมการดูแลสุขภาพ เมื่อแอปเติบโตขึ้น เราพบกรณีของ Edge และข้อบกพร่องด้านไลบรารีที่บุคคลที่สามไม่เต็มใจที่จะแก้ไขเพิ่มเติม นอกจากนี้ Forward Health ต้องการเพิ่มคุณสมบัติใหม่ที่ไม่ได้รับการสนับสนุนจากไลบรารีของบุคคลที่สาม การเปลี่ยนไปใช้โซลูชันที่กำหนดเองเป็นขั้นตอนต่อไป
นั่นคือตอนที่เราเริ่มทำงานกับ MongooseIM MIM เป็นโซลูชันโอเพ่นซอร์สที่ใช้โปรโตคอล XMPP ที่เป็นที่ยอมรับ เราทำงานร่วมกับบริษัทภายนอก Erlang Solutions Limited เพื่อตั้งค่าแบ็กเอนด์ของเราและให้การสนับสนุนด้วยการใช้โซลูชันที่กำหนดเอง
ในตอนแรก ทุกอย่างเกี่ยวกับการส่งข้อความดูแตกต่างออกไป ก่อนหน้านี้ เราตอบสนองทุกความต้องการของเราโดย SDK และ REST API ตอนนี้ เมื่อใช้ MongooseIM เราต้องใช้เวลาสักพักเพื่อทำความเข้าใจธรรมชาติของ XMPP และใช้ SDK ของเราเอง ปรากฎว่าเซิร์ฟเวอร์ XMPP "กระดูกเปล่า" ส่งผ่าน stanzas (ข้อความ XML) ระหว่างไคลเอนต์ในแบบเรียลไทม์เท่านั้น บทอาจมีหลายประเภท เช่น ข้อความแชท การแสดงตน คำขอ และการตอบกลับตามปกติ คุณสามารถเพิ่มโมดูลต่างๆ ลงในเซิร์ฟเวอร์ได้หลากหลาย เช่น จัดเก็บข้อความ และให้ลูกค้าสอบถาม
ในฝั่งไคลเอ็นต์ (Android, iOS) มี SDK ระดับต่ำอยู่บ้าง น่าเสียดายที่พวกเขาทำหน้าที่เป็นเพียงเลเยอร์ที่เปิดใช้งานการสื่อสารกับ MongooseIM และโมดูลที่เสียบได้บางส่วนที่เรียกว่า XEPs (XMPP Extension Protocol รับผิดชอบในการส่งการแจ้งเตือนแบบพุชสำหรับทุกข้อความ) สถาปัตยกรรมทั้งหมดสำหรับการจัดการข้อความ การจัดเก็บและการสืบค้นข้อความ จะต้องดำเนินการโดยทีมงานของเรา
สิ่งที่ช่วยเราได้คือ ห้องสมุดบุคคลที่สาม ที่เราใช้ก่อนหน้านี้ มันมี API ที่ผ่านการคิดมาเป็นอย่างดี ดังนั้นเราจึงทำให้โซลูชันของเราทำงานในลักษณะเดียวกัน เราแยกโค้ดเฉพาะของ XMPP ออกเป็น SDK ภายในของเราด้วยอินเทอร์เฟซที่สอดคล้องกับโค้ดจากโซลูชันก่อนหน้านี้ ส่งผลให้มีการเปลี่ยนแปลงเพียงเล็กน้อยในรหัสแอปพลิเคชันของเราหลังการย้ายข้อมูล
ระหว่างการใช้งาน MongooseIM เรารู้สึกประหลาดใจหลายครั้งกับองค์ประกอบที่เราคิดว่าจะเป็นมาตรฐาน แต่ไม่มีให้เราใช้ แม้แต่ XEP
การใช้คุณสมบัติหลักของการแชทบน XMPP
การประทับเวลา
คุณอาจคิดว่าการประทับเวลานั้นเรียบง่ายเหมือนที่เราทำเหมือน “ฉันได้รับข้อความ ฉันแสดงสิ่งนี้บน UI พร้อมการประทับเวลา” ไม่ ไม่ง่ายอย่างนั้น ตามค่าเริ่มต้น บทข้อความไม่มีฟิลด์การประทับเวลา โชคดีสำหรับทีมของเรา XMPP เป็นโปรโตคอลที่ขยายได้ง่าย ในส่วนแบ็กเอนด์ เราได้นำคุณลักษณะที่กำหนดเองมาใช้ โดยเพิ่มการประทับเวลาให้กับทุกข้อความที่ส่งผ่านเซิร์ฟเวอร์ MongooseIM จากนั้นผู้รับจะมีการประทับเวลาแนบไปกับข้อความ
เหตุใดผู้ส่งจึงเพิ่มการประทับเวลาด้วยตนเองไม่ได้ เราไม่รู้ว่าพวกเขาตั้งเวลาโทรศัพท์ไว้ถูกต้องหรือเปล่า
เหตุใดจึงไม่มี XEP สำหรับสิ่งนั้น อาจเป็นเพราะ XMPP เป็นโปรโตคอลแบบเรียลไทม์ ดังนั้นตามหลักทฤษฎีแล้ว ทุกข้อความที่ส่งจะได้รับทันที
แก้ไข: ดังที่ Florian Schmaus ชี้ให้เห็นว่า: "มีอยู่จริงหนึ่งแม้ว่าจะพลาดได้ง่ายเนื่องจากชื่อที่สับสน: XEP-0203: การจัดส่งล่าช้า" จะเพิ่มการประทับเวลาให้กับข้อความก็ต่อเมื่อการจัดส่งล่าช้า มิฉะนั้น ข้อความถูกส่งไปเมื่อสักครู่นี้
ข้อความออฟไลน์
เมื่อผู้ใช้ทั้งสองลงชื่อเข้าใช้แอปพลิเคชัน พวกเขาสามารถส่งข้อความถึงกันแบบเรียลไทม์ แต่ถ้าหนึ่งในนั้นออฟไลน์อยู่ล่ะ คำตอบอย่างรวดเร็วคือ: ข้อความจะต้องถูกบัฟเฟอร์ในแบ็กเอนด์ คุณลักษณะข้อความออฟไลน์จะจัดการงานนี้และส่งบทที่บัฟเฟอร์ทั้งหมดไปยังผู้ใช้เมื่อพวกเขากลับเข้าสู่ระบบ
แต่แล้วมีคำถามหลายข้อเกิดขึ้น:
- ข้อความเหล่านี้ควรบัฟเฟอร์นานเท่าใด
- มีกี่คน?
- ควรส่งใหม่หลังจากเข้าสู่ระบบอีกครั้งหรือไม่ แต่มันจะทำให้ลูกค้าท่วมท้นด้วยข้อความใช่ไหม
- จะเกิดอะไรขึ้นหากผู้ใช้เข้าสู่ระบบแต่ไม่เข้าสู่การแชทด้วยข้อความใหม่ พวกเขาทั้งหมดจะหายไป?
- จะเกิดอะไรขึ้นหากผู้ใช้เข้าสู่ระบบบนอุปกรณ์หลายเครื่อง
เห็นได้ชัดว่าฟีเจอร์ข้อความออฟไลน์สามารถส่งข้อความไปยังอุปกรณ์เครื่องแรกเพื่อกลับมาออนไลน์ได้เท่านั้น จากนั้นข้อความเหล่านั้นจะสูญหายไปสำหรับอุปกรณ์อื่นๆ ทั้งหมด เราตัดสินใจยกเลิกคุณลักษณะนี้ และจัดเก็บข้อความบนแบ็กเอนด์ XMPP ด้วยวิธีที่ต่างออกไป

การจัดการที่เก็บข้อความ (MAM)
MAM เป็นที่เก็บข้อมูลบนเซิร์ฟเวอร์สำหรับข้อความ เมื่อไคลเอนต์เข้าสู่ระบบ พวกเขาสามารถสอบถามเซิร์ฟเวอร์สำหรับข้อความ คุณสามารถสอบถามตามหน้า คุณสามารถสอบถามตามวันที่ มีความยืดหยุ่น — คุณยังสามารถค้นหาหน้าก่อนหรือหลังข้อความด้วย ID เฉพาะ เพิ่มตัวกรองสำหรับข้อความจากการสนทนาที่แน่นอน
แต่นี่คือการจับ ข้อความแชทปกติจะถูกเก็บไว้ในข้อความ MAM ซึ่งมี ID เฉพาะของตัวเอง เมื่อผู้ใช้ได้รับข้อความแชทในสตรีม ข้อความนั้นไม่มี MAM ID พวกเขาต้องสอบถาม MAM เพื่อรับมัน
การดึงข้อมูลจาก MAM เป็นคำขอของเครือข่าย ซึ่งหมายความว่าอาจใช้เวลานานพอสมควร เมื่อผู้ใช้เข้าสู่แชท พวกเขาต้องการเห็นข้อความทันที ดังนั้นเราจึงต้องการ ฐานข้อมูลท้องถิ่น
เมื่อผู้ใช้ได้รับข้อความในสตรีม (ข้อความออนไลน์) เราจะบันทึกลงในฐานข้อมูลท้องถิ่นและแสดงให้ผู้ใช้เห็น ด้วยวิธีนี้ เราจะแสดงข้อความที่มาถึงผู้ใช้อย่างรวดเร็วตามเวลาจริง
นอกจากนี้ ทุกครั้งที่พวกเขาเข้าสู่หน้าจอแชท เราจะดาวน์โหลดข้อความทั้งหมดจากตอนนี้ไปยังข้อความ MAM ใหม่ล่าสุดที่จัดเก็บไว้ในฐานข้อมูลในเครื่องสำหรับการสนทนานั้น และใส่ลงในฐานข้อมูล โดยไม่สนใจข้อความที่ซ้ำกัน
นี่คือวิธีที่เราจัดการกับการจัดเก็บข้อความเก่า นอกจากนี้ เรามั่นใจว่าในฐานข้อมูลมีชุดข้อความที่สมบูรณ์สำหรับการสนทนาเฉพาะระหว่างข้อความแรกและข้อความสุดท้ายจาก MAM
เพื่อติดตามข้อความที่ดาวน์โหลดจาก MAM เราได้เพิ่มคุณสมบัติสองรายการในเอนทิตีการสนทนา:
- รหัส MAM ของข้อความ MAM ใหม่ล่าสุดในฐานข้อมูล
- รหัส MAM ของข้อความ MAM ที่เก่าที่สุดในฐานข้อมูล
การจัดการชุดข้อความ MAM ที่แตกเป็นเสี่ยงๆ ในฐานข้อมูลภายในเครื่องจะมีปัญหาอย่างมาก
นอกจากนี้ การมีทั้งสองคุณสมบัตินี้สำหรับทุกการสนทนาช่วยให้เราสามารถจัดเก็บข้อความแชทปกติในฐานข้อมูลโดยไม่สนใจ wrapper — ข้อความ MAM และเมื่อผู้ใช้เข้าสู่แชท เราสามารถแสดงข้อความล่าสุดจากฐานข้อมูลและดึงข้อความที่หายไปจาก MAM ในพื้นหลัง
กล่องจดหมาย
แอปที่ใช้แชททุกแอปต้องมีหน้าจอที่มีรายการแชท ซึ่งคุณจะเห็นชื่อ ข้อความล่าสุด และจำนวนข้อความที่ยังไม่ได้อ่าน มันต้องมีทางออก!
อันที่จริง ไม่มี... มีบางอย่างที่เรียกว่าบัญชีรายชื่อ — มันสามารถเก็บรายชื่อผู้ใช้ที่แท็กเป็น "เพื่อน" ได้ ขออภัย ไม่มีข้อความสุดท้ายหรือจำนวนข้อความที่ยังไม่ได้อ่านแนบมากับพวกเขา แน่นอน คุณสามารถรับข้อมูลที่จำเป็นจากส่วนหลังเป็นส่วนๆ ตอนแรกเราอยากจะทำแบบนั้น แต่จะทำได้ช้าและซับซ้อนกว่าจะทำได้ นั่นคือตอนที่เราเริ่มทำงานกับ Erlang Solutions ในคุณลักษณะ Inbox ซึ่งกำลังดำเนินการไปสู่โอเพ่นซอร์สด้วย
เมื่อผู้ใช้เชื่อมต่อกับแบ็กเอนด์ XMPP แอปจะดึงกล่องจดหมาย ซึ่งมีการสนทนาทั้งหมดของผู้ใช้รายนั้น ทั้งการแชทแบบตัวต่อตัวและแบบทีม แต่ละคนมีข้อความสุดท้ายแนบอยู่และจำนวนข้อความที่ยังไม่ได้อ่าน แอปพลิเคชันจะบันทึกกล่องจดหมายเข้าทั้งหมดไปยังฐานข้อมูลในเครื่อง เมื่อผู้ใช้อยู่ในแอปและมีข้อความใหม่เข้ามา เราจะอัปเดตสถานะกล่องจดหมายในเครื่อง ด้วยวิธีนี้ แอปจึงไม่จำเป็นต้องดึงกล่องจดหมายสำหรับข้อความใหม่ทุกข้อความ
สรุป
โซลูชันการแชทของบริษัทอื่นบางรายการมีความเป็นนามธรรมในระดับสูง ไม่เป็นไรถ้าคุณต้องการสร้างแอปพลิเคชันแชทแบบง่ายๆ การนำโซลูชันที่ใช้ XMPP ของเราไปใช้ในแอป Forward ทำให้เราสามารถเข้าถึงระดับต่ำได้ดีขึ้นมาก ซึ่งทำให้การแก้ปัญหาง่ายขึ้นมาก แน่นอนว่าต้องใช้เวลาพอสมควร แต่ตอนนี้เราทราบแล้วว่าเราสามารถจัดเตรียมคุณลักษณะที่กำหนดเองเพื่อช่วยให้แพทย์ในสหราชอาณาจักรสื่อสารในลักษณะที่ปลอดภัยและง่ายดายซึ่งได้รับการอนุมัติจาก NHS
การส่งข้อความเป็นเรื่องเกี่ยวกับการสื่อสารแบบเรียลไทม์ที่มีประสิทธิภาพสูง เมื่อเปลี่ยนไปใช้ MIM เราสามารถเพิ่มประสิทธิภาพทุกส่วนของโซลูชันเพื่อปรับปรุงความเร็ว ความน่าเชื่อถือ และความไว้วางใจในที่สุด ขณะนี้ เรามีโค้ดทั้งหมด ดังนั้นจึงง่ายต่อการติดตาม นอกจากนี้ เรายังอยู่ในช่วงการรักษาเสถียรภาพและรายงานจำนวนหนึ่งที่เกี่ยวข้องกับการรับส่งข้อความก็ลดลงอย่างมาก ผู้ใช้พอใจกับความสามารถในการไว้วางใจแพลตฟอร์ม
การออกแบบและเขียน SDK ของเราเองเป็นงานที่ท้าทายและเราชอบมัน เป็นสิ่งที่แตกต่างจากแอปพลิเคชันทั่วไปที่คุณต้องดึงข้อมูลจากเซิร์ฟเวอร์และแสดงบนหน้าจอ ระหว่างการใช้งาน เราเข้าใจตัวเลือกการออกแบบมากมายของ API ไลบรารีของบุคคลที่สามที่เราใช้ก่อนหน้านี้ ทำไม เพราะเราเคยเจอปัญหาเดียวกัน