Upgrade to Pro — share decks privately, control downloads, hide ads and more …

pyconjp 2016 ライトニング用(未確定)

pyconjp 2016 ライトニング用(未確定)

nameのまま

6dbe360915689b269ab4fa510743762b?s=128

英 谷口

August 16, 2016
Tweet

Transcript

  1. Pythonでクラウドサービスを使ってみた

  2. 【クラウドサービス】 ネットワーク経由で提供される いろいろなサービス

  3. 【メリット】 気軽に商売ができる

  4. 具体例

  5. Pythonから操作可能 boto3 googleapiclient

  6. その1 EC2を起動してみた

  7. from boto3.session import Session def start_ec2() session = Session(aws_access_key_id, #認証

    aws_secret_access_key, region_name=region_name) ec2 = session.resource('ec2') #EC2のリソース取得 instance = ec2.Instance(instance_id) #インスタンスオブジェクト取得 if instance.state['Name'] == 'running': #すでに起動していた場合 return True instance.start() #インスタンス起動 instance.wait_until_running() #起動するまで待機 if instance.state['Name'] == 'running': #起動確認 return True return False
  8. タイムラグ

  9. リージョンリソース不足

  10. We currently do not have sufficient c4.8xlarge capacity in the

    Availability Zone you requested
  11. その2 S3からファイルを取得してみた

  12. from boto3.session import Session session = Session(aws_access_key_id, #認証 aws_secret_access_key, region_name=region_name)

    s3 = session.resource('s3') #S3のリソース取得 bucket = s3.Bucket(bucket_name) #バケットオブジェクト取得 param = { 'Prefix': prefix } for target_item in bucket.objects.filter(**param): #前方一致したアイテム情報 yield target_item.key
  13. from cStringIO import StringIO from boto3.session import Session def get_file_obj():

    session = Session(aws_access_key_id, #認証 aws_secret_access_key, region_name=region_name) s3 = session.resource('s3') #S3のリソース取得 obj = s3.Object(bucket_name, key) #ファイルオブジェクトを取得 return StringIO(obj.get()['Body'].read()) #読み込み *素直にファイルとしてダウンロードしてくる方法もある
  14. 同一リージョンだと早い

  15. その3 Google Storageに ファイルをアップロードしてみる

  16. まずはトークンの取得

  17. import json from urllib import urlencode from urllib2 import Request,

    urlopen def get_access_token() google_account_config = { #接続情報設定 'client_id': client_id, 'client_secret': client_secret, 'refresh_token': refresh_token, 'grant_type': 'refresh_token', } request = Request('https://accounts.google.com/o/oauth2/token', data=urlencode(google_account_config), headers={ 'Content-Type': 'application/x-www-form-urlencoded', 'Accept': 'application/json' } ) #リクエスト情報設定 response = json.load(urlopen(request)) #リクエスト return response['access_token'] #レスポンスからトークン取得
  18. 続いてサービスオブジェクト取得

  19. from oauth2client.client import AccessTokenCredentials from googleapiclient.discovery import build def get_sevice_object()

    token = get_access_token() credentials = AccessTokenCredentials(token, 'MyAgent/1.0', None) service = build('storage', 'v1', credentials=credentials) return service
  20. ようやくファイルアップロード

  21. from googleapiclient.http import MediaFileUpload def upload_file(): service = get_sevice_object() media

    = MediaFileUpload(local_file_path, resumable=True) request = service.objects().insert(bucket=bucket_name, name=storage_file_path, media_body=media) while True: progress, response = request.next_chunk() if progress: print '{0} is uploading {1}/100'.format(base_name, int(100 * progress.progress())) else: break
  22. ≪注意点≫

  23. EC2上から行うときは、 リトライ機能(エラー処理)は必須 *GCEからやれば、話は違うかも

  24. その4 BigQueryにデータを インポートしてみる

  25. def get_source_schema(): return [ {'name': 'id', 'type': 'STRING', 'mode': 'REQUIRED'},

    {'name': 'time_stamp', 'type': 'TIMESTAMP', 'mode': 'REQUIRED'}, {'name': 'num', 'type': 'INTEGER'}, {'name': 'value', 'type': 'STRING', 'mode': 'REQUIRED'} ]
  26. import uuid def create_load_data_body(): return { 'jobReference': { 'projectId': project_id

    'job_id': str(uuid.uuid4()) }, 'configuration': { 'load': { 'sourceUris': ['gs:' + storage_path], 'schema': { 'fields': get_source_schema() }, 'destinationTable': { 'projectId': project_id 'datasetId': data_set_id, 'tableId': table_id } } } }
  27. from oauth2client.client import AccessTokenCredentials from googleapiclient.discovery import build def get_sevice_object()

    token = get_access_token() credentials = AccessTokenCredentials(token, 'MyAgent/1.0', None) service = build('bigquery', 'v2', credentials=credentials) return service
  28. import time def execute_job() body = create_load_data_body() service = get_sevice_object()

    job = service.jobs().insert(projectId=project_id, body=body).execute(num_retries=5) job_get = service.jobs().get(projectId=project_id, jobId=job['jobReference']['jobId']) while True: time.sleep(5) job_resource = job_get.execute(num_retries=5) if job_resource['status']['state'] == 'DONE': return job_resource
  29. csvとかgzとかできる

  30. ストリームインサートも出来る でも有料

  31. その5 BigQueryにクエリを 発行してみる

  32. from oauth2client.client import AccessTokenCredentials from googleapiclient.discovery import build def get_sevice_object()

    token = get_access_token() credentials = AccessTokenCredentials(token, 'MyAgent/1.0', None) service = build('bigquery', 'v2', credentials=credentials) return service
  33. def get_query_data() return { 'query': query, #実行したいクエリ 'timeoutMs': 1000 #最大待機時間

    }
  34. def query() sevice = get_sevice_object() query_data = get_query_data() response =

    sevice.jobs().query(projectId=project_id, body=query_data).execute(num_retries=5) for page in paging(service.jobs().getQueryResults, num_retries=5, **response['jobReference']): if page['jobComplete'] is False: raise Exception('job is not complete') if page['totalRows'] == '0': yield create_record_dict([]) return row_list = [] for row in page['rows']: values = [] for value in row['f']: values.append(value['v']) yield value_list
  35. def paging(request_func, num_retries=5, **kwargs) has_next = True while has_next: response

    = request_func(**kwargs).execute(num_retries=num_retries) if 'pageToken' in response: kwargs['pageToken'] = response['pageToken'] else: has_next = False yield response
  36. 注意点

  37. データ処理量に注意

  38. Resources exceeded during query execution. For more information, see https://cloud.google.com/bigquery/troubleshootin

    g-errors
  39. 理由

  40. ORDER BY

  41. OUTER JOIN

  42. 対応策

  43. def get_query_data() return { 'query': query, #実行したいクエリ 'timeoutMs': 1000, #最大待機時間

    'allowLargeResults': True #結果データサイズが大きい時、どうするか }
  44. あんまりやりたくない 理由:追加料金発生 あくまで奥の手

  45. ORDER句を使わない 外部結合しない

  46. メモリ(例:redis)に貯めこむ メモリのデータを参照 独自にソート 独自にデータ結合

  47. 感覚値 ElastiCache ↓ |__|________________{超えられない壁}_| ↑                       ↑  実際のメモリ  

    RDB(Aurora)
  48. ビッグなデータを内部メモリに入れるなんて 狂気の沙汰

  49. その6 SQSからQueueを 出し入れしてみる

  50. from boto3.session import Session def get_queue_object(): session = Session(aws_access_key_id, #認証

    aws_secret_access_key, region_name=region_name) sqs = session.resource('sqs') #SQSのリソース取得 queue = sqs.get_queue_by_name(QueueName=queue_name) return queue
  51. def put_queue_object(): queue = get_queue_object() #queueオブジェクト取得 queue.send_message(MessageBody=message) #メッセージ送信

  52. def get_queue_object(): queue = get_queue_object() #queueオブジェクト取得 messages = queue.receive_messages(3) #最大メッセージ数指定可能

    if len(messages) == 0: return [] entries = [] result_list = [] for message in messages: result_list.append(message.body) #メッセージ本体 entries.append({ 'Id': message.message_id, #メッセージメタデータ 'ReceiptHandle': message.receipt_handle }) response = queue.delete_messages( Entries=entries #明示的に削除する必要あり ) if response['ResponseMetadata']['HTTPStatusCode'] != 200: raise Exception('delete messages is error') return result_list
  53. pip install cloud_lib

  54. https://github.com/Akira-Taniguchi/cloud_lib