คุณเคยสร้างแบบจำลองอนุกรมเวลาที่ยอดเยี่ยม ซึ่งสามารถคาดการณ์ยอดขายหรือทำนายราคาหุ้นได้เพียงเพื่อดูความล้มเหลวในโลกแห่งความเป็นจริงหรือไม่? นี่เป็นความหงุดหงิดที่พบบ่อย โมเดลของคุณทำงานได้อย่างสมบูรณ์แบบบนเครื่องของคุณ แต่ทันทีที่คุณปรับใช้มันในคอนเทนเนอร์ Docker ดูเหมือนว่าจะเกิดภาวะความจำเสื่อม มันลืมทุกสิ่งที่รู้เมื่อวานนี้ ทำให้การคาดการณ์สำหรับวันพรุ่งนี้ไร้ประโยชน์
ไม่ต้องกังวล. นี่ไม่น่าจะมีข้อบกพร่องในโมเดลของคุณ มันเป็นข้อขัดแย้งระหว่างวิธีการออกแบบโมเดลอนุกรมเวลาและคอนเทนเนอร์ Docker
โมเดลอนุกรมเวลาล้วนเกี่ยวกับหน่วยความจำ พวกเขาต้องจำอดีตเพื่อทำนายอนาคต แต่คอนเทนเนอร์ Docker ถูกสร้างขึ้นมาให้ไม่มีสถานะและหลงลืม โดยจะล้างหน่วยความจำทุกครั้งที่รีสตาร์ท ความขัดแย้งขั้นพื้นฐานนี้สามารถเปลี่ยนแบบจำลองที่ทรงพลังให้กลายเป็นแบบจำลองที่ไร้ค่าในการผลิตได้
ในบทความนี้ เราจะแก้ไขปัญหานั้น เราจะให้แบบจำลองอนุกรมเวลาของคุณมีหน่วยความจำถาวร คุณจะได้เรียนรู้วิธีสร้างบริการคาดการณ์ที่พร้อมใช้งานจริงซึ่งใช้ Redis เป็นสมองภายนอกและวอลุ่ม Docker เพื่อให้แน่ใจว่าหน่วยความจำจะยังคงอยู่เมื่อรีสตาร์ท เราจะอธิบายตัวอย่างแบบลงมือปฏิบัติจริงทีละขั้นตอน เพื่อให้คุณสามารถเรียนรู้วิธีสร้างระบบที่ทั้งชาญฉลาดและเชื่อถือได้อย่างไม่น่าเชื่อ
สิ่งที่เราจะกล่าวถึง:
-
คู่มือนี้เหมาะสำหรับใคร
-
การทำความเข้าใจปัญหา
-
แล้วแบบจำลองอนุกรมเวลาคืออะไร
-
1. คอนเทนเนอร์เป็นแบบชั่วคราวโดยการออกแบบ
-
2. สูญเสียบริบทระหว่างการคาดคะเน
-
3. จำลองภาวะความจำเสื่อมเมื่อรีสตาร์ท
-
-
วิธีแก้ปัญหา:การจัดเก็บสถานะภายนอก
-
การนำไปปฏิบัติจริง
-
เริ่มต้นด้วยแนวทางที่เสียหาย
-
วิธีแก้ไขด้วยโวลุ่ม
-
รหัสจัดการกับสถานะอย่างไร
-
ทดสอบจุดสิ้นสุดด้านสุขภาพ
-
-
แล้วการปรับขนาดล่ะ
-
การปรับขนาดแนวนอนด้วย Redis Cluster
-
ความพร้อมใช้งานสูงด้วย Redis Sentinel
-
ใช้บริการ Redis ที่มีการจัดการ
-
-
ข้อผิดพลาดทั่วไปที่ควรหลีกเลี่ยง
-
อย่าถือว่าปริมาณทำงาน
-
อย่าละเลยขีดจำกัดหน่วยความจำ Redis
-
อย่าข้ามการตรวจสอบ
-
-
บทสรุป
คู่มือนี้เหมาะกับใคร
เพื่อให้ได้รับประโยชน์สูงสุดจากบทช่วยสอนนี้ การมีบางสิ่งที่เตรียมไว้จะเป็นประโยชน์ เราจะเจาะลึกลงไปในงานโค้ดและบรรทัดคำสั่ง ดังนั้นการเตรียมการเพียงเล็กน้อยจะช่วยได้มาก
-
เครื่องมือหลักสำหรับโปรเจ็กต์นี้คือ Docker และ Docker Compose ตรวจสอบให้แน่ใจว่าคุณได้ติดตั้งและใช้งานบนคอมพิวเตอร์ของคุณ
-
คุณจะพบว่ามันง่ายกว่าที่จะปฏิบัติตามหากคุณพอใจกับพื้นฐานของ Docker, Python และเฟรมเวิร์กเว็บ Flask ประสบการณ์บรรทัดคำสั่งเล็กน้อยจะเป็นประโยชน์สำหรับการรันคำสั่งในบทช่วยสอน
-
แต่ไม่ต้องกังวลหากคุณไม่เคยใช้ Redis มาก่อน สิ่งที่คุณต้องรู้ก็คือมันเป็นฐานข้อมูลในหน่วยความจำที่รวดเร็ว เราจะจัดการส่วนที่เหลือไปพร้อมกัน
คิดว่านี่เป็นไกด์นำเที่ยว ตราบใดที่คุณสงสัยและมีเครื่องมือพื้นฐานพร้อม คุณจะมีรูปร่างที่ดี
การทำความเข้าใจปัญหา
ก่อนที่จะพูดถึงวิธีแก้ปัญหา ก่อนอื่นมาทำความเข้าใจให้ชัดเจนก่อนว่าแบบจำลองอนุกรมเวลาคืออะไร จากนั้นจึงสำรวจว่าทำไมการจัดคอนเทนเนอร์จึงยุ่งยากมาก
แล้วแบบจำลองอนุกรมเวลาคืออะไร
พูดง่ายๆ ก็คือ แบบจำลองอนุกรมเวลาคือแบบจำลองประเภทหนึ่งที่วิเคราะห์จุดข้อมูลที่รวบรวมในช่วงเวลาหนึ่งเพื่อทำนายค่าในอนาคต คิดว่ามันเหมือนกับการพยากรณ์อากาศ นักอุตุนิยมวิทยาไม่ได้มองแค่ท้องฟ้าในขณะนี้ โดยจะพิจารณาอุณหภูมิ ความกดอากาศ และรูปแบบลมจากสองสามชั่วโมงและวันที่ผ่านมาเพื่อคาดการณ์ว่าจะเกิดอะไรขึ้นในวันพรุ่งนี้
แบบจำลองอนุกรมเวลาทำสิ่งเดียวกันกับข้อมูล ไม่ว่าจะเป็นการเข้าชมเว็บไซต์ ราคาหุ้น หรือการใช้พลังงาน ประเด็นสำคัญก็คือประวัติศาสตร์มีความสำคัญ ลำดับของเหตุการณ์ในอดีตให้บริบทที่จำเป็นในการทำนายอนาคตอย่างชาญฉลาด
ต่อไปนี้คือสิ่งที่จะพังเมื่อคุณใส่โมเดลเหล่านี้ใน Docker
1. คอนเทนเนอร์เป็นแบบชั่วคราวโดยการออกแบบ
คอนเทนเนอร์นักเทียบท่ามีไว้เพื่อให้ไร้สัญชาติ สิ่งนี้ใช้งานได้ดีกับ API ส่วนใหญ่ จุดสิ้นสุดโปรไฟล์ผู้ใช้? ไร้สัญชาติ รูปแบบการวิเคราะห์ความรู้สึก? ไร้สัญชาติ พวกเขารับอินพุต ส่งคืนเอาต์พุต และลืมทุกสิ่งที่อยู่ระหว่างนั้น
โมเดลอนุกรมเวลาไม่ทำงานในลักษณะนี้ พวกเขาต้องการบริบทจากการคาดการณ์ครั้งก่อน หากไม่มีสิ่งนี้ โมเดลของคุณก็จะตาบอด
2. สูญเสียบริบทระหว่างการคาดการณ์
การทำนายแต่ละครั้งเกิดขึ้นอย่างแยกจากกัน โมเดลของคุณได้รับจุดข้อมูลจุดเดียวและทำการเดาโดยไม่รู้ว่าอะไรเกิดขึ้นก่อนหน้านี้ สิ่งนี้ทำลายจุดประสงค์ทั้งหมดของการสร้างแบบจำลองอนุกรมเวลา
คุณอาจคิดว่า:"ฉันจะโหลดข้อมูลประวัติทั้งหมดในทุกคำขอ" แต่แนวทางนั้นล้มเหลวด้วยเหตุผลสองประการ:
-
มันช้า. ช้ามากถ้าคุณมีจุดข้อมูลนับพัน
-
มันไม่ปรับขนาด เมื่อคุณมีซีรีส์หลายชุดหรือมีปริมาณคำขอสูง คุณจะไปถึงขีดจำกัดด้านประสิทธิภาพอย่างรวดเร็ว
3. ความจำเสื่อมแบบจำลองเมื่อรีสตาร์ท
ทุกครั้งที่คุณปรับใช้เวอร์ชันใหม่หรือคอนเทนเนอร์ล่ม สถานะสะสมทั้งหมดจะหายไป โมเดลของคุณเริ่มต้นจากศูนย์ ในการผลิต สิ่งนี้เป็นสิ่งที่ยอมรับไม่ได้
วิธีแก้ปัญหา:การจัดเก็บสถานะภายนอก
แทนที่จะรักษาสถานะไว้ในคอนเทนเนอร์ เราจะย้ายมันออกไปข้างนอก Redis กลายเป็นหน่วยความจำของโมเดล
รูปแบบมีลักษณะดังนี้:
Client Request → Flask API → Redis → Prediction with Context
คอนเทนเนอร์ของคุณไม่มีสถานะและสามารถเปลี่ยนได้ แต่ระบบโดยรวมจะรักษาสถานะผ่าน Redis
การใช้งานจริง
มาสร้างสิ่งนี้กันเถอะ โคลนพื้นที่เก็บข้อมูลสาธิต:
git clone https://github.com/ag-chirag/docker-redis-time-series
cd docker-redis-time-series
เริ่มต้นด้วยแนวทางที่แตกหัก
04รหัส> ไฟล์แสดงสิ่งที่ไม่ควรทำ:
services:
api:
build: ./flask-api
ports:
- "5000:5000"
redis:
image: redis:alpine
สังเกตว่ามีอะไรหายไป? ไม่มีเล่ม Redis เก็บข้อมูลไว้ในระบบไฟล์ของคอนเทนเนอร์ ซึ่งหมายความว่าข้อมูลนั้นเป็นข้อมูลชั่วคราว
เรียกใช้:
docker compose -f docker-compose.initial.yml up
ทำนายเล็กน้อย:
curl -X POST http://localhost:5000/predict \
-H "Content-Type: application/json" \
-d '{
"series_id": "demo",
"historical_data": [
{"timestamp": "2024-01-01T12:00:00", "value": 10},
{"timestamp": "2024-01-01T12:01:00", "value": 20},
{"timestamp": "2024-01-01T12:02:00", "value": 30}
]
}'
คุณจะได้รับคำตอบว่า Redis ใช้งานได้:
{
"data_points_used": 3,
"prediction": 40,
"redis_connected": true
}
ตอนนี้เริ่มบริการใหม่:
docker compose down
docker compose -f docker-compose.initial.yml up
ทำนายกันอีก ตรวจสอบ 17 สนาม มันรีเซ็ต ข้อมูลประวัติทั้งหมดของคุณหายไป นี่คือสิ่งที่เราพยายามหลีกเลี่ยง
วิธีแก้ไขด้วยวอลุ่ม
25 ที่ถูกต้อง เพิ่มความคงอยู่:
services:
api:
build: ./flask-api
ports:
- "5000:5000"
environment:
- REDIS_HOST=redis
redis:
image: redis:alpine
command: redis-server --appendonly yes
volumes:
- redis_data:/data
volumes:
redis_data:
แล้ว Volume คืออะไรและทำงานอย่างไร
คิดว่าไดรฟ์ข้อมูล Docker เป็นฮาร์ดไดรฟ์ภายนอกเฉพาะสำหรับคอนเทนเนอร์ของคุณ ตามค่าเริ่มต้น เมื่อคอนเทนเนอร์เขียนข้อมูล จะทำเช่นนั้นกับเลเยอร์ชั่วคราวที่จะถูกทำลายเมื่อคอนเทนเนอร์ถูกลบออก โวลุ่มเป็นวิธีหนึ่งในการบันทึกข้อมูลนั้นอย่างถาวร
นี่คือวิธีการทำงาน:
-
Docker สร้างและจัดการพื้นที่จัดเก็บข้อมูลพิเศษบนเครื่องโฮสต์ ซึ่งแยกออกจากระบบไฟล์ของคอนเทนเนอร์โดยสิ้นเชิง ใน docker-compose.yml ของเรา
36ส่วนที่ด้านล่างจะบอก Docker ให้สร้างโวลุ่มที่มีชื่อชื่อว่า41. -
เมื่อคอนเทนเนอร์ Redis เริ่มต้น
58line บอกให้ Docker "เสียบปลั๊ก" ฮาร์ดไดรฟ์ภายนอกนี้ เชื่อมต่อ68เพิ่มระดับเสียงเป็น77ไดเร็กทอรีภายในคอนเทนเนอร์ -
ตอนนี้เมื่อใดก็ตามที่กระบวนการ Redis ภายในคอนเทนเนอร์จะเขียนข้อมูลไปที่
80ไดเร็กทอรี (ซึ่งเราได้กำหนดค่าให้ทำ) จริงๆ แล้วเขียนไปที่90ระดับเสียงบนเครื่องโฮสต์ -
เมื่อคุณเรียกใช้ docker compose down คอนเทนเนอร์ Redis จะถูกทำลาย แต่
104ปริมาณไม่ถูกแตะต้อง เหมือนกับการถอดปลั๊กฮาร์ดไดรฟ์ภายนอก และข้อมูลยังคงปลอดภัย ครั้งถัดไปที่คุณเรียกใช้ docker compose up คอนเทนเนอร์ Redis ใหม่จะถูกสร้างขึ้น ไดรฟ์ข้อมูลจะถูกแนบอีกครั้ง และ Redis จะค้นหาข้อมูลเก่าทั้งหมดจากตำแหน่งที่ทิ้งไว้
กลไกนี้เป็นกุญแจสำคัญในการมอบบริการเก็บสถานะของเราด้วยหน่วยความจำที่สามารถรีสตาร์ทได้
เรียกใช้เวอร์ชันที่แก้ไขแล้ว:
docker compose up --build
ส่งคำทำนายหลายประการเพื่อสร้างสถานะ:
for i in {1..5}; do
curl -X POST http://localhost:5000/predict \
-H "Content-Type: application/json" \
-d "{
\"series_id\": \"demo\",
\"historical_data\": [{\"timestamp\": \"2024-01-01T12:0$i:00\", \"value\": $((i*10))}]
}"
done
ตอนนี้มาถึงการทดสอบ รีสตาร์ททุกอย่าง:
docker compose down
docker compose up
ทำนายกันอีก ดูที่ 118 . รวมถึงประเด็นก่อนหน้าทั้งหมด โมเดลจะดำเนินการต่อจากจุดที่ค้างไว้
วิธีนี้ได้ผลเนื่องจากไดรฟ์ข้อมูลมีอยู่อย่างเป็นอิสระจากวงจรการใช้งานคอนเทนเนอร์
โค้ดจัดการกับสถานะอย่างไร
Flask API ใน 123 เก็บแต่ละจุดข้อมูลใน Redis โดยใช้ชุดที่เรียงลำดับ:
def store_data_point(series_id, timestamp, value):
key = f"ts:{series_id}"
redis_client.zadd(key, {json.dumps({"ts": timestamp, "val": value}): timestamp})
เมื่อทำการทำนาย ระบบจะดึงข้อมูลประวัติล่าสุด:
def get_recent_data(series_id, limit=100):
key = f"ts:{series_id}"
data = redis_client.zrange(key, -limit, -1)
return [json.loads(d) for d in data]
ชุดเรียงลำดับ Redis ช่วยให้คุณเรียงลำดับเวลาอัตโนมัติ วอลุ่มช่วยให้มั่นใจได้ว่าข้อมูลนี้จะยังคงอยู่เมื่อรีสตาร์ท
ทดสอบจุดสิ้นสุดด้านสุขภาพ
ตรวจสอบว่าทุกอย่างเชื่อมต่ออย่างถูกต้อง:
curl http://localhost:5000/health
คุณควรเห็น:
{
"model_loaded": true,
"redis_connected": true,
"status": "healthy"
}
ถ้า 134 เป็นเท็จ โปรดตรวจสอบบันทึกนักเทียบท่าของคุณ ปัญหาทั่วไปคือการกำหนดค่าเครือข่ายหรือ Redis เริ่มทำงานไม่ถูกต้อง
แล้วการปรับขนาดล่ะ
การตั้งค่านี้ทำงานได้ดีสำหรับการปรับใช้อินสแตนซ์เดียว เมื่อการเข้าชมเพิ่มขึ้น คุณมีทางเลือกสองสามทาง
การปรับสเกลแนวนอนด้วย Redis Cluster
เพื่อให้มีปริมาณงานสูง ให้กระจายข้อมูลของคุณไปยังโหนด Redis หลายโหนด Redis Cluster จัดการการแบ่งส่วนโดยอัตโนมัติ
ความพร้อมใช้งานสูงด้วย Redis Sentinel
เพิ่มความสามารถในการเฟลโอเวอร์เพื่อให้ที่จัดเก็บสถานะของคุณไม่กลายเป็นจุดล้มเหลวเพียงจุดเดียว Sentinel ตรวจสอบอินสแตนซ์ Redis และส่งเสริมการจำลองเมื่ออินสแตนซ์หลักล้มเหลว
ใช้บริการ Redis ที่มีการจัดการ
AWS ElastiCache, Azure Cache สำหรับ Redis หรือ Google Cloud Memorystore จัดการภาระการปฏิบัติงาน คุณมุ่งเน้นไปที่โมเดลของคุณ เพราะโมเดลจะจัดการกับความน่าเชื่อถือของ Redis
ข้อมูลเชิงลึกที่สำคัญ:คอนเทนเนอร์ API ของคุณยังคงไร้สถานะ คุณปรับขนาดร้านค้าของรัฐได้อย่างอิสระ
ข้อผิดพลาดทั่วไปที่ควรหลีกเลี่ยง
ฉันไม่สามารถเน้นย้ำสิ่งนี้ได้เพียงพอ:ทดสอบความเพียรของคุณก่อนปรับใช้กับการใช้งานจริง
อย่าถือว่าปริมาณทำงาน
รีสตาร์ทคอนเทนเนอร์ของคุณจริง ๆ และตรวจสอบว่าสถานะยังคงมีอยู่ ฉันพบว่าการปรับใช้งานล้มเหลวเนื่องจากมีผู้ลืมติดตั้งวอลลุมในการผลิต
อย่าละเลยขีดจำกัดหน่วยความจำ Redis
Redis เก็บทุกสิ่งไว้ในความทรงจำ ตรวจสอบการใช้หน่วยความจำของคุณ ตั้งค่านโยบาย maxmemory ให้เหมาะสมกับภาระงานของคุณ หากหน่วยความจำไม่เพียงพอ Redis จะเริ่มถอดคีย์ออกหรือปฏิเสธการเขียน
อย่าข้ามการตรวจสอบ
เพิ่มการตรวจสุขภาพ ตรวจสอบสถานะการเชื่อมต่อ Redis ติดตามเวลาแฝงของการคาดการณ์ คุณต้องการทราบเมื่อสิ่งต่างๆ พัง ไม่ใช่เรียนรู้จากผู้ใช้ที่โกรธแค้น
บทสรุป
โมเดลอนุกรมเวลาจำเป็นต้องมีหน่วยความจำ คอนเทนเนอร์นักเทียบท่าสูญเสียหน่วยความจำตามค่าเริ่มต้น วิธีแก้ปัญหานั้นง่ายมาก:แยกสถานะออกจากการคำนวณ
ใช้ Redis เป็นที่เก็บสถานะภายนอก ใช้โวลุ่มนักเทียบท่าเพื่อคงสถานะนั้นไว้ โมเดลของคุณยังคงชาญฉลาด คอนเทนเนอร์ของคุณสามารถเปลี่ยนได้ และการปรับใช้ของคุณก็จะเชื่อถือได้
รหัสการทำงานแบบเต็มมีอยู่ที่ github.com/ag-chirag/docker-redis-time-series โคลนมัน รันมัน ทำลายมัน เรียนรู้จากมัน
และจำไว้ว่า:วิธีแก้ปัญหาที่ง่ายที่สุดที่ได้ผลมักจะเป็นวิธีที่ถูกต้อง คุณไม่จำเป็นต้องใช้ Kubernetes และ StatefulSets เสมอไป บางครั้ง Docker Compose และโวลุ่มก็เพียงพอแล้ว
เรียนรู้การเขียนโค้ดฟรี หลักสูตรโอเพ่นซอร์สของ freeCodeCamp ช่วยให้ผู้คนมากกว่า 40,000 คนได้งานในตำแหน่งนักพัฒนา เริ่มต้น