Publish/Subscribe (หรือ pub/sub) เป็นรูปแบบวิศวกรรมซอฟต์แวร์ที่ใช้มามาหลายทศวรรษ แต่ก่อนหน้านี้มักต้องการเซิร์ฟเวอร์ข้อความเฉพาะและความรู้เฉพาะทางจึงจะมีประโยชน์
Redis pub/sub เป็นการนำรูปแบบ publish/subscribe มาใช้งานแบบเบาและเรียบง่าย ซึ่งเป็นฟีเจอร์ของทุกเซิร์ฟเวอร์ Redis นับตั้งแต่版本 2.0 หมายความว่ามันง่ายต่อการใช้งานทุกที่ที่ Redis ถูกปรับใช้ และระบบ pub/sub ที่รวดเร็วและเรียบง่ายสามารถสร้างได้อย่างรวดเร็วโดยการ deploy Redis
เพื่อเข้าใจว่า Redis pub/sub เหมาะกับแอปหรือไม่ สำคัญต้องเข้าใจก่อนการออกแบบและเป้าหมายของ pub/sub แล้วค่อยพิจารณารายละเอียดเฉพาะของการนำ Redis pub/sub ไปใช้
ภาพรวม Pub/sub
การออกแบบ Pub/sub: แยก "publishers" ออกจาก "subscribers"
การลดการพึ่งพาและการแบ่งความรู้เป็นเป้าหมายหลักในการออกแบบซอฟต์แวร์ที่ขยายได้ รูปแบบการส่งข้อความ publish/subscribe (AKA pub/sub) แยกส่วนของซอฟต์แวร์ที่ เผยแพร่ ข้อความออกจากส่วนที่ ดำเนินการต่อ ข้อความ เพื่อเข้าใจดีขึ้น มาดูตัวอย่าง:
ตัวอย่าง "Publishers"
- แอปที่ให้ส่งข้อความไปห้องแชท
- คอนเทนเนอร์ Docker ประกาศสุขภาพหรือบริการ
- แอปประกาศราคาการซื้อขายหุ้น
- เซ็นเซอร์อุณหภูมิในบ้านประกาศค่าที่อ่านได้
- ผู้กระจายข้อความในเกมหลายผู้ใช้ ("Elon ถูกกินโดย grue")
ตัวอย่าง "Subscribers"
- แอปที่ฟังข้อความในห้องแชท
- แอปที่ส่งการแจ้งเตือนไป Slack
- ไคลเอ็นต์มือถือใช้ดูเหตุการณ์เรียลไทม์
- บริการ logging บันทึกเหตุการณ์เพื่อวิเคราะห์ภายหลัง
รูปแบบ pub/sub ช่วยให้คุณหลีกเลี่ยงการคิดมากเกินไปเกี่ยวกับ subscribers ขณะทำงานบน publishers และในทางกลับกัน ในตัวอย่างข้างต้น เราสามารถนึกภาพได้ว่าอาจมีหลาย subscribers สนใจข้อความจาก publisher เพียงตัวเดียว Subscribers อาจอยากฟัง ทุก publishers
ใน pub/sub publisher ไม่ต้องรู้จัก subscribers – มัน push ข้อความไปยัง ช่องทาง (channel) (เรียกว่า topic ในระบบอื่น) และเดินต่อไป ผู้สมัครรับที่กำลังฟังอยู่บนช่องทางนั้นเมื่อข้อความถูกเผยแพร่ จะได้รับข้อความ
Subscribers ออกแบบมาเพื่อฟังช่องทางหนึ่งหรือหลายช่องทางและตอบสนองต่อข้อความที่เข้ามา หาก subscriber ไม่ทันกับอัตราข้อความที่เผยแพร่ มันจะพลาดข้อความบางส่วน นี่เป็นการออกแบบที่มีประโยชน์: อนุญาตให้ระบบขยายตัวเกินความจุของ subscribers ที่ช้า Publishers เดินต่อไปเร็วโดยไม่ถูกชะลอโดยพฤติกรรม subscriber
เป้าหมาย Pub/sub: ขยายการส่งมอบ ไม่ใช่ภาระงาน
Pub/sub เป็นรูปแบบที่ใช้ในการขยายซอฟต์แวร์ – สำคัญต้องเข้าใจว่าช่วยขยายอะไรบ้าง การแยกแยะสำคัญระหว่าง pub/sub และ message queueing
ในรูปแบบ queueing คิว (หรือ list ใน Redis) เป็นบัฟเฟอร์ข้อความที่จะประมวลผล ในขณะที่ pool ของ workers pop รายการจาก list และจัดการ ในโมเดลนี้ การขยายขนาด pool workers ขยายความเร็วในการประมวลผลคิว เพราะแต่ละข้อความส่งไป worker เพียงตัวเดียว ทุก workers จัดการข้อความใดๆ แบบเดียวกันทุกตัว
แต่ใน pub/sub ระบบพยายามส่งข้อความทั้งหมดของช่องทางไปยัง subscribers ทั้งหมด เป็นรูปแบบ many-to-many ที่แต่ละ subscriber ทำอย่างต่างกันกับข้อความ – ตัวเขียน log ทนทาน ตัวส่งไป Slack ตัวดังนาฬิกาในสำนักงานขายท้องถิ่น ฯลฯ
สรุปคือ pub/sub ขยายการ ส่งมอบ ข้อความ ส่วน queueing ขยายการ ประมวลผลภาระงาน ของข้อความ Redis ใช้บ่อยสำหรับทั้งสองเป้าหมาย ดู Sidekiq ตัวอย่างยอดนิยมของ queueing ด้วย Redis
รายละเอียดเฉพาะของ Redis pub/sub
Pub/sub เป็นรูปแบบที่มีมานาน และแม้รูปแบบหลักจะเหมือนกัน แต่ฟีเจอร์เฉพาะแตกต่างกันมากระหว่างการนำไปใช้
Redis pub/sub เป็นการนำไปใช้แบบเบาและรวดเร็ว เพื่อเข้าใจการออกแบบมันดีที่สุด จะดูฟีเจอร์บางอย่างที่ ไม่ เป็นส่วนหนึ่งของ Redis pub/sub:
- ไม่มี persistence หรือแคชค่า
- ไม่มีการรับประกันการส่งมอบ
- ไม่มีการเพิ่มประสิทธิภาพสำหรับ cluster... ยัง
ไม่มี Persistence: "แต่คิดว่าเป็นห้องแชท..."
ไม่เหมือนการดำเนินการ Redis ส่วนใหญ่ที่อาจเขียนลงดิสก์ Redis pub/sub ไม่ persistent ข้อความที่เผยแพร่ถูกส่งตรงไปยัง subscribers แล้วทิ้ง ไม่มีบันทึกเก็บไว้ในหน่วยความจำหรือดิสก์ของ Redis
นี่อาจสับสนผู้ใช้ใหม่ที่ได้ยินว่า Redis pub/sub ใช้สร้างห้องแชทหลายคน คิดถึงเครื่องมืออย่าง Slack – ล็อกอินแล้วเห็นข้อความล่าสุดและรับข้อความใหม่ทั้งหมด จริงๆ แล้ว "การเห็นข้อความล่าสุด" ไม่ใช่ส่วนหนึ่งของ pub/sub เลย ต้องจัดการแยกต่างหาก Pub/sub 只 ให้ความสามารถในการส่งมอบข้อความใหม่ ในความหมายนี้ pub/sub เหมือน live stream – เปิดแล้วเริ่มได้ข้อมูล แต่ไม่เรียนรู้อะไรก่อนที่จะเปิด ตอนเติม: Internet Relay Chat (IRC) ใช้โมเดล pub/sub ไม่มีประวัติหรือการเก็บข้อความในตัว – นั่นคือเหตุผลที่เมตาฟอร์ห้องแชทพบบ่อย
จริงๆ คุณยังสร้างห้องแชทด้วย Redis และ pub/sub ได้ โดยให้แน่ใจว่าข้อความไม่ได้แค่เผยแพร่ แต่ยังถูก push เข้า list เพื่อให้ผู้ใช้เห็นประวัติข้อความ
ไม่มีการรับประกันการส่งมอบ
Subscribers ไม่ได้รับประกันว่าจะได้รับข้อความในโมเดล pub/sub หาก subscriber มีปัญหาเครือข่าย ไม่ทันอ่านข้อความพอ หรือไม่ได้แนบอยู่เมื่อข้อความถูกเผยแพร่ มันจะไม่ได้รับข้อความ Publishers ส่งข้อความไปช่องทางได้แม้ไม่มี subscriber ฟัง – ข้อความเหล่านั้นถูกทิ้ง
ระบบข้อความบางอย่างใช้ read receipts หรือ "acks" หรือเก็บบัฟเฟอร์ต่อ subscriber เพื่อป้องกันการตัดการเชื่อมต่อสั้นๆ Redis เลือกทางง่าย: ถ้าคุณพลาดข้อความ คุณพลาดไปแล้ว ข้อความที่ ต้อง ถึงผู้รับ ต้องส่งด้วยวิธีอื่น
การแลกเปลี่ยนนี้ดูแย่กว่าจริง การไม่มี acknowledgement และ buffering ต่อ subscriber ทำให้ Redis pub/sub ประมวลผลข้อความ ได้อย่างรวดเร็วมาก และมีระบบมากมายที่ได้ประโยชน์จากการส่งมอบข้อความแบบ fair-weather
การขยาย Cluster ไม่มีประสิทธิภาพ ตอนนี้...
Pub/sub เป็นโซลูชันสำหรับการขยาย จึงสำคัญต้องพิจารณาการขยายไม่แค่ข้อความ แต่วิทยุที่ใช้ส่งข้อความด้วย ระบบข้อความหลายอย่าง รวมถึง RabbitMQ และ Kafka ถูกออกแบบสำหรับความพร้อมใช้งานสูงและคุณสมบัติการขยายที่สมเหตุสมผลเมื่อระบบ messaging เติบโต
Redis Cluster (ส่วนหนึ่งของ Redis นับจาก 3.0) มีการสนับสนุน Redis pub/sub ในตัว พร้อมข้อจำกัดสำคัญ ข้อความที่เผยแพร่ทุกข้อความถูก broadcast ไปยังทุกสมาชิกของ Redis cluster ซึ่งทำให้ cluster ใหญ่ถูกเพ่งกับトラฟฟิกได้อย่างรวดเร็ว
คำตอบสั้นคือ ใช้ pub/sub บนเซิร์ฟเวอร์ Redis เดี่ยว หรือ cluster เฉพาะ pub/sub ขนาดเล็ก – ทั้งสองรับมือจำนวนข้อความมากได้ ยาวนาน Redis Cluster จะมีฟีเจอร์ฉลาดกว่าสำหรับการจัดเส้นทางข้อความเฉพาะที่จำเป็น แต่ฟีเจอร์นั้นยังอยู่ในขั้นออกแบบ
สรุป
โดยรวม Redis pub/sub เป็นเครื่องมือที่มีประโยชน์สำหรับขยายซอฟต์แวร์ การขาดฟีเจอร์ที่เราดูข้างต้นเป็นการแลกเปลี่ยนออกแบบ ทำให้ Redis เรียบง่ายและรวดเร็ว แทนที่จะเป็นยาวิธีแก้ทุกอย่างสำหรับการส่งข้อความ
เหมือนส่วนอื่นๆ ของ Redis มันไม่ได้ตัดเย็บสำหรับทุกกรณีใช้งานเฉพาะทาง แต่พาคุณไปไกลได้มากด้วยความเข้าใจบ้าง คู่กับฟีเจอร์อื่นๆ ของ Redis จะกลายเป็นเครื่องมือทรงพลังในกล่องเครื่องมือของนักพัฒนา
ด้วยภาพรวมระดับสูงเสร็จแล้ว คุณคงพร้อมดูตัวอย่างโค้ด pub/sub ไปที่ Redis Pub/Sub: How To ต่อไป