GitHub พลิกโฉม Star History: ลดรีเควสต์เหลือ 1% พร้อมเพิ่มความเป็นส่วนตัว

Maintainer มักตรวจสอบประวัติการให้ดาว (star history) เพื่อหาคำตอบว่าการเปิดตัวโปรเจกต์หรือการปล่อยเวอร์ชันใหม่ส่งผลต่อความนิยมอย่างไร ซึ่งที่ผ่านมาการสร้างกราฟจาก GitHub API จำเป็นต้องดึงข้อมูลรายชื่อ stargazer ทุกคนพร้อมเวลาที่กดให้ดาว แล้วจึงนำมาสรุปผลภายหลัง
การออกแบบเดิมก่อให้เกิดปัญหาสำคัญ 2 ประการ คือข้อมูลระบุตัวตนผู้ใช้เสี่ยงต่อการถูก scraping เพื่อนำไปใช้ในแคมเปญสแปมและ Social Engineering ส่วนในแง่เทคนิค endpoint เดิมบังคับให้ฐานข้อมูลต้องประมวลผลข้อมูลมหาศาลเพียงเพื่อคืนค่าข้อมูลแค่หน้าเดียว
ล่าสุด GitHub ได้สร้าง endpoint ใหม่ที่คืนค่าจำนวนดาวรายวันสูงสุด 30 สัปดาห์ในการรีเควสต์ครั้งเดียว โดยไม่มีข้อมูลระบุตัวตนติดมาด้วย ซึ่งหัวใจสำคัญคือการลดภาระฐานข้อมูลผ่าน การกรองดาวตามเวลาก่อนที่จะทำการนับข้อมูล
สิ่งที่ maintainer ต้องการจากประวัติการให้ดาว
เบื้องต้น GitHub ได้จัดการความเสี่ยงด้วยการ จำกัดรายชื่อ stargazer และ watcher ให้เฉพาะผู้ดูแล repository และผู้ร่วมสมทบ (collaborators) ซึ่งส่งผลกระทบต่อเครื่องมือภายนอกที่เคยใช้ข้อมูลนี้คำนวณกราฟประวัติการให้ดาว
จากการพูดคุยกับ maintainer พบว่าสิ่งที่พวกเขาต้องการจริงๆ คือ "กราฟเส้น" เพื่อดูแนวโน้มการเติบโต ไม่ใช่ชื่อผู้ใช้รายบุคคล เมื่อข้อมูลระบุตัวตนไม่ใช่สิ่งจำเป็นอีกต่อไป ทีมวิศวกรจึงสามารถออกแบบ aggregate endpoint ที่ดึงการเปลี่ยนแปลงของจำนวนดาวตามช่วงเวลาที่ต้องการได้โดยตรง
เมื่อการเปลี่ยนแปลง API กระทบต่อ Star History ผู้ใช้ต่างรวมตัวกันสนับสนุนโปรเจกต์ ทีม Community ของ GitHub รับฟังและเชื่อมโยงเรากับทีม product engineering ซึ่งได้เจาะลึกกรณีการใช้งานของเราและทำงานร่วมกับเราเพื่อออกแบบ endpoint ที่สร้างมาเพื่อจุดประสงค์นี้โดยเฉพาะ สถานการณ์ที่ยากลำบากกลายเป็นการร่วมมือที่สร้างสรรค์ระหว่าง GitHub, Star History และชุมชนในวงกว้าง ซึ่งนำไปสู่ทางออกที่ดีกว่าในที่สุด
Tianzhou Chen, maintainer ของ star-history.com และผู้ร่วมก่อตั้ง Bytebase
ทำไม endpoint เดิมถึงมีต้นทุนสูง
Endpoint GET /repos/{owner}/{repo}/stargazers เดิมถูกออกแบบมาเพื่อบอกว่า "ใคร" ให้ดาวบ้าง มันทำงานแบบแบ่งหน้า (paginated list) ซึ่งไม่ได้ถูกสร้างมาเพื่อเป็นบันทึกเหตุการณ์ทางประวัติศาสตร์ (historical event log) ทำให้เมื่อต้องการสร้างกราฟอนุกรมเวลา (time series) ระบบต้องดึงข้อมูล stargazer ปัจจุบันทุกคนขึ้นมาประมวลผลใหม่หมด
ตัวอย่างเช่น repository react/react ที่มีดาวกว่า 251,000 ดวง ต้องใช้การรีเควสต์ถึง 2,511 ครั้งเพื่อสร้างกราฟ ซึ่งมักจะติดปัญหา rate limits นอกจากนี้ทุกรีเควสต์ยังทำให้ฐานข้อมูลต้องนับจำนวนดาวทั้งหมดซ้ำๆ เพื่อคำนวณหน้ากระดาษ ส่งผลให้ query ทำงานช้าและบางครั้งถูกระบบป้องกันระงับการทำงานเนื่องจากใช้เวลานานเกินไป
ผลจากการจำกัดการเข้าถึงแบบเดิมช่วยให้ภาระงานของฐานข้อมูลลดลงอย่างเห็นได้ชัด โดยเวลาที่ใช้ใน count query ลดลงถึง 80%
แนวทางที่เราพิจารณา
การถอดข้อมูลระบุตัวตนช่วยเรื่องความเป็นส่วนตัว แต่โจทย์ที่ยากกว่าคือการลดภาระการสแกนข้อมูลดาวทั้งหมด
การเก็บเหตุการณ์ไว้โดยไม่มีการระบุตัวตน
แนวทางแรกคือการคืนค่าเพียง starred_at โดยไม่มีชื่อผู้ใช้ แม้จะช่วยเรื่องความเป็นส่วนตัวและให้เครื่องมือเดิมทำงานต่อได้ แต่ผู้ใช้ยังคงต้องทำ pagination และประมวลผลข้อมูลจำนวนมากเพื่อสรุปผลเอง ซึ่งยังไม่ใช่การแก้ปัญหาที่ต้นเหตุ
การสรุปผลรวม (Aggregating) แล้วจึงทำ pagination
การจัดกลุ่มดาวลงในถัง (buckets) รายวันหรือรายสัปดาห์ดูเหมือนจะเป็นทางออกที่ดี แต่หากใช้คำสั่ง SQL ทั่วไป ฐานข้อมูลยังคงต้องหาดาวทั้งหมดมาจัดกลุ่มและเรียงลำดับก่อนที่จะใช้ LIMIT และ OFFSET เพื่อแบ่งหน้า ซึ่งไม่ได้ช่วยลดต้นทุนการประมวลผลสำหรับโปรเจกต์ยอดนิยมที่มีข้อมูลหลักล้านแถว
การกรองตามเวลาก่อนจัดกลุ่ม
การออกแบบใหม่เลือกใช้วิธีแบ่งหน้าตามสัปดาห์ปฏิทิน โดยจะกรองข้อมูลจาก index ตามช่วงเวลา created_at ก่อน แล้วค่อยจัดกลุ่มเป็นจำนวนนับรายวัน หนึ่งรีเควสต์จึงครอบคลุมประวัติได้สูงสุด 30 สัปดาห์
วิธีนี้ช่วยให้ react/react ลดจำนวนรีเควสต์จาก 2,511 ครั้ง เหลือเพียง 24 ครั้ง และฐานข้อมูลจะตรวจสอบข้อมูลแต่ละจุดเพียงครั้งเดียวตลอดประวัติทั้งหมด นอกจากนี้รูปแบบการตอบสนองยังเป็นมาตรฐานเดียวกับ weekly commit activity endpoint หรือ GET /repos/{owner}/{repo}/stats/commit_activity อีกด้วย
อย่างไรก็ตาม การกรองตามช่วงเวลายังมีข้อจำกัด หากสัปดาห์ใดมีผู้กดให้ดาวหนาแน่นผิดปกติ อาจยังคงสร้างภาระต่อระบบได้ในระดับหนึ่ง แต่ในภาพรวมถือว่ามีประสิทธิภาพดีกว่าเดิมมาก
สิ่งที่เราได้เรียนรู้
- การตอบสนองที่เล็กลงไม่ได้หมายความว่าการ query จะถูกลงเสมอไป: การใช้
LIMITไม่ได้ช่วยลดภาระการจัดกลุ่มและเรียงลำดับข้อมูลมหาศาลในฐานข้อมูล - เริ่มจากสิ่งที่ผู้คนพยายามจะทำจริงๆ: เมื่อรู้ว่าเปรียบเทียบแนวโน้มคือหัวใจสำคัญ ข้อมูลระบุตัวตนจึงไม่ใช่สิ่งจำเป็น
- คืนค่าเฉพาะสิ่งที่จำเป็น: การตัดข้อมูลส่วนเกินช่วยลดความเสี่ยงในการนำข้อมูลไปใช้ในทางที่ผิด
- ชัดเจนเกี่ยวกับข้อเสีย: ระบบใหม่มีเงื่อนไขเรื่องขอบเขตปฏิทินและผลกระทบจากดาวที่ถูกลบ ซึ่งเป็นสิ่งที่ผู้ใช้ API ต้องทำความเข้าใจ
คุณสามารถเริ่มใช้งานเพื่อ รับประวัติการให้ดาวของ repository และร่วมแสดงความคิดเห็นได้ที่ GitHub Community discussion
ความคิดเห็น (0)
เข้าสู่ระบบเพื่อร่วมแสดงความเห็น
สมัครสมาชิกมาเป็นคนแรกที่แสดงความเห็นกันเลยโบร
