(นี่เป็นบทความจากบล็อกที่ผมดูแลเอง เนื้อหาหลักเขียนด้วยความช่วยเหลือจากผู้ช่วย AI ที่ทำงานกับผมชื่อ Shiro และหากมีส่วนใดอ่านผิดหรือตีความคลาดเคลื่อนก็จะขอบคุณมากหากช่วยแจ้งให้ทราบ)

เซิร์ฟเวอร์เฟดิเวิร์สขนาดเล็ก sukhi-fedi ซึ่งเป็น SNS แบบเครือข่ายที่เซิร์ฟเวอร์เชื่อมต่อหากันเหมือน Mastodon ได้ถอด fedify (ไลบรารีที่รันบน Bun worker) ออก ซึ่งเดิมรับหน้าที่ประกอบ JSON-LD (งานทำรูปแบบข้อความให้เซิร์ฟเวอร์คุยกันรู้เรื่อง) และ HTTP signatures (ขั้นตอนลายเซ็นเพื่อตรวจสอบว่าข้อความเป็นของจริง) แล้วบันทึกการทำใหม่ทั้งหมดด้วย Elixir โดยตรง บทความนี้ไม่ใช่การพูดให้ร้าย แต่ครึ่งหนึ่งคือเรื่อง "ข้อดีของ fedify ที่เพิ่งได้รู้เมื่อจากมา"

  • ตั้งแต่แรกก็ไม่ได้ใช้ความสามารถแบบเฟรมเวิร์กของ fedify (createFederation, inbox listener, dispatcher ฯลฯ — เครื่องมือระดับบนที่จัดการความสามารถด้าน federation ให้ทั้งหมด) และยืมมาใช้แค่ชิ้นส่วนชั้นล่างสุดเท่านั้น:

    • คลาส vocab
    • toJsonLd/fromJsonLd (ตัวแปลงที่สลับรูปแบบข้อความไปมา)
    • signRequest/verifyRequest ที่เข้าใจวิธีลงลายเซ็นทั้ง draft-cavage และ RFC 9421
    • LD signatures, document loader
    • การนำเข้า/ส่งออกคีย์/JWK (รูปแบบมาตรฐานสำหรับเก็บ public key)
  • เหตุผลที่ย้ายออกมีสามข้อ:

    1. ทันทีที่ตัดสินใจว่าจะไม่ใช้เฟรมเวิร์ก สิ่งที่ fedify เคยจัดการให้แบบฟรี ๆ (การตอบ Accept ให้ Follow, idempotency (กลไกที่ทำให้แม้คำขอเดิมจะเข้ามาหลายครั้ง ผลลัพธ์ถูกนำไปใช้แค่ครั้งเดียว), authorized fetch, instance actor) ก็ต้องทำเองทั้งหมดอยู่แล้ว ของที่เหลือจึงมีแค่ชิ้นส่วนพื้นฐาน ทำให้ขอบเขตงานย้ายชัดเจน
    2. เป้าหมายคือเซิร์ฟเวอร์เล็กที่มีหน่วยความจำ 512~768MB แต่ในการทดสอบความทนทาน Elixir วิ่งจบได้อย่างเสถียรที่ 130MB ขณะที่ Bun worker เพียงตัวเดียวเกิด OOM (ตายเพราะหน่วยความจำไม่พอ) ที่ 120MB ส่วนเดียวในระบบที่รันด้วยภาษาอื่นกลับทั้งหนักที่สุดและเปราะที่สุด
    3. ตัวขอบเขตระหว่างภาษาและโปรเซสเองเป็นต้นเหตุของปัญหา ต้องคงข้อมูลต้นฉบับไว้เพื่อตรวจสอบลายเซ็น, กู้คืนที่อยู่ที่ถูก tunnel เปลี่ยนไป, ห่อคีย์ใน DB เป็น JWK แล้วส่งข้ามไปยังอีกโปรเซส ฯลฯ ไม่ใช่ความผิดของ fedify แต่เป็นงานเดินท่อที่เพิ่มขึ้นเรื่อย ๆ
  • งานเปลี่ยนระบบจบลงใน 12 ไฟล์ ราว 2,100 บรรทัด โครงสร้าง message queue คงเดิม แค่ให้เข้าร่วมกลุ่มเดิม และการสลับระบบก็มีเพียง "หยุด Bun container" เท่านั้น

  • สิ่งที่ทำหน้าที่เป็นตาข่ายนิรภัยกลับเป็น fedify เอง ลายเซ็น Ed25519 และการทำ normalization แบบ URDNA2015 (กฎจัดเรียงเอกสารให้ได้ลำดับเดิมเสมอ) เป็นวิธีที่ถ้าอินพุตเหมือนกันก็จะได้ผลลัพธ์เหมือนเดิมเสมอ จึงสามารถใช้โค้ด fedify จริงสร้าง "ข้อมูลคำตอบที่ถูกต้อง" ไว้ล่วงหน้า แล้วตรวจสอบผลที่ย้ายมาเป็น Elixir ได้แบบไม่ให้ผิดแม้แต่อักขระเดียว

  • Bun worker ปลดระวางแล้ว แต่ยังไม่ได้ลบออก ทุกวันนี้ยังคงอยู่ในสภาพแวดล้อมพัฒนาเพื่อสร้างข้อมูลคำตอบที่ถูกต้อง

  • ทีม fedify กำลังสร้าง DrFed(https://drfed.org/) ซึ่งเป็นเครื่องมือดีบัก ActivityPub โดยจะมีความสามารถวินิจฉัยว่าการ federation พังในขั้นตอนไหน (DNS/TLS/HTTP/ลายเซ็น/JSON-LD) รวมถึงดีบักเกอร์ที่ให้ไล่ดูขั้นตอนของวิธีลงลายเซ็นทั้งสองแบบทีละสเต็ป (ได้รับการสนับสนุนจาก NLnet NGI0, โอเพนซอร์ส AGPL-3.0, ขณะนี้กำลังพัฒนา)

  • สรุปคือ: ถ้าจะใช้เฟรมเวิร์กทั้งก้อนด้วย TypeScript/JavaScript fedify ก็ยังคงเป็นตัวเลือกที่ดีที่สุด ฟังก์ชัน ActivityPub ของ Ghost, hackers.pub, Hollo ล้วนทำงานอยู่บนมัน

ยังไม่มีความคิดเห็น

ยังไม่มีความคิดเห็น