Si të krijoni auto-skaluesin tuaj për një klaster

PĂ«rshĂ«ndetje! Ne edukojmĂ« njerĂ«zit pĂ«r punĂ«n me tĂ« dhĂ«na tĂ« mĂ«dha. ËshtĂ« e pamundur tĂ« imagjinohet njĂ« program arsimor pĂ«r tĂ« dhĂ«na tĂ« mĂ«dha pa njĂ« klaster tĂ« vetin, mbi tĂ« cilin tĂ« gjithĂ« pjesĂ«marrĂ«sit punojnĂ« sĂ« bashku. PĂ«r kĂ«tĂ« arsye, nĂ« programin tonĂ« ai Ă«shtĂ« gjithmonĂ« atje 🙂 Ne merremi me konfigurimin, tunimin dhe administrimin e tij, ndĂ«rsa studentĂ«t e aktivizojnĂ« atje punĂ«t MapReduce dhe pĂ«rdorin Spark.

Në këtë post, do të flasim se si ne zgjidhëm problemin e ngarkesës së pandershme të klasterit, duke shkruar skalerin tonë automatik, duke përdorur cloud. Zgjidhjet Cloud të Mail.ru.

Problemi

Klasteri ynë përdoret jo krejtësisht në një mënyrë tipike. Shfrytëzimi është shumë i pabarabartë. Për shembull, ka aktivitete praktike kur të gjithë 30 persona dhe mësuesi hyjnë në klaster dhe fillojnë ta përdorin atë. Ose ndodhin ditë para afateve kur ngarkesa rritet shumë. Në të gjitha pjesët e tjera, klasteri punon në mënyrë të nën-shfrytëzuar.

Zgjidhja №1 – Ă«shtĂ« tĂ« mbash njĂ« klaster qĂ« do tĂ« pĂ«rballojĂ« ngarkesat maksimale, por do tĂ« jetĂ« i papunĂ« nĂ« gjithĂ« kohĂ«n tjetĂ«r.

Zgjidhja №2 – Ă«shtĂ« tĂ« mbash njĂ« klaster tĂ« vogĂ«l, nĂ« tĂ« cilin tĂ« shtosh manualisht node para aktiviteteve dhe gjatĂ« ngarkesave maksimale.

Zgjidhja №3 – Ă«shtĂ« tĂ« mbash njĂ« klaster tĂ« vogĂ«l dhe tĂ« shkruash njĂ« skaler automatik, qĂ« do tĂ« monitorojĂ« ngarkesĂ«n aktuale tĂ« klasterit dhe vetĂ«, duke pĂ«rdorur API tĂ« ndryshme, do tĂ« shtojĂ« dhe fshijĂ« node nga klasteri.

NĂ« kĂ«tĂ« post, do tĂ« flasim pĂ«r zgjidhjen №3. Ky skaler automatik Ă«shtĂ« shumĂ« i varur nga faktorĂ«t e jashtĂ«m, dhe shpesh ofruesit e tij nuk e ofrojnĂ«. Ne pĂ«rdorim infrastrukturĂ«n cloud tĂ« Mail.ru Cloud Solutions dhe shkruam njĂ« skaler automatik, duke pĂ«rdorur API MCS. Dhe pasi ne edukojmĂ« pĂ«r punĂ«n me tĂ« dhĂ«na, e kemi vendosur tĂ« tregojmĂ« se si mund tĂ« shkruani njĂ« skaler tĂ« tillĂ« pĂ«r qĂ«llimet tuaja dhe tĂ« pĂ«rdorni me cloud-in tuaj.

Kushtet e nevojshme

Së pari, ju duhet të keni një klaster Hadoop. Ne, për shembull, përdorim distribuimin HDP.

Për të pasur node që mund të shtohen dhe hiqen shpejt, ju duhet të keni një shpërndarje të caktuar rolesh mbi node.

  1. Node Master. Këtu nuk ka nevojë për shpjegime të mëtejshme: node kryesore e klasterit, mbi të cilën aktivizohet, për shembull, drejtuesi i Spark, nëse jeni duke përdorur modalitetin interaktiv.
  2. Node Data. Kjo është node ku ndodhen të dhënat në HDFS dhe aty ndodhin gjithashtu llogaritjet.
  3. Node Computation. Kjo është node, mbi të cilin nuk ruhet asgjë në HDFS, por aty ndodhin llogaritjet.

NjĂ« moment i rĂ«ndĂ«sishĂ«m. Autoskalimi do tĂ« ndodhi pĂ«r shkak tĂ« node-ve tĂ« tipit tĂ« tretĂ«. NĂ«se filloni tĂ« hiqni dhe shtoni node tĂ« tipit tĂ« dytĂ«, reagimi do tĂ« jetĂ« shumĂ« i ngadaltĂ« – dekomishimi dhe rekomishimi do tĂ« marrin orĂ« nĂ« klasterin tuaj. Kjo, natyrisht, nuk Ă«shtĂ« ajo qĂ« prisni nga autoskalimi. Pra, node-t e tipit tĂ« parĂ« dhe tĂ« dytĂ« nuk i prekim. Ata do tĂ« pĂ«rfaqĂ«sojnĂ« njĂ« klaster minimalisht tĂ« qĂ«ndrueshĂ«m, qĂ« do tĂ« ekzistojĂ« gjatĂ« gjithĂ« kohĂ«s sĂ« programit.

Pra, skaleri ynë automatik është shkruar në Python 3, përdor API-në Ambari për menaxhimin e shërbimeve të klasterit, përdor API nga Mail.ru Cloud Solutions (MCS) për të aktivizuar dhe ndaluar makinacak.

Arkitektura e zgjidhjes

  1. Moduli autoscaler.py. Ai përmban tre klasa: 1) funksione për punën me Ambari, 2) funksione për punën me MCS, 3) funksione që lidhen drejtpërdrejt me logjikën e funksionimit të skalerit automatik.
  2. Skripti observer.py. Në thelb përbëhet nga rregulla të ndryshme: kur dhe në çfarë momentesh të thërrasë funksionet e skalerit automatik.
  3. Skedari i konfigurimit config.py. Aty ndodhet, për shembull, lista e node-ve të lejuara për autoskalim dhe parametra të tjerë që ndikojnë, për shembull, në sa kohë të prisni nga momenti kur është shtuar një node e re. Aty ndodhen gjithashtu dhe timestamp-et e fillimit të aktiviteteve, për t'u siguruar që para aktivitetit të aktivizohet konfigurimi maksimal i lejuar i klasterit.

Tani le të shikojmë pjesët e kodit që ndodhen brenda dy skedarëve të parë.

1. Moduli autoscaler.py

Klasa Ambari

Ja si duket një pjesë kodit që përmban klasën 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

Mund të shihni një implementim të funksionit më sipër si shembull. stop_all_services, i cili ndalon të gjitha shërbimet në nodën e duhur të grumbullit.

Kur keni klasën Ambari ju jepni:

  • ambari_url, pĂ«r shembull, nĂ« formĂ«n e 'http://localhost:8080/api/v1/clusters/',
  • cluster_name – emri i grumbullit tuaj nĂ« Ambari,
  • headers = {'X-Requested-By': 'ambari'}
  • dhe brenda auth ndodhen kredencialet tuaja pĂ«r Ambari: auth = ('login', 'password').

Funksioni vetĂ« pĂ«rbĂ«het nga disa thirrje pĂ«rmes REST API nĂ« Ambari. Nga pikĂ«pamja logjike, fillimisht marrim listĂ«n e shĂ«rbimeve tĂ« aktivizuara nĂ« nodĂ«, dhe mĂ« pas kĂ«rkojmĂ« nĂ« kĂ«tĂ« grumbull, nĂ« kĂ«tĂ« nodĂ«, qĂ« shĂ«rbimet nga lista tĂ« kalojnĂ« nĂ« gjendjen INSTALLED. Funksionet pĂ«r aktivizimin e tĂ« gjitha shĂ«rbimeve, pĂ«r kalimin e nodave nĂ« gjendjen Maintenance etj. duken ngjashĂ«m – ato janĂ« thjesht disa kĂ«rkesa pĂ«rmes API.

Klasës Mcs

Ja si duket një pjesë kodit që përmban klasën 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

Kur keni klasën Mcs ne i kalojmë id e projektit brenda cloud-it dhe id e përdoruesit, si dhe fjalëkalimin e tij. Në funksionin vm_turn_on duam të aktivizojmë njërën nga makinat. Logjika këtu është pak më e komplikuar. Në fillim të kodit bëhet thirrja e tre funksioneve të tjera: 1) na nevojitet të marrëim token-in, 2) na nevojitet të konvertojmë hostname-in në emrin e makinës në MCS, 3) të marrim id e kësaj makine. Më pas bëjmë një kërkesë post dhe aktivizojmë këtë makinë.

Këtu është funksioni për marrjen e token-it:

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

Klasës Autoscaler

Ky klas përmban funksione që lidhen me logjikën e funksionimit të saj.

Ja si duket një pjesë e kodit të këtij klasi:

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('Decommission 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

Ne marrim si input klasat Ambari dhe Mcs, lista e nodave të lejuara për shkallëzim, si dhe parametrat e konfigurimit të nodave: memoria dhe CPU, të dedikuara për nodën në YARN. Ka gjithashtu 2 parametra të brendshëm q_ram, q_cpu, të cilat janë radhë. Me anë të tyre ruajmë vlerat e ngarkesës aktuale të klasterit. Nëse shohim se në pesë minutat e fundit ka pasur ngarkesë të lartë, ne marrim vendimin për të shtuar +1 nod në klaster. E njëjta është e vërtetë edhe për gjendjen e nën-ngarkesës së klasterit.

Në kodin më sipër është një shembull funksioni që heq një makinë nga klasteri dhe e ndalon atë në cloud. Fillimisht ndodh dekomisionimi YARN Nodemanager, pastaj aktivizohet moda Maintenance, më pas ndalojmë të gjitha shërbimet në makinën dhe ndajmë makinën virtuale në cloud.

2. Skripti observer.py

Shembulli i kodit nga aty:

nëse scaler.assert_up(config.scale_up_thresholds) == True:
        hostname = cloud.get_vm_to_up(config.scaling_hosts)
        nëse hostname != None:
            status1 = scaler.scale_up(hostname)
            nëse status1 == 'Sukses':
                text = {"text": "{0} është shkallëzuar me sukses".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)

Në të ne kontrollojmë nëse kushtet për rritjen e kapaciteve të klasterit janë përmbushur dhe nëse ka ndonjë makinë të lirë, të marrim emrin e saj, ta shtojmë në klaster dhe publikojmë një mesazh për këtë në Slack të ekipit tonë. Pas kësaj fillon perioda e ftohjes, kur nuk shtojmë dhe as heqim asgjë nga klasteri, por vetëm monitorojmë ngarkesën. Nëse ajo është stabilizuar dhe është brenda koridorit optimal të vlerave të ngarkesës, ne vazhdojmë monitorimin. Nëse një nod nuk mjafton, shtojmë edhe një.

Për rastet kur kemi një seancë përpara, ne e dimë me siguri se një nod nuk do të jetë e mjaftueshme, prandaj menjëherë fillojmë të gjitha nodat e lira dhe i mbajmë aktive deri në fund të seancës. Kjo ndodh përmes një liste timestamp-esh të seancave.

Përfundimi

Autoskaleri – Ă«shtĂ« njĂ« zgjidhje e mirĂ« dhe e pĂ«rshtatshme pĂ«r ata raste kur keni njĂ« ngarkesĂ« tĂ« paekuilibruar tĂ« klasterit. Ju arrini nĂ« tĂ« njĂ«jtĂ«n kohĂ« konfigurimin e nevojshĂ«m tĂ« klasterit pĂ«r ngarkesa maksimale dhe duke mos e mbajtur kĂ«tĂ« klaster nĂ« kohĂ«n e nĂ«n-ngarkesĂ«s, kurseni burimet. Po ashtu, kjo ndodh nĂ« mĂ«nyrĂ« automatike pa ndihmĂ«n tuaj. VetĂ« autoskaleri nuk Ă«shtĂ« mĂ« shumĂ« se njĂ« grup kĂ«rkesash pĂ«r API-nĂ« e menaxherit tĂ« klasterit dhe API-nĂ« e ofruesit tĂ« cloud-it, tĂ« shkruara sipas njĂ« logjike tĂ« caktuar. E rĂ«ndĂ«sishme Ă«shtĂ« tĂ« mbahet mend ndarja e nodave nĂ« 3 tipe, siç kemi shkruar mĂ« parĂ«. Dhe do tĂ« keni sukses.

Burimi: habr.com

Bleni hostim tĂ« besueshĂ«m pĂ«r faqe me mbrojtje nga DDoS, serverĂ« VPS VDS đŸ”„ Bleni hostim tĂ« besueshĂ«m pĂ«r faqe me mbrojtje nga DDoS, serverĂ« VPS VDS | ProHoster