څنګه د کلستر لپاره خپل آټوسکلر جوړ کړئ

سلام! موږ خلکو ته روزنه ورکوو چې د لوی ډیټا سره کار وکړي. دا ناشونې ده چې د لوی ډیټا په اړه یو تعلیمي برنامه د خپل کلستر پرته تصور کړئ، چې ټول ګډونوال په ګډه کار کوي. د دې دلیل لپاره، زموږ برنامه تل دا لري 🙂 موږ د دې په ترتیب کولو ، تنظیم کولو او اداره کولو کې بوخت یو ، او هلکان په مستقیم ډول هلته د MapReduce دندې پیلوي او سپارک کاروي.

پدې پوسټ کې به موږ تاسو ته ووایو چې څنګه موږ د کلاوډ په کارولو سره زموږ د خپل آټوسکلر لیکلو سره د غیر مساوي کلستر بار کولو ستونزه حل کړه Mail.ru کلاوډ حلونه.

ستونزه

زموږ کلستر په عادي حالت کې نه کارول کیږي. تصفیه خورا غیر مساوي ده. د مثال په توګه، عملي ټولګي شتون لري، کله چې ټول 30 کسان او یو ښوونکی کلستر ته لاړ شي او کارول یې پیل کړي. یا بیا، د نیټې څخه مخکې ورځې شتون لري کله چې بار خورا ډیریږي. پاتې وخت کلستر د انډرلوډ حالت کې کار کوي.

د حل # 1 دا دی چې یو کلستر وساتئ چې د لوړ بارونو سره مقاومت وکړي، مګر پاتې وخت به بې کاره وي.

د حل # 2 دا دی چې یو کوچنی کلستر وساتئ، کوم چې تاسو په لاسي ډول د ټولګیو څخه مخکې او د لوړ بارونو په وخت کې نوډونه اضافه کړئ.

د حل # 3 دا دی چې یو کوچنی کلستر وساتئ او یو آٹو سکیلر ولیکئ چې د کلستر اوسنی بار وڅاري او د مختلف APIs په کارولو سره له کلستر څخه نوډونه اضافه او لرې کړي.

پدې پوسټ کې به موږ د حل # 3 په اړه وغږیږو. دا آټوسکلر د داخلي فاکتورونو پرځای په بهرني فکتورونو پورې اړه لري ، او چمتو کونکي اکثرا دا نه وړاندې کوي. موږ د Mail.ru کلاوډ سولیوشن کلاوډ زیربنا کاروو او د MCS API په کارولو سره یو آټوسکلر لیکلی. او له هغه ځایه چې موږ د ډیټا سره کار کولو څرنګوالی ښوولی ، موږ پریکړه وکړه چې وښیو چې تاسو څنګه کولی شئ د خپلو موخو لپاره ورته آټوسکلر ولیکئ او د خپل کلاوډ سره یې وکاروئ.

اړتیاوې

لومړی، تاسو باید د هډوپ کلستر ولرئ. د مثال په توګه، موږ د HDP توزیع کاروو.

د دې لپاره چې ستاسو نوډونه په چټکۍ سره اضافه او لرې شي، تاسو باید د نوډونو ترمنځ د رولونو یو مشخص ویش ولرئ.

  1. ماسټر نوډ. ښه، په ځانګړې توګه د هیڅ شی تشریح کولو ته اړتیا نشته: د کلستر اصلي نوډ، په کوم کې، د بیلګې په توګه، سپارک ډرایور په لاره اچول شوی، که تاسو د متقابل حالت کاروئ.
  2. د نیټې نوډ. دا هغه نوډ دی چې تاسو یې په HDFS کې ډاټا ذخیره کوئ او چیرې چې حسابونه ترسره کیږي.
  3. د کمپیوټري نوډ. دا یو نوډ دی چیرې چې تاسو په HDFS کې هیڅ شی نه ذخیره کوئ ، مګر چیرې چې محاسبه کیږي.

مهم ټکی. اتوماتیک کول به د دریم ډول نوډونو له امله پیښ شي. که تاسو د دویم ډول نوډونو اخیستل او اضافه کول پیل کړئ، د غبرګون سرعت به خورا ټیټ وي - له منځه وړل او بیا تکرار کول به ستاسو په کلستر کې ساعتونه ونیسي. دا، البته، هغه څه ندي چې تاسو یې د اتوماتیک کولو څخه تمه لرئ. دا دی، موږ د لومړي او دویم ډول نوډونو ته لاس نه ورکوو. دوی به د لږترلږه ګټور کلستر استازیتوب وکړي چې د پروګرام په ټوله موده کې به شتون ولري.

نو، زموږ آټوسکلر په Python 3 کې لیکل شوی، د کلستر خدماتو اداره کولو لپاره Ambari API کاروي، کاروي API د Mail.ru کلاوډ حلونو څخه (MCS) د ماشینونو د پیل او بندولو لپاره.

د حل جوړښت

  1. انډول autoscaler.py. دا درې ټولګي لري: 1) د امباري سره کار کولو لپاره فنکشنونه، 2) د MCS سره کار کولو لپاره فنکشنونه، 3) د آټوسکلر منطق سره مستقیم تړاو لري.
  2. سکریپټ observer.py. په لازمي ډول دا مختلف مقررات لري: کله او په کومو شیبو کې د آټوسکلر فنکشن ته زنګ ووهئ.
  3. د ترتیب فایل config.py. دا د مثال په توګه، د نوډونو لیست لري چې د اتوماتیک کولو او نورو پیرامیټونو لپاره اجازه لري چې اغیزه کوي، د بیلګې په توګه، د نوي نوډ اضافه کولو څخه څومره وخت انتظار کول. د ټولګیو د پیل لپاره مهال ویشونه هم شتون لري، ترڅو د ټولګي څخه مخکې د کلستر ډیری اجازه ورکړل شوي ترتیب پیل شي.

راځئ چې اوس د لومړي دوه فایلونو دننه د کوډ ټوټې وګورو.

1. Autoscaler.py ماډل

د امباري ټولګي

دا هغه څه دي چې د کوډ یوه ټوټه چې ټولګي لري داسې ښکاري Ambari:

class Ambari:
    def __init__(self, ambari_url, cluster_name, headers, auth):
        self.ambari_url = ambari_url
        self.cluster_name = cluster_name
        self.headers = headers
        self.auth = auth

    def stop_all_services(self, hostname):
        url = self.ambari_url + self.cluster_name + '/hosts/' + hostname + '/host_components/'
        url2 = self.ambari_url + self.cluster_name + '/hosts/' + hostname
        req0 = requests.get(url2, headers=self.headers, auth=self.auth)
        services = req0.json()['host_components']
        services_list = list(map(lambda x: x['HostRoles']['component_name'], services))
        data = {
            "RequestInfo": {
                "context":"Stop All Host Components",
                "operation_level": {
                    "level":"HOST",
                    "cluster_name": self.cluster_name,
                    "host_names": hostname
                },
                "query":"HostRoles/component_name.in({0})".format(",".join(services_list))
            },
            "Body": {
                "HostRoles": {
                    "state":"INSTALLED"
                }
            }
        }
        req = requests.put(url, data=json.dumps(data), headers=self.headers, auth=self.auth)
        if req.status_code in [200, 201, 202]:
            message = 'Request accepted'
        else:
            message = req.status_code
        return message

پورته، د مثال په توګه، تاسو کولی شئ د فعالیت تطبیق وګورئ stop_all_services، کوم چې په مطلوب کلستر نوډ کې ټول خدمات ودروي.

ټولګي ته د ننوتلو په وخت کې Ambari تاسو تېر شئ:

  • ambari_urlد مثال په توګه، لکه 'http://localhost:8080/api/v1/clusters/',
  • cluster_name - په امباري کې ستاسو د کلستر نوم،
  • headers = {'X-Requested-By': 'ambari'}
  • او دننه auth دلته د امباري لپاره ستاسو ننوتل او پټنوم دی: auth = ('login', 'password').

فنکشن پخپله امباري ته د REST API له لارې د څو زنګونو څخه ډیر څه ندي. د منطقي نظر څخه، موږ لومړی په نوډ کې د چلولو خدماتو لیست ترلاسه کوو، او بیا په ورکړل شوي کلستر کې، په ورکړل شوي نوډ کې، د لیست څخه دولت ته د خدماتو لیږدولو غوښتنه کوو. INSTALLED. د ټولو خدماتو پیل کولو لپاره دندې، دولت ته د نوډونو لیږدولو لپاره Maintenance وغيره ورته ورته ښکاري - دا د API له لارې یوازې یو څو غوښتنې دي.

کلاس Mcs

دا هغه څه دي چې د کوډ یوه ټوټه چې ټولګي لري داسې ښکاري Mcs:

class Mcs:
    def __init__(self, id1, id2, password):
        self.id1 = id1
        self.id2 = id2
        self.password = password
        self.mcs_host = 'https://infra.mail.ru:8774/v2.1'

    def vm_turn_on(self, hostname):
        self.token = self.get_mcs_token()
        host = self.hostname_to_vmname(hostname)
        vm_id = self.get_vm_id(host)
        mcs_url1 = self.mcs_host + '/servers/' + self.vm_id + '/action'
        headers = {
            'X-Auth-Token': '{0}'.format(self.token),
            'Content-Type': 'application/json'
        }
        data = {'os-start' : 'null'}
        mcs = requests.post(mcs_url1, data=json.dumps(data), headers=headers)
        return mcs.status_code

ټولګي ته د ننوتلو په وخت کې Mcs موږ د پروژې ID په کلاوډ کې دننه او د کارونکي ID او همدارنګه د هغه پټنوم پاس کوو. په فعالیت کې vm_turn_on موږ غواړو چې یو له ماشینونو څخه فعال کړو. دلته منطق یو څه ډیر پیچلی دی. د کوډ په پیل کې، درې نورې دندې ویل کیږي: 1) موږ اړتیا لرو یو نښه ترلاسه کړو، 2) موږ اړتیا لرو چې کوربه نوم په MCS کې د ماشین په نوم بدل کړو، 3) د دې ماشین ID ترلاسه کړئ. بیا ، موږ په ساده ډول د پوسټ غوښتنه کوو او دا ماشین لانچ کوو.

دا هغه څه دي چې د نښه ترلاسه کولو فعالیت داسې ښکاري:

def get_mcs_token(self):
        url = 'https://infra.mail.ru:35357/v3/auth/tokens?nocatalog'
        headers = {'Content-Type': 'application/json'}
        data = {
            'auth': {
                'identity': {
                    'methods': ['password'],
                    'password': {
                        'user': {
                            'id': self.id1,
                            'password': self.password
                        }
                    }
                },
                'scope': {
                    'project': {
                        'id': self.id2
                    }
                }
            }
        }
        params = (('nocatalog', ''),)
        req = requests.post(url, data=json.dumps(data), headers=headers, params=params)
        self.token = req.headers['X-Subject-Token']
        return self.token

د Autoscaler ټولګي

دا ټولګي پخپله د عملیاتي منطق پورې اړوند دندې لري.

دا هغه څه دي چې د دې ټولګي لپاره د کوډ یوه برخه داسې ښکاري:

class Autoscaler:
    def __init__(self, ambari, mcs, scaling_hosts, yarn_ram_per_node, yarn_cpu_per_node):
        self.scaling_hosts = scaling_hosts
        self.ambari = ambari
        self.mcs = mcs
        self.q_ram = deque()
        self.q_cpu = deque()
        self.num = 0
        self.yarn_ram_per_node = yarn_ram_per_node
        self.yarn_cpu_per_node = yarn_cpu_per_node

    def scale_down(self, hostname):
        flag1 = flag2 = flag3 = flag4 = flag5 = False
        if hostname in self.scaling_hosts:
            while True:
                time.sleep(5)
                status1 = self.ambari.decommission_nodemanager(hostname)
                if status1 == 'Request accepted' or status1 == 500:
                    flag1 = True
                    logging.info('Decomission request accepted: {0}'.format(flag1))
                    break
            while True:
                time.sleep(5)
                status3 = self.ambari.check_service(hostname, 'NODEMANAGER')
                if status3 == 'INSTALLED':
                    flag3 = True
                    logging.info('Nodemaneger decommissioned: {0}'.format(flag3))
                    break
            while True:
                time.sleep(5)
                status2 = self.ambari.maintenance_on(hostname)
                if status2 == 'Request accepted' or status2 == 500:
                    flag2 = True
                    logging.info('Maintenance request accepted: {0}'.format(flag2))
                    break
            while True:
                time.sleep(5)
                status4 = self.ambari.check_maintenance(hostname, 'NODEMANAGER')
                if status4 == 'ON' or status4 == 'IMPLIED_FROM_HOST':
                    flag4 = True
                    self.ambari.stop_all_services(hostname)
                    logging.info('Maintenance is on: {0}'.format(flag4))
                    logging.info('Stopping services')
                    break
            time.sleep(90)
            status5 = self.mcs.vm_turn_off(hostname)
            while True:
                time.sleep(5)
                status5 = self.mcs.get_vm_info(hostname)['server']['status']
                if status5 == 'SHUTOFF':
                    flag5 = True
                    logging.info('VM is turned off: {0}'.format(flag5))
                    break
            if flag1 and flag2 and flag3 and flag4 and flag5:
                message = 'Success'
                logging.info('Scale-down finished')
                logging.info('Cooldown period has started. Wait for several minutes')
        return message

موږ د ننوتلو لپاره ټولګي منو. Ambari и Mcs، د نوډونو لیست چې د اندازه کولو لپاره اجازه لري، او همدارنګه د نوډ ترتیب کولو پیرامیټونه: حافظه او cpu په YARN کې نوډ ته تخصیص شوي. دلته 2 داخلي پیرامیټونه q_ram، q_cpu هم شتون لري، کوم چې قطارونه دي. د دوی په کارولو سره، موږ د اوسني کلستر بار ارزښتونه ذخیره کوو. که موږ وګورو چې په تیرو 5 دقیقو کې په دوامداره توګه ډیر شوی بار شتون لري ، نو موږ پریکړه کوو چې موږ اړتیا لرو په کلستر کې +1 نوډ اضافه کړو. ورته د کلستر د کم استعمال حالت لپاره ریښتیا ده.

پورته کوډ د یو فنکشن مثال دی چې ماشین له کلستر څخه لیرې کوي او په بادل کې یې ودروي. لومړی دلته یو له منځه وړل دی YARN Nodemanager، بیا موډ فعالیږي Maintenance، بیا موږ په ماشین کې ټول خدمات ودروو او په بادل کې مجازی ماشین بند کړو.

2. سکریپټ څارونکي.py

له دې ځایه کوډ نمونه:

if scaler.assert_up(config.scale_up_thresholds) == True:
        hostname = cloud.get_vm_to_up(config.scaling_hosts)
        if hostname != None:
            status1 = scaler.scale_up(hostname)
            if status1 == 'Success':
                text = {"text": "{0} has been successfully scaled-up".format(hostname)}
                post = {"text": "{0}".format(text)}
                json_data = json.dumps(post)
                req = requests.post(webhook, data=json_data.encode('ascii'), headers={'Content-Type': 'application/json'})
                time.sleep(config.cooldown_period*60)

په دې کې، موږ ګورو چې ایا د کلستر ظرفیت لوړولو لپاره شرایط رامینځته شوي او ایا په ذخیره کې کوم ماشینونه شتون لري، د دوی څخه یو کوربه نوم ترلاسه کړئ، په کلستر کې یې اضافه کړئ او زموږ د ټیم سلیک کې یې په اړه پیغام خپور کړئ. له هغې وروسته پیل کیږي cooldown_period، کله چې موږ له کلستر څخه هیڅ شی نه اضافه کوو یا لرې کوو ، مګر په ساده ډول د بار څارنه کوو. که دا ثبات ولري او د غوره بار ارزښتونو دهلیز کې وي، نو موږ په ساده ډول څارنې ته دوام ورکوو. که یو نوډ کافی نه و، نو موږ یو بل اضافه کړو.

د هغو قضیو لپاره چې موږ مخکې درس لرو، موږ دمخه په ډاډه توګه پوهیږو چې یو نوډ به کافي نه وي، نو موږ سمدلاسه ټول وړیا نوډونه پیل کوو او د لوست تر پای پورې یې فعال وساتو. دا د فعالیت مهال ویشونو لیست په کارولو سره پیښیږي.

پایلې

Autoscaler د هغو قضیو لپاره یو ښه او مناسب حل دی کله چې تاسو د غیر مساوي کلستر بار کولو تجربه کوئ. تاسو په ورته وخت کې د لوړ بارونو لپاره مطلوب کلستر ترتیب ترلاسه کوئ او په ورته وخت کې دا کلستر د انډرلوډ پرمهال مه ساتئ، پیسې خوندي کړئ. ښه، دا ټول ستاسو د ګډون پرته په اتوماتيک ډول پیښیږي. آټوسکلر پخپله د کلستر مدیر API او د کلاوډ چمتو کونکي API ته د غوښتنو له یوې سیټ پرته نور څه ندي ، د یو ځانګړي منطق سره سم لیکل شوي. هغه څه چې تاسو حتما په یاد ولرئ د نوډونو ویش په 3 ډولونو کې دی ، لکه څنګه چې موږ دمخه لیکلي. او تاسو به خوشحاله شئ.

سرچینه: www.habr.com

Add a comment