उत्पादन में मशीन लर्निंग मॉडल को तैनात करने का कार्य हमेशा दर्द और पीड़ा होता है, क्योंकि निगरानी और गलती सहिष्णुता की दुनिया में एक आरामदायक ज्यूपिटर नोटबुक से बाहर निकलना बहुत असुविधाजनक होता है।
हमने पहले ही ऑनलाइन सिनेमा आइवी
की सिफारिश प्रणाली को फिर से शुरू करने के बारे में लिखा था। पिछले एक साल में, हमने लगभग एप्लिकेशन आर्किटेक्चर को अंतिम रूप नहीं दिया (वैश्विक से - केवल अप्रचलित अजगर 2.7 और अजगर 3.4 से "ताजा" अजगर 3.6 तक बढ़ते हुए), लेकिन हमने कुछ नए एमएल मॉडल जोड़े और तुरंत उत्पादन में नए एल्गोरिदम को रोल करने की समस्या में भाग गए। लेख में, मैं अपाचे एयरफ्लो के रूप में इस तरह के कार्य प्रवाह प्रबंधन उपकरण को लागू करने में हमारे अनुभव के बारे में बताऊंगा: टीम को इसकी आवश्यकता क्यों थी, मौजूदा समाधान के अनुरूप क्या नहीं था, किन बैटरियों को रास्ते में कटौती करनी थी और क्या आया।
→ रिपोर्ट का वीडियो संस्करण YouTube पर (03:00:00 से शुरू)
यहाँ देखा जा सकता
है ।
हाइड्रा टीम
मैं आपको परियोजना के बारे में थोड़ा बताऊंगा: ivi सामग्री की हजारों इकाइयों की दसियों संख्या है, हमारे पास RuNet की सबसे बड़ी कानूनी निर्देशिकाओं में से एक है। Ivi वेब संस्करण का मुख्य पृष्ठ कैटलॉग से एक व्यक्तिगत कट है, जो उपयोगकर्ता को उसकी प्रतिक्रिया (विचार, रेटिंग, और इसी तरह) के आधार पर सबसे अधिक समृद्ध, सबसे अधिक प्रासंगिक सामग्री प्रदान करने के लिए डिज़ाइन किया गया है।
सिफारिश प्रणाली का ऑनलाइन हिस्सा 600 आरपीएस तक के लोड के साथ फ्लास्क बैकएंड एप्लिकेशन है। ऑफ़लाइन, प्रति माह 250 मिलियन से अधिक सामग्री दृश्यों पर मॉडल को प्रशिक्षित किया जाता है। प्रशिक्षण के लिए डेटा तैयारी पाइपलाइन स्पार्क पर लागू की जाती है, जो हाइव रिपॉजिटरी के शीर्ष पर चलती है।
टीम में अब 7 डेवलपर्स हैं जो दोनों मॉडल बनाने और उन्हें उत्पादन में रोल करने में लगे हुए हैं - यह एक बड़ी टीम है जिसे कार्य प्रवाह के प्रबंधन के लिए सुविधाजनक उपकरण की आवश्यकता होती है।
ऑफ़लाइन वास्तुकला
नीचे आप अनुशंसा प्रणाली के लिए डेटा प्रवाह इन्फ्रास्ट्रक्चर आरेख देखते हैं।
दो डेटा स्टोरेज को यहां दर्शाया गया है - उपयोगकर्ता प्रतिक्रिया (विचार, रेटिंग) के लिए हाइव और विभिन्न व्यावसायिक जानकारी (सामग्री विमुद्रीकरण आदि के प्रकार) के लिए पोस्टग्रेज, जबकि पोस्टग्रेज से हाइव पर स्थानांतरण समायोजित किया जाता है। स्पार्क एप्लिकेशन का एक पैकेट हाइव का डेटा चूसता है: और इस डेटा पर हमारे मॉडल को प्रशिक्षित करता है (व्यक्तिगत सिफारिशों के लिए एएलएस, सामग्री समानता के विभिन्न सहयोगी मॉडल)।
स्पार्क एप्लिकेशन को पारंपरिक रूप से एक समर्पित वर्चुअल मशीन से प्रबंधित किया गया है, जिसे हम क्रोन + शेल स्क्रिप्ट के एक गुच्छा का उपयोग करके हाइड्रा-अपडेटर कहते हैं। इस बंडल को इवी ऑपरेशंस डिपार्टमेंट में पुराने समय में बनाया गया था और इसने बहुत अच्छा काम किया। शेल-स्क्रिप्ट स्पार्क-एप्लिकेशन लॉन्च करने के लिए एक एकल प्रविष्टि बिंदु था - अर्थात, प्रत्येक नए मॉडल ने इस स्क्रिप्ट को समाप्त करने के बाद ही ठेस में स्पिन करना शुरू कर दिया।
मॉडल प्रशिक्षण की कुछ कलाकृतियाँ शाश्वत भंडारण के लिए HDFS में संग्रहीत की जाती हैं (और किसी को वहां से डाउनलोड करने और सर्वर पर स्थानांतरित करने के लिए जहां ऑनलाइन भाग घूम रहा है), और कुछ सीधे स्पार्क ड्राइवर से रेडिस फास्ट स्टोरेज में लिखे जाते हैं, जिनका हम सामान्य रूप से उपयोग करते हैं। ऑनलाइन भाग के कई दर्जन अजगर प्रक्रियाओं के लिए मेमोरी।
इस तरह की वास्तुकला ने समय के साथ कई नुकसान जमा किए हैं:
आरेख से पता चलता है कि डेटा प्रवाह में एक जटिल और जटिल संरचना है - इस अच्छे, विकास और संचालन के प्रबंधन के लिए एक सरल और स्पष्ट उपकरण के बिना डरावनी, क्षय और पीड़ा में बदल जाएगा।
स्पार्क एप्लिकेशन को प्रबंधित करने के अलावा, व्यवस्थापक स्क्रिप्ट बहुत सारी उपयोगी चीजें करती है: युद्ध में सेवाओं को फिर से शुरू करना, एक रेडिस डंप और अन्य सिस्टम चीजें। जाहिर है, ऑपरेशन की एक लंबी अवधि में, स्क्रिप्ट कई कार्यों से आगे निकल गई है, क्योंकि हमारे प्रत्येक नए मॉडल ने इसमें कुछ दर्जन लाइनें बनाई हैं। कार्यक्षमता के लिहाज से यह लिपि बहुत अधिक भारित लगने लगी थी, इसलिए, अनुशंसा प्रणाली की एक टीम के रूप में, हम स्पार्क अनुप्रयोगों को लॉन्च करने और प्रबंधित करने की चिंता करने वाली कार्यक्षमता का एक हिस्सा कहीं बाहर निकालना चाहते थे। इन उद्देश्यों के लिए, हमने एयरफ्लो का उपयोग करने का निर्णय लिया।
एयरफ्लो के लिए बैसाखी
इन सभी समस्याओं को हल करने के अलावा, निश्चित रूप से, रास्ते में हमने खुद के लिए नए बनाए हैं - स्पार्क अनुप्रयोगों को लॉन्च करने और मॉनिटर करने के लिए एयरफ्लो को तैनात करना मुश्किल हो गया।
मुख्य कठिनाई यह थी कि कोई भी हमारे लिए पूरे बुनियादी ढांचे को फिर से तैयार नहीं करेगा, क्योंकि devops resource एक दुर्लभ चीज है। इस कारण से, हमें न केवल एयरफ्लो को लागू करना था, बल्कि इसे मौजूदा प्रणाली में एकीकृत करना था, जो खरोंच से देखा जाना बहुत कठिन है।
मैं उन दर्द के बारे में बात करना चाहता हूं जो हमें कार्यान्वयन प्रक्रिया के दौरान हुए थे, और बैसाखी जिसे हमें एयरफ्लो प्राप्त करने के लिए गश करना था।
पहला और मुख्य दर्द : ऑपरेशन विभाग के एक बड़े शेल स्क्रिप्ट में एयरफ्लो को कैसे एकीकृत किया जाए।
यहां समाधान सबसे स्पष्ट है - हमने ट्रिगर_डैग कुंजी के साथ एयरफ्लो बाइनरी का उपयोग करके सीधे शेल स्क्रिप्ट से ग्राफ़ को ट्रिगर करना शुरू किया। इस दृष्टिकोण के साथ, हम एयरफ्लो शेड्यूलर का उपयोग नहीं करते हैं, और वास्तव में स्पार्क एप्लिकेशन को उसी ताज के साथ लॉन्च किया जाता है - यह धार्मिक रूप से बहुत सही नहीं है। लेकिन हमें मौजूदा समाधान के साथ एक सहज एकीकरण मिला। यहां यह शुरुआत हमारे मुख्य स्पार्क एप्लिकेशन की शेल स्क्रिप्ट से शुरू होती है, जिसे ऐतिहासिक रूप से हाइड्रामैट्रीस कहा जाता है।
log "$FUNCNAME started" local RETVAL=0 export AIRFLOW_CONFIG=/opt/airflow/airflow.cfg AIRFLOW_API=api/dag_last_run/hydramatrices/all log "run /var/www/airflow/bin/airflow trigger_dag hydramatrices" /var/www/airflow/bin/airflow trigger_dag hydramatrices 2>&1 | tee -a $LOGFILE
दर्द: संचालन विभाग
की शेल स्क्रिप्ट को किसी तरह से एयरफ्लो ग्राफ की स्थिति का निर्धारण करना चाहिए ताकि इसके निष्पादन प्रवाह को नियंत्रित किया जा सके।
क्रच: हमने शेल स्क्रिप्ट्स के अंदर DAG निगरानी के लिए समापन बिंदु के साथ Airflow REST API का विस्तार किया। अब प्रत्येक ग्राफ में तीन अवस्थाएँ हैं: RUNNING, SUCCEED, FAILED।
वास्तव में, एयरफ्लो में गणना शुरू करने के बाद, हम बस नियमित रूप से रनिंग ग्राफ को प्रदूषित करते हैं: हम यह निर्धारित करने के लिए जीईटी अनुरोध को बुलेट करते हैं कि क्या डीएजी पूरा हो गया है या नहीं। जब मॉनिटरिंग समापन बिंदु ग्राफ़ के सफल निष्पादन के बारे में प्रतिक्रिया देता है, तो शेल स्क्रिप्ट अपने प्रवाह को निष्पादित करना जारी रखती है।
मैं कहना चाहता हूं कि Airflow REST API एक ज्वलंत चीज है जो आपको लचीले ढंग से अपनी पाइपलाइनों को कॉन्फ़िगर करने की अनुमति देती है - उदाहरण के लिए, आप POST मापदंडों को रेखांकन के लिए अग्रेषित कर सकते हैं।
Airflow एपीआई विस्तार सिर्फ एक पायथन वर्ग है जो कुछ इस तरह दिखता है:
import json import os from airflow import settings from airflow.models import DagBag, DagRun from flask import Blueprint, request, Response airflow_api_blueprint = Blueprint('airflow_api', __name__, url_prefix='/api') AIRFLOW_DAGS = '{}/dags'.format( os.path.dirname(os.path.dirname(os.path.abspath(__file__))) ) class ApiResponse: """ GET """ STATUS_OK = 200 STATUS_NOT_FOUND = 404 def __init__(self): pass @staticmethod def standard_response(status: int, payload: dict) -> Response: json_data = json.dumps(payload) resp = Response(json_data, status=status, mimetype='application/json') return resp def success(self, payload: dict) -> Response: return self.standard_response(self.STATUS_OK, payload) def error(self, status: int, message: str) -> Response: return self.standard_response(status, {'error': message}) def not_found(self, message: str = 'Resource not found') -> Response: return self.error(self.STATUS_NOT_FOUND, message)
हम शेल स्क्रिप्ट में API का उपयोग करते हैं - हम प्रत्येक 10 मिनट में समापन बिंदु पर मतदान करते हैं:
TRIGGER=$? [ "$TRIGGER" -eq "0" ] && log "trigger airflow DAG succeeded" || { log "trigger airflow DAG failed"; return 1; } CMD="curl -s http://$HYDRA_SERVER/$AIRFLOW_API | jq .dag_last_run.state" STATE=$(eval $CMD) while [ $STATE == \"running\" ]; do log "Generating matrices in progress..." sleep 600 STATE=$(eval $CMD) done [ $STATE == \"success\" ] && RETVAL=0 || RETVAL=1 [ $RETVAL -eq 0 ] && log "$FUNCNAME succeeded" || log "$FUNCNAME failed" return $RETVAL
दर्द : यदि आप कभी भी स्पार्क-सबमिट क्लस्टर मोड में स्पार्क जॉब चलाते हैं, तो आप जानते हैं कि STDOUT में लॉग "SPARK APPLICATION_ID IS RUNNING" लाइनों के साथ एक अनियंत्रित शीट है। स्पार्क एप्लिकेशन के लॉग स्वयं देखे जा सकते हैं, उदाहरण के लिए, यार्न लॉग कमांड का उपयोग। शेल स्क्रिप्ट में, इस समस्या को बस हल किया गया था: एक एसएसएच सुरंग को क्लस्टर मशीनों में से एक के लिए खोला गया था और इस मशीन के लिए क्लाइंट मोड में स्पार्क-सबमिट निष्पादित किया गया था। इस स्थिति में, STDOUT में पठनीय और समझने योग्य लॉग होंगे। एयरफ्लो में, हमने हमेशा क्लस्टर-निर्णय का उपयोग करने का निर्णय लिया, और ऐसी संख्या काम नहीं करेगी।
क्रच: स्पार्क-सबमिट काम करने के बाद, हम application_id द्वारा ड्राइवर लॉग को HDFS से खींचते हैं और इसे एयरफ्लो इंटरफ़ेस में केवल पायथन प्रिंट () ऑपरेटर के माध्यम से प्रदर्शित करते हैं। केवल नकारात्मक - एयरफ्लो इंटरफ़ेस में, लॉग केवल स्पार्क-सबमिट के काम करने के बाद दिखाई देते हैं, आपको अन्य स्थानों में रियलटाइम का पालन करना होगा - उदाहरण के लिए, यार्न वेब थूथन।
def get_logs(config: BaseConfig, app_id: str) -> None: """ :param config: :param app_id: """ hdfs = HDFSInteractor(config) logs_path = '/tmp/logs/{username}/logs/{app_id}'.format(username=config.CURRENT_USERNAME, app_id=app_id) logs_files = hdfs.files_in_folder(logs_path) logs_files = [file for file in logs_files if file[-4:] != '.tmp'] for file in logs_files: with hdfs.hdfs_client.read(os.path.join(logs_path, file), encoding='utf-8', delimiter='\n') as reader: print_line = False for line in reader: if re.search('stdout', line) and len(line) > 30: print_line = True if re.search('stderr', line): print_line = False if print_line: print(line)
दर्द : परीक्षकों और डेवलपर्स के लिए, एयरफ्लो टेस्ट बेंच होना अच्छा होगा, लेकिन हम डेवॉप्स संसाधनों की बचत कर रहे हैं, इसलिए हमने सोचा कि लंबे समय तक परीक्षण वातावरण कैसे तैनात किया जाए।
क्रच: हमने एयरक्राफ्ट को एक डॉकटर कंटेनर में पैक किया, और डॉकरीफाइल ने स्पार्क नौकरियों के साथ रिपॉजिटरी में इसे सही तरीके से रखा। इस प्रकार, प्रत्येक डेवलपर या परीक्षक स्थानीय मशीन पर अपना एयरफ्लो बढ़ा सकते हैं। इस तथ्य के कारण कि अनुप्रयोग क्लस्टर-मोड में चलते हैं, डॉक के लिए स्थानीय संसाधनों की लगभग आवश्यकता नहीं है।
स्पार्क की एक स्थानीय स्थापना डॉक कंटेनर और पर्यावरण चर के माध्यम से इसके पूरे विन्यास में छिपी हुई थी - अब आपको पर्यावरण स्थापित करने में कई घंटे खर्च करने की आवश्यकता नहीं है। नीचे मैंने Airflow के साथ एक कंटेनर के लिए डॉक फ़ाइल टुकड़ा के साथ एक उदाहरण दिया, जहां आप देख सकते हैं कि Airflow का उपयोग कैसे किया जाता है:
FROM ubuntu:16.04 ARG AIRFLOW_VERSION=1.9.0 ARG AIRFLOW_HOME ARG USERNAME=airflow ARG USER_ID ARG GROUP_ID ARG LOCALHOST ARG AIRFLOW_PORT ARG PIPENV_PATH ARG PROJECT_HYDRAMATRICES_DOCKER_PATH RUN apt-get update \ && apt-get install -y \ python3.6 \ python3.6-dev \ && update-alternatives --install /usr/bin/python3 python3.6 /usr/bin/python3.6 0 \ && apt-get -y install python3-pip RUN mv /root/.pydistutils.cf /root/.pydistutils.cfg RUN pip3 install pandas==0.20.3 \ apache-airflow==$AIRFLOW_VERSION \ psycopg2==2.7.5 \ ldap3==2.5.1 \ cryptography
Airflow के कार्यान्वयन के परिणामस्वरूप, हमने निम्नलिखित परिणाम प्राप्त किए:
- रिलीज़ चक्र को कम करना: एक नया मॉडल (या डेटा तैयारी पाइपलाइन) को रोल आउट करना अब एक नया एयरफ़्लो ग्राफ लिखने के लिए नीचे आता है, ग्राफ़ खुद को भंडार में संग्रहीत किया जाता है और कोड के साथ तैनात किया जाता है। यह प्रक्रिया पूरी तरह से डेवलपर के हाथों में है। Admins खुश हैं, अब हम उन्हें trifles पर नहीं खींच रहे हैं।
- स्पार्क एप्लिकेशन लॉग जो सीधे नरक में जाते थे, अब एआईफ्लो में एक सुविधाजनक एक्सेस इंटरफ़ेस के साथ संग्रहीत हैं। आप HDFS निर्देशिकाओं में बिना किसी दिन के लॉग देख सकते हैं।
- असफल गणना को इंटरफ़ेस में एक बटन के साथ फिर से शुरू किया जा सकता है, यह बहुत सुविधाजनक है, यहां तक कि जून भी इसे संभाल सकता है।
- आप स्थानीय मशीन पर स्पार्क सेटिंग्स में चलने के बिना इंटरफ़ेस से स्पार्क नौकरियों को गोली मार सकते हैं। परीक्षक खुश हैं - स्पार्क-सबमिट के लिए सही ढंग से काम करने के लिए सभी सेटिंग्स पहले से ही डॉकरफाइल में बनाई गई हैं
- एफ़्लो मानक बन्स - शेड्यूल, गिरी हुई नौकरियों को फिर से शुरू करना, सुंदर रेखांकन (उदाहरण के लिए, एप्लिकेशन निष्पादन समय, सफल और असफल लॉन्च के आंकड़े)।
आगे कहाँ जाना है? अब हमारे पास बड़ी संख्या में डेटा स्रोत और सिंक हैं, जिनमें से संख्या बढ़ेगी। किसी भी हाइडरामैट्रीस रिपॉजिटरी वर्ग में परिवर्तन एक और पाइपलाइन (या ऑनलाइन भाग में भी) में दुर्घटनाग्रस्त हो सकता है:
- क्लिकहाउस ओवरफ्लो → हाइव
- डेटा प्रीप्रोसेसिंग: हाइव → हाइव
- सी 2 सी मॉडल तैनात करें: हाइव → रेडिस
- निर्देशिकाओं की तैयारी (सामग्री विमुद्रीकरण के प्रकार की तरह): पोस्टग्रैज → रेडिस
- मॉडल की तैयारी: स्थानीय एफएस → एचडीएफएस
ऐसी स्थिति में, हमें वास्तव में डेटा तैयार करने में पाइपलाइनों के स्वत: परीक्षण के लिए एक स्टैंड की आवश्यकता है। यह रिपॉजिटरी में परीक्षण परिवर्तनों की लागत को काफी कम कर देगा, उत्पादन में नए मॉडल के रोलिंग को गति देगा और नाटकीय रूप से परीक्षकों में एंडोर्फिन के स्तर को बढ़ाएगा। लेकिन एयरफ्लो के बिना, इस तरह के ऑटो परीक्षण के लिए एक स्टैंड तैनात करना असंभव होगा!
एयरफ्लो को लागू करने में हमारे अनुभव के बारे में बताने के लिए मैंने यह लेख लिखा है, जो एक समान स्थिति में अन्य टीमों के लिए उपयोगी हो सकता है - आपके पास पहले से ही एक बड़ी कार्य प्रणाली है, और आप कुछ नया, फैशनेबल और युवा बनाने की कोशिश करना चाहते हैं। कार्य प्रणाली के किसी भी अपडेट से डरने की ज़रूरत नहीं है, आपको कोशिश करने और प्रयोग करने की आवश्यकता है - ऐसे प्रयोग आमतौर पर आगे के विकास के लिए नए क्षितिज खोलते हैं।