క్లస్టర్ కోసం మీ స్వంత ఆటోస్కేలర్‌ను ఎలా తయారు చేసుకోవాలి

హలో! పెద్ద డేటాతో పని చేయడానికి మేము వ్యక్తులకు శిక్షణ ఇస్తాము. దాని స్వంత క్లస్టర్ లేకుండా పెద్ద డేటాపై విద్యా కార్యక్రమాన్ని ఊహించడం అసాధ్యం, దీనిలో పాల్గొనే వారందరూ కలిసి పని చేస్తారు. ఈ కారణంగా, మా ప్రోగ్రామ్ ఎల్లప్పుడూ దానిని కలిగి ఉంటుంది :) మేము దాని కాన్ఫిగరేషన్, ట్యూనింగ్ మరియు అడ్మినిస్ట్రేషన్‌లో నిమగ్నమై ఉన్నాము మరియు అబ్బాయిలు నేరుగా MapReduce ఉద్యోగాలను అక్కడ ప్రారంభించి, స్పార్క్‌ని ఉపయోగిస్తారు.

క్లౌడ్‌ని ఉపయోగించి మా స్వంత ఆటోస్కేలర్‌ను వ్రాయడం ద్వారా అసమాన క్లస్టర్ లోడింగ్ సమస్యను ఎలా పరిష్కరించామో ఈ పోస్ట్‌లో మేము మీకు తెలియజేస్తాము Mail.ru క్లౌడ్ సొల్యూషన్స్.

సమస్య

మా క్లస్టర్ సాధారణ మోడ్‌లో ఉపయోగించబడదు. పారవేయడం చాలా అసమానంగా ఉంది. ఉదాహరణకు, ఆచరణాత్మక తరగతులు ఉన్నాయి, మొత్తం 30 మంది వ్యక్తులు మరియు ఒక ఉపాధ్యాయుడు క్లస్టర్‌కి వెళ్లి దానిని ఉపయోగించడం ప్రారంభించినప్పుడు. లేదా మళ్లీ, లోడ్ బాగా పెరిగినప్పుడు గడువుకు ముందు రోజులు ఉన్నాయి. మిగిలిన సమయంలో క్లస్టర్ అండర్‌లోడ్ మోడ్‌లో పనిచేస్తుంది.

పరిష్కారం #1 అనేది పీక్ లోడ్‌లను తట్టుకునే క్లస్టర్‌ను ఉంచడం, కానీ మిగిలిన సమయంలో పనిలేకుండా ఉంటుంది.

పరిష్కారం #2 అనేది ఒక చిన్న క్లస్టర్‌ను ఉంచడం, దీనికి మీరు తరగతులకు ముందు మరియు పీక్ లోడ్‌ల సమయంలో మాన్యువల్‌గా నోడ్‌లను జోడించడం.

పరిష్కారం #3 ఒక చిన్న క్లస్టర్‌ను ఉంచడం మరియు క్లస్టర్ యొక్క ప్రస్తుత లోడ్‌ను పర్యవేక్షించే ఆటోస్కేలర్‌ను వ్రాయడం మరియు వివిధ APIలను ఉపయోగించి, క్లస్టర్ నుండి నోడ్‌లను జోడించడం మరియు తీసివేయడం.

ఈ పోస్ట్‌లో మనం పరిష్కారం #3 గురించి మాట్లాడుతాము. ఈ ఆటోస్కేలర్ అంతర్గత అంశాల కంటే బాహ్య కారకాలపై ఎక్కువగా ఆధారపడి ఉంటుంది మరియు ప్రొవైడర్లు తరచుగా దీనిని అందించరు. మేము Mail.ru క్లౌడ్ సొల్యూషన్స్ క్లౌడ్ ఇన్‌ఫ్రాస్ట్రక్చర్‌ని ఉపయోగిస్తాము మరియు MCS APIని ఉపయోగించి ఆటోస్కేలర్‌ను వ్రాసాము. మరియు డేటాతో ఎలా పని చేయాలో మేము బోధిస్తాము కాబట్టి, మీరు మీ స్వంత ప్రయోజనాల కోసం ఇలాంటి ఆటోస్కేలర్‌ను ఎలా వ్రాయవచ్చో మరియు దానిని మీ క్లౌడ్‌తో ఎలా ఉపయోగించవచ్చో చూపాలని మేము నిర్ణయించుకున్నాము

కనీసావసరాలు

ముందుగా, మీరు తప్పనిసరిగా హడూప్ క్లస్టర్‌ని కలిగి ఉండాలి. ఉదాహరణకు, మేము HDP పంపిణీని ఉపయోగిస్తాము.

మీ నోడ్‌లను త్వరగా జోడించడానికి మరియు తీసివేయడానికి, మీరు నోడ్‌ల మధ్య నిర్దిష్ట పాత్రల పంపిణీని కలిగి ఉండాలి.

  1. మాస్టర్ నోడ్. బాగా, ఇక్కడ వివరించడానికి ప్రత్యేకంగా ఏమీ అవసరం లేదు: క్లస్టర్ యొక్క ప్రధాన నోడ్, ఉదాహరణకు, మీరు ఇంటరాక్టివ్ మోడ్‌ను ఉపయోగిస్తే, స్పార్క్ డ్రైవర్ ప్రారంభించబడుతుంది.
  2. తేదీ నోడ్. ఇది మీరు HDFSలో డేటాను నిల్వ చేసే నోడ్ మరియు గణనలు ఎక్కడ జరుగుతాయి.
  3. కంప్యూటింగ్ నోడ్. ఇది మీరు HDFSలో దేనినీ నిల్వ చేయని నోడ్, కానీ ఇక్కడ లెక్కలు జరుగుతాయి.

ముఖ్యమైన పాయింట్. మూడవ రకం నోడ్‌ల కారణంగా ఆటోస్కేలింగ్ జరుగుతుంది. మీరు రెండవ రకం నోడ్‌లను తీసుకోవడం మరియు జోడించడం ప్రారంభిస్తే, ప్రతిస్పందన వేగం చాలా తక్కువగా ఉంటుంది - ఉపసంహరణ మరియు రీకమిట్ చేయడానికి మీ క్లస్టర్‌లో గంటలు పడుతుంది. ఇది ఆటోస్కేలింగ్ నుండి మీరు ఆశించేది కాదు. అంటే, మేము మొదటి మరియు రెండవ రకాల నోడ్లను తాకము. అవి ప్రోగ్రామ్ వ్యవధిలో ఉండే కనీస ఆచరణీయ క్లస్టర్‌ను సూచిస్తాయి.

కాబట్టి, మా ఆటోస్కేలర్ పైథాన్ 3లో వ్రాయబడింది, క్లస్టర్ సేవలను నిర్వహించడానికి అంబరీ APIని ఉపయోగిస్తుంది, ఉపయోగాలు Mail.ru క్లౌడ్ సొల్యూషన్స్ నుండి API (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 మేము క్లౌడ్ లోపల ప్రాజెక్ట్ ఐడిని మరియు వినియోగదారు ఐడిని అలాగే అతని పాస్‌వర్డ్‌ను పాస్ చేస్తాము. ఫంక్షన్ లో 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

ఆటోస్కేలర్ క్లాస్

ఈ తరగతి ఆపరేటింగ్ లాజిక్‌కు సంబంధించిన విధులను కలిగి ఉంది.

ఈ తరగతికి సంబంధించిన కోడ్ ముక్క ఇలా కనిపిస్తుంది:

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లో నోడ్‌కు కేటాయించబడ్డాయి. q_ram, q_cpu అనే 2 అంతర్గత పారామితులు కూడా ఉన్నాయి, అవి క్యూలు. వాటిని ఉపయోగించి, మేము ప్రస్తుత క్లస్టర్ లోడ్ యొక్క విలువలను నిల్వ చేస్తాము. గత 5 నిమిషాల్లో స్థిరంగా పెరిగిన లోడ్ ఉన్నట్లు మనం చూస్తే, క్లస్టర్‌కి +1 నోడ్‌ని జోడించాలని మేము నిర్ణయించుకుంటాము. క్లస్టర్ అండర్ యుటిలైజేషన్ స్థితికి కూడా ఇదే వర్తిస్తుంది.

క్లస్టర్ నుండి యంత్రాన్ని తీసివేసి క్లౌడ్‌లో నిలిపివేసే ఫంక్షన్‌కి ఎగువ కోడ్ ఉదాహరణ. మొదట డీకమిషన్ ఉంది YARN Nodemanager, అప్పుడు మోడ్ ఆన్ అవుతుంది Maintenance, అప్పుడు మేము మెషీన్‌లోని అన్ని సేవలను ఆపివేస్తాము మరియు క్లౌడ్‌లోని వర్చువల్ మెషీన్‌ను ఆఫ్ చేస్తాము.

2. స్క్రిప్ట్ observer.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, మేము క్లస్టర్ నుండి ఏదైనా జోడించనప్పుడు లేదా తీసివేయనప్పుడు, కానీ కేవలం లోడ్‌ను పర్యవేక్షించండి. ఇది స్థిరీకరించబడి, సరైన లోడ్ విలువల కారిడార్‌లో ఉంటే, మేము కేవలం పర్యవేక్షణను కొనసాగిస్తాము. ఒక నోడ్ సరిపోకపోతే, మేము మరొకదాన్ని జోడిస్తాము.

మనకు పాఠం ఉన్న సందర్భాల్లో, ఒక నోడ్ సరిపోదని మాకు ఇప్పటికే ఖచ్చితంగా తెలుసు, కాబట్టి మేము వెంటనే అన్ని ఉచిత నోడ్‌లను ప్రారంభించి, పాఠం ముగిసే వరకు వాటిని చురుకుగా ఉంచుతాము. కార్యాచరణ సమయముద్రల జాబితాను ఉపయోగించి ఇది జరుగుతుంది.

తీర్మానం

మీరు అసమాన క్లస్టర్ లోడింగ్‌ను అనుభవించినప్పుడు ఆ సందర్భాలలో ఆటోస్కేలర్ మంచి మరియు అనుకూలమైన పరిష్కారం. మీరు పీక్ లోడ్‌ల కోసం కావలసిన క్లస్టర్ కాన్ఫిగరేషన్‌ను ఏకకాలంలో సాధిస్తారు మరియు అదే సమయంలో అండర్‌లోడ్ సమయంలో ఈ క్లస్టర్‌ను ఉంచవద్దు, డబ్బు ఆదా అవుతుంది. అలాగే, మీ భాగస్వామ్యం లేకుండా ఇవన్నీ స్వయంచాలకంగా జరుగుతాయి. ఆటోస్కేలర్ అనేది క్లస్టర్ మేనేజర్ API మరియు క్లౌడ్ ప్రొవైడర్ APIకి ఒక నిర్దిష్ట తర్కం ప్రకారం వ్రాయబడిన అభ్యర్థనల సమితి తప్ప మరేమీ కాదు. మీరు ఖచ్చితంగా గుర్తుంచుకోవాల్సిన విషయం ఏమిటంటే, మేము ఇంతకు ముందు వ్రాసినట్లుగా, నోడ్‌లను 3 రకాలుగా విభజించడం. మరియు మీరు సంతోషంగా ఉంటారు.

మూలం: www.habr.com

ఒక వ్యాఖ్యను జోడించండి