這是學習筆記的第 1777篇文章
今天在接入備份任務配置的時候也是一波三折,解決了業務元數據的問題,也逐步熟悉了業務,對於現有的備份情況會越來越有把握。
業務問題過去之後很快就碰到了性能問題,這個也是之前的處理中沒有意識到的。比如現在我嘗試逐步介入備份任務的時候,每次接入10個,添加了配置任務,會在系統的crontab中生成一條定時任務配置。
整個平臺暫時只負責任務並行調度,即分成幾組並行任務,任務時間調度,即任務什麼時候開始,怎麼去銜接任務的執行時間。
大體的使用界面如下:
在接入之後,確認元數據沒有問題的時候,我們開啓數據同步操作,會在元數據中同步配置,然後下推crontab的配置到系統任務中,但是這個時候原有的異步請求AJAX拋出了異常,大體的日誌如下:
/usr/local/DBA_SCRIPTS/mysql/crontab_automanage.sh -h 1 -m 59 -o add -c mysqlfullbackup -H xxxx -P 4306 {u'mission_id': u'25089', u'failed': {}, u'success': {u'xxxxx': [u'20181018 17:54:43 Create crontab task...', u'20181018 17:54:43 Clear crontab tmp file', u'20181018 17:54:43 remove crontab xtraback up_innodb_full_v6 on tmp file', u'20181018 17:54:43 Job complete']}, u'unreachable': {}} {u'mission_id': u'25089', u'failed': {}, u'success': {u'xxxxx': [u'20181018 17:54:43 Create crontab task...', u'20181018 17:54:43 Clear crontab tmp file', u'20181018 17:54:43 remove crontab xtraback up_innodb_full_v6 on tmp file', u'20181018 17:54:43 Job complete']}, u'unreachable': {}} Thu Oct 18 17:54:43 2018 - uwsgi_response_writev_headers_and_body_do(): Broken pipe [core/writer.c line 306] during POST /backup/mysql_backupconf_batch_sync/ (192.168.xxxx) IOError: write error
可以看到這個問題是在請求的過程中發生了異常,根據配置很可能是超時導致,使用ansible_adhoc觸發每次執行大約需要2秒,30多個剛好觸發了臨界點。
這裏恰好就是程序端實現的一個瓶頸,目前的任務執行是輪詢,也即爲串行執行模式,按照這種方式,如果任務的數量增加,那麼系統的交互時長會直線上升,體驗會很差,而且任務的執行很可能會中斷。
整體的一個流程設計圖如下:
注意這裏是可以稱爲執行器,但是還離調度器有點距離。
這個部分怎麼改進呢,可以參考下面的圖:
我們下發的任務都可以先接受,然後慢慢執行,這樣就好比對於前端馬上有了反饋,整個任務的後端執行是真正的異步方式,這個時候是串行還是並行就沒那麼敏感了,如果想要提高執行效率,那麼可以配置多個worker,否則就是串行的方式。
從代碼的層面來簡單說一下如何改進,代碼中我們封裝了ansible_adhoc,通過裝飾器,我們可以把它封裝爲一個異步任務。
@shared_task def ansible_adhoc(user, hosts, module, command, sudo=False): url = 'http://xxxxxx:8000/dba/ansible/adhoc' body = {"hosts": hosts, "module": module, "module_args": command, "sudo": sudo} return_dict = {} 。。。。。
後端的業務邏輯如下,是會通過循環的方式調用ansible_adhoc
def mysql_backupconf_batch_sync(request): return_dict = {} mysql_xtrabackup_schedulers = mysql_xtrabackup_scheduler.objects.all() for temp in mysql_xtrabackup_schedulers: print temp.os_crontab mysql_backupconfig.objects.filter(backup_ip=temp.backup_ip,backup_instanceport=temp.backup_instanceport).update( os_crontab=temp.os_crontab ) begin_hour = int(temp.os_crontab.split(":")[0]) begin_minute = int(temp.os_crontab.split(":")[1]) commend = "/usr/local/DBA_SCRIPTS/mysql/crontab_automanage.sh -h %s -m %s -o add -c mysqlfullbackup -H %s -P %s" % ( begin_hour, begin_minute,temp.backup_ip,temp.backup_instanceport) print(commend) result = ansible_adhoc('dba_mysql', temp.backup_ip, "script", commend, True) print(result) return JsonResponse({'msg': '更新成功', "code": 200, 'data': return_dict})
在這個代碼的基礎上,只需要添加一個函數,即可變得高大上,切換爲隊列模式,間接實現了併發。
def mysql_backupconf_batch_sync(request): return_dict = {} mysql_xtrabackup_schedulers = mysql_xtrabackup_scheduler.objects.all() for temp in mysql_xtrabackup_schedulers: print temp.os_crontab mysql_backupconfig.objects.filter(backup_ip=temp.backup_ip,backup_instanceport=temp.backup_instanceport).update( os_crontab=temp.os_crontab ) begin_hour = int(temp.os_crontab.split(":")[0]) begin_minute = int(temp.os_crontab.split(":")[1]) commend = "/usr/local/DBA_SCRIPTS/mysql/crontab_automanage.sh -h %s -m %s -o add -c mysqlfullbackup -H %s -P %s" % ( begin_hour, begin_minute,temp.backup_ip,temp.backup_instanceport) print(commend) result = ansible_adhoc.delay('dba_mysql', temp.backup_ip, "script", commend, True) print(result) return JsonResponse({'msg': '更新成功', "code": 200, 'data': return_dict})
當然程序端的併發也是需要視情況而定,而不要一位爲了技術酸爽而本末倒置。
按照這種方式,整個任務的串行,並行都可以做到基本可控。
後續在這個基礎上,在celery方向上需要考慮五類任務的接入:
1)異步任務,這個是celrey原生支持的
2)定時任務,這個是celery原生支持的
3)crontab,這個是保留原本的crontab,但是執行時間可以根據配置靈活的調度產生,這樣執行和時間就可以做到解耦合。
4)API,這個計劃作爲內部和外部使用兩種模式,通過API的方式把執行結果封裝到隊列裏面,對於變更執行類的需求,通過這種方式是比較適合的,可以極大提高系統吞吐率。