Fanboi Channel

มิตรสหายนักพัฒนาซอฟต์แวร์ท่านหนึ่ง

Last posted

Total of 367 posts

249 Nameless Fanboi Posted ID:eiNX0LuEe4

https://hifumin.app Techstack
หมดนี่เสียเดือนละ 2 บาท ด้วยพลังแห่ง Serverless
(Average Request: 350k / month)
Hifumin เป็น Opensource Hentai Platform สร้างขึ้นเพราะรำคาญโฆษณาของ nHentai + รู้สึกหงุดหงิดที่บางทีก็ช้าไปหน่อย เลยเขียนใหม่เองหมด แบบ optimized มาโคตรดี ไม่มีโฆษณา และเป็น Opensource โดยสมบูรณ์ มีแผนจะ integrate กับ H Platform อื่นอยู่ แน่นอนทั้งหมดนี่เขียนเองคนเดียว
Note: Stack ทั้งหมดนี่เลือกจากราคาถูกสุดเป็นหลัก ถ้าจะเน้นประสิทธิภาพ จะเป็นอีกแบบนึง
Service ตระกูล Hifumin ทุกตัวเป็น micro-service ที่ deploy เป็น Serverless บน Google Cloud Run คิดค่าใช้จ่ายตาม CPU Allocation Time แต่ด้วยการจูน performance มาดี เลยเสียเงินตรงนี้น้อยมาก ข้อเสียคือมี coldstart อยู่บ้างถ้าไม่มี request ซักพัก
Service หลักๆ จะแบ่งเป็น
- Frontend (Hifumi): hifumin.app
- หน้าบ้านรับ User เป็น PWA, Cache ด้วย Service Worker
- Hentai-related API (Akashic): api.hifumin.app
- Public GraphQL API (สำหรับทุกคน ไม่มี CORs) สำหรับใช้ดึงข้อมูลมาจาก nHentai API แล้ว จัดการ format และ cache เองให้พร้อมมี mirror server ที่ update เองทุกๆ 3 ชั่วโมง
- User-related API (Galahad): user.hifumin.app
- API สำหรับใช้เก็บข้อมูล user หรืออะไรที่เกี่ยวข้องกับ User
- Source / Translation API: rosmontis.hifumin.app

250 Nameless Fanboi Posted ID:eiNX0LuEe4

- Reverse Proxy สำหรับหา hentai จากภาพ หรือหา ภาษาอื่นจากภาพ (Experimental: ตอนนี้กำลังทำการแปลอยู่)
Frontend (Hifumi)
- https://github.com/saltyaom/hifumin/tree/bismarck
Main ตอนนี้ยังเป็น Nextjs อยู่แต่กำลังเขียนใหม่เป็น Svelte บน branch Bismarck
Hifumi เป็น PWA ที่ optimize มาค่อนข้างดี Average bundle size ประมาณ 40K ต่อหน้า แต่ ส่วนใหญ่ถูก cache เอาไว้ด้วย Workbox บน runtime หมดแล้ว ทำให้เวลาโหลดหน้าใหม่ ทุกอย่างจะถูก Cache ไว้หมด ยกเว้น API, ถ้าเป็น local assets จะเป็น CacheFirst แล้วที่เหลือ key หลักๆ จะเป็น StaleWhileRevalidate ที่จะ invalidate cache ให้เอง เลยไม่มีปัญหาเรื่อง cache invalidation
เอาจริง เขียนใหม่มา 4-5 รอบได้แล้ว 555555~
วิวัฒนาการมาจาก React > Nextjs (Stylus) > Nextjs (Tailwind) แล้วสุดท้ายมาปักหลักลงที่ Svelte Kit เพราะ performance ดีมาก
Public API จะเป็น GraphQL หมด แล้ว Internal API (เช่น User) จะเป็น REST API เพราะ overhead น้อยกว่า (มาก) แต่แลกมาด้วยความ Flexible ที่น้อยลง
GraphQL Driver เป็นตัวที่เขียนเองคือ @saltyaom/gql กับ gq เพราะว่า driver ส่วนใหญ่จะจัดการเรื่อง AST Tree ของ GraphQL ก่อนส่ง request เลยทำให้ขนาดใหญ่ แต่เราต้องการแค่ส่ง Request ได้ก็พอ (eg. fetch syntax sugar สำหรับ GraphQL ที่เขียน plugin เพิ่มได้) เลยทำให้ขนาดเหลือไม่เกิน 1KB

251 Nameless Fanboi Posted ID:eiNX0LuEe4

หน้า dynamic ใช้หลักการเดียวกับ Nextjs คือใช้ Incremental Static Regeneration แล้วใช้ StaleWhileRevalidate ในการ invalidate cache ทำให้ไม่ต้อง build hentai ทีเดียว 39x,xxx หน้า แล้วฝั่ง SSR ค่อย cache API request
Hentai-related API (Akashic)
- https://github.com/saltyaom/akashic
หลักๆ คือ เป็น Reverse Proxy สำหรับ nHentai API อีกทีนึง แต่ตัว API ของ nHentai คือ CORs, ไม่ช้าไม่เร็ว, Format ไม่สวย, ล่มบ่อย และโดน Rate Limit เลยทำให้ต้องหาทาง Workaround เองจนสุดท้ายต้องมาเขียน Reverse Proxy เอง
เขียนด้วย Rust (Actix Web) ที่ต้องการรีด performance ของ GraphQL ด้วยความที่ overhead เยอะกว่า REST มาก + เพื่อลดค่าใช้จ่ายของ Cloud Run CPU Allocation เลยเลือกใช้ Rust
ที่คือ API มีปัญหาเรื่อง Rate Limit เลยทำให้เรียก API ติดกันไม่ได้ แต่มีทางออกคือ การทำ Reverse Caching
ทีนี้ถ้าเลื่อนลงไปจะเห็นว่าเรา List Github ในกลุ่ม Database ซึ่งไม่ได้ต้องใจจะเกรียนแต่เราใช้ Github เป็น Database จริงๆ เพราะ
1. Free ถ้าใช้ Database หรือ Storage จะเสียเงิน
2. เราเสก cronjob ด้วย Github Action ให้ dumb nHentai API และ Comments ทั้งหมดมาเก็บเป็น json file แล้วเก็บไว้ใน repo นึง ซึ่งจะทำงานทุกๆ 3 ชั่วโมง
- https://github.com/saltyaom.../hifumin-mirror/tree/generated
ด้วยความที่มันเป็น Public Data เลยไม่มีปัญหาอะไร
ตัว Akashic จะดึง API มาจาก Mirror Server ก่อนแล้วค่อย Fallback ไปที่ API ของ nHentai อีกที จากนั้นจะจัดการ format เป็น แบบที่อ่านง่ายกว่า แล้วค่อยส่งค่าคืนเป็น GraphQL อีกทีนึง ส่วนระหว่าง request ใช้ Apollo ในการ Monitor Request, GraphCDN ในการ cache query และ Cloudflare ในการ Cache Request ที่ซ้ำกัน ด้วยความที่จูนมาดี Allocation Time เลยน้อยมาก
User-Related API (Galahad)
- https://github.com/saltyaom/galahad
เป็น API Server ที่จัดการข้อมูลฝั่ง user (authen, cloud save, etc.) ที่เขียนด้วย Node เพราะหลักๆ ไม่ได้มีอะไรมากนอกจาก CRUD ตรงๆ + Node ถนัดเรื่อง Non-Blocking IO และมี ORM และ DB Driver ให้ใช้เยอะมาก แต่เพราะติด cost เลยใช้อะไรได้ไม่เยอะ
หลักๆ คือใช้ Planetscale ต่อด้วย Prisma และ Redis ต่อด้วย ioredis
ใช้ Planetscale เพราะเป็น Serverless Database ที่ไม่ต้อง Host เอง แถมได้ใช้ฟรี 1 พันล้าน Read, 10 ล้าน Write, 10GB Storage ฟรี ถ้าเกินก็จ่ายไม่กี่ $ ข้อเสียที่ไม่เป็นข้อเสียคือเป็น MySQL (ส่วนตัวนิยม Postgres กว่า) เอาไว้เก็บข้อมูลทั่วๆ ไปได้เลย
ส่วน Redis สำหรับเก็บ Session โดยเฉพาะเพราะเป็น In-Memory Database อย่างที่ทุกคนรู้, Redis มี Cloud ให้ใช้ได้ผ่าน Redis Lab ฟรี 30MB อาจฟังดูเหมือนน้อย แต่ต้องอย่าลืมว่าเราเอาไว้เก็บ active session อย่างเดียว ซึ่ง session ที่เราสร้างมามี format เป็น nanoID (21 Character) ซึ่งถ้าจะใช้ให้ถึง 30MB คร่าวๆ ก็คือต้องมี active session ประมาณ 9 แสนขึ้นไป ถ้าเกินก็จะเสีย $7 ต่อเดือนแล้ว storage จะขึ้นเป็น 100MB แต่ถ้าถึงตอนนั้นจริงๆ คนใช้ก็คงเกิน 3 ล้าน active session แล้ว ก็คงย้ายลง Raspberry PI 4B RAM 8GB ที่มีอยู่แล้วเป็น dedicated server ได้ ก็จะเก็บ active session เกิน 100ล้าน active session ได้สบายๆ
ส่วนตัวชอบ Prisma มาก เป็น ORM ที่ชอบที่สุดละ Generate Code + Type มาให้ใช้ได้เลย เบื้องหลังมี Query Engine ที่เขียนด้วย Rust embed มาให้ด้วย + มี Admin Tools ที่ชื่อ Prisma Studio มาเป็น GUI ให้จัดการ Database ได้แบบง่ายๆ ด้วย
จริงๆ ตอนแรกชั่งใจระหว่าง CockroachDB กับ PlanetScale แต่เลือก PlanetScale เพราะ ตามความเข้าใจ เป็น MySQL ที่ fork มาก่อนเองแล้วเอา

252 Nameless Fanboi Posted ID:eiNX0LuEe4

มา run บน Vitess ซึ่ง Scale MySQL ได้ Vertical Scaling แบบน่ากลัวมาก คือ Scale Cluster หลักแสนเครื่องพร้อมกันได้ + มี feature branching คือเหมือน Github Branch เลยแต่เป็น Database ทำให้ไม่ต้องกังวลเรื่อง Migration ว่าจะมี Type Conflict หรือต้องจำลอง Database เอง
Source / Translation API (Rosmontis)
https://rosmontis.hifumin.app
เป็น API Server สำหรับการทำ Reverse Image Search และใช้ Image Processing ในการอ่านคำและระบุตำแหน่งจากรูปภาพ และแปลด้วย ตัว API ตอนนี้เขียนด้วย Node และ ใช้ Web Assembly ฝั่งหลังบ้าน (ตอนนี้มีใช้ Neon สำหรับ Rust Binding อยู่)
อันนี้ยังเป็น internal อยู่ เพราะมี Technical Dept เรื่อง secret ทำให้ยัง public ไม่ได้ + ไม่รู้จะได้ใช้จริงไหม + ถ้าจะใช้จริงจะมี fixed cost อย่างน้อย $6 ต่อเดือนสำหรับ SourceNao API, Google Cloud Storage สำหรับเก็บ ephemral storage
ตอนนี้ public version เป็นแค่ Reverse Image Search อย่างเดียวซึ่งทดลองใช้เพราะต้องการคำนวนค่าใช้จ่ายของ Cloud Storage หลายๆ ตัว
Tooling อื่นๆ
- Astro มี internal project ที่ใช้อยู่
- Vite ฝั่ง SvelteKit, Vitest สำหรับ Test
- SWC ใช้ bundle Node หลังบ้าน, Jest สำหรับ Test
- Lagrange (Internal ตอนนี้เป็น Rust + SvelteKit) แทน Postman
- WRK สำหรับ Loadtest
- GraphCDN สำหรับ cache GraphQL Request
- Pulumi สำหรับ Google Cloud automation
- Wrangler deploy ขึ้น Cloudflare Worker ด้วย Github Workflow สำหรับ Performance-Critical Function
- Hifumi ตอนนี้ใช้ Cloud Run แต่กำลังวัด performance และ Coldstart ระหว่าง Cloud Run, Netlify, และ Cloudflare Pages อยู่ แต่ดูทรงคงได้ย้าย
- Google Cloud Build สำหรับ CI/CD Cloud Run ที่โยนขึ้น Github
- Fusejs สำหรับ Web Client-side search
- และก็เราเป็นที่แรกที่มี nHentai อยู่ใน List ขึ้นเป็นหนึ่งใน Techstack 😎
ที่เห็นทั้งหมดนี่เป็น Opensource ทั้งหมดที่เขียนทั้งหมดเองคนเดียวตอนว่าง
เอาจริงๆ ถ้าไม่จำกัดเรื่องเงินจะได้เห็น Techstack คนละแบบกันเลย อาจจะได้เห็น ScyllaDB internal ZeroMQ, Kong + Consul บน k8s กระจายทั่ว AWS, GCP
แต่จุดประสงค์หลักๆ คือต้องการลดค่าใช้จ่ายทุกอย่างให้ใกล้เคียง 0 มากที่สุดเลยได้มาเป็น Stack ที่เห็น หรือก็คือที่เห็น Technical ทั้งหมดนี่เกิดมาจาก "การอยากอ่าน Hentai ที่ไม่มีโฆษณานั่นแหละ"

Be Civil — "Be curious, not judgemental"

  • FAQs — คำถามที่ถามบ่อย (การใช้บอร์ด การแบน ฯลฯ)
  • Policy — เกณฑ์การใช้งานเว็บไซต์
  • Guidelines — ข้อแนะนำในการใช้งานเว็บไซต์
  • Deletion Request — แจ้งลบและเกณฑ์การลบข้อความ
  • Law Enforcement — แจ้งขอ IP address

All contents are responsibility of its posters.