Cloudflare Workers ตอนนี้เขียนด้วย Python ได้แล้ว
(blog.cloudflare.com)- Cloudflare Workers รองรับการเขียนด้วย Python ในสถานะ โอเพนเบต้า โดยผสาน Pyodide เข้ากับ workerd ซึ่งเป็นรันไทม์ Workers แบบโอเพนซอร์สโดยตรง เพื่อขยายโมเดลที่เดิมเน้น JavaScript
- Python Workers รองรับ binding เดิมตั้งแต่วันแรก เช่น Vectorize, Workers AI, R2, Durable Objects และสามารถ import แพ็กเกจ Python บางรายการ เช่น FastAPI, Langchain, Numpy ได้
- พื้นฐานการใช้งานคือ Pyodide ซึ่งเป็นพอร์ต WebAssembly ของ CPython และใช้ FFI ระหว่าง JavaScript กับ Python เพื่อจัดการ Request, Response, Fetch API และ binding ทรัพยากรของ Cloudflare จากโค้ด Python
- Cloudflare รัน import ในช่วงเวลาที่ deploy และสร้าง สแนปช็อตหน่วยความจำเชิงเส้นของ WebAssembly เพื่อลดต้นทุนการเริ่มต้น Pyodide และแพ็กเกจ ทำให้ cold start ของ Python Worker พื้นฐานลดลงเหลือต่ำกว่า 1 วินาที
- เวอร์ชัน Python และการอัปเดต Pyodide/แพ็กเกจจะถูกจัดการด้วย Compatibility Dates และ Compatibility Flags โดย Worker ที่ยังค้างอยู่กับรีลีส Python ที่สิ้นสุดระยะซัพพอร์ต 5 ปีแล้ว จะถูกย้ายอัตโนมัติไปยังรีลีส Python ที่เก่ารองลงมา
โอเพนเบต้าของ Python Workers
- สามารถใช้งาน Python Workers บน Cloudflare Workers ได้ในสถานะโอเพนเบต้า
- ต่างจากการรองรับภาษาอื่นนอกเหนือจาก JavaScript ที่ผ่านมา ครั้งนี้ผสาน implementation ของ Python เข้ากับรันไทม์ workerd โดยตรง
- binding ของ Cloudflare ที่รองรับตั้งแต่วันแรกประกอบด้วยรายการต่อไปนี้
- Python Workers สามารถ import แพ็กเกจ Python ยอดนิยมบางส่วนได้ เช่น FastAPI, Langchain, Numpy
- ไม่จำเป็นต้องมี ขั้นตอน build หรือ toolchain ภายนอกแยกต่างหาก
ส่วนที่การคอมไพล์เป็น WebAssembly อย่างเดียวไม่เพียงพอ
- Workers รองรับ WebAssembly มาตั้งแต่ปี 2018 และ Worker แต่ละตัวจะรันใน V8 isolate ซึ่งเป็นเอนจิน JavaScript แบบเดียวกับ Chrome
- โดยหลักการแล้ว หลายภาษา รวมถึง Python สามารถรันบน Workers ได้หากคอมไพล์เป็น WebAssembly หรือ JavaScript ก่อน
- แอปพลิเคชันจริงต้องการมากกว่าการรัน “hello world” และการรองรับ ระบบนิเวศของแพ็กเกจ ที่นักพัฒนาคุ้นเคยเป็นสิ่งสำคัญ
- Python Workers เป็นรูปแบบเริ่มต้นของความพยายามที่จะรองรับภาษาอื่นนอกเหนือจาก JavaScript บน Workers ในฐานะภาษา first-class
ลำดับการทำงานของ Python Worker
- เมื่อ Pyodide ถูก ฝังไว้ใน workerd แล้ว Python Worker จะสามารถประมวลผลคำขอผ่าน handler
on_fetchได้ - ใน
wrangler.tomlให้กำหนดไฟล์.pyเป็นmainและตั้งค่าcompatibility_flags = ["python_workers"] - เมื่อรัน
npx wrangler@latest devรันไทม์ Workers จะจัดการสิ่งต่อไปนี้- กำหนดเวอร์ชัน Pyodide ที่ต้องใช้ตาม compatibility date
- สร้าง isolate สำหรับ Worker และฉีด Pyodide ให้อัตโนมัติ
- ส่งโค้ด Python ให้ Pyodide
- สภาพแวดล้อมการรัน Python ถูกจัดการภายใน และแพลตฟอร์มเป็นผู้จัดเตรียมให้คล้ายกับ JavaScript Workers
เหตุผลที่ Pyodide เหมาะกับ Workers
- Pyodide เป็น implementation ที่พอร์ต CPython ไปยัง WebAssembly และตีความโค้ด Python โดยไม่ต้องคอมไพล์ล่วงหน้าเป็นรูปแบบอื่น
- มีไลบรารีมาตรฐานของ Python ส่วนใหญ่ และมี Foreign Function Interface (FFI) ที่เรียก JavaScript API จาก Python ได้
- ออกแบบให้ build อินเทอร์พรีเตอร์หลักและโมดูล Python แบบ native แต่ละตัวเป็นโมดูล WebAssembly แยกกัน และสามารถ ลิงก์แบบไดนามิก ได้ใน runtime
- Workers หลายตัวที่รันบนเครื่องเดียวกันสามารถแชร์ code footprint ของโมดูลได้ ซึ่งสำคัญต่อสภาพแวดล้อมของ Cloudflare ที่รัน Workers หลายพันตัวต่อเครื่อง
- ภาษาส่วนใหญ่ที่ target ไปยัง WebAssembly ยังไม่รองรับ dynamic linking จึงมักทำให้แต่ละแอปพลิเคชันต้องรวมสำเนารันไทม์ของภาษานั้นไว้เอง
Dynamic linking ระหว่าง Pyodide กับ WebAssembly
- WebAssembly เป็นสภาพแวดล้อม sandbox ที่แยกจากโฮสต์รันไทม์ ดังนั้นงานที่ไม่ใช่การคำนวณล้วน ๆ เช่น การอ่านไฟล์ จะต้องมี runtime environment เป็นผู้จัดเตรียมและให้โมดูล import
- target WebAssembly ของ LLVM แบ่งออกเป็นสามแบบ
wasm32-unknown-unknown: ไม่提供ไลบรารีมาตรฐาน C หรืออินเทอร์เฟซ system callwasm32-wasi: ใช้อินเทอร์เฟซระบบมาตรฐานที่ WASI runtime implement ไว้wasm32-unknown-emscripten: กำหนด import ที่จำเป็นและ output ไลบรารี JavaScript ที่ implement สิ่งเหล่านั้นมาพร้อมกัน
- Pyodide ใช้ Emscripten เพื่อจัดเตรียมอินเทอร์พรีเตอร์ CPython, FFI ระหว่าง Python-JavaScript และแพ็กเกจ Python จาก third party ที่คอมไพล์เป็น WebAssembly
- ในบรรดา target เหล่านี้ ปัจจุบันมีเพียง Emscripten เท่านั้นที่รองรับ dynamic linking
- WASI ยังไม่รองรับ abstraction สำหรับ dynamic linking อย่าง
dlopen/dlsymที่ CPython ใช้
FFI ที่เชื่อม Python กับ JavaScript
- ตัวอย่าง Python Worker นำ
Responseของ JavaScript เข้ามาด้วยfrom js import Response - FFI ของ Pyodide ทำให้เข้าถึงฟังก์ชันทั้งหมดของ JavaScript จาก Python ได้ ช่วยลดปัญหาที่ Python Workers จะด้อยกว่า JavaScript Workers ในด้านความสามารถ
- immutable type เช่น string และ number จะถูกแปลงระหว่างสองภาษาอย่างโปร่งใส ส่วน object ที่แก้ไขได้จะถูกห่อด้วย proxy ที่เหมาะสม
- เมื่อส่ง object ของ JavaScript ไปยัง Python, Pyodide จะตรวจสอบ protocol ของ JavaScript ที่ object นั้นรองรับ และประกอบคลาสที่ implement protocol ของ Python ที่สอดคล้องกันแบบไดนามิก
- หากรองรับ JavaScript iteration protocol ก็จะรองรับ Python iteration protocol ด้วย
- หากเป็น Promise หรือ thenable ใน Python จะกลายเป็น object ที่ await ได้
- ในลำดับการประมวลผลคำขอ object
Requestของ JavaScript ที่เข้ามาจะถูกห่อเป็นJsProxyที่เข้าถึงได้จากโค้ด Python และค่าที่ handler ของ Python คืนกลับจะถูกแปลงเป็น objectResponseของ JavaScript
Dynamic linking และแพ็กเกจ Python
- แพ็กเกจ Python จำนวนมากนำเข้าไลบรารี native ผ่าน C FFI และหากต้องการให้ทำงานในรันไทม์ Workers ไลบรารีเหล่านี้ต้องถูกคอมไพล์เป็น WebAssembly
- Pyodide ถูก build ด้วย Emscripten จึง override C FFI ของ Python และเมื่อแพ็กเกจพยายามโหลดไลบรารี native รันไทม์ Workers จะโหลดโมดูล WebAssembly ที่จัดเตรียมไว้ให้
- Dynamic linking ทำให้ Pyodide รองรับแพ็กเกจ Python หลายรายการที่มี dependency เป็นไลบรารี native ได้
- Static linking ต้องโหลดโค้ดทั้งหมดที่จำเป็นก่อนรันไบนารี แต่ dynamic linking เป็นวิธีที่จ่ายต้นทุนเมื่อถึงเวลาที่จำเป็น
- Workers สร้าง filesystem ที่ดูเหมือน distribution ของ Python สำหรับ Worker แต่ละตัวใน runtime โดยไฟล์พื้นฐานจะถูกแชร์ระหว่าง Workers
- ปัจจุบันไฟล์ถูกแชร์ระหว่าง Workers แต่จะถูกคัดลอกสำหรับ isolate ใหม่แต่ละตัว และในอนาคตมองว่าสามารถแชร์ underlying resource ได้มากขึ้นด้วยเทคนิค copy-on-write
การรองรับไลบรารี HTTP client และ server
- Python มีไลบรารี HTTP client จำนวนมาก เช่น httpx, urllib3, requests แต่ไม่ได้ทำงานได้โดยค่าเริ่มต้นบน Pyodide
- ไลบรารีเหล่านี้ใช้ raw sockets และโมเดลความปลอดภัยของเบราว์เซอร์กับ CORS ไม่อนุญาตให้ทำเช่นนั้น ดังนั้นใน Workers runtime จึงต้องใช้วิธีอื่น
-
ไคลเอนต์แบบอะซิงโครนัส
- ไลบรารีที่รองรับคำขอแบบอะซิงโครนัส เช่น aiohttp และ httpx สามารถใช้ Fetch API ของ Workers ได้
- Cloudflare แพตช์ไลบรารีผ่าน Pyodide FFI เพื่อให้ใช้ Fetch API ของ JavaScript
- แพตช์ httpx ประกอบด้วยโค้ดน้อยกว่า 100 บรรทัด
-
ไคลเอนต์แบบซิงโครนัสและข้อจำกัด
- Python API จำนวนมากเป็นแบบ ซิงโครนัส และในกรณีนี้จะไม่สามารถใช้ Fetch API แบบอะซิงโครนัสโดยตรงได้
- ใน urllib3 มี contribution สำหรับรองรับเบราว์เซอร์ของ Pyodide โดยใช้
Atomics.wait()กับ fetch worker thread หรือใช้ XMLHttpRequest แบบซิงโครนัส - ปัจจุบัน Cloudflare Workers ไม่รองรับ worker threads และ
XMLHttpRequestแบบซิงโครนัส ดังนั้นทั้งสองแนวทางนี้จึงไม่ทำงานใน Python Workers - ปัจจุบันยังไม่รองรับคำขอแบบซิงโครนัส
-
WebAssembly Stack Switching
- WebAssembly มีข้อเสนอ stage 3 ที่เพิ่มการสลับสแต็ก และ V8 มี implementation แล้ว
- ผู้ร่วมพัฒนา Pyodide ได้เพิ่มการรองรับ stack switching มาตั้งแต่เดือนกันยายน 2022 และเกือบพร้อมใช้งานแล้ว
- เมื่อมีการรองรับนี้
run_syncของ Pyodide จะสามารถบล็อกเพื่อรอให้ awaitable เสร็จสิ้นได้ ทำให้มีเส้นทางสำหรับรองรับคำขอแบบซิงโครนัส
FastAPI และ ASGI
- FastAPI เป็นไลบรารีที่ใช้กันมากในการนิยามเซิร์ฟเวอร์ด้วย Python และใช้โปรโตคอล ASGI
- แอปพลิเคชัน FastAPI ไม่ได้อ่านหรือเขียน socket โดยตรง โดยปกติ ASGI server เช่น uvicorn จะรับผิดชอบการจัดการ raw socket
- ด้วยโครงสร้างนี้ FastAPI เองจึงสามารถทำงานบน Cloudflare Workers ได้โดยไม่ต้องแพตช์หรือเปลี่ยนแปลง
- เพียงแทนที่ uvicorn ด้วย ASGI server ที่รันภายใน Workers ได้
- implementation แรกอยู่ใน asgi.py ของ workerd และรวมอยู่ใน Pyodide fork ที่ Cloudflare ดูแล
- Cloudflare มีแผนจะเพิ่มความสามารถให้ครบขึ้นและเพิ่ม test coverage ก่อน upstream ไปยัง Pyodide
การนำเข้าแพ็กเกจ Python
- Python Workers รองรับแพ็กเกจ Python บางส่วนที่ Pyodide จัดเตรียมให้โดยตรง
- แพ็กเกจที่รองรับมีเช่น numpy, httpx, FastAPI, Langchain เป็นต้น
- หากต้องการนำเข้าแพ็กเกจ ให้เพิ่มชื่อแพ็กเกจลงใน
requirements.txtโดยไม่ต้องระบุหมายเลขเวอร์ชัน - เวอร์ชันของแพ็กเกจแต่ละตัวจะถูกจัดเตรียมโดย Pyodide โดยตรง
- ตอนนี้สามารถใช้แพ็กเกจในการพัฒนาในเครื่องได้ และคาดว่าในอีกไม่กี่สัปดาห์จะสามารถ deploy Workers ที่กำหนด dependencies ใน
requirements.txtได้ - Cloudflare ระบุว่าจะดูแล Pyodide fork ของตนเองเพื่อให้แพตช์เฉพาะสำหรับ Workers runtime และจะนำการเปลี่ยนแปลงกลับไปยัง upstream ของ Pyodide
Cold start และ memory snapshot
- ขนาดของ Pyodide เองอยู่ที่ 6.4MB และแพ็กเกจ Python ก็อาจมีขนาดใหญ่ได้เช่นกัน
- หากใส่ Pyodide เข้าไปใน Worker ตามเดิมแล้วอัปโหลดไปยัง Cloudflare ค่าใช้จ่ายในการโหลด isolate ใหม่จะสูง ทำให้ cold start ช้า
- บนคอมพิวเตอร์ที่เร็วและเครือข่ายที่ดี Pyodide ใช้เวลาประมาณ 2 วินาทีในการเริ่มต้นบนเบราว์เซอร์ โดยใช้เวลาเครือข่าย 1 วินาทีและ CPU 1 วินาที
- เมื่อรัน
npx wrangler@latest deployกระบวนการ deploy จะทำงานดังนี้- Wrangler อัปโหลดโค้ด Python และ
requirements.txtไปยัง Workers API - Workers runtime ตรวจสอบโค้ด Python และ dependencies
- สร้าง isolate ใหม่และฉีด Pyodide กับแพ็กเกจที่ระบุเข้าไปโดยอัตโนมัติ
- สแกนและรันคำสั่ง import ในโค้ด Worker จากนั้นสร้าง snapshot ของ WebAssembly linear memory ของ Worker
- deploy snapshot นี้และโค้ด Python ไปยังเครือข่ายของ Cloudflare
- รัน top-level scope เช่นเดียวกับ JavaScript Worker
- Wrangler อัปโหลดโค้ด Python และ
- เมื่อมีคำขอเข้ามา ระบบจะโหลด snapshot นี้เพื่อ bootstrap Worker ใน isolate จึงหลีกเลี่ยงค่าใช้จ่ายการเริ่มต้นที่แพงได้
- cold start ของ Python Worker พื้นฐานลดลงเหลือ ต่ำกว่า 1 วินาที
-
การใช้ snapshot ซ้ำ
- ปัจจุบัน memory snapshot ที่สร้างขึ้นตอนอัปโหลด Python Worker เป็นของ Worker นั้นโดยเฉพาะ และไม่สามารถแชร์กับ Python Workers ตัวอื่นได้ แม้จะมีส่วนที่เหมือนกันเป็นจำนวนมาก
- Cloudflare มองว่าสามารถสร้าง snapshot ที่แชร์กันเพียงชุดเดียวไว้ล่วงหน้า และโหลดล่วงหน้าเข้าไปในพูลของ pre-warmed isolate ที่มี Pyodide runtime โหลดไว้แล้วได้
- ด้วยวิธีนี้ Python Worker ก็จะเข้าใกล้โมเดลที่ runtime ถูกจัดเตรียมแบบ on-demand เหมือน JavaScript Worker
- Cloudflare มองว่าการใช้ snapshot ซ้ำเป็นวิธีสำคัญที่สุดในการลด cold start ให้ต่ำลงอีกตลอดช่วงเวลาที่เหลือของปี 2024
การจัดการเวอร์ชัน Python ด้วย Compatibility Dates
- Cloudflare Workers มีโมเดลที่คาดหวังว่า Worker ที่ deploy ไปแล้วจะยังคงรันต่อไปได้แม้ไม่มีการอัปเดต
- ความเสถียรนี้จัดให้ผ่าน Compatibility Dates และ Compatibility Flags
- ใน Python ทั้ง Pyodide และ CPython ต่างก็มีเวอร์ชันของตนเอง และเวอร์ชันใหม่อาจมี breaking change รวมอยู่ได้
- Python เวอร์ชันใหม่จะออกทุกปีในเดือนสิงหาคม และ Pyodide เวอร์ชันใหม่จะออกหลังจากนั้น 6 เดือน
- เมื่อเพิ่ม Pyodide เวอร์ชันใหม่เข้าไปใน Workers จะถูกวางไว้หลัง Compatibility Flag และจะเปิดใช้งานเฉพาะหลัง Compatibility Date ที่กำหนดเท่านั้น
- Python release มี ระยะเวลาสนับสนุน 5 ปี และ Python เวอร์ชันที่พ้นช่วงสนับสนุนแล้วจะไม่ได้รับแพตช์ความปลอดภัย
- Python Worker ที่ยังคงอยู่กับ Python release เก่าหลังผ่านไป 5 ปี จะถูกย้ายอัตโนมัติไปยัง Python release ที่เก่าลำดับถัดไป
- Cloudflare คาดว่าในกรณีส่วนใหญ่ Python Worker จะยังทำงานต่อได้โดยไม่มีปัญหา แต่แนะนำให้อัปเดต compatibility date เป็นประจำเพื่อให้อยู่ภายในช่วงสนับสนุน
- ระหว่าง Python release แพ็กเกจก็จะถูกอัปเดตและเพิ่มด้วยวิธี opt-in เช่นเดียวกัน โดยตัวอย่าง flag จะอยู่ในรูปแบบ
python_3.17_packages_2025_03_01
การผูกของ Python Workers
- ด้วย Pyodide FFI จึงสามารถเข้าถึงออบเจ็กต์ เมธอด และฟังก์ชันของ JavaScript ได้โดยตรงจาก Python
- ด้วยโครงสร้างนี้ binding API ทั้งหมดสำหรับทรัพยากรของ Cloudflare จึงรองรับใน Python Workers ตั้งแต่วันแรก
- ออบเจ็กต์
envของแฮนด์เลอร์ Python เป็นออบเจ็กต์ JavaScript และ Pyodide มี proxy API ที่จัดการการแปลงชนิดข้อมูลระหว่างภาษา - สำหรับ KV namespace สามารถ
awaitenv.FOO.put()และenv.FOO.get()ใน Python เพื่อเขียนและอ่านค่าได้ - Web API ก็ใช้งานได้ในลักษณะเดียวกัน และสามารถ import JavaScript global อย่าง
Responseจากโมดูลjsได้
แผนสำหรับ API ที่เป็น Python มากขึ้น
- Cloudflare ตระหนักว่ารูปแบบอย่าง
from js import Responseยังไม่เป็น Python เท่าไร และมีแผนจะ提供 API ที่ idiomatic มากขึ้นสำหรับ Python Workers - workers-rs ที่เปิดตัวในปี 2021 เคย提供 binding แบบ Rust สำหรับ JavaScript API แต่ละตัวของ Workers
- Python Workers ก็มีแผนไปในทิศทางเดียวกัน โดยจะเริ่มจาก binding ของ Workers AI และ Vectorize ก่อน
- workers-rs ของ Rust ต้องใช้และอัปเดต dependency ภายนอก แต่ API ของ Python Workers จะถูกฝังไว้โดยตรงใน Workers runtime
- เมื่ออัปเดต compatibility date ก็จะสามารถใช้ API แบบ Python ล่าสุดได้
- อาจมีการ提供บางส่วนของ raw socket API ในไลบรารีมาตรฐานของ Python โดยอิงจาก JavaScript
connect()API ของ Workers - Cloudflare คาดหวังว่าจะเริ่มความพยายามในการสร้าง serverless API มาตรฐานที่ให้ความสามารถเทียบเท่า JavaScript พร้อมทั้งใช้งานง่ายสำหรับนักพัฒนา Python
ทิศทางในอนาคต
- การรองรับภาษาโปรแกรมใหม่อย่างจริงจังต้องอาศัยการลงทุนมากกว่าแค่ “hello world”
- จากผลสำรวจ Stack Overflow 2023 Python เป็นภาษาที่มีการใช้งานมากเป็นอันดับสองรองจาก JavaScript
- Cloudflare ระบุว่าจะปรับปรุงประสิทธิภาพของ Python Workers อย่างต่อเนื่อง และขยายขอบเขตการรองรับแพ็กเกจ Python
- ช่องทางรับฟีดแบ็กคือช่อง Python Workers ใน Cloudflare Developers Discord และ workerd GitHub discussion
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
ดีใจที่เห็น Cloudflare ให้ความสำคัญกับการ รัน Python บน Edge ด้วย WebAssembly มากขึ้น
จากมุมมองของคนที่ทำเรื่องการรัน Python บน WebAssembly ที่ Edge กับ Wasmer มา สรุปได้ว่า Cloudflare Workers เปิดใช้ Python บน Edge โดยใช้ Pyodide ซึ่งเป็น Python ที่คอมไพล์เป็น WebAssembly ด้วย Emscripten
โครงสร้างคือผูก Pyodide เข้ากับ Workerd และพยายามลดเวลาเริ่มต้นด้วย V8 snapshot โดยในกรณีที่ดีที่สุด cold start ของ Python จะอยู่ที่ประมาณ 1 วินาที
อย่างไรก็ตาม วิธีปัจจุบันผูกติดกับเวอร์ชัน Python/Pyodide ที่ Workerd ฝังมา และการ resolve แพ็กเกจก็ผูกกับ Workerd อย่างมาก ทำให้ใน runtime มีแนวโน้มว่าจะอนุญาตเฉพาะแพ็กเกจ native ที่คอมไพล์ไว้ล่วงหน้าเท่านั้น ตัวอย่างเช่น การใช้ numpy เวอร์ชันเฉพาะอาจยุ่งยากได้
ในเชิงโครงสร้างยังผูกอยู่กับโลกของ JS/V8 ดังนั้นด้วยสถาปัตยกรรมปัจจุบัน ดูเหมือนจะยากที่จะทำ เวลาเริ่มต้นต่ำกว่า 100ms ได้
ถึงอย่างนั้นก็ยินดีกับรีลีสนี้ และหวังว่าผู้คนจะสร้างแอปเจ๋ง ๆ ออกมา
https://pyodide.org/
https://github.com/cloudflare/workerd/blob/main/docs/pyodide...
https://github.com/cloudflare/workerd/pull/1875
แก้ไข: ปรับคำว่า “proof of concept” เป็น “รีลีส” ตามคำอธิบายของทีม Cloudflare
เรามีแผนจะอัปเดตแพ็กเกจอย่าง langchain หรือ numpy ที่กล่าวถึงค่อนข้างบ่อย
ถ้าอธิบายเพิ่มได้ว่าทำไมมองว่า V8 เป็นปัจจัยจำกัดก็คงดี V8 เป็น WebAssembly runtime ที่ทรงพลัง และ optimization ส่วนใหญ่ที่วางแผนไว้ก็ไม่ได้พึ่งพา engine ชั้นล่างมากนัก
อีกอย่าง นี่ไม่ใช่ proof of concept แต่เป็น เบต้า ที่จะปรับปรุงต่อเนื่องไปจนถึง GA
https://wasmer.io/templates?language=python
Cloudflare มีของดีมากมายด้านโฮสติ้งและฐานข้อมูล แต่ในฐานะ แพลตฟอร์มนักพัฒนา ดูเหมือนทำการตลาดได้ไม่ดีนัก ทำให้ Vercel หรือ Netlify ได้ส่วนแบ่งการรับรู้ไปพอสมควร
นอกเหนือจากนั้น สงสัยว่า Cloudflare มีบริการโฮสติ้งคอนเทนเนอร์ที่ไม่ยึดติดกับภาษาแบบ Google Cloud Run หรือไม่
ราคาและผลิตภัณฑ์ยอดเยี่ยมมาก
บางฟีเจอร์ใช้ไม่ได้เลย และบางฟีเจอร์รองรับได้แค่บางส่วน
ถ้าต้องเอาเวลาอันมีค่าของนักพัฒนาไปแก้ปัญหาแบบนี้ แพลตฟอร์มทางเลือกอย่าง Vercel, Netlify, Deno Deploy ก็ลื่นไหลกับความต้องการของทีมมากกว่า และทำให้โฟกัสกับการพัฒนาได้ง่ายกว่าเรื่องโครงสร้างพื้นฐาน
ค่าแบนด์วิดท์ของ Vercel กับ Netlify แพงกว่าผู้ให้บริการคลาวด์ส่วนใหญ่ 40~50 เท่า และบน Cloudflare แบนด์วิดท์แทบไม่เป็นต้นทุนเลย
การเรียก Edge function ของ Vercel กับ Netlify ก็แพงกว่า Cloudflare 6 เท่า ตัวเลขนี้ยังไม่รวมค่า compute time ซึ่งบน Cloudflare ฟรี
เหตุผลแทบจะ唯一ที่ Vercel ได้รับความนิยมคือเป็นที่ที่ดีที่สุดสำหรับโฮสต์ NextJS และนั่นอาจเป็นเหตุผลที่ทำให้การ deploy NextJS ไปที่อื่นทำได้ยาก
ผมใช้ Workers ใน production มาประมาณ 4 ปีแล้วและชอบมัน แต่แอปส่วนใหญ่ก็ยังรันอยู่บน คอนเทนเนอร์
เคยใช้ JS Workers กับไซต์ที่วางไว้หน้า Cloudflare ใช้งานง่ายและเร็วมาก อยากย้าย แอป Django ทั้งหมด ที่อยู่หลังไซต์ไปใช้ D1 database ด้วย
ทราฟฟิกยังต่ำเลยยังอยู่ในฟรีเทียร์ แต่ทำง่ายมากจนยินดีจะจ่ายเงิน
ถ้ามี การเปรียบเทียบประสิทธิภาพ กับ JS Worker ก็น่าจะช่วยได้ น่าสนใจดี แต่ดูเหมือนมีหลายเลเยอร์เกี่ยวพันกัน จึงอาจช้าได้
ไม่ได้คาดหวังว่าจะได้ประสิทธิภาพเท่ากัน แต่ถ้ารู้ภาพรวมคร่าว ๆ ของ trade-off ก็คงดี
ตอนนี้ cold start ของ Python ช้ากว่า JavaScript Worker ที่มีขนาดเท่ากัน Worker พื้นฐานแบบ “Hello World” ที่เขียนด้วย JavaScript มีเวลา cold start แทบใกล้ 0 แต่ Python Worker อยู่ต่ำกว่า 1 วินาที
เพราะเมื่อมี request เข้ามา ต้องโหลด Pyodide เข้า Worker แบบ on-demand และในบล็อกได้อธิบายงานที่ทำเพื่อทำให้ Pyodide พร้อมใช้งานล่วงหน้าเพื่อลดส่วนนี้
อย่างไรก็ตาม หลังจาก Python Worker จบ cold start แล้ว ความต่างจะใกล้เคียงกับส่วนขอบมากขึ้น และอาจอยู่ระดับไม่กี่มิลลิวินาที ขึ้นอยู่กับว่าใน request เกิดอะไรขึ้นบ้าง
ตอนข้าม “bridge” ระหว่าง JavaScript กับ WebAssembly เช่น เวลาทำ I/O หรืองาน async จะมีค่าใช้จ่ายเล็กน้อย แต่ควรมองว่าอยู่ระดับ ไมโครวินาที ไม่ใช่มิลลิวินาที และโดยทั่วไปเล็กมาก
คนที่ใช้ Worker ที่ไวต่อประสิทธิภาพบางส่วนก็เขียนด้วย Rust อยู่แล้ว: https://github.com/cloudflare/workers-rs ซึ่งก็อาศัย bridge ระหว่าง JavaScript กับ WebAssembly เช่นกัน
Python interpreter บน WebAssembly ที่ Pyodide ให้มานั้นยังไม่เร็วเท่ากับการปรับแต่งที่สั่งสมมาหลายปีเพื่อทำให้ JavaScript เร็วบน V8 ถึงอย่างนั้น Pyodide ก็ยังอยู่ในช่วงต้นเมื่อเทียบกับ JS engine ของ V8 และดูเหมือนยังมีจุดที่เพิ่มประสิทธิภาพได้มาก อยากส่งการปรับปรุงประสิทธิภาพกลับ upstream และก็มีข้อเสนอ WebAssembly บางอย่างที่ช่วยได้
สงสัยว่าเลือก lzma เพื่อแสดงเรื่องการแยกกักโดยตั้งใจหรือเปล่า หรือบังเอิญเป็นแบบนั้นเพราะข่าวเทคโนโลยีเมื่อสัปดาห์ก่อน
https://news.ycombinator.com/item?id=39865810
น่าจะเป็น game changer พอสมควรสำหรับการรัน งานเกี่ยวกับ AI บน Cloudflare รอสิ่งนี้มานานพอสมควรแล้ว
ถ้ายังไม่ได้ดู ก็น่าลองดูอีกสองประกาศที่ออกวันนี้ด้วย
“Leveling up Workers AI: General Availability and more new capabilities”
https://blog.cloudflare.com/workers-ai-ga-huggingface-loras-...
“Running fine-tuned models on Workers AI with LoRAs”
https://blog.cloudflare.com/fine-tuned-inference-with-loras
วันนี้ลองใช้แล้วดี และสามารถไปถึงขั้นรันได้เร็วมาก
แต่สงสัยว่าควรทำอย่างไรให้ สภาพแวดล้อมพัฒนาในเครื่อง เข้าใจไลบรารีที่ฝังอยู่ในการใช้งาน Python ของ CFW
เช่น มีไลบรารี
asgiอยู่ และอยากให้ linter ไม่ทำเครื่องหมายว่าไม่รู้จักมัน แต่ไลบรารีนี้มีอยู่เฉพาะตอน runtime ของ handleron_fetchและไม่ได้มีอยู่จริงบนเครื่องพัฒนาในเครื่อง เลยยังหาวิธีแก้ไม่ได้ใช้ CF Pages กับเว็บ static แล้วได้ผลดี และผลิตภัณฑ์ของ Cloudflare ที่ให้บริการ open-source LLM ในลักษณะบริการก็น่าสนใจ
เหตุผลหลักที่ทำให้ยังสร้างอะไรบน Cloudflare ได้ไม่มากกว่านี้คือ การขาดการรองรับ Python และตั้งตารอจะลองใช้ฟีเจอร์นี้
ทำให้รันอะไรขึ้นมาได้เร็ว และไม่ต้องกังวลเรื่อง infra มากนัก
การเพิ่ม Python เข้ามาน่ายินดีมาก และถ้า Go ได้รับการรองรับแบบ first-class ด้วยก็คงดี
สงสัยว่าข้อจำกัดที่ต้อง ใช้ได้เฉพาะแพ็กเกจ Pyodide จะทำงานอย่างไรกับ build ที่ไม่ใช่เรื่องเล็ก
มีโค้ดจำนวนมากที่ไม่ใช่ pure Python และหากจะรองรับแอป production จริง ๆ ก็น่าจะมีหลายอย่างที่ต้อง rebuild เอง
การที่ Cloudflare นำมาใช้อาจช่วยดึงแพ็กเกจเข้ามาเพิ่มได้ และถ้า 80/20 rule ใช้ได้ในกรณีนี้ ก็น่าจะดีพอ
อย่างที่บล็อกกล่าวไว้ ปัญหาใหญ่ที่สุดคือการรองรับแพ็กเกจที่เกี่ยวกับ server และ request แน่นอนว่ามีประโยชน์บน Cloudflare Workers แต่พอร์ตยากเพราะมักใช้ raw socket และ concurrency บางรูปแบบ
อยากให้ CloudFlare ทำ Workers ที่มี WASM เป็นเป้าหมาย first-class พร้อม API ทั่วไปที่ไม่ผูกกับ JS Workers
ตอนนี้ก็ deploy โค้ด WASM ได้อยู่แล้ว จึงใช้ได้แทบทุกภาษาในทางปฏิบัติ แต่ไม่ใช่ native เพราะรันอยู่ใน context ของ JS
มี overhead และความกระอักกระอ่วนเล็กน้อยตอน deploy
สุดท้ายผมคิดว่าบริการทั้งหมดจะถูก deploy โดยตรงไปยัง runtime WASM ที่ถูกทำให้ปลอดภัย ไม่ใช่ container คล้ายกับกระแสที่เคยย้ายจาก image ไปเป็น container
ตอนนี้ข้อดีของการใช้ภาษาอย่าง Rust บน Cloudflare Edge ยังไม่มากนัก เพราะข้อได้เปรียบด้านประสิทธิภาพจำนวนมากถูกหักล้างด้วย overhead และเวลาเริ่มต้น
ตัวอย่าง: https://github.com/WasmEdge/WasmEdge