Helo! Rydym yn hyfforddi pobl i weithio gyda data mawr. Mae'n amhosibl dychmygu rhaglen addysgol ar ddata mawr heb ei chlwstwr ei hun, y mae'r holl gyfranogwyr yn cydweithio arno. Am y rheswm hwn, mae ein rhaglen bob amser wedi ei :) Rydym yn cymryd rhan yn ei ffurfweddu, tiwnio a gweinyddu, ac mae'r guys yn uniongyrchol lansio MapReduce swyddi yno ac yn defnyddio Spark.
Yn y swydd hon byddwn yn dweud wrthych sut y gwnaethom ddatrys y broblem o lwytho clwstwr anwastad trwy ysgrifennu ein autoscaler ein hunain gan ddefnyddio'r cwmwl
problem
Nid yw ein clwstwr yn cael ei ddefnyddio mewn modd nodweddiadol. Mae gwaredu yn anwastad iawn. Er enghraifft, mae dosbarthiadau ymarferol, pan fydd pob un o'r 30 o bobl ac athro yn mynd i'r clwstwr ac yn dechrau ei ddefnyddio. Neu eto, mae yna ddyddiau cyn y dyddiad cau pan fydd y llwyth yn cynyddu'n fawr. Gweddill yr amser mae'r clwstwr yn gweithredu yn y modd tanlwytho.
Ateb #1 yw cadw clwstwr a fydd yn gwrthsefyll llwythi brig, ond a fydd yn segur weddill yr amser.
Ateb #2 yw cadw clwstwr bach, yr ydych chi'n ychwanegu nodau ato â llaw cyn dosbarthiadau ac yn ystod llwythi brig.
Ateb #3 yw cadw clwstwr bach ac ysgrifennu awtoscaler a fydd yn monitro llwyth presennol y clwstwr a, gan ddefnyddio gwahanol APIs, ychwanegu a thynnu nodau o'r clwstwr.
Yn y swydd hon byddwn yn siarad am ateb #3. Mae'r autoscaler hwn yn ddibynnol iawn ar ffactorau allanol yn hytrach na rhai mewnol, ac yn aml nid yw darparwyr yn ei ddarparu. Rydym yn defnyddio seilwaith cwmwl Mail.ru Cloud Solutions ac yn ysgrifennu awtoscaler gan ddefnyddio'r API MCS. Ac ers i ni ddysgu sut i weithio gyda data, fe benderfynon ni ddangos sut y gallwch chi ysgrifennu autoscaler tebyg at eich dibenion eich hun a'i ddefnyddio gyda'ch cwmwl
Rhagofynion
Yn gyntaf, rhaid bod gennych glwstwr Hadoop. Er enghraifft, rydym yn defnyddio'r dosbarthiad HDP.
Er mwyn i'ch nodau gael eu hychwanegu a'u tynnu'n gyflym, rhaid bod gennych chi ddosbarthiad penodol o rolau ymhlith y nodau.
- Prif nod. Wel, nid oes unrhyw beth arbennig o angenrheidiol i'w esbonio yma: prif nod y clwstwr, y mae'r gyrrwr Spark yn cael ei lansio arno, er enghraifft, os ydych chi'n defnyddio'r modd rhyngweithiol.
- Nod dyddiad. Dyma'r nod rydych chi'n storio data arno ar HDFS a lle mae cyfrifiadau'n digwydd.
- Nod cyfrifiadura. Mae hwn yn nod lle nad ydych chi'n storio unrhyw beth ar HDFS, ond lle mae cyfrifiadau'n digwydd.
Pwynt pwysig. Bydd graddoli awtomatig yn digwydd oherwydd nodau o'r trydydd math. Os byddwch yn dechrau cymryd ac ychwanegu nodau o'r ail fath, bydd y cyflymder ymateb yn isel iawn - bydd datgomisiynu ac ailymrwymo yn cymryd oriau ar eich clwstwr. Nid dyma, wrth gwrs, yw'r hyn rydych chi'n ei ddisgwyl o awtoscaling. Hynny yw, nid ydym yn cyffwrdd â nodau'r math cyntaf a'r ail fath. Byddant yn cynrychioli clwstwr hyfyw lleiaf a fydd yn bodoli trwy gydol y rhaglen.
Felly, mae ein autoscaler wedi'i ysgrifennu yn Python 3, yn defnyddio'r API Ambari i reoli gwasanaethau clwstwr, defnyddiau
Pensaernïaeth datrysiad
- Modiwl
autoscaler.py
. Mae'n cynnwys tri dosbarth: 1) swyddogaethau ar gyfer gweithio gydag Ambari, 2) swyddogaethau ar gyfer gweithio gyda MCS, 3) swyddogaethau sy'n ymwneud yn uniongyrchol â rhesymeg y autoscaler. - Sgript
observer.py
. Yn ei hanfod mae'n cynnwys rheolau gwahanol: pryd ac ar ba eiliadau i alw'r awtoscaler yn swyddogaethau. - Ffeil ffurfweddu
config.py
. Mae'n cynnwys, er enghraifft, rhestr o nodau a ganiateir ar gyfer graddoli awtomatig a pharamedrau eraill sy'n effeithio, er enghraifft, pa mor hir i aros o'r eiliad yr ychwanegwyd nod newydd. Mae yna hefyd stampiau amser ar gyfer dechrau dosbarthiadau, fel bod y cyfluniad clwstwr uchaf a ganiateir yn cael ei lansio cyn y dosbarth.
Gadewch i ni nawr edrych ar y darnau o god y tu mewn i'r ddwy ffeil gyntaf.
1. modiwl Autoscaler.py
Dosbarth Ambari
Dyma sut olwg sydd ar ddarn o god sy'n cynnwys dosbarth 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
Uchod, fel enghraifft, gallwch edrych ar weithrediad y swyddogaeth stop_all_services
, sy'n atal pob gwasanaeth ar y nod clwstwr dymunol.
Wrth y fynedfa i'r dosbarth Ambari
byddwch yn pasio:
ambari_url
, er enghraifft, fel'http://localhost:8080/api/v1/clusters/'
,cluster_name
– enw eich clwstwr yn Ambari,headers = {'X-Requested-By': 'ambari'}
- a'r tu mewn
auth
dyma'ch mewngofnodi a'ch cyfrinair ar gyfer Ambari:auth = ('login', 'password')
.
Nid yw'r swyddogaeth ei hun yn ddim mwy na chwpl o alwadau trwy'r API REST i Ambari. O safbwynt rhesymegol, rydym yn gyntaf yn derbyn rhestr o wasanaethau rhedeg ar nod, ac yna'n gofyn ar glwstwr penodol, ar nod penodol, i drosglwyddo gwasanaethau o'r rhestr i'r wladwriaeth INSTALLED
. Swyddogaethau ar gyfer lansio pob gwasanaeth, ar gyfer trosglwyddo nodau i'r wladwriaeth Maintenance
ac ati yn edrych yn debyg - dim ond ychydig o geisiadau ydyn nhw trwy'r API.
Dosbarth Mcs
Dyma sut olwg sydd ar ddarn o god sy'n cynnwys dosbarth 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
Wrth y fynedfa i'r dosbarth Mcs
rydym yn trosglwyddo id y prosiect y tu mewn i'r cwmwl a'r ID defnyddiwr, yn ogystal â'i gyfrinair. Mewn swyddogaeth vm_turn_on
rydym am droi un o'r peiriannau ymlaen. Mae'r rhesymeg yma ychydig yn fwy cymhleth. Ar ddechrau'r cod, gelwir tair swyddogaeth arall: 1) mae angen inni gael tocyn, 2) mae angen i ni drosi'r enw gwesteiwr yn enw'r peiriant yn MCS, 3) cael id y peiriant hwn. Nesaf, rydym yn syml yn gwneud cais post ac yn lansio'r peiriant hwn.
Dyma sut olwg sydd ar y swyddogaeth ar gyfer cael tocyn:
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
Dosbarth Autoscaler
Mae'r dosbarth hwn yn cynnwys swyddogaethau sy'n gysylltiedig â'r rhesymeg gweithredu ei hun.
Dyma sut olwg sydd ar ddarn o god ar gyfer y dosbarth hwn:
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
Rydym yn derbyn dosbarthiadau ar gyfer mynediad. Ambari
и Mcs
, rhestr o nodau a ganiateir ar gyfer graddio, yn ogystal â pharamedrau cyfluniad nodau: cof a cpu a ddyrennir i'r nod yn YARN. Mae yna hefyd 2 baramedr mewnol q_ram, q_cpu, sef ciwiau. Gan eu defnyddio, rydym yn storio gwerthoedd y llwyth clwstwr cyfredol. Os gwelwn fod llwyth wedi cynyddu'n gyson dros y 5 munud diwethaf, yna byddwn yn penderfynu bod angen ychwanegu nod +1 i'r clwstwr. Mae'r un peth yn wir am gyflwr tanddefnyddio clwstwr.
Mae'r cod uchod yn enghraifft o swyddogaeth sy'n tynnu peiriant o'r clwstwr a'i atal yn y cwmwl. Yn gyntaf mae datgomisiynu YARN Nodemanager
, yna mae'r modd yn troi ymlaen Maintenance
, yna byddwn yn atal pob gwasanaeth ar y peiriant ac yn diffodd y peiriant rhithwir yn y cwmwl.
2. Sgript arsylwr.py
Cod sampl oddi yno:
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)
Ynddo, rydym yn gwirio a oes amodau wedi'u creu ar gyfer cynyddu capasiti'r clwstwr ac a oes unrhyw beiriannau wrth gefn, cael enw gwesteiwr un ohonynt, ei ychwanegu at y clwstwr a chyhoeddi neges amdano ar Slack ein tîm. Ar ôl hynny mae'n dechrau cooldown_period
, pan na fyddwn yn ychwanegu neu'n tynnu unrhyw beth o'r clwstwr, ond yn syml yn monitro'r llwyth. Os yw wedi sefydlogi a'i fod o fewn coridor y gwerthoedd llwyth gorau posibl, yna yn syml iawn rydym yn parhau i fonitro. Os nad oedd un nod yn ddigon, yna rydym yn ychwanegu un arall.
Mewn achosion pan fydd gennym wers o'n blaenau, rydym eisoes yn gwybod yn sicr na fydd un nod yn ddigon, felly rydym yn cychwyn yr holl nodau rhydd ar unwaith ac yn eu cadw'n actif tan ddiwedd y wers. Mae hyn yn digwydd gan ddefnyddio rhestr o stampiau amser gweithgaredd.
Casgliad
Mae Autoscaler yn ddatrysiad da a chyfleus ar gyfer yr achosion hynny pan fyddwch chi'n profi llwythiad clwstwr anwastad. Rydych chi ar yr un pryd yn cyflawni'r cyfluniad clwstwr dymunol ar gyfer llwythi brig ac ar yr un pryd peidiwch â chadw'r clwstwr hwn yn ystod y tanlwytho, gan arbed arian. Wel, ac mae hyn i gyd yn digwydd yn awtomatig heb eich cyfranogiad. Nid yw'r autoscaler ei hun yn ddim mwy na set o geisiadau i'r rheolwr clwstwr API a'r API darparwr cwmwl, wedi'u hysgrifennu yn unol â rhesymeg benodol. Yr hyn y mae angen i chi ei gofio yn bendant yw rhannu nodau yn 3 math, fel y gwnaethom ysgrifennu'n gynharach. A byddwch yn hapus.
Ffynhonnell: hab.com