Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Redis

เชี่ยวชาญ Redis Pub/Sub: คู่มือปฏิบัติจริงฉบับสมบูรณ์

บทความภาพรวมของเราเกี่ยวกับ Redis pub/sub อธิบายถึงวัตถุประสงค์ของ pub/sub และอธิบายการเลือกออกแบบของ Redis pub/sub โดยเฉพาะ เราจะมาดูวิธีใช้ Redis pub/sub โดยอธิบายทีละขั้นตอนแต่ละแนวคิดหลัก: ช่องทาง (channels), การเผยแพร่ (publishing), การสมัครรับ (subscribing), และการจับคู่รูปแบบ (pattern-matching) โดยใช้ไคลเอ็นต์ noderedis สำหรับ Node.js

การทำความเข้าใจช่องทาง (Channels)

ช่องทาง (channel) คือชื่อที่ใช้จัดประเภทข้อความที่เผยแพร่บนระบบ pub/sub ช่องทางสามารถมีชื่อที่ขึ้นอยู่กับระบบ เช่น system-health:i-36a44b83, trade-prices:RAX, temp-reading:living-room หรือชื่อทั่วไปอย่าง events ผู้สมัครรับที่สนใจข้อมูลที่ปรากฏบนช่องทางใดช่องทางหนึ่งสามารถฟังได้ และผู้เผยแพร่และผู้สมัครรับใหม่เพิ่มเข้ามาได้ง่ายๆ ขณะที่ระบบเติบโต

เพื่อดูว่ามีช่องทางไหนทำงานอยู่บนเซิร์ฟเวอร์ Redis สามารถใช้คำสั่ง PUBSUB CHANNELS ซึ่งคืนค่าว่างเมื่อระบบยังไม่ได้ใช้ pub/sub:

$ redis-cli pubsub channels (empty list or set)

ช่องทางมีอยู่บนระบบก็ต่อเมื่อมีผู้สมัครรับฟังข้อความบนมัน ดังนั้นไม่จำเป็นต้อง "สร้าง" หรือ "ลบ" ช่องทาง – มันมีอยู่เฉพาะขณะที่มีผู้สมัครรับฟัง เพื่อดูเรื่องนี้ เราสามารถใช้ redis-cli ทำหน้าที่ subscriber ในคอนโซลหนึ่ง และรัน PUBSUB CHANNELS อีกครั้งในอีกคอนโซลหนึ่ง:

คอนโซล 1:

$ redis-cli subscribe events Reading messages... (press Ctrl-C to quit) 1) "subscribe" 2) "events" 3) (integer) 1

คอนโซล 2:

$ redis-cli pubsub channels 1) "events"

ทันทีที่คอนโซล 1 ตัดการเชื่อมต่อ ระบบจะกลับมายังสถานะไม่มีช่องทางอีกครั้ง

การเผยแพร่ข้อความ (Publishing Messages)

ไวยากรณ์คำสั่ง

คำสั่ง PUBLISH ใช้สำหรับเผยแพร่ข้อความ

PUBLISH channel message

ผู้สมัครรับทุกคนที่ฟังอยู่บนช่องทางจะได้รับข้อความ หากไม่มีผู้สมัครรับอยู่ข้อความจะถูกทิ้ง

ตัวอย่าง Node.js

หลังจากสร้างการเชื่อมต่อปกติไป Redis ใช้ publish ได้เหมือนคำสั่งอื่นๆ:

var client = require("redis").createClient(); client.publish("temp-reading:living-room", "37.0");

การใช้ร่วมกับคำสั่ง Redis อื่นๆ

การเผยแพร่ข้อมูลไปยังช่องทางเป็นการดำเนินการที่รวดเร็ว จึงมักใช้ร่วมกับการดำเนินการอื่นๆ การรวมการดำเนินการแบบนี้ปลดล็อกพลังของ Redis:

var client = require("redis").createClient(); client.multi() .publish("temp-reading:living-room", "37.0") .lpush("recent-temperatures", "37.0") .ltrim("recent-temperatures", 0, 99) .exec();

นี่คือการดำเนินการเดียวกับตัวอย่างก่อนหน้าสำหรับระบบ pub/sub แต่ในธุรกรรม MULTI/EXEC เดียวกัน อุณหภูมียังถูก push เข้า list ที่เก็บอุณหภูมิล่าสุด 100 ค่า

ตัวอย่างสั้นนี้แสดงวิธีผสาน Redis pub/sub เข้ากับการออกแบบระบบใหญ่กว่าที่รวมประวัติข้อความ การดำเนินการแบบข้างต้นช่วยให้ไคลเอ็นต์อื่นๆ สามารถคิวรีค่าล่าสุดและสมัครรับค่าใหม่ได้พร้อมกัน

การสมัครรับข้อความ (Subscribing to Messages)

ไวยากรณ์คำสั่ง

คำสั่ง SUBSCRIBE ใช้สำหรับสมัครรับช่องทาง คำสั่งนี้ทำให้ไคลเอ็นต์เข้าสู่สถานะ "subscribed" พิเศษ ที่ไม่ส่งคำสั่งอื่นได้อีก ยกเว้น SUBSCRIBE หรือ UNSUBSCRIBE เพิ่มเติม

SUBSCRIBE channel [channel ...]

ตัวอย่าง Node.js

Subscriber นี้ใช้ร่วมกับตัวอย่าง publisher ก่อนหน้าได้:

var subscriber = require("redis").createClient(); subscriber.on("message", function(channel, message) { console.log("A temperature of " + message + " was read."); }); subscriber.subscribe("temp-reading:living-room");

นี้ใช้ event emitter เรียกฟังก์ชันทุกครั้งที่มีข้อความเข้ามา ฟังก์ชันจัดการเพียง log อุณหภูมิไปที่คอนโซล – แต่ทำอะไรก็ได้

การใช้คำสั่งอื่นกับ Subscribers

какกล่าวไว้ ไคลเอ็นต์ที่สมัครรับอยู่ในโหมดพิเศษและไม่สามารถใช้คำสั่งอื่นได้ หากต้องการใช้คำสั่งอื่น ต้องสร้างการเชื่อมต่อไคลเอ็นต์แยกต่างหากไป Redis:

var redis = require("redis") , subscriber = redis.createClient() , client = redis.createClient(); subscriber.on("message", function(channel, message) { console.log("A temperature of " + message + " was read."); client.incr("temp-count"); }); subscriber.subscribe("temp-reading:living-room");

ตัวจัดการนี้ log ข้อความไปคอนโซลและเพิ่มตัวนับ Redis ในบางกรณีคุณอาจคำนวณผลลัพธ์และเผยแพร่ผลลัพธ์นั้นไปยังช่องทางแยกต่างหากสำหรับ subscriber อื่นอ่าน – อย่าเผยแพร่กลับไปช่องทางเดิมที่คุณฟังอยู่ ไม่งั้นจะเกิดลูปอันไม่มีที่สิ้นสุด :)

การจับคู่รูปแบบ (Pattern Matching)

ไวยากรณ์คำสั่ง

คำสั่ง PSUBSCRIBE ใช้สำหรับจับคู่รูปแบบช่องทาง

PSUBSCRIBE pattern [pattern ...]

ทำงานเหมือนคำสั่ง SUBSCRIBE ปกติ แต่อนุญาตให้จับคู่ช่องทางที่มีชื่อตรงกับรูปแบบ นี่ช่วยให้ผู้เผยแพร่ระบุข้อมูลได้เฉพาะเจาะจง และผู้สมัครรับฟังหลายช่องทางได้โดยไม่ต้องรู้ชื่อช่องทางแน่นอน

รูปแบบที่รองรับง่ายๆ: * ตรงกับอักขระใดๆ ? ตรงกับอักขระเดี่ยว และวงเล็บเหลี่ยมใช้สำหรับจับคู่ชุดอักขระที่ยอมรับได้ เช่น [acd]

จับคู่อ่านค่าอุณหภูมิจากห้องหลายห้อง:

PSUBSCRIBE temp-reading:*

จับคู่เหตุการณ์จาก A/B tests เช่น site-link:logo:a:clickrate และ site-link:logo:b:clickrate:

PSUBSCRIBE site-link:logo:?:clickrate

จับคู่เหตุการณ์ข้ามชุดอินสแตนซ์ AWS สำหรับเหตุการณ์ที่เผยแพร่ เช่น system-health:us-east-1a:i-36a44b83 และ system-health:us-east-1c:i-73657420636f636f6:

PSUBSCRIBE system-health:us-east-1[acd]:i-*

ตัวอย่าง Node.js

ในตัวอย่างนี้ ซึ่งใช้ร่วมกับตัวอย่างการเผยแพร่ก่อนหน้าได้เช่นกัน อุณหภูมิถูก log พร้อมกับห้องที่อ่านค่า

var subscriber = require("redis").createClient(); subscriber.on("pmessage", function(pattern, channel, message) { var room = channel.split(":")[1]; console.log("A temperature of " + message + " was read in " + room); }); subscriber.psubscribe("temp-reading:*");

Subscriber แบบ pattern-based ได้รับรายละเอียดเพิ่มใน callback: ไม่ใช่แค่ช่องทางและข้อความ แต่ยังรวมรูปแบบที่จับคู่ได้ – เนื่องจาก subscriber ฟังหลายช่องทางหรือรูปแบบได้

หมายเหตุข้างเคียง: ลักษณะประสิทธิภาพของ PUBLISH

ทุกคำสั่งใน Redis มี time complexity ที่ระบุเอาไว้ และส่วนใหญ่เป็นไปอย่างเข้าใจง่าย เนื่องจากการดำเนินการ PUBLISH รู้สึกง่ายมาก (เกือบเหมือน SET) อาจคิดว่า complexity เป็น O(1) แต่จริงๆ time complexity ของ PUBLISH เพิ่มขึ้นแบบเส้นตรงตามพฤติกรรมของ subscribers

เมื่อคำสั่ง PUBLISH รัน มันต้องเดินผ่าน patterns ทั้งหมดที่สมัครรับซึ่งอาจตรงกับช่องทาง และ subscribers ทั้งหมดที่ควรได้รับข้อความ ทำให้ time complexity เป็น O(N+M)

การปรับใช้ส่วนใหญ่จะไม่มีปัญหาประสิทธิภาพกับ complexity ของ PUBLISH แต่การติดตามประสิทธิภาพคำสั่งนั้นตามเวลายังคงสำคัญ – ระมัดระวังถ้าโค้ดของคุณสร้าง patterns ของช่องทางให้ฟังโดยอัตโนมัติ

โค้ดของคุณที่นี่?

เรายินดีนำเสนอ walk-through ตัวอย่างแอปที่สร้างด้วย Redis pub/sub หากคุณรู้จักตัวอย่างดีๆ ส่งข้อความมาที่ support@redisgreen.net – เราจะพยายามนำโค้ดที่เห็นมาแสดง