1 คะแนน โดย GN⁺ 4 시간 전 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • แคชถูกนำมาใช้เพื่อลดภาระของฐานข้อมูล แต่เครื่องมือที่ใช้ง่ายอย่าง Redis มักค่อยๆ ถูก พึ่งพาเหมือนเป็นสตอเรจถาวร เมื่อเวลาผ่านไป
  • ปัญหาไม่ได้อยู่ที่ฟีเจอร์ persistence ของ Redis แต่คือกระบวนการปฏิบัติงานที่ทำให้คอมโพเนนต์ซึ่งเริ่มต้นจากการเป็น แคชแบบชั่วคราว เข้าไปผูกกับสถานะหลักของแอปพลิเคชัน
  • memcached ตามคำนิยามอย่างเป็นทางการคือ distributed memory object caching system และไม่ได้ตั้งอยู่บนแนวคิดการเก็บข้อมูลลงดิสก์ จึงจัดการได้ง่ายกว่าในฐานะเวิร์กโหลดแคชแบบไร้สถานะ
  • memcached หลายอินสแตนซ์ไม่ได้ถูกแบ่งโดยเซิร์ฟเวอร์ แต่ฝั่งไคลเอนต์จะใช้รายการ URL และการแฮชคีย์ในการกระจาย และเมื่อโหนดล่มก็จะถูกเอาออกจาก hasher ก่อน แล้วค่อยพยายามเชื่อมต่อใหม่ภายหลัง
  • แทนที่จะเพิ่มแคชก่อนเพียงเพราะ “ฐานข้อมูลช้า” ควรตรวจสอบ slow query และ index ที่ขาดหายไป ก่อน

ช่วงเวลาที่ Redis เปลี่ยนจากแคชเป็นสตอเรจ

  • เวลาดูแลอินฟราสตรักเจอร์ มักได้ยินคำขอว่า “ต้องมีแคช” อยู่บ่อยๆ และ Redis ที่คุ้นเคยและมีฟีเจอร์มากก็มักเป็นตัวเลือกแรกที่นึกถึง
  • หน้าเว็บของ Redis ชู Redis Iris ซึ่งเป็น real-time context engine สำหรับแอป AI ไว้อย่างเด่นชัด แต่ก็เป็นทิศทางที่เข้าใจได้ เพราะ Redis เป็นบริษัทที่ต้องทำรายได้
  • เมื่อดีพลอย Redis และส่งต่อ connection string ให้แล้ว ช่วงแรกมันจะทำงานเหมือน แคชที่เชื่อถือได้

ปัญหาที่เกิดขึ้นหลังจากนั้นไม่กี่เดือน

  • เมื่อเวลาผ่านไป cache.set("key", "value") เรียบง่ายกว่า INSERT INTO table VALUES ('key', 'value') มาก ผู้คนจึงเริ่มปฏิบัติต่อ Redis แบบนี้
    • เป็นคอมโพเนนต์ที่มีอยู่ตลอดเวลา เป็นที่เก็บข้อมูล แบบพฤตินัยแล้วคือ ฐานข้อมูล
    • เริ่มมอง REmote DIctionary Server ว่าเป็นสตอเรจถาวร ไม่ใช่แคชแบบชั่วคราว
  • ทั้งคุณและเพื่อนร่วมทีมปฏิบัติการอาจไม่รู้ตัว และเพราะทุกคนคิดว่าแคชจะถูกมองเป็นสิ่งชั่วคราว ระบบแจ้งเตือน (alerting) จึงตรวจจับเรื่องนี้ไม่ได้
    • ปัญหาจะโผล่มาก็ต่อเมื่อไปทำอะไรกับ Redis เช่นอัปเกรด ย้ายโหนด หรือเกิดอุบัติเหตุอย่างถาด HDD ของเซิร์ฟเวอร์ RAID0 หลุดออกมา
  • ประเด็นสำคัญไม่ใช่ว่า Redis ไม่มีฟีเจอร์ persistence แต่คือความคลาดเคลื่อนของสมมติฐานที่ว่า Redis ที่นำมาใช้เป็นแคชจะถูกใช้งานเหมือนแคช
  • ถ้ามาพบการพึ่งพานี้ทีหลัง Redis ก็จะผูกกับแอปพลิเคชันลึกเกินกว่าจะถอดออกได้ง่าย และสุดท้ายต้อง ดูแลรักษาและมอนิเตอร์ มันเหมือน “สัตว์เลี้ยง”

ทำไม memcached จึงตรงไปตรงมากว่าในบทบาทของแคช

  • memcached คือ “ระบบแคชอ็อบเจ็กต์ในหน่วยความจำแบบกระจายตัว ฟรี โอเพนซอร์ส และประสิทธิภาพสูง” และเป็นแคชแบบทั่วไปที่มีไว้เพื่อลดภาระของฐานข้อมูลและทำให้เว็บแอปพลิเคชันแบบไดนามิกเร็วขึ้น
  • ในเฟรมเวิร์กที่รองรับ plug-in caching อย่าง Django สามารถเปลี่ยน caching backend ได้
  • แม้จะมีฟีเจอร์น้อยกว่า Redis แต่เหตุผลที่ควรเลือก memcached คือ คุณลักษณะด้านการปฏิบัติการ ที่เรียบง่ายกว่า
    • จัดการ downtime ได้ง่าย: ไลบรารีฝั่งไคลเอนต์มักเพิกเฉยต่อข้อยกเว้นการเชื่อมต่อ และ get แบบง่ายๆ ก็อาจคืนค่าเริ่มต้นหรือ None ได้แม้เซิร์ฟเวอร์จะล่ม
    • memcached ไม่มีฟีเจอร์คลัสเตอร์ในตัว จึงกลับทำให้ การทำคลัสเตอร์ สะดวกกว่า
      • ถ้าตั้งค่า URL หลายตัวในไลบรารีฝั่งไคลเอนต์ ก็จะเลือกอินสแตนซ์เป้าหมายด้วยการแฮชคีย์
      • เมื่อการเรียกจากไคลเอนต์ตรวจพบว่าอินสแตนซ์ล่ม ก็จะ นำโหนดออกจาก hasher และหลังจากเวลาหนึ่งจะพยายามเชื่อมต่อใหม่โดยอัตโนมัติ
    • ภาระเรื่อง persistence ลดลงโดยโครงสร้าง: memcached ไม่บันทึกลงดิสก์ จึงเหมาะกับการจัดตารางลงที่ใดก็ได้ในฐานะเวิร์กโหลดแบบไร้สถานะ
  • แม้จะสร้างแนวทางปฏิบัติการคล้ายกันด้วย Redis ได้ แต่สถาปัตยกรรมของ memcached ใกล้กับแนวทางนี้มากกว่า จึง เข้าใจและใช้งานเป็นแคชได้อย่างเป็นธรรมชาติ
  • memcached เป็นแอปพลิเคชันที่ค่อนข้างเรียบง่าย และอีกเหตุผลที่เลือกใช้คือ แทบไม่มีโอเวอร์เฮดแม้จะรันหลายสิบอินสแตนซ์ที่มีขนาดแคชราว 64MB
  • ปัญหาจำนวนมากที่ดูเหมือนว่า “ฐานข้อมูลช้า” จริงๆ แล้วเริ่มจาก slow query หรือ index ที่หายไป ดังนั้นนอกจากเพิ่มแคชแล้วก็ควรดูการปรับแต่งคิวรีด้วย
  • หากสนใจการตัดสินใจด้านการออกแบบของ memcached ใน memcached blog มีบทความน่าสนใจมากมาย หนึ่งในนั้นคือบทความเดือนพฤษภาคม “กว่าจะได้คำตอบจริงๆ แล้วใช้เวลานานแค่ไหน? (How Long Does That Response Take… For Real?)”

1 ความคิดเห็น

 
GN⁺ 4 시간 전
ความเห็นจาก Hacker News
  • Redis เป็นเทคโนโลยีที่ยอดเยี่ยม แต่ผมมองว่ามันลำบากเพราะพยายามทำสองบทบาทที่ต่างกันไปพร้อมกันให้ดี คือ โครงสร้างข้อมูลแบบคงอยู่ถาวร และ แคชแบบชั่วคราว
    ใน Redis เอง ทั้งสองอย่างนี้ก็ผสมกันได้ไม่ดีนัก จึงเป็นลักษณะเปิดหรือปิด persistence แบบทั้งระบบ
    สำหรับแคชล้วน ๆ ผมจะใช้ memcached หรือสิ่งที่เทียบเท่ากัน และจะใช้ Redis ที่เปิด persistence ก็ต่อเมื่อจำเป็นต้องมีโครงสร้างข้อมูลอย่างพวกกระดานคะแนน
    ที่ $WORK เราไม่ได้ใช้ทั้งคู่ แต่เก็บข้อมูลของชั้นแคชสำหรับงานช้าไว้ทั้งในระบบไฟล์และในตาราง DB ที่ใช้งานเหมือน key-value store
    DB ช่วยประสานปัญหา thundering herd ส่วนการอ่านจากเซิร์ฟเวอร์เดียวกันจะอ่านจากระบบไฟล์อย่างเดียว ขณะที่การอ่านจากเซิร์ฟเวอร์อื่นจะดู DB หนึ่งครั้งแล้วคงไว้ในระบบไฟล์
    จะเปลี่ยนชั้นระบบไฟล์เป็น memcached ก็ได้ แต่จนถึงตอนนี้มันทำงานได้ดีมาก

    • หลังจากเคยใช้งาน Memcachedb (memcache + bdb สำหรับ persistence) ในช่วงปลายยุค 2000 ผมก็ได้ข้อสรุปแทบจะเหมือนกัน
      Redis มีฟีเจอร์มากกว่าชัดเจน และ antirez ก็เป็นคนที่มีเสน่ห์และถ่อมตัวอย่างน่าทึ่ง จึงเข้าใจได้ว่าทำไม Redis ถึงได้รับความนิยมมากกว่า
      ถึงอย่างนั้น สำหรับผม memcached คือจุดสูงสุดของแนวคิด เลือกเทคโนโลยีที่น่าเบื่อไว้ก่อน มาโดยตลอด
      ในฐานะวิศวกรแพลตฟอร์ม ผมรองรับได้ทั้งสองแบบ แต่ถ้านักพัฒนาเริ่มใช้ฟีเจอร์ขั้นสูงของ Redis อย่าง persistence, replication, clustering ผมจะพยายามตรวจสอบว่าเขาเข้าใจข้อเสียของการตัดสินใจนั้นดีพอหรือยัง
    • แค่ใช้ตาราง DB แบบ key-value store ควบกับระบบไฟล์ ก็ทำอะไรได้เยอะมากแล้วก่อนจะต้องจ่ายต้นทุนในการตั้งระบบแคชเฉพาะทาง
      ทุกครั้งที่ผมเสนอแนวทางแบบนี้ ผมต้องถกเถียงกับคนที่ยังประสบการณ์น้อยและรู้สึกว่าแคชจำเป็นต้องอยู่ใน datastore เฉพาะทางอยู่เสมอในงานวิศวกรรมจริงนับครั้งไม่ถ้วน
  • ไม่ใช่ว่า memcache จะหลีกเลี่ยงปัญหาเหล่านี้ได้เลย
    ผมเคยดูแลระบบที่ขยายตัวด้วย memcache ในช่วงกลางยุค 2000 และนักพัฒนาก็ตกหลุมพรางแบบเดียวกับที่บทความยกตัวอย่างในกรณี Redis
    พวกเขาพยายามใช้ memcache เพื่อเลี่ยงกฎของระบบกระจาย และเพราะ การเสพติดแคช จึงกำหนดขนาดฝูงเซิร์ฟเวอร์บนสมมติฐานว่า memcache จะต้องทำงานอยู่เสมอ พอมันล่มก็ระเบิดราวกับ DDoS ทันที
    ยังมี write amplification ที่เมื่อโฮสต์ใดโฮสต์หนึ่งลบคีย์ที่มี TPS สูง โฮสต์อื่นทั้งหมดก็จะพยายามเติมคีย์นั้นใหม่ด้วยการกระหน่ำเรียกบริการที่พึ่งพาอยู่, hot key ก็กลายเป็น hot host, และยังรัน memcached ร่วมกับ service daemon จนเกิด CPU spike ปริศนาอีกด้วย
    บางครั้งคำเรียก memcache ก็หายเข้า blackhole เพราะความคงค้างของรายการ DNS เก่า
    ทั้งหมดนี้หลีกเลี่ยงได้ถ้าใช้ memcache ให้ดีกว่านี้ แต่แรงล่อใจให้ใช้เกินขอบเขตมันสูงเกินไป

  • ปัญหา Redis/Valkey ที่ผู้เขียนกล่าวถึง ผมคิดว่าแทบจะเคยเจอมาหมดแล้วใน production
    เคยมีเหตุขัดข้องที่ Valkey ไม่มีนโยบายหน่วยความจำ ทำให้กินหน่วยความจำจนหมดและเกิดข้อผิดพลาดการเขียน append-only file และก็เคยมีกรณีที่ดิสก์เต็มจริง ๆ จนเขียน AOF ไม่สำเร็จ
    เคยมีกรณีที่คาดหวังเต็มที่ว่า Redis จะต้องยังมีชีวิต ทำงานอยู่ และเต็มไปด้วยข้อมูลผู้ใช้ทั้งหมด โดยไม่มีทางถอยกลับสู่เส้นทางช้า จนเกิด 500 error
    ยังเคยเห็นการใช้ sorted set และโครงสร้างข้อมูลอื่นอย่างสร้างสรรค์ โดยอาศัยว่าชุดเหล่านั้นจะไม่มีวันถูกไล่ออกอย่างเด็ดขาด
    แม้จะเห็นกับตาแบบนี้ ผมก็ยังรู้สึกว่ายากที่จะเริ่มจากแนะนำ memcache ก่อน Redis
    การออกแบบแอปให้มีการจัดวางแคชที่เป็นมิตรกับ memcache อาจซับซ้อน และถ้าทีมใหญ่พอใช้ memcache ก็มักมีโอกาสสูงมากที่จะสุดท้ายหาทางไปสู่จุดที่ต้องใช้ Redis อยู่ดี
    แล้วคุณก็ต้องดูแลเทคโนโลยีแคช 2 ตัว

    • ถ้าใครตัดสินใจใช้ Redis ในงานที่ไม่ใช่แคช ก็เท่ากับว่าคุณมี เทคโนโลยีแคช 2 ตัว อยู่แล้ว
      Redis instance ที่ตั้งไว้สำหรับแคชจะเอาไปใช้วัตถุประสงค์อื่นไม่ได้, instance สำหรับแคชต้องมี eviction, และ instance ที่ไม่ใช่แคชต้องไม่มี eviction
      สุดท้ายก็ต้องมี Redis ตัวที่สองที่ตั้งค่าต่างออกไป
      พูดตรง ๆ การออกแบบแอปให้มีการจัดวางแคชที่เป็นมิตรกับ memcache ก็เหมือนกับการออกแบบให้เป็นมิตรกับ Redis
      รูปแบบของ application cache พวกนี้เหมือนกันหมด คือดึงมาก่อน ถ้าไม่มีก็คำนวณแล้วค่อย set
    • ถ้ายังไม่มี ผมจะสร้าง abstraction interface ขึ้นมา โดยให้ขอคีย์พร้อมส่ง async function หรือ lambda ที่จะไปดึงค่าจากต้นทางเมื่อเกิด cache miss
      var value = cache.lookup( keyname, () => db.query(...), TimeSpan.FromMinutes(5) // or CacheOptions );
      แบบนี้จะไปเส้นทางสำรองหรือแทรกค่าได้ทันทีเมื่อเกิด cache miss
    • การไม่ต้องดูแลเทคโนโลยีแคช 2 ตัว เป็นเหตุผลที่ชนะได้เสมอ
  • อีกคุณสมบัติหนึ่งของ memcache ที่ไม่ค่อยถูกพูดถึงคือ ทุก operation ถูกออกแบบให้เป็น O(1)
    นี่เป็นการออกแบบที่ผู้สร้างเลือกอย่างตั้งใจ จึงมีข้อจำกัดอยู่บ้าง แต่รับประกันได้ว่าจะไม่เกิดการค้างแบบสุ่มใน operation ง่าย ๆ
    ส่วน Redis ใช้แกนการออกแบบแบบ single-thread จึงสามารถรัน operation ที่มีความซับซ้อนตามอำเภอใจได้ และในมุมของนักพัฒนาก็อาจรู้สึกว่าตัวเองฉลาดขึ้นเมื่อใช้งานมัน แต่ทุกอย่างที่เหลือจะต้องรอจนกว่า operation นั้นจะจบ

  • ในโปรเจ็กต์โอเพนซอร์สหรือโปรแกรมที่ต้องบำรุงรักษาระยะยาว เรื่องแบบนี้เกิดขึ้นบ่อย
    พอ codebase ใหญ่ขึ้น ก็สุดท้ายเริ่มรองรับสิ่งที่ไม่ได้อยู่ในแผนเดิม
    พอฟีเจอร์มากขึ้น ผู้ใช้ก็เพิ่มขึ้นด้วย บางคนใช้แค่ฟีเจอร์เก่า บางคนรับฟีเจอร์ใหม่ สุดท้ายค่าบางค่ากลายเป็นค่าเริ่มต้นโดยพฤตินัยจนไม่ค่อยดูเหมือนเป็นตัวเลือกอีกต่อไป
    ถ้ายก Redis เป็นตัวอย่าง ปิด AOF แล้วมันก็ทำงานเป็นแคช in-memory แบบข้อมูลหายได้ แต่คนส่วนใหญ่ก็ไม่ได้มองมันแบบนั้น
    เลยมีตรรกะว่าของที่มีฟีเจอร์น้อยและเรียบง่ายกว่าน่าจะดีกว่า และในบริบทนี้ Memcached เป็นตัวอย่างของแนวทางแบบ worse-is-better
    สำหรับทีมใหญ่ เรื่องนี้สมเหตุสมผลมาก แต่โปรเจ็กต์โอเพนซอร์สจำเป็นต้องมีอัปเดตสม่ำเสมอเพื่อให้ได้เงินทุนหรือแรงสนับสนุนต่อเนื่อง จึงมีความตึงเครียดที่แฝงอยู่
    บางครั้งก็ลงเอยด้วยการแตก fork หรือโปรเจ็กต์ลูกที่เชี่ยวชาญเฉพาะทางในพื้นที่เฉพาะ
    โดยส่วนตัวผมคิดว่าไม่มีคำตอบตายตัวและขึ้นอยู่กับบริบท
    เพราะแม้แต่การสื่อสารเองก็ไม่ใช่ของฟรี

    • ปัญหาที่ผมมีกับ microservices ก็อยู่ตรงที่การสื่อสารไม่ใช่ของฟรีนี่แหละ
      ดูเหมือนนักพัฒนาจะไม่ตระหนักเรื่องนี้กันเลย
    • ตัวอย่างที่ชัดที่สุดคือคนคิดว่า Redis ทำงานเป็นแค่แคชที่ข้อมูลหายได้เมื่อ crash หรือปิดระบบ
      ผมคิดว่าเป็นเพราะพวกเขาเปลี่ยนจาก Memcached มาเป็น Redis แล้วคาดหวังให้มันเหมือนเดิมทุกอย่าง
    • ในระบบขนาดใหญ่ AOF ทำให้เกิดปัญหาขัดข้องได้ ก็เลยปิดมันไป
      ถึงอย่างนั้นมันก็ยังเป็นแคชที่ยอดเยี่ยมอยู่ดี
  • ช่วงไม่กี่ปีที่ผ่านมา ผมทำงานกับ Flask พอสมควร แม้จะไม่ใช่งานเต็มเวลา แต่ก็ใช้มันเป็นส่วนหนึ่งของ tech stack ของธุรกิจอีคอมเมิร์ซขนาดเล็ก
    ในสแตก Python สำหรับ MongoEngine, SQLAlchemy, Celery และ Google/eBay/Shopify ผมเจอกับกับระเบิดและความประหลาดสารพัด แต่ไม่เคยเจอแบบนั้นกับ Redis
    อาจเป็นเพราะเราไม่ให้สิทธิ์แอดมินกับใครก็ตามที่คิดว่า Redis เป็น persistent store แต่พูดตามตรง ผมอยากเรียก Redis ว่าเป็น เทคโนโลยีที่แข็งแกร่งและออกแบบมาอย่างดีมาก
    API เรียบง่ายสุด ๆ และทุกครั้งที่ต้องทำอะไรแปลก ๆ สักหน่อย มันก็มีวิธีที่สมเหตุสมผลและคิดมาดีรองรับอยู่

    • ตอนนี้ผมกำลังเริ่มโปรเจ็กต์ด้วย Flask, SQLAlchemy, Celery และอยากฟังเพิ่มเติมว่าทำไมควรเลี่ยง Celery และควรใช้อะไรแทน
    • ในโลกของผม ระบบแคชอย่าง memcached กับ Redis ก็เป็นแค่แคชสำหรับใส่และดึงข้อมูล
      จะใช้ระบบทำให้ใช้ไม่ได้อย่างการติดแท็กก็คงได้
      ผมสงสัยจริง ๆ ว่ามีอะไรแปลก ๆ ที่ทำกับระบบแคชได้บ้าง และคนนิยมใช้แคชทำอะไรนอกเหนือจากแค่แคชข้อมูล
  • ผมชอบ memcached แต่ถ้าตั้ง Redis ให้เป็นแคชแบบข้อมูลหายได้แล้วผู้คนกลับปฏิบัติกับมันเหมือนเป็น ที่เก็บข้อมูลถาวร นั่นก็ไม่ใช่ความผิดของ Redis
    ยิ่งเมื่อ memcached เองก็ไม่ถาวรเหมือนกัน การเปรียบเทียบแบบนั้นยิ่งแปลกเข้าไปใหญ่

    • ในหลายบริษัท และน่าจะส่วนใหญ่ด้วย Redis ไม่ได้ถูกมองว่าเป็นแคชที่หายไปเมื่อไรก็ได้ แต่เป็น ฐานข้อมูลโปรดักชันที่ทนทานจริง และถูกใช้งานแบบนั้น
      ถ้าไม่มีใครบอกไว้ต่างหาก ก็ไม่แปลกที่นักพัฒนาใหม่จะตั้งสมมติฐานแบบนั้น
  • Memcached เป็นผู้กอบกู้ของโลกแคชในยุคที่มันออกมา
    และก็ดีที่มันถูกสร้างโดย Brad Fitzpatrick สำหรับ LiveJournal ในปี 2003
    แต่ละโพสต์ในฟีดผู้ใช้อาจมีข้อจำกัดการเข้าถึงต่างกัน จึงสามารถแคชได้ทั้งระดับโพสต์และทั้งหน้า
    ผมใช้มันอยู่หลายปีกับ Ruby on Rails หน้าเว็บเร็วขึ้นและมันก็ทำงานได้ดีเฉย ๆ
    ข้อเสียและในแง่ความเร็วก็เป็นข้อดีด้วย คือแคชถูกเก็บไว้ใน หน่วยความจำ ไม่ใช่บนดิสก์
    ถ้าข้อมูลที่ต้องแคชมีขนาดใหญ่มากและเป็นเว็บไซต์ขนาดใหญ่ ค่าโฮสต์อาจแพงได้
    ในกรณีนั้น Solid Cache เป็นผู้กอบกู้สำหรับผม
    โปรเจ็กต์ที่กำลังทำอยู่ตอนนี้มีแคชเกิน 100GB เก็บไว้บนดิสก์ของ PostgreSQL ค้นหาได้เร็วด้วยดัชนี และ Rails ก็จัดการหมดอายุอัตโนมัติด้วยการลบแถวนั้นออก
    ถ้าขนาดแคชเล็กกว่านี้และใช้ Redis อยู่แล้ว ผมก็คงใช้ Redis ต่อไปเลย
    แต่ถ้าความเร็วสำคัญที่สุด ผมจะลอง benchmark Memcached กับ Redis

  • ความที่ memcached เป็นของชั่วคราว กับการที่คนจะนำมันไปใช้เหมือนของถาวรหรือไม่ เป็นคนละประเด็นกัน
    ถ้าอัตรา cache hit ดูเหมือนจะอยู่ที่ 99.9% และมันมีอยู่ตลอด ไม่นานเดี๋ยวก็ต้องมีคนเขียนโค้ดที่พึ่งพาพฤติกรรมแบบนั้น
    ผมคิดว่าในโหมดพัฒนา อาจช่วยได้ถ้าไลบรารีฝั่งไคลเอนต์คืนค่า null สัก 10% ของครั้งทั้งหมด

  • memcached เร็วกว่า Redis แบบเหลือเชื่อสำหรับงาน แคชคีย์-ค่า ที่เรียบง่าย
    มันมีเธรด และถูกปรับแต่งมาอย่างมากให้ทำสิ่งเดียวได้ดีมาก
    ขณะที่ Redis ให้ความรู้สึกใกล้เคียงกับ Python heap กลางที่แชร์กันสำหรับงานสารพัดมากกว่า พร้อมโครงสร้างข้อมูลทุกแบบและความเป็น single-threaded
    ที่ Notion ใช้ Redis หลายอย่าง แต่ให้ memcached รับหน้าที่แคชจริง

    • ยืนยันได้ว่าในงานคีย์-ค่า มันไม่ได้เร็วกว่าขนาดนั้น
      โดยเฉลี่ยอยู่ราว 300 ไมโครวินาที เทียบกับ 350 ไมโครวินาที ต่อการอ่าน
      เรื่องที่เป็น single-threaded ก็ไม่ค่อยสำคัญนัก เพราะคอขวดไม่ใช่ CPU แต่เป็น reactive I/O
    • เธรดไม่ใช่ของฟรี
      มันช่วยให้ใช้คอร์ CPU ได้มากขึ้น แต่ถ้าโหลดไม่ได้สูงมาก memcached แบบ single-threaded ก็ใช้ CPU น้อยกว่าแบบ multi-threaded