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

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 อีกด้วย

อย่างไรก็ตาม การกรองตามช่วงเวลายังมีข้อจำกัด หากสัปดาห์ใดมีผู้กดให้ดาวหนาแน่นผิดปกติ อาจยังคงสร้างภาระต่อระบบได้ในระดับหนึ่ง แต่ในภาพรวมถือว่ามีประสิทธิภาพดีกว่าเดิมมาก

สิ่งที่เราได้เรียนรู้

  1. การตอบสนองที่เล็กลงไม่ได้หมายความว่าการ query จะถูกลงเสมอไป: การใช้ LIMIT ไม่ได้ช่วยลดภาระการจัดกลุ่มและเรียงลำดับข้อมูลมหาศาลในฐานข้อมูล
  2. เริ่มจากสิ่งที่ผู้คนพยายามจะทำจริงๆ: เมื่อรู้ว่าเปรียบเทียบแนวโน้มคือหัวใจสำคัญ ข้อมูลระบุตัวตนจึงไม่ใช่สิ่งจำเป็น
  3. คืนค่าเฉพาะสิ่งที่จำเป็น: การตัดข้อมูลส่วนเกินช่วยลดความเสี่ยงในการนำข้อมูลไปใช้ในทางที่ผิด
  4. ชัดเจนเกี่ยวกับข้อเสีย: ระบบใหม่มีเงื่อนไขเรื่องขอบเขตปฏิทินและผลกระทบจากดาวที่ถูกลบ ซึ่งเป็นสิ่งที่ผู้ใช้ API ต้องทำความเข้าใจ

คุณสามารถเริ่มใช้งานเพื่อ รับประวัติการให้ดาวของ repository และร่วมแสดงความคิดเห็นได้ที่ GitHub Community discussion

Source: GitHub Blog
ดูแลงานแปลและเรียบเรียงโดย NatapolK

ความคิดเห็น (0)

เข้าสู่ระบบเพื่อร่วมแสดงความเห็น

สมัครสมาชิก

มาเป็นคนแรกที่แสดงความเห็นกันเลยโบร