පොකුරක් සඳහා ඔබේම ස්වයංක්‍රීය පරිමාණය සාදා ගන්නේ කෙසේද

ආයුබෝවන්! විශාල දත්ත සමඟ වැඩ කිරීමට අපි මිනිසුන් පුහුණු කරමු. සියලුම සහභාගිවන්නන් එකට වැඩ කරන තමන්ගේම පොකුරක් නොමැතිව විශාල දත්ත පිළිබඳ අධ්‍යාපනික වැඩසටහනක් සිතාගත නොහැකිය. මේ හේතුව නිසා, අපගේ වැඩසටහනේ සෑම විටම එය ඇත 🙂 අපි එහි වින්‍යාසය, සුසර කිරීම සහ පරිපාලනය කිරීමේ නිරතව සිටින අතර, පිරිමි ළමයින් එහි MapReduce රැකියා කෙලින්ම දියත් කර Spark භාවිතා කරයි.

වලාකුළ භාවිතයෙන් අපගේම ස්වයංක්‍රීය පරිමාණය ලිවීමෙන් අසමාන පොකුරු පැටවීමේ ගැටලුව විසඳූ ආකාරය මෙම ලිපියෙන් අපි ඔබට කියමු. Mail.ru Cloud Solutions.

ප්රශ්නය

අපගේ පොකුර සාමාන්‍ය මාදිලියක භාවිතා නොවේ. බැහැර කිරීම ඉතා අසමාන වේ. උදාහරණයක් ලෙස, ප්රායෝගික පන්ති ඇත, සියලු 30 දෙනා සහ ගුරුවරයෙකු පොකුරට ගොස් එය භාවිතා කිරීමට පටන් ගන්නා විට. නැත්තම් ආයෙත් load එක ගොඩක් වැඩි වෙන කාල සීමාවට කලින් දවස් තියෙනවා. ඉතිරි කාලය තුළ පොකුර ක්‍රියාත්මක වන්නේ underload මාතයෙන්.

විසඳුම #1 යනු උපරිම බරට ඔරොත්තු දෙන නමුත් ඉතිරි කාලය තුළ ක්‍රියා විරහිතව පවතින පොකුරක් තබා ගැනීමයි.

විසඳුම #2 යනු කුඩා පොකුරක් තබා ගැනීමයි, පන්තිවලට පෙර සහ උපරිම බර පැටවීමේදී ඔබ අතින් නෝඩ් එකතු කරන්න.

විසඳුම #3 යනු කුඩා පොකුරක් තබා ගැනීම සහ පොකුරේ වත්මන් භාරය නිරීක්ෂණය කරන ස්වයංක්‍රීය පරිමාණයක් ලිවීම සහ විවිධ API භාවිතා කරමින්, පොකුරෙන් නෝඩ් එකතු කිරීම සහ ඉවත් කිරීමයි.

මෙම ලිපියෙන් අපි විසඳුම අංක 3 ගැන කතා කරමු. මෙම ස්වයංක්‍රීය පරිමාණය අභ්‍යන්තර සාධකවලට වඩා බාහිර සාධක මත බෙහෙවින් රඳා පවතින අතර සැපයුම්කරුවන් බොහෝ විට එය ලබා නොදේ. අපි Mail.ru Cloud Solutions වලාකුළු යටිතල ව්‍යුහය භාවිතා කරන අතර MCS API භාවිතයෙන් ස්වයංක්‍රීය පරිමාණයක් ලිවීය. අපි දත්ත සමඟ වැඩ කරන ආකාරය උගන්වන බැවින්, ඔබේම අරමුණු සඳහා සමාන ස්වයංක්‍රීය පරිමාණයක් ලිවිය හැකි ආකාරය පෙන්වීමට සහ එය ඔබේ වලාකුළ සමඟ භාවිතා කිරීමට අපි තීරණය කළෙමු.

පූර්ව අවශ්යය

පළමුව, ඔබට Hadoop පොකුරක් තිබිය යුතුය. උදාහරණයක් ලෙස, අපි HDP බෙදාහැරීම භාවිතා කරමු.

ඔබගේ නෝඩ් ඉක්මනින් එකතු කිරීම සහ ඉවත් කිරීම සඳහා, ඔබට නෝඩ් අතර නිශ්චිත බෙදාහැරීමක් තිබිය යුතුය.

  1. ප්රධාන නෝඩය. හොඳයි, විශේෂයෙන් කිසිවක් පැහැදිලි කිරීමට අවශ්ය නැත: ඔබ අන්තර් ක්රියාකාරී මාදිලිය භාවිතා කරන්නේ නම්, උදාහරණයක් ලෙස, Spark ධාවකය දියත් කරන ලද පොකුරේ ප්රධාන නෝඩය.
  2. දින නෝඩය. ඔබ HDFS මත දත්ත ගබඩා කරන සහ ගණනය කිරීම් සිදු කරන නෝඩය මෙයයි.
  3. පරිගණක නෝඩය. මෙය ඔබ HDFS මත කිසිවක් ගබඩා නොකරන නමුත් ගණනය කිරීම් සිදු වන නෝඩයකි.

වැදගත් කරුණක්. තුන්වන වර්ගයේ නෝඩ් හේතුවෙන් ස්වයංක්‍රීය පරිමාණය සිදුවනු ඇත. ඔබ දෙවන වර්ගයේ නෝඩ් ලබා ගැනීම සහ එකතු කිරීම ආරම්භ කරන්නේ නම්, ප්‍රතිචාර දැක්වීමේ වේගය ඉතා අඩු වනු ඇත - විසන්ධි කිරීම සහ නැවත සකස් කිරීම සඳහා ඔබේ පොකුරේ පැය ගණනක් ගතවනු ඇත. මෙය, ඇත්ත වශයෙන්ම, ඔබ ස්වයංක්‍රීය පරිමාණයෙන් බලාපොරොත්තු වන දේ නොවේ. එනම්, අපි පළමු හා දෙවන වර්ගවල නෝඩ් ස්පර්ශ නොකරමු. ඔවුන් වැඩසටහනේ කාලසීමාව පුරාම පවතින අවම ශක්‍ය පොකුරක් නියෝජනය කරනු ඇත.

එබැවින්, අපගේ autoscaler Python 3 හි ලියා ඇත, පොකුරු සේවා කළමනාකරණය කිරීමට Ambari API භාවිතා කරයි, භාවිතා කරයි Mail.ru Cloud Solutions වෙතින් API (MCS) යන්ත්‍ර ආරම්භ කිරීම සහ නැවැත්වීම සඳහා.

විසඳුම් ගෘහ නිර්මාණ ශිල්පය

  1. මොඩියුලය autoscaler.py. එහි පන්ති තුනක් අඩංගු වේ: 1) අම්බාරි සමඟ වැඩ කිරීම සඳහා වන කාර්යයන්, 2) MCS සමඟ වැඩ කිරීම සඳහා වන කාර්යයන්, 3) ස්වයංක්‍රීය පරිමාණයේ තර්කනයට කෙලින්ම සම්බන්ධ ශ්‍රිත.
  2. පිටපත observer.py. අත්යවශ්යයෙන්ම එය විවිධ නීති වලින් සමන්විත වේ: autoscaler කාර්යයන් ඇමතීමට කවදාද සහ කුමන මොහොතකද යන්න.
  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) මෙම යන්ත්‍රයේ හැඳුනුම්පත ලබා ගන්න. මීළඟට, අපි හුදෙක් තැපැල් ඉල්ලීමක් කර මෙම යන්ත්රය දියත් කරමු.

ටෝකනයක් ලබා ගැනීමේ කාර්යය පෙනෙන්නේ මෙයයි:

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 හි නෝඩයට වෙන් කර ඇත. පෝලිම් වන q_ram, q_cpu යන අභ්‍යන්තර පරාමිති 2ක් ද ඇත. ඒවා භාවිතා කරමින්, අපි වත්මන් පොකුරු භාරයේ අගයන් ගබඩා කරමු. පසුගිය මිනිත්තු 5 තුළ අඛණ්ඩව වැඩි බරක් ඇති බව අපි දුටුවහොත්, අපි පොකුරට +1 නෝඩය එකතු කළ යුතු බව අපි තීරණය කරමු. පොකුරු ඌන උපයෝගිතා තත්ත්වය සඳහා ද එයම වේ.

ඉහත කේතය පොකුරෙන් යන්ත්‍රයක් ඉවත් කර වලාකුළෙහි නතර කරන ශ්‍රිතයකට උදාහරණයකි. මුලින්ම තියෙන්නේ decommissioning එකක් YARN Nodemanager, එවිට මාදිලිය සක්රිය වේ Maintenance, එවිට අපි යන්ත්රයේ සියලුම සේවාවන් නතර කර වලාකුළු තුළ අථත්ය යන්ත්රය අක්රිය කරමු.

2. Script 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)

එහි දී, පොකුරේ ධාරිතාව වැඩි කිරීම සඳහා කොන්දේසි නිර්මානය කර තිබේද යන්න සහ සංචිතයේ යන්ත්‍ර තිබේද යන්න පරීක්ෂා කර, ඒවායින් එකක සත්කාරක නාමය ලබාගෙන, එය පොකුරට එකතු කර අපගේ කණ්ඩායමේ Slack හි ඒ පිළිබඳ පණිවිඩයක් ප්‍රකාශයට පත් කරන්නෙමු. ඉන් පසුව එය ආරම්භ වේ cooldown_period, අපි පොකුරෙන් කිසිවක් එකතු නොකරන හෝ ඉවත් නොකරන විට, නමුත් සරලව පැටවීම නිරීක්ෂණය කරන්න. එය ස්ථායී වී ඇත්නම් සහ ප්‍රශස්ත පැටවුම් අගයන්හි කොරිඩෝව තුළ තිබේ නම්, අපි සරලව නිරීක්ෂණය කරන්නෙමු. එක් නෝඩයක් ප්රමාණවත් නොවේ නම්, අපි තවත් එකක් එකතු කරමු.

අපට ඉදිරි පාඩමක් ඇති අවස්ථා සඳහා, එක් නෝඩයක් ප්‍රමාණවත් නොවන බව අපි දැනටමත් නිසැකවම දනිමු, එබැවින් අපි වහාම සියලුම නොමිලේ නෝඩ් ආරම්භ කර පාඩම අවසන් වන තෙක් ඒවා ක්‍රියාකාරීව තබා ගනිමු. මෙය ක්‍රියාකාරකම් වේලා මුද්‍රා ලැයිස්තුවක් භාවිතයෙන් සිදුවේ.

නිගමනය

ඔබ අසමාන පොකුරු පැටවීම අත්විඳින විට එම අවස්ථා සඳහා Autoscaler හොඳ සහ පහසු විසඳුමක් වේ. ඔබ එකවර උපරිම බර සඳහා අපේක්ෂිත පොකුරු වින්‍යාසය සාක්ෂාත් කර ගන්නා අතර ඒ සමඟම මුදල් ඉතිරි කර ගනිමින් බර පැටවීමේදී මෙම පොකුරු තබා නොගන්න. හොඳයි, තවද මේ සියල්ල ඔබගේ සහභාගීත්වයෙන් තොරව ස්වයංක්‍රීයව සිදුවේ. ස්වයංක්‍රීය පරිමාණය යනු කිසියම් තර්කයකට අනුව ලියා ඇති පොකුරු කළමණාකරු API සහ cloud provider API වෙත ඉල්ලීම් සමූහයකට වඩා වැඩි දෙයක් නොවේ. ඔබ අනිවාර්යයෙන්ම මතක තබා ගත යුතු දෙය නම් අප කලින් ලියා ඇති පරිදි නෝඩ් වර්ග 3 කට බෙදීමයි. තවද ඔබ සතුටු වනු ඇත.

මූලාශ්රය: www.habr.com

අදහස් එක් කරන්න