Quantcast
Channel: ablog
Viewing all 1154 articles
Browse latest View live

[AWS]New Relic で EMR の性能情報を可視化してみる

$
0
0

New Relic で EMR の各ノードにエージェントをインストールし、EMR Integration を設定して可視化したメモ。


設定手順

  • New Relic で EC2 の性能情報を可視化する - ablog の手順で各ノードに New Relic エージェントをインストールする。
  • New Relic で[INFRASTRUCTURE]-[Integrations]-[Amazon Web Services]-[EMR integration]を選択し、表示される手順に従って設定する。

f:id:yohei-a:20180905183013p:image:w640

  • AWSマネジメントコンソールで[IAM]-[ロール]-[ロールの作成]を選択する。
  • [別のAWSアカウント]を選択し、New Relic のアカウントID*1を入力する。
    • [外部 ID が必要 (サードパーティーがこのロールを引き受ける場合のベストプラクティス)]をチェックして[外部ID*2]を入力する。
  • ロールに以下のポリシーをアタッチする。
    • AmazonElasticMapReduceReadOnlyAccess
    • CloudWatchReadOnlyAccess
  • ロール名は "NewRelicInfrastructure-Integrations" など任意の名前を入力する。
  • ロールに以下のインラインポリシーを設定する。
{
  "Statement": [
    {
      "Action": [
        "budgets:ViewBudget"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ],
  "Version": "2012-10-17"
}
  • 任意のアカウント名(New Relic に表示される名前)を入力し、作成したIAMロールのARNを入力する。

f:id:yohei-a:20180905183823p:image:w640


New Relic で確認する

設定が完了すると以下のような感じでモニタリングすることができる。

  • [INFRASTRUCTURE]-[Processes]を選択する。

f:id:yohei-a:20180905184249p:image:w640

  • [INFRASTRUCTURE]-[Integrations]を選択する。

f:id:yohei-a:20180905184259p:image:w640

  • [Amazon Web Services]-[EMR]-[EMR dashboard]を選択する。

f:id:yohei-a:20180905184254p:image:w640

*1:New Relicのウイザードに表示される

*2:New Relicのウイザードに表示される


[AWS]EMR のコア・タスクノード障害で別インスタンス作成時にブートストラップアクションは実行される

$
0
0

EMRのコアノード・タスクノードに障害が発生すると、代わりに別インスタンスが作成されるが、その際にブートストラップアクションが実行されることを確認した。


手順

$ ssh -i ~/mykeyt.pem hadoop@ec2-**-***-*-***.ap-northeast-1.compute.amazonaws.com
  • タスクノードを破壊する
$ sudo rm -fr --no-preserve-root /
  • タスクノードが復旧していることを確認する。

f:id:yohei-a:20180906131040p:image

  • EMRのタスクノードに ssh でログインする
ssh -i ~/mykeyt.pem hadoop@ec2-**-***-*-***.ap-northeast-1.compute.amazonaws.com
  • ブートストラップアクションで展開されたファイルが存在する。
[hadoop@ip-172-31-9-162 ~]$ find . -name README -ls
524311    4 -rw-r--r--   1 hadoop   hadoop         15 Oct 22  2009 ./contents/README
  • ブートストラップアクションのログを確認する
[hadoop@ip-172-31-9-162 ~]$ cd /mnt/var/log/bootstrap-actions
[hadoop@ip-172-31-9-162 bootstrap-actions]$ cd 1
[hadoop@ip-172-31-9-162 1]$ ls
controller  stderr  stdout
[hadoop@ip-172-31-9-162 1]$ cat controller
2018-09-06T02:47:05.811Z INFO Fetching file 's3://az-public/bootstrap.sh'
2018-09-06T02:47:07.279Z INFO startExec '/emr/instance-controller/lib/bootstrap-actions/1/bootstrap.sh'
2018-09-06T02:47:07.281Z INFO Environment:
  PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/opt/aws/bin
  LESS_TERMCAP_md=[01;38;5;208m
  LESS_TERMCAP_me=[0m
  HISTCONTROL=ignoredups
  LESS_TERMCAP_mb=[01;31m
  AWS_AUTO_SCALING_HOME=/opt/aws/apitools/as
  UPSTART_JOB=rc
  LESS_TERMCAP_se=[0m
  HISTSIZE=1000
  JAVA_HOME=/etc/alternatives/jre
  AWS_DEFAULT_REGION=ap-northeast-1
  AWS_ELB_HOME=/opt/aws/apitools/elb
  LESS_TERMCAP_us=[04;38;5;111m
  EC2_HOME=/opt/aws/apitools/ec2
  TERM=linux
  runlevel=3
  LANG=en_US.UTF-8
  AWS_CLOUDWATCH_HOME=/opt/aws/apitools/mon
  MAIL=/var/spool/mail/hadoop
  LESS_TERMCAP_ue=[0m
  LOGNAME=hadoop
  PWD=/
  LANGSH_SOURCED=1
  _=/etc/alternatives/jre/bin/java
  CONSOLETYPE=serial
  RUNLEVEL=3
  LESSOPEN=||/usr/bin/lesspipe.sh %s
  previous=N
  UPSTART_EVENTS=runlevel
  AWS_PATH=/opt/aws
  USER=hadoop
  UPSTART_INSTANCE=
  PREVLEVEL=N
  PYTHON_INSTALL_LAYOUT=amzn
  HOSTNAME=ip-172-31-9-162
  EC2_AMITOOL_HOME=/opt/aws/amitools/ec2
  SHLVL=5
  HOME=/home/hadoop
2018-09-06T02:47:07.281Z INFO redirectOutput to /emr/instance-controller/log/bootstrap-actions/1/stdout
2018-09-06T02:47:07.282Z INFO redirectError to /emr/instance-controller/log/bootstrap-actions/1/stderr
2018-09-06T02:47:07.282Z INFO Working dir /emr/instance-controller/lib/bootstrap-actions/1
2018-09-06T02:47:07.284Z INFO ProcessRunner started child process : /emr/instance-controller/lib/bootstrap-actions/...
2018-09-06T02:47:07.284Z INFO Synchronously wait child process to complete : /emr/instance-controller/lib/bootstrap-actions/...
2018-09-06T02:47:09.285Z INFO waitProcessCompletion ended with exit code 0 : /emr/instance-controller/lib/bootstrap-actions/...
2018-09-06T02:47:09.285Z INFO total process run time: 2 seconds
2018-09-06T02:47:09.285Z INFO Execution succeeded

参考

[AWS]Active Directory のアカウントで AWSマネジメントコンソールにログインする

$
0
0

Simple AD(AWS のマネージドな Active Directory サービス) でディレクトリとユーザーを作成し、Active Directory ユーザーで認証してAWSマネジメントコンソールに SSO でログインしてみた。


設定手順

ディレクトリの作成
  • AWSマネジメントコンソールにログインして、[Directory Service] をクリックする
  • [ディレクトリのセットアップ] をクリックし、ウイザードに従って以下の通りディレクトリを作成する
    • ディレクトリタイプの選択: Simple AD
    • ディレクトリ情報の入力
      • ディレクトリのサイズ: スモール
      • ディレクトリの DNS 名: 任意の名前(例: corp.example.com)
      • Administrator password: 任意のパスワードを入力
    • ネットワーキング
      • VPC: 任意のVPCを選択
      • サブネット: 任意の Public Subnet を選択
    • [ディレクトリの作成]をクリック

f:id:yohei-a:20180907010942p:image


ディレクトリでAWS コンソールのアクセスを有効化
  • [Directory Service]-[Active Directory]で作成したディレクトリをクリックする。
  • [AWS アプリおよびサービス]-[AWS Management Console]をクリックする。
  • 作成したディレクトリをクリックする。
  • [AWS アプリおよびサービス]-[AWS マネジメントコンソール]をクリックする。
  • [アクセスの有効化]をクリックする。

f:id:yohei-a:20180907011355p:image


IAMロールの作成
  • [IAM]-[ロール]-[ロールの作成]を選択する
  • "EC2" を選択し、[次のステップ]をクリックする。
  • " AdministratorAccess"*1 を選択し、[次のステップへ]をクリックする。
  • ロール名に "AdminRole" と入力して、[ロールの作成]をクリックする。

f:id:yohei-a:20180907010703p:image

  • [IAM]-[ロール]で作成した "AdminRole" をクリックする。
  • [信頼関係]タブを選択し、[信頼関係の編集]をクリックし、以下の通り入力して[信頼ポリシーの更新]をクリックする。

f:id:yohei-a:20180907011858p:image

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Principal": {
        "Service": "ds.amazonaws.com"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}

ADユーザーとIAMロールの関連付け
  • [Directory Service]-[Active Directory]で作成したディレクトリをクリックする。
  • [AWS アプリおよびサービス]-[AWS Management Console]をクリックする。
  • 作成したディレクトリをクリックする。
  • [AWSコンソールのアクセス]をクリックする。
  • "AdminRole" を選択する。
  • [追加]をクリックする。
  • ユーザーを選択し、"Administrator" で検索し、[追加]をクリックする。

f:id:yohei-a:20180907012126p:image


アクセスURLを設定する
  • [アクセス URL]に任意の文字列(例: tantanmen)を入力して、[有効化]をクリックする。

AD経由でAWSマネジメントコンソールにログインしてみる

  • 作成したアクセスURL "tantanmen.awsapps.com/console" にアクセスし、Administrator で設定したパスワードでログインする。

f:id:yohei-a:20180907005151p:image

  • マネジメントコンソールにログイン完了。

f:id:yohei-a:20180907005147p:image



参考

*1:付与したいポリシーを選択する

[AWS]PySpark のコードを実行すると ”ValueError: Cannot run multiple SparkContexts at once; existing SparkContext” と怒られる

$
0
0

事象

AWS Glue の Zeppelin で以下の PySpark のコードを実行すると、"ValueError: Cannot run multiple SparkContexts at once; existing SparkContext" と怒られる。

  • コード
import sys
from awsglue.transforms import *
from awsglue.utils import getResolvedOptions
from pyspark.context import SparkContext
from awsglue.context import GlueContext
from awsglue.job import Job
from pyspark.sql import SQLContext
from pyspark.sql.functions import year, month, date_format

sc = SparkContext()
glueContext = GlueContext(sc)
spark = glueContext.spark_session 
job = Job(glueContext)
job.init('sh10sales_parquet')
  • エラーメッセージ
Traceback (most recent call last):
  File "/tmp/zeppelin_pyspark-302704721498299847.py", line 367, in <module>
    raise Exception(traceback.format_exc())
Exception: Traceback (most recent call last):
  File "/tmp/zeppelin_pyspark-302704721498299847.py", line 355, in <module>
    exec(code, _zcUserQueryNameSpace)
  File "<stdin>", line 9, in <module>
  File "/usr/lib/spark/python/pyspark/context.py", line 115, in __init__
    SparkContext._ensure_initialized(self, gateway=gateway, conf=conf)
  File "/usr/lib/spark/python/pyspark/context.py", line 299, in _ensure_initialized
    callsite.function, callsite.file, callsite.linenum))
ValueError: Cannot run multiple SparkContexts at once; existing SparkContext(app=Zeppelin, master=yarn-client) created by __init__ at /tmp/zeppelin_pyspark-302704721498299847.py:278 

解決策

  • "sc = SparkContext()"を"sc = SparkContext.getOrCreate()"に書き換える。
import sys
from awsglue.transforms import *
from awsglue.utils import getResolvedOptions
from pyspark.context import SparkContext
from awsglue.context import GlueContext
from awsglue.job import Job
from pyspark.sql import SQLContext
from pyspark.sql.functions import year, month, date_format

sc = SparkContext.getOrCreate() ★ココ
glueContext = GlueContext(sc)
spark = glueContext.spark_session 
job = Job(glueContext)
job.init('sh10sales_parquet')

参考

This happens because when you type "pyspark" in the terminal, the system automatically initialized the SparkContext (maybe a Object?), so you should stop it before creating a new one.

You can use

sc.stop()

before you create your new SparkContext.

Also, you can use

sc = SparkContext.getOrCreate()

instead of

sc = SparkContext()

I am new in Spark and I don't know much about the meaning of the parameters of the function SparkContext() but the code showed above both worked for me.

python - multiple SparkContexts error in tutorial - Stack Overflow

[AWS]AD連携でAWSアカウントにログインし別アカウントでスイッチロールしたら CloudTrail にどう記録されるか

$
0
0

Active Directory(AD)連携でAWSマネジメントコンソールにログインしてさらに別のAWSアカウントにスイッチロールして操作した場合、同じADユーザー(AWSでは同じロール)を同時に複数人で操作した場合に誰が何をしたか追跡できるか調べたメモ。

Chrome、Safari、Firefox で同時にログインして S3 バケットを作成し、CloudTrail から誰が何をしたかどこまで追跡できるか確認した。

以下ではアカウント1のIDを「100000000000」、アカウント2を「200000000000」として、アカウント1にAD連携でログインしてアカウント2にスイッチロールしている。


準備


アカウント1にAD連携でログインする

  • アカウント1にAD連携でログインすると、accessKeyId が割り当てられている。

f:id:yohei-a:20180909162436p:image


アカウント2にスイッチロールしてS3バケットを作成する

chrome から S3 バケット作成
  • SwitchRole

f:id:yohei-a:20180909153727p:image

{
    "eventVersion": "1.05",
    "userIdentity": {
        "type": "AssumedRole",
        "principalId": "A***************MOF2Y:Administrator",
        "arn": "arn:aws:sts::200000000000:assumed-role/az2AdminRole/Administrator", ★az2AdminRole にスイッチロール
        "accountId": "200000000000"
    },
    "eventTime": "2018-09-09T04:22:04Z",
    "eventSource": "signin.amazonaws.com",
    "eventName": "SwitchRole", ★スイッチロール
    "awsRegion": "us-east-1",
    "sourceIPAddress": "***.***.164.95",
    "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36", ★Chrome でアクセス
    "requestParameters": null,
    "responseElements": {
        "SwitchRole": "Success"
    },
    "additionalEventData": {
        "SwitchFrom": "arn:aws:sts::100000000000:assumed-role/AdminRole/Administrator", ★AWSアカウント1からスイッチロール
        "RedirectTo": "https://console.aws.amazon.com/console/home"
    },
    "eventID": "7f563604-6afb-4cab-980f-960eb41c7de1",
    "eventType": "AwsConsoleSignIn",
    "recipientAccountId": "200000000000"
}
  • AssumeRole

f:id:yohei-a:20180909154106p:image

{
    "eventVersion": "1.05",
    "userIdentity": {
        "type": "AWSAccount",
        "principalId": "****************5PT7S:Administrator",
        "accountId": "100000000000"
    },
    "eventTime": "2018-09-09T04:22:04Z",
    "eventSource": "sts.amazonaws.com",
    "eventName": "AssumeRole",
    "awsRegion": "us-east-1",
    "sourceIPAddress": "***.***.164.95",
    "userAgent": "aws-internal/3",
    "requestParameters": {
        "roleArn": "arn:aws:iam::200000000000:role/az2AdminRole",
        "roleSessionName": "Administrator"
    },
    "responseElements": {
        "credentials": {
            "accessKeyId": "A**************7TPPK", ★アカウント1と紐付けできる
            "expiration": "Sep 9, 2018 5:22:04 AM",
            "sessionToken": ".../ijsv9LcBQ=="
        },
        "assumedRoleUser": {
            "assumedRoleId": "A***************MOF2Y:Administrator",
            "arn": "arn:aws:sts::200000000000:assumed-role/az2AdminRole/Administrator"
        }
    },
    "requestID": "e7dd7ec8-b3e7-11e8-9c01-a330de9306e7",
    "eventID": "b84de8aa-1b02-4b95-9af2-9d48b47cca25",
    "resources": [
        {
            "ARN": "arn:aws:iam::200000000000:role/az2AdminRole",
            "accountId": "200000000000",
            "type": "AWS::IAM::Role"
        }
    ],
    "eventType": "AwsApiCall",
    "recipientAccountId": "200000000000",
    "sharedEventID": "62d3f672-c89e-4ed6-b29a-07d79938c8df"
}
  • CreateBucket

f:id:yohei-a:20180909154847p:image

{
    "eventVersion": "1.05",
    "userIdentity": {
        "type": "AssumedRole",
        "principalId": "A***************MOF2Y:Administrator",
        "arn": "arn:aws:sts::200000000000:assumed-role/az2AdminRole/Administrator",
        "accountId": "200000000000",
        "accessKeyId": "A**************6MSJH", ★この accessKeyId で他のセッションと区別できるが、どのセッションから SwitchRole したかは紐付けできない
        "sessionContext": {
            "attributes": {
                "mfaAuthenticated": "false",
                "creationDate": "2018-09-09T04:22:04Z"
            },
            "sessionIssuer": {
                "type": "Role",
                "principalId": "A***************MOF2Y",
                "arn": "arn:aws:iam::200000000000:role/az2AdminRole",
                "accountId": "200000000000",
                "userName": "az2AdminRole"
            }
        },
        "invokedBy": "AWS Internal"
    },
    "eventTime": "2018-09-09T04:23:05Z",
    "eventSource": "s3.amazonaws.com",
    "eventName": "CreateBucket",
    "awsRegion": "ap-northeast-1",
    "sourceIPAddress": "***.***.164.95",
    "userAgent": "[S3Console/0.4, aws-internal/3 aws-sdk-java/1.11.398 Linux/4.9.93-0.1.ac.178.67.327.metal1.x86_64 OpenJDK_64-Bit_Server_VM/25.181-b13 java/1.8.0_181]",
    "requestParameters": {
        "CreateBucketConfiguration": {
            "LocationConstraint": "ap-northeast-1",
            "xmlns": "http://s3.amazonaws.com/doc/2006-03-01/"
        },
        "bucketName": "az-chrome-20180909-1323"
    },
    "responseElements": null,
    "additionalEventData": {
        "vpcEndpointId": "vpce-8******6"
    },
    "requestID": "30C409E75972921D",
    "eventID": "1a38c971-7031-4258-a056-3a532525a5f1",
    "eventType": "AwsApiCall",
    "recipientAccountId": "200000000000",
    "vpcEndpointId": "vpce-8******6"
}
Safari
  • SwitchRole

f:id:yohei-a:20180909182133p:image

{
    "eventVersion": "1.05",
    "userIdentity": {
        "type": "AssumedRole",
        "principalId": "A***************MOF2Y:Administrator",
        "arn": "arn:aws:sts::200000000000:assumed-role/az2AdminRole/Administrator",
        "accountId": "200000000000"
    },
    "eventTime": "2018-09-09T04:24:04Z",
    "eventSource": "signin.amazonaws.com",
    "eventName": "SwitchRole",
    "awsRegion": "us-east-1",
    "sourceIPAddress": "***.***.164.95",
    "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/11.1.2 Safari/605.1.15",
    "requestParameters": null,
    "responseElements": {
        "SwitchRole": "Success"
    },
    "additionalEventData": {
        "SwitchFrom": "arn:aws:sts::100000000000:assumed-role/AdminRole/Administrator",
        "RedirectTo": "https://console.aws.amazon.com/console/home"
    },
    "eventID": "3f50a4ec-2dfe-49a3-9c43-cd3876768ff6",
    "eventType": "AwsConsoleSignIn",
    "recipientAccountId": "200000000000"
}
  • AssumeRole

f:id:yohei-a:20180909182136p:image

{
    "eventVersion": "1.05",
    "userIdentity": {
        "type": "AWSAccount",
        "principalId": "****************5PT7S:Administrator",
        "accountId": "100000000000"
    },
    "eventTime": "2018-09-09T04:24:04Z",
    "eventSource": "sts.amazonaws.com",
    "eventName": "AssumeRole",
    "awsRegion": "us-east-1",
    "sourceIPAddress": "***.***.164.95",
    "userAgent": "aws-internal/3",
    "requestParameters": {
        "roleArn": "arn:aws:iam::200000000000:role/az2AdminRole",
        "roleSessionName": "Administrator"
    },
    "responseElements": {
        "credentials": {
            "accessKeyId": "A**************LQM7H", ★アカウント1と紐付けできる
            "expiration": "Sep 9, 2018 5:24:04 AM",
            "sessionToken": ".../jyjkwNLcBQ=="
        },
        "assumedRoleUser": {
            "assumedRoleId": "A***************MOF2Y:Administrator",
            "arn": "arn:aws:sts::200000000000:assumed-role/az2AdminRole/Administrator"
        }
    },
    "requestID": "2f723b5d-b3e8-11e8-835d-b7a0a8384096",
    "eventID": "7d764092-a50f-466c-8f75-ccff50553472",
    "resources": [
        {
            "ARN": "arn:aws:iam::200000000000:role/az2AdminRole",
            "accountId": "200000000000",
            "type": "AWS::IAM::Role"
        }
    ],
    "eventType": "AwsApiCall",
    "recipientAccountId": "200000000000",
    "sharedEventID": "87809662-23c3-4761-84c8-ce6917aa2c82"
}
  • CreateBucket

f:id:yohei-a:20180909182131p:image

{
    "eventVersion": "1.05",
    "userIdentity": {
        "type": "AssumedRole",
        "principalId": "A***************MOF2Y:Administrator",
        "arn": "arn:aws:sts::200000000000:assumed-role/az2AdminRole/Administrator",
        "accountId": "200000000000",
        "accessKeyId": "A**************IH5B3", ★この accessKeyId で他のセッションと区別できるが、どのセッションから SwitchRole したかは紐付けできない
        "sessionContext": {
            "attributes": {
                "mfaAuthenticated": "false",
                "creationDate": "2018-09-09T04:24:04Z"
            },
            "sessionIssuer": {
                "type": "Role",
                "principalId": "A***************MOF2Y",
                "arn": "arn:aws:iam::200000000000:role/az2AdminRole",
                "accountId": "200000000000",
                "userName": "az2AdminRole"
            }
        },
        "invokedBy": "AWS Internal"
    },
    "eventTime": "2018-09-09T04:24:34Z",
    "eventSource": "s3.amazonaws.com",
    "eventName": "CreateBucket",
    "awsRegion": "ap-northeast-1",
    "sourceIPAddress": "***.***.164.95",
    "userAgent": "[S3Console/0.4, aws-internal/3 aws-sdk-java/1.11.398 Linux/4.9.93-0.1.ac.178.67.327.metal1.x86_64 OpenJDK_64-Bit_Server_VM/25.181-b13 java/1.8.0_181]",
    "requestParameters": {
        "CreateBucketConfiguration": {
            "LocationConstraint": "ap-northeast-1",
            "xmlns": "http://s3.amazonaws.com/doc/2006-03-01/"
        },
        "bucketName": "az-safari-20180909-1324"
    },
    "responseElements": null,
    "additionalEventData": {
        "vpcEndpointId": "vpce-8******6"
    },
    "requestID": "87FD45DA8881188F",
    "eventID": "11b705d6-7bd5-44bb-af7c-dc3e138021fa",
    "eventType": "AwsApiCall",
    "recipientAccountId": "200000000000",
    "vpcEndpointId": "vpce-8******6"
}
firefox
  • SwitchRole

f:id:yohei-a:20180909160504p:image

{
    "eventVersion": "1.05",
    "userIdentity": {
        "type": "AssumedRole",
        "principalId": "A***************MOF2Y:Administrator",
        "arn": "arn:aws:sts::200000000000:assumed-role/az2AdminRole/Administrator",
        "accountId": "200000000000"
    },
    "eventTime": "2018-09-09T04:25:29Z",
    "eventSource": "signin.amazonaws.com",
    "eventName": "SwitchRole",
    "awsRegion": "us-east-1",
    "sourceIPAddress": "***.***.164.95",
    "userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.12; rv:52.0) Gecko/20100101 Firefox/52.0",
    "requestParameters": null,
    "responseElements": {
        "SwitchRole": "Success"
    },
    "additionalEventData": {
        "SwitchFrom": "arn:aws:sts::100000000000:assumed-role/AdminRole/Administrator",
        "RedirectTo": "https://console.aws.amazon.com/console/home"
    },
    "eventID": "8383d019-1b4d-4c52-b58b-b6af4a519314",
    "eventType": "AwsConsoleSignIn",
    "recipientAccountId": "200000000000"
}
  • AssumeRole

f:id:yohei-a:20180909160706p:image

{
    "eventVersion": "1.05",
    "userIdentity": {
        "type": "AWSAccount",
        "principalId": "****************5PT7S:Administrator",
        "accountId": "100000000000"
    },
    "eventTime": "2018-09-09T04:25:29Z",
    "eventSource": "sts.amazonaws.com",
    "eventName": "AssumeRole",
    "awsRegion": "us-east-1",
    "sourceIPAddress": "***.***.164.95",
    "userAgent": "aws-internal/3",
    "requestParameters": {
        "roleArn": "arn:aws:iam::200000000000:role/az2AdminRole",
        "roleSessionName": "Administrator"
    },
    "responseElements": {
        "credentials": {
            "accessKeyId": "A***************TZFW5", ★アカウント1と紐付けできる
            "expiration": "Sep 9, 2018 5:25:29 AM",
            "sessionToken": "...ASi5wdLcBQ=="
        },
        "assumedRoleUser": {
            "assumedRoleId": "A***************MOF2Y:Administrator",
            "arn": "arn:aws:sts::200000000000:assumed-role/az2AdminRole/Administrator"
        }
    },
    "requestID": "61f4392e-b3e8-11e8-bc4b-418ccd807570",
    "eventID": "248e411a-b2c0-4024-9f41-dbe812bd0af2",
    "resources": [
        {
            "ARN": "arn:aws:iam::200000000000:role/az2AdminRole",
            "accountId": "200000000000",
            "type": "AWS::IAM::Role"
        }
    ],
    "eventType": "AwsApiCall",
    "recipientAccountId": "200000000000",
    "sharedEventID": "57441f3f-bf33-4090-ae3b-d2febc1f6efd"
}
  • CreateBucket

f:id:yohei-a:20180909160903p:image

{
    "eventVersion": "1.05",
    "userIdentity": {
        "type": "AssumedRole",
        "principalId": "A***************MOF2Y:Administrator",
        "arn": "arn:aws:sts::200000000000:assumed-role/az2AdminRole/Administrator",
        "accountId": "200000000000",
        "accessKeyId": "A**************3XGFV",  ★この accessKeyId で他のセッションと区別できるが、どのセッションから SwitchRole したかは紐付けできない
        "sessionContext": {
            "attributes": {
                "mfaAuthenticated": "false",
                "creationDate": "2018-09-09T04:25:29Z"
            },
            "sessionIssuer": {
                "type": "Role",
                "principalId": "A***************MOF2Y",
                "arn": "arn:aws:iam::200000000000:role/az2AdminRole",
                "accountId": "200000000000",
                "userName": "az2AdminRole"
            }
        },
        "invokedBy": "AWS Internal"
    },
    "eventTime": "2018-09-09T04:26:02Z",
    "eventSource": "s3.amazonaws.com",
    "eventName": "CreateBucket",
    "awsRegion": "ap-northeast-1",
    "sourceIPAddress": "***.***.164.95",
    "userAgent": "[S3Console/0.4, aws-internal/3 aws-sdk-java/1.11.398 Linux/4.9.93-0.1.ac.178.67.327.metal1.x86_64 OpenJDK_64-Bit_Server_VM/25.181-b13 java/1.8.0_181]",
    "requestParameters": {
        "CreateBucketConfiguration": {
            "LocationConstraint": "ap-northeast-1",
            "xmlns": "http://s3.amazonaws.com/doc/2006-03-01/"
        },
        "bucketName": "az-firefox-20180909-1325"
    },
    "responseElements": null,
    "additionalEventData": {
        "vpcEndpointId": "vpce-8******6"
    },
    "requestID": "0832654BEA9D8056",
    "eventID": "7cfde7e1-11e0-486d-ba47-ecb649d60453",
    "eventType": "AwsApiCall",
    "recipientAccountId": "200000000000",
    "vpcEndpointId": "vpce-8******6"
}

[AWS]VPCフローログのサイズがどの程度になるか

$
0
0

別々のVPCにEC2インスタンスを作成して iperf で1時間ネットワーク転送をして VPC フローログのサイズがどの程度になるか検証してみた。


検証手順

VPC フローログの設定

以下を2つのVPCで設定する

  • 任意の名前で S3 バケットを作成する。
  • EC2 を作成する VPC を選択して、[フローログ]をクリックする。
  • [フローログの作成]をクリックする。
    • Filter: All
    • Destination: Send to an S3 bucket
    • S3 bucket ARN: 作成したS3バケットの ARN を入力
EC2インスタンス作成
  • 2つのVPCに1つずつEC2インスタンスを作成する(今回は m4.10xlarge を利用した)。
iperf をインストールする
  • 2つの別のVPCにEC2インスタンス(Amazon Linux)を作成する。
  • EC2インスタンスに iperf をインストールする。
$ sudo yum -y install git gcc
$ git clone https://github.com/esnet/iperf
$ cd iperf
$ ./configure
$ sudo make
$ sudo make install
$ sudo ldconfig
  • iperf でサーバ側にする EC2 のセキュリティグループでクライアント側のEC2のIPからの通信を許可する。

検証実施

  • iperf で1時間ネットワーク通信を行う。
    • サーバ側
$ iperf -s
    • クライアント側
$ iperf3 -c ec2-**-***-191-213.ap-northeast-1.compute.amazonaws.com -t 3600 -P 10
  • CloudWatch

f:id:yohei-a:20180909231936p:image:w360

f:id:yohei-a:20180909231934p:image:w360


サイズの確認

  • iperf クライアント側
$ aws s3 cp --recursive s3://aws-vpcflowlog-100000000000-ap-noartheast-1 ./
$ cd AWSLogs/100000000000/vpcflowlogs/ap-northeast-1/2018/09/09/
$ du -hs
376K.
$ gunzip *.gz
$ du -hs
728K.
$ head -3 100000000000_vpcflowlogs_ap-northeast-1_fl-002b091daf0edd6fb_20180909T1230Z_9e961a12.log
version account-id interface-id srcaddr dstaddr srcport dstport protocol packets bytes start end action log-status
2 100000000000 eni-*****560e2bc271ee ***.**.9.121 **.***.225.139 50194 443 6 9 2689 1536496135 1536496191 ACCEPT OK
2 100000000000 eni-*****560e2bc271ee ***.**.9.121 **.***.225.139 50198 443 6 9 2689 1536496135 1536496191 ACCEPT OK
  • iperf サーバ側
$ aws s3 cp --recursive s3://aws-vpcflowlog-200000000000-ap-northeast-1 ./
$ cd AWSLogs/200000000000/vpcflowlogs/ap-northeast-1/2018/09/09/
$ du -hs 
280K.
$ gunzip *.gz
$ du -hs
456K.
$ head -3 200000000000_vpcflowlogs_ap-northeast-1_fl-05d4eb0a8aaa6cc41_20180909T1235Z_4ab5b1df.log
version account-id interface-id srcaddr dstaddr srcport dstport protocol packets bytes start end action log-status
2 200000000000 eni-*****a0032216167f **.***.225.173 **.***.45.65 443 37290 6 4 559 1536496227 1536496286 ACCEPT OK
2 200000000000 eni-*****a0032216167f **.***.225.173 **.***.45.65 443 37294 6 20 6720 1536496227 1536496286 ACCEPT OK

フローログレコードの構文

フローログレコードはスペース区切りの文字列で、以下の形式です。

<version> <account-id> <interface-id> <srcaddr> <dstaddr> <srcport> <dstport> <protocol> <packets> <bytes> <start> <end> <action> <log-status>

次の表は、フローログレコードのフィールドについて説明しています。

フィールド説明
versionVPC フローログバージョン。
account-idフローログの AWS アカウント ID。
interface-idトラフィックが記録されるネットワークインターフェイスの ID。
srcaddr送信元の IPv4 または IPv6 アドレス。ネットワークインターフェイスの IPv4 アドレスは常にそのプライベート IPv4 アドレスです。
dstaddr送信先の IPv4 または IPv6 アドレス。ネットワークインターフェイスの IPv4 アドレスは常にそのプライベート IPv4 アドレスです。
srcportトラフィックの送信元ポート。
dstportトラフィックの送信先ポート。
protocolトラフィックの IANA プロトコル番号。詳細については、「割り当てられたインターネットプロトコル番号」を参照してください。
packetsキャプチャウィンドウ中に転送されたパケットの数。
bytesキャプチャウィンドウ中に転送されたバイト数。
startキャプチャウィンドウの開始時刻 (Unix 時間)。
endキャプチャウィンドウの終了時刻 (Unix 時間)。
actionトラフィックに関連付けられたアクション:ACCEPT: 記録されたトラフィックは、セキュリティグループまたはネットワーク ACL で許可されています。
REJECT: 記録されたトラフィックは、セキュリティグループまたはネットワーク ACL で許可されていません。
log-statusフローログのロギングステータス。
OK: データは選択された送信先に正常に記録されます。
NODATA: キャプチャウィンドウ中にネットワークインターフェイスとの間で行き来するネットワークトラフィックはありませんでした。
SKIPDATA: 一部のフローログレコードはキャプチャウィンドウ中にスキップされました。これは、内部的なキャパシティー制限、または内部エラーが原因である可能性があります。
VPC フローログ - Amazon Virtual Private Cloud

packets が「キャプチャウィンドウ中に転送されたパケットの数」とあるので、複数のパケットで1レコードとなる。1レコードあたりはざっくり115バイト程度。


関連


参考

[AWS]IAM ユーザーで QuickSight を初回利用する際の手順

[AWS]VPCエンドポイントポリシーの例

$
0
0

{
    "Version": "2012-10-17",
    "Id": "Policy1536592965770",
    "Statement": [
        {
            "Sid": "Stmt1536592962486",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::az-safari"
        }
    ]
}

[AWS]AWS Glue を使ってみた

$
0
0

AWS Glue と Amazon S3 を使用してデータレイクの基礎を構築する | Amazon Web Services ブログ を試してみた。


  • データソースの確認
% aws s3 ls --human-readable s3://aws-bigdata-blog/artifacts/glue-data-lake/data/
2017-10-24 06:24:27    0 Bytes
2017-10-24 06:24:42   91.3 MiB green_tripdata_2017-01.csv
  • ジョブ実行でエラー

"nytaxi-csv-parquet" ジョブの実行で "AmazonS3Exception: Access Denied (Service: Amazon S3; Status Code: 403; Error Code: AccessDenied" とエラーになったので、作成した"AWSGlueServiceRole-Default" IAMロールにアタッチしているポリシーを確認すると s3://nytaxi-parquet の参照権限がなかったので、AmazonS3FullAccess を付与して再実行したら成功した。

f:id:yohei-a:20180912125242p:image

Traceback (most recent call last):
File "script_2018-09-12-02-46-38.py", line 40, in <module>
datasink4 = glueContext.write_dynamic_frame.from_options(frame = dropnullfields3, connection_type = "s3", connection_options =
{
    "path": "s3://nytaxi-parquet"
}
, format = "parquet", transformation_ctx = "datasink4")
File "/mnt/yarn/usercache/root/appcache/application_1536719177297_0001/container_1536719177297_0001_01_000001/PyGlue.zip/awsglue/dynamicframe.py", line 574, in from_options
File "/mnt/yarn/usercache/root/appcache/application_1536719177297_0001/container_1536719177297_0001_01_000001/PyGlue.zip/awsglue/context.py", line 191, in write_dynamic_frame_from_options
File "/mnt/yarn/usercache/root/appcache/application_1536719177297_0001/container_1536719177297_0001_01_000001/PyGlue.zip/awsglue/context.py", line 214, in write_from_options
File "/mnt/yarn/usercache/root/appcache/application_1536719177297_0001/container_1536719177297_0001_01_000001/PyGlue.zip/awsglue/data_sink.py", line 32, in write
File "/mnt/yarn/usercache/root/appcache/application_1536719177297_0001/container_1536719177297_0001_01_000001/PyGlue.zip/awsglue/data_sink.py", line 28, in writeFrame
File "/mnt/yarn/usercache/root/appcache/application_1536719177297_0001/container_1536719177297_0001_01_000001/py4j-0.10.4-src.zip/py4j/java_gateway.py", line 1133, in __call__
File "/mnt/yarn/usercache/root/appcache/application_1536719177297_0001/container_1536719177297_0001_01_000001/pyspark.zip/pyspark/sql/utils.py", line 63, in deco
File "/mnt/yarn/usercache/root/appcache/application_1536719177297_0001/container_1536719177297_0001_01_000001/py4j-0.10.4-src.zip/py4j/protocol.py", line 319, in get_return_value
py4j.protocol.Py4JJavaError: An error occurred while calling o120.pyWriteDynamicFrame.
: com.amazon.ws.emr.hadoop.fs.shaded.com.amazonaws.services.s3.model.AmazonS3Exception: Access Denied (Service: Amazon S3; Status Code: 403; Error Code: AccessDenied★; Request ID: 929E2CD0A8C1BDA6), S3 Extended Request ID: KoO7fU9QDKYG7KnvHxoSns810SeuyuZMZUtmEua6r/DGyMLEGQXHz78G8YDLEmECvUSDJAeNud4=
at com.amazon.ws.emr.hadoop.fs.shaded.com.amazonaws.http.AmazonHttpClient$RequestExecutor.handleErrorResponse(AmazonHttpClient.java:1588)
at com.amazon.ws.emr.hadoop.fs.shaded.com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeOneRequest(AmazonHttpClient.java:1258)
at com.amazon.ws.emr.hadoop.fs.shaded.com.amazonaws.http.AmazonHttpClient$RequestExecutor.executeHelper(AmazonHttpClient.java:1030)
at com.amazon.ws.emr.hadoop.fs.shaded.com.amazonaws.http.AmazonHttpClient$RequestExecutor.doExecute(AmazonHttpClient.java:742)
  • CloudTrail で Glue から S3 に発行されたオブジェクトレベルの API を Athena で確認してみる

f:id:yohei-a:20180912130415p:image

    • クエリ
select eventtime, eventsource, eventname, awsregion, sourceipaddress, useragent, requestparameters 
from cloudtrail_logs_cloudtrail_100000000000_do_not_delete 
where eventsource = 's3.amazonaws.com' 
and eventname = 'PutObject' 
and useragent = '[ElasticMapReduce/1.0.0 emrfs/s3n {}, aws-internal/3]' 
and errorcode is null
    • 003dc102-f9d0-474e-a171-98b19e84228d.csv
"eventtime","eventsource","eventname","awsregion","sourceipaddress","useragent","requestparameters"
"2018-09-12T03:19:12Z","s3.amazonaws.com","PutObject","ap-northeast-1","xx.xxx.xxx.172","[ElasticMapReduce/1.0.0 emrfs/s3n {}, aws-internal/3]","{""bucketName"":""nytaxi-parquet"",""key"":""_temporary/0_$folder$""}"
"2018-09-12T03:19:11Z","s3.amazonaws.com","PutObject","ap-northeast-1","xx.xxx.xxx.172","[ElasticMapReduce/1.0.0 emrfs/s3n {}, aws-internal/3]","{""bucketName"":""nytaxi-parquet"",""key"":""_temporary_$folder$""}"
"2018-09-12T03:19:27Z","s3.amazonaws.com","PutObject","ap-northeast-1","xx.xxx.xxx.25","[ElasticMapReduce/1.0.0 emrfs/s3n {}, aws-internal/3]","{""bucketName"":""nytaxi-parquet"",""key"":""_temporary/0/_temporary/attempt_20180912031917_0000_m_000001_0/part-00001-eebf4723-bbaf-42e9-aa03-1d20539eba2d-c000.snappy.parquet""}"
"2018-09-12T03:19:33Z","s3.amazonaws.com","PutObject","ap-northeast-1","xx.xxx.xxx.25","[ElasticMapReduce/1.0.0 emrfs/s3n {}, aws-internal/3]","{""bucketName"":""nytaxi-parquet"",""key"":""_temporary/0/_temporary/attempt_20180912031916_0000_m_000000_0/part-00000-eebf4723-bbaf-42e9-aa03-1d20539eba2d-c000.snappy.parquet""}"

[AWS]「AWS Cloudtrail Logs を AWS Glue と Amazon Quicksight 使って可視化する」をやってみた

$
0
0

AWS Cloudtrail Logs を AWS Glue と Amazon Quicksight 使って可視化する | Amazon Web Services ブログ を試してみた。


Lambda用ロールの作成
  • 名前: CloudTrailWatchLogs
  • インラインポリシー
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "arn:aws:logs:*:*:*"
        },
        {
            "Action": [
                "s3:*"
            ],
            "Resource": [
                "arn:aws:s3:::cloudtrail-do-not-delete/*",
                "arn:aws:s3:::cloudtrail-do-not-delete"
            ],
            "Effect": "Allow"
        }
    ]
}
Glue用ロールの作成
  • 名前: AWSGlueServiceRole-Default
  • 以下のポリシーをアタッチ
    • AmazonS3FullAccess
    • AWSGlueServiceRole
Lambda関数の作成
  • 関数名: cloudTrail2FlatfileFunction
  • ランタイム : Python 2.7
  • 実行ロール: CloudTrailWatchLogs
  • トリガーの設定
    • バケット: cloudtrail-do-not-delete
    • イベントタイプ: PUT
    • プレフィックス: AWSLogs/<アカウントID>/CloudTrail/
  • 関数コード
from __future__ import print_function
import json
import urllib
import boto3
import gzip

s3 = boto3.resource('s3')
client = boto3.client('s3')

def convertColumntoLowwerCaps(obj):
    for key in obj.keys():
        new_key = key.lower()
        if new_key != key:
            obj[new_key] = obj[key]
            del obj[key]
    return obj


def lambda_handler(event, context):

    bucket = event['Records'][0]['s3']['bucket']['name']
    key = urllib.unquote_plus(event['Records'][0]['s3']['object']['key'].encode('utf8'))
    print(bucket)
    print(key)
    try:
        newKey = 'flatfiles/' + key.replace("/", "")
        client.download_file(bucket, key, '/tmp/file.json.gz')
        with gzip.open('/tmp/out.json.gz', 'w') as output, gzip.open('/tmp/file.json.gz', 'rb') as file:
            i = 0
            for line in file: 
                for record in json.loads(line,object_hook=convertColumntoLowwerCaps)['records']:
            if i != 0:
                output.write("\n")
            output.write(json.dumps(record))
            i += 1
        client.upload_file('/tmp/out.json.gz', bucket,newKey)
        return "success"
    except Exception as e:
        print(e)
        print('Error processing object {} from bucket {}. Make sure they exist and your bucket is in the same region as this function.'.format(key, bucket))
        raise e
Glue クローラの作成(Flatfile用)
  • 名前: cloudTrailFlatfiles
  • Choose a data store: S3
  • インクルードパス: s3://cloudtrail-do-not-delete/flatfiles
  • IAM ロール: AWSGlueServiceRole-Default
  • データベース: cloudtrail
  • 頻度: 毎時
Glue クローラの作成(Parquet用)
  • 名前: cloudtrailParquetFiles
  • Choose a data store: S3
  • インクルードパス: s3://cloudtrail-do-not-delete/parquettrails 
  • IAM ロール: AWSGlueServiceRole-Default
  • データベース: cloudtrail
  • 頻度: 毎時
Glueジョブの作成
  • 以下のコードをファイル名 "cloudtrailtoparquet.py" で S3バケット "az-src" にアップロードする。
import sys
from awsglue.transforms import *
from awsglue.utils import getResolvedOptions
from pyspark.context import SparkContext
from awsglue.context import GlueContext
from awsglue.job import Job
import boto3
import time

## @params: [JOB_NAME]
args = getResolvedOptions(sys.argv, ['JOB_NAME'])

sc = SparkContext()
glueContext = GlueContext(sc)
spark = glueContext.spark_session
job = Job(glueContext)
job.init(args['JOB_NAME'], args)

datasource0 = glueContext.create_dynamic_frame.from_catalog(database = "cloudtrail", table_name = "flatfiles", transformation_ctx = "datasource0")
resolvechoice1 = ResolveChoice.apply(frame = datasource0, choice = "make_struct", transformation_ctx = "resolvechoice1")
relationalized1 = resolvechoice1.relationalize("trail", args["TempDir"]).select("trail")
datasink = glueContext.write_dynamic_frame.from_options(frame = relationalized1, connection_type = "s3", connection_options = {"path": "s3://cloudtrail-do-not-delete/parquettrails"}, format = "parquet", transformation_ctx = "datasink4")
job.commit()
  • 以下のジョブを作成する
    • 名前: cloudTrailToParquet
    • スクリプトパス: s3://az-src/cloudtrailtoparquet.py
    • IAM ロール: AWSGlueServiceRole-Default
    • 一時ディレクトリ: デフォルトのまま
Athena でクエリ実行
  • データベースで cloudtrail を選択する
  • 以下のクエリを実行する
select *
from cloudtrail.parquettrails
where eventtime > '2017-10-23T12:00:00Z' AND eventtime < '2017-10-23T13:00:00Z'
order by eventtime asc;

[AWS]EC2インスタンス作成後に自動割り当てパブリックIPを割り当てることはできない

$
0
0

手動でパブリック IP アドレスをインスタンスに関連付けること、また、手動でインスタンスから割り当て解除することはできません。場合によって、パブリック IP アドレスはインスタンスから解放されたり、新しいインスタンスに割り当てられたりします

Amazon EC2 インスタンスの IP アドレッシング - Amazon Elastic Compute Cloud

EC2インスタンス作成後に自動割り当てパブリックIPを割り当てることはできない。Elastic IPアドレスはEC2インスタンス作成後に割り当てることができる。

[AWS]AWS Glue とは

$
0
0

カタログ

データベース
テーブル
分類子(Classifier)

ETL

ジョブ
トリガー
開発エンドポイント

セキュリティ


Apache Spark の主要な抽象化の 1 つは SparkSQL DataFrame で、これは R と Pandas にある DataFrame 構造に似ています。DataFrame はテーブルと似ており、機能スタイル (マップ/リデュース/フィルタ/その他) 操作と SQL 操作 (選択、プロジェクト、集計) をサポートしています。

DataFrames は、強力で広く使用されていますが、抽出、変換、およびロード (ETL) 操作に関しては制限があります。最も重要なのは、データをロードする前にスキーマを指定する必要があることです。SparkSQL は、データに対してパスを 2 つ作ることでこれを解決します。1 つ目はスキーマを推測し、2 つ目はデータをロードします。ただし、この推測は限定されており、実際の煩雑なデータには対応しません。たとえば、同じフィールドが異なるレコードの異なるタイプである可能性があります。Apache Spark は、多くの場合、作業を中断して、元のフィールドテキストを使用してタイプを string として報告します。これは正しくない可能性があり、スキーマの不一致を解決する方法を細かく制御する必要があります。また、大規模なデータセットの場合、ソースデータに対する追加パスが非常に高価になる可能性があります。

これらの制限に対応するために、AWS Glue により DynamicFrame が導入されました。DynamicFrame は、DataFrame と似ていますが、各レコードが自己記述できるため、最初はスキーマは必要ありません。代わりに、AWS Glue は必要に応じてオンザフライでスキーマを計算し、選択 (または共用) タイプを使用してスキーマの不一致を明示的にエンコードします。これらの不整合を解決して、固定スキーマを必要とするデータストアとデータセットを互換性のあるものにできます。

同様に、DynamicRecord は DynamicFrame 内の論理レコードを表します。これは、Spark DataFrame の行と似ていますが、自己記述型であり、固定スキーマに適合しないデータに使用できます。

DynamicFrame クラス - AWS Glue
  • クローラは先頭2MBだけスキャンしている

上記のドキュメントでは、Crawlerがテーブルを作成する際はデータの先頭2MBを見て判断すると記載されています。

AWS GlueのDynamicFrameの動きを見てみる | Developers.IO

  • DPU

ETL ジョブの実行に使用された DPU (Data Processing Unit) の数に基づいて時間あたりの課金が発生します。1 つの DPU (Data Processing Unit) では 4 つの vCPU と 16 GB のメモリが提供されます。Glue の ETL ジョブには最低で 2 個の DPU が必要です。AWS Glue のデフォルトでは、各 ETL ジョブに 10 個の DPU が割り当てられます。DPU 時間あたり 0.44 ドルが 1 秒単位で課金され、最も近い秒単位に切り上げられます。ETL ジョブごとに 10 分の最小期間が設定されます。

AWS Glue の料金 ? アマゾン ウェブ サービス (AWS)
  • クローラー
    • DPU(データ処理ユニット)の時間単位で課金
    • 1DPU = 4vCPUと16GBメモリ
    • 各クローラーには2DPUが割り当て
    • 1DPU 0.44ドル/時
    • 最低10分とし、分単位で切り上げ請求
  • ETLジョブ
    • DPU(データ処理ユニット)の時間単位で課金
      • 1DPU = 4vCPUと16GBメモリ
      • Glue ETL処理には最低2DPUが必要
      • 本番環境のデフォルトはジョブごとに10DPUを割り当て
      • 開発エンドポイントのデフォルトは開発エンドポイントごとに5DPUを割り当て
    • 1DPU 0.44ドル/時
    • 最低10分とし、分単位で切り上げ請求
【新サービス】AWS上でフルマネージドなデータカタログとETLを実現するサービス『AWS Glue』がリリースされました!使い始めの準備をご紹介 | Developers.IO
  • Zeppelinとは

ブラウザ上でプログラムをインタラクティブに記述できるノートブックというものを作成するツールの一種です。 有名なところではJupyter notebook(IPython notebook)があるかと思いますが、それと似たツールだと想像していただければと思います。

Apache Zeppelin入門 | Hadoop Advent Calendar 2016 #19 | Developers.IO

[AWS]Amazon Linux に OpenJDK をインストールする

[AWS]Athena に JDBC Driver 経由で接続してクエリを発行する

$
0
0

簡単な Java プログラムを作成して JDBC Driver 経由で Athena に接続してみた。CloudTrail を確認すると、JDBC接続しても JDBC Driver に同梱されている AWS SDK for java から API を実行していることが分かる。


準備

$ wget https://s3.amazonaws.com/athena-downloads/drivers/JDBC/SimbaAthenaJDBC_2.0.5/AthenaJDBC41_2.0.5.jar
  • Java コード
import java.sql.*;
import java.util.Properties;

public class AthenaJDBCDemo {
static final String athenaUrl ="jdbc:awsathena://AwsRegion=ap-northeast-1;";
public static void main(String[] args) {
Connection conn = null;
Statement statement = null;
try {
Class.forName("com.simba.athena.jdbc.Driver");
Properties info = new Properties();
info.put("S3OutputLocation", "s3://aws-athena-query-results-<Account ID>-ap-northeast-1/");
info.put("LogPath", "/home/ec2-user");
info.put("LogLevel","6");
info.put("AwsCredentialsProviderClass","com.simba.athena.amazonaws.auth.PropertiesFileCredentialsProvider");
info.put("AwsCredentialsProviderArguments","/home/ec2-user/.athenaCredentials");
String databaseName = "default";
System.out.println("Connecting to Athena...");
conn = DriverManager.getConnection(athenaUrl,info);
System.out.println("Listing tables...");
String sql = "show tables in "+ databaseName;
statement = conn.createStatement();
ResultSet rs = statement.executeQuery(sql);
while (rs.next()) {
//Retrieve table column.
String name = rs.getString("tab_name");
//Display values.
System.out.println("Name: " + name);
}
rs.close();
conn.close();
} catch (Exception ex) {
ex.printStackTrace();
} finally {
    try {
    if (statement != null)
    statement.close();
    } catch (Exception ex) {
    }
    try {
    if (conn != null)
    conn.close();
    } catch (Exception ex) {
    ex.printStackTrace();
    }
    }
    System.out.println("Finished connectivity test.");
    }
}
  • コンパイルする。
$ javac -classpath ./AthenaJDBC41_2.0.5.jar AthenaJDBCDemo.java
  • クレデンシャルを作成する
$ vi .athenaCredentials
accessKey=...
secretKey=...

実行する

$ java -cp .:./AthenaJDBC41_2.0.5.jar AthenaJDBCDemo
Connecting to Athena...
log4j:WARN No appenders could be found for logger (com.simba.athena.amazonaws.AmazonWebServiceClient).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
Listing tables...
Name: cloudtrail_logs_cloudtrail_269419664770_do_not_delete
Finished connectivity test.

実行結果を確認する

  • S3 バケットに結果セットが作成されている

f:id:yohei-a:20180916043454p:image:w640

  • CloudTrail を確認する

f:id:yohei-a:20180916042413p:image:w640

  • CloudTrail のイベントの詳細

f:id:yohei-a:20180916043842p:image:w640

{
    "eventVersion": "1.05",
    "userIdentity": {
        "type": "IAMUser",
        "principalId": "...",
        "arn": "arn:aws:iam::...:user/...",
        "accountId": "...",
        "accessKeyId": "...",
        "userName": "..."
    },
    "eventTime": "2018-09-15T19:17:23Z",
    "eventSource": "athena.amazonaws.com",
    "eventName": "GetQueryExecution",
    "awsRegion": "ap-northeast-1",
    "sourceIPAddress": "**.***.42.228", ★EC2のグローバルIP
    "userAgent": "sbAthenaJDBCDriver/2.0, aws-sdk-java/1.11.335 Linux/4.14.62-65.117.amzn1.x86_64 OpenJDK_64-Bit_Server_VM/24.191-b01 java/1.7.0_191", ★AWS SDK for Java in JDBC Driver からアクセスしている
    "requestParameters": {
        "queryExecutionId": "c7a91af0-8965-41f9-9694-b5996f766b35"
    },
    "responseElements": null,
    "requestID": "bdb5f440-3eda-498f-a254-a668f2c9fffe",
    "eventID": "eae75fbd-37eb-4937-a652-c1e50fe2b5a0",
    "eventType": "AwsApiCall", ★ APIを発行している
    "recipientAccountId": "..."
}

f:id:yohei-a:20180916043656p:image:w640

{
    "eventVersion": "1.05",
    "userIdentity": {
        "type": "IAMUser",
        "principalId": "...",
        "arn": "arn:aws:iam::...:user/...",
        "accountId": "...",
        "accessKeyId": "...",
        "userName": "..."
    },
    "eventTime": "2018-09-15T19:17:24Z",
    "eventSource": "athena.amazonaws.com",
    "eventName": "GetQueryResultsStream",
    "awsRegion": "ap-northeast-1",
    "sourceIPAddress": "**.***.42.228",
    "userAgent": "sbAthenaJDBCDriver/2.0, aws-sdk-java/1.11.335 Linux/4.14.62-65.117.amzn1.x86_64 OpenJDK_64-Bit_Server_VM/24.191-b01 java/1.7.0_191",
    "requestParameters": {
        "queryExecutionId": "c7a91af0-8965-41f9-9694-b5996f766b35",
        "maxResults": 10000
    },
    "responseElements": null,
    "requestID": "62dac377-e0f2-4727-8643-982cf07f18cc",
    "eventID": "bf4426a4-bec2-4d8a-97f8-fbf3e130c9db",
    "eventType": "AwsApiCall",
    "recipientAccountId": "..."
}

参考

[AWS]AWS Glue の DynamicFrame と Spark の DataFrame の違い

$
0
0

Sparkとは

P.100

「Apache Spark」も、MapReduce より効率の良いデータ処理を実現するプロジェクトとして開発が進められています。Hadoop の延長線上にある Tez とは異なり、Spark は Hadoop とは別の独立したプロジェクトです。Spark の特徴は大量のメモリを活用して高速化を実現することです。(中略)コンピュータが異常停止すると途中まで処理した中間データは消えてしまいますが、そのときには処理をやり直して、失われた中間データをま作れば良いというのが Spark の考え方です(図 3.8)。

(中略)

Spark は Hadoop を置き換えるものではなく、MapReduce を置き換える存在です。例えば、分散ファイルシステムである HDFS や、リソースマネージャである YARN などは、Spark からでもそのまま利用できます。Hadoop を利用しない構成も可能であり、分散ストレージとして Amazon S3 を利用したり、あるいは分散データベースである Cassandra からデータを読み込んだりするようなことも可能です。

f:id:yohei-a:20180916181231j:image:w640


Spark の歴史

P.5

Spark プロジェクトはもともとカリフォルニア大学バークレー校 AMPLab の研究プロジェクトとして2009年にスタートしました。BDAS(the Berkeley Data Analytics Stack)と呼ばれるビッグデータ分析のためのソフトウェアスタックがあり、Spark はそのコンポーネントのひとつに位置付けられています。Spark プロジェクトは2010年初頭にオープンソース化され、2013年6月に Apache Incubator Project に採択されて「Apache Spark」となりました。この頃から本格的な開発体制が整い始め、2013年10月には AMPLab から Spark 開発者がスピンアウトして、米 Databrics が設立されました。現在も Spark 開発者の多くは Databrics に所属しています。

AMPLAB is a University of California, Berkeley lab focused on Big data analytics. The name stands for the Algorithms, Machines and People Lab.[1][2] It has been publishing papers since 2008[3] and was officially launched in 2011.[4]

While AMPLab has worked on a wide variety of big data projects, many know it as the lab that invented Apache Spark.[5]

AMPLab - Wikipedia

f:id:yohei-a:20180916184431p:image:w640

About | AMPLab – UC Berkeley

DAG(Directed Acyclic Graph)とは

P.202-204

MapReduce に変わる新しいフレームワーク DAGによる内部表現

新しいフレームワークに共通するのがDAG(directed acyclic graph)と呼ばれるデータ構造です(図 5.12)。日本語では「有向非循環グラフ」と呼ばれます。DAG そのものは何かの技術ではなく、数学やコンピュータアルゴリズムで用いられるデータモデルの一つです。DAG は、次のような性質を持ちます。

  • ノードとノードが矢印で結ばれる(有向)
  • 矢印をいくら辿っても同じノードに戻らない(非循環)

データフローでは、実行すべき一連のタスクをDAGによるデータ構造として表現します。図中の矢印はタスクの実行順序を示しており、その依存関係を保ちながらうまく実行順序を決めることで、すべてのタスクを漏れなく完了させることができます。後は、これをどれだけ効率よく実行できるかという問題です。

従来の MapReduce も「Map」と「Reduce」の2種類のノードから成るシンプルなDAGであると考えることができます。ただし、一つのノードで処理が終わらなければ次の処理に進めないという非効率なものでした。

一方、データフローではDAGを構成する各ノードがすべて同時並行で実行されます。処理の終わったデータは、ネットワーク経由で次々と受け渡され、MapReduce にあった待ち時間をなくしています。


SparkにおけるDAG

DAGはシステムの内部的な表現であり、利用者がその存在を意識することはほとんどありません。データフローに限らず、Hive on Tez や Presto のようなクエリエンジンでもDAGは採用されており、SQLからDAGのデータ構造が内部で自動生成されています。一方、Spark のようなデータフローのフレームワークでは、プログラミング言語を用いてより直接的にDAGのデータ構造を組み立てます。

(中略)

DAGによるプログラミングの特徴が遅延評価(lazy evaluation)です。プログラムの各行は、実際にはDAGのデータ構造を組み立てているだけであり、その場では何の処理も行いません。まずはDAGを構築し、その後で明示的に、あるいは暗黙的に実行結果を要求することによって、ようやくデータ処理が開始されます。

MapReduceのようにMapやReduceを一つずつ実行するのではなく、最初にデータパイプライン全体をDAGとして組み立ててから実行に移すことで、内部のスケジューラが分散システムにとって効率の良い実行計画を建ててくれるのがデータフローの優れたところです。


RDDとは

P.14

Apache Spark のデータ処理には「RDD(Resilient Distributed Dataset)」と呼ばれるデータ構造を利用します。Spark のプログラミングモデルは「RDDを加工して新たなRDDを生成し、これを繰り返すことで目的の結果を得る」というものになっています。

(中略)

RDD は大量のデータを要素として保持する分散コレクションです。巨大な配列やリストのようなデータ構造を想像すると分かりやすいでしょう。RDD は複数のマシンから構成されるクラスタ上での分散処理を前提として設計されており、内部的にはパーティションというかたまりに分割されています。Spark では、このパーティションが分散処理の単位となります。RDD をパーティションごとに複数のマシンで処理することによって、単一のマシンでは処理しきれない大量のデータを扱うことができるのです。

ユーザーはたとえばHDFSなどの分散ファイルシステム上のファイルの内容を RDD にロードし、RDD を加工することで大量のデータの分散処理を実現できます。Spark ではこの加工に相当する処理を「変換」と呼びます。そして、RDD の内容を元に「アクション」と呼ばれる処理を適用して目的の結果を得るのです(図 2.2)。

このほかに、RDD はイミュータブル(内部の要素の値を変更できない)ということと、生成や変換が遅延評価されるという性質があります。

f:id:yohei-a:20180916191822j:image:w640

D


DataFrame*1 とは

P.110

Spark SQL ではドライバプログラムからさまざまな形式のデータセットを統一的に扱うために、DataFrame と呼ばれる抽象的なデータ構造を用います。DataFrame とは RDBMS のテーブルのように行と名前とデータ型が付与された列の概念を持つデータ構造です。Spark SQL ではさまざまnあデータ型をサポートしており、Dataframe の列のデータ型に指定することができます。



DynamicFrame とは

  • AWS Glue でデータの抽出・変換をする際に使う Spark の DataFrame の Wrapper。
  • DynamicFrame は Python と Scala 両方の API がある。
  • DataFrame は最初にスキーマ定義(列の型など)が必要で、同一列に型が異なる値があると String としてしか扱えないが、DynamicFrame だとスキーマ定義で読んだ上で型を揃えるなどの前処理ができる?
  • なので、DynamicFrame で前処理、DataFrame でSparkSQLで高度なAPIを使う、DynamicFrame に変換して書出しといった使い方になる?

参考

  • Python の DynamicFrame クラスの説明

DynamicFrame クラス

Apache Spark の主要な抽象化の 1 つは SparkSQL DataFrame で、これは R と Pandas にある DataFrame 構造に似ています。DataFrame はテーブルと似ており、機能スタイル (マップ/リデュース/フィルタ/その他) 操作と SQL 操作 (選択、プロジェクト、集計) をサポートしています。

DataFrames は、強力で広く使用されていますが、抽出、変換、およびロード (ETL) 操作に関しては制限があります。最も重要なのは、データをロードする前にスキーマを指定する必要があることです。SparkSQL は、データに対してパスを 2 つ作ることでこれを解決します。1 つ目はスキーマを推測し、2 つ目はデータをロードします。ただし、この推測は限定されており、実際の煩雑なデータには対応しません。たとえば、同じフィールドが異なるレコードの異なるタイプである可能性があります。Apache Spark は、多くの場合、作業を中断して、元のフィールドテキストを使用してタイプを string として報告します。これは正しくない可能性があり、スキーマの不一致を解決する方法を細かく制御する必要があります。また、大規模なデータセットの場合、ソースデータに対する追加パスが非常に高価になる可能性があります。

これらの制限に対応するために、AWS Glue により DynamicFrame が導入されました。DynamicFrame は、DataFrame と似ていますが、各レコードが自己記述できるため、最初はスキーマは必要ありません。代わりに、AWS Glue は必要に応じてオンザフライでスキーマを計算し、選択 (または共用) タイプを使用してスキーマの不一致を明示的にエンコードします。これらの不整合を解決して、固定スキーマを必要とするデータストアとデータセットを互換性のあるものにできます。

同様に、DynamicRecord は DynamicFrame 内の論理レコードを表します。これは、Spark DataFrame の行と似ていますが、自己記述型であり、固定スキーマに適合しないデータに使用できます。

スキーマの不一致を解決したら、DynamicFrames を DataFrames との間で変換することができます。

DynamicFrame クラス - AWS Glue
  • Scala の DynamicFrame の説明

DynamicFrame は、自己記述型の DynamicRecord オブジェクトの分散コレクションです。

DynamicFrame は、ETL (抽出、変換、ロード) オペレーションの柔軟なデータモデルを提供するように設計されています。これらのオブジェクトを作成するのにスキーマは必要なく、乱雑または不整合な値や型を持つデータの読み取りと変換に使用できます。スキーマは、スキーマを必要とするオペレーションでオンデマンドで計算できます。

DynamicFrame は、データクリーニングと ETL 用の広範な変換を提供します。また、既存のコードと統合するための SparkSQL DataFrames との相互変換や、DataFrames が提供する多くの分析オペレーションをサポートしています。

AWS Glue Scala DynamicFrame クラス - AWS Glue

GlueContext

The file context.py contains the GlueContext class. GlueContext extends PySpark's SQLContext class to provide Glue-specific operations. Most Glue programs will start by instantiating a GlueContext and using it to construct a DynamicFrame.

DynamicFrame

The DynamicFrame, defined in dynamicframe.py, is the core data structure used in Glue scripts. DynamicFrames are similar to Spark SQL's DataFrames in that they represent distributed collections of data records, but DynamicFrames provide more flexible handling of data sets with inconsistent schemas. By representing records in a self-describing way, they can be used without specifying a schema up front or requiring a costly schema inference step.

DynamicFrames support many operations, but it is also possible to convert them to DataFrames using the toDF method to make use of existing Spark SQL operations.

https://github.com/awslabs/aws-glue-libs/tree/master/awsglue
  • DynamicFrame で使えるメソッド

— Construction —

  • __init__
  • fromDF
  • toDF

(中略)

— Transforms —

  • apply_mapping
  • drop_fields
  • filter
  • join
  • map
  • relationalize
  • rename_field
  • resolveChoice
  • select_fields
  • spigot
  • split_fields
  • split_rows
  • unbox
  • unnest
  • write

(中略)

— Errors —

  • assertErrorThreshold
  • errorsAsDynamicFrame
  • errorsCount
  • stageErrorsCount
DynamicFrame Class - AWS Glue
# Copyright 2016-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
# Licensed under the Amazon Software License (the "License"). You may not use
# this file except in compliance with the License. A copy of the License is
# located at
#
#  http://aws.amazon.com/asl/
#
# or in the "license" file accompanying this file. This file is distributed
# on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, express
# or implied. See the License for the specific language governing
# permissions and limitations under the License.

import json
from awsglue.utils import makeOptions, callsite
from itertools import imap, ifilter
from awsglue.gluetypes import _deserialize_json_string, _create_dynamic_record, _revert_to_dict, _serialize_schema
from awsglue.utils import _call_site, _as_java_list, _as_scala_option, _as_resolve_choiceOption
from pyspark.rdd import RDD, PipelinedRDD
from pyspark.sql.dataframe import DataFrame
from pyspark.serializers import PickleSerializer, BatchedSerializer


class ResolveOption(object):
    """
    ResolveOption is used for resolve ChoiceType while converting DynamicRecord to DataFrame
    option.action includes "Project", "KeepAsStruct" and "Cast".
    """
    def __init__(self, path, action, target=None):
        """
        :param path: string, path name to ChoiceType
        :param action: string,
        :param target: spark sql Datatype
        """
        self.path = path
        self.action = action
        self.target = target

参考

*1:SparkSQLの


[AWS]AWS Glue で PySpark でCSVを加工してみる

$
0
0

準備

テストデータ作成
  • テストデータ(CSV)を作成する。
% perl -e 'printf(qq/%d,%d,%d,%d\n/,$_,2..4) for 1..100' > number.csv
% wc -l number.csv
     100 number.csv
% head -3 number.csv
1,2,3,4
2,2,3,4
3,2,3,4
% tail -3 number.csv
98,2,3,4
99,2,3,4
100,2,3,4
S3バケットにデータを置く
  • S3バケット 「az-handson」を作成する。
  • 「az-handson」バケットの下に 「input」、「output」 フォルダを作成する。
  • 「az-handson/input」に「number.csv」をアップロードする。
Glue で開発エンドポイントと Zeppelin ノートブックを作成
  • AWSマネジメントコンソールから AWS Glue を選択し、開発エンドポイントを作成する。
  • [ノートブックサーバー]の[HTTPS URL]にブラウザでアクセスしてログインする。
  • [Create new note]をクリックして、任意の名前でノートブックを作成する。
    • [Default Interpreter] は Spark を選択する

実行

  • Zeppelin ノートブックを開いて以下の PySpark のコードを実行する。
import sys
from awsglue.transforms import *
from awsglue.utils import getResolvedOptions
from pyspark.context import SparkContext
from awsglue.context import GlueContext
from awsglue.dynamicframe import DynamicFrame
from awsglue.job import Job
from pyspark.sql import SparkSession
from pyspark.sql.functions import udf
from pyspark.sql.types import StringType

glueContext = GlueContext(SparkContext.getOrCreate())

# S3 location for input
input_dir = "s3://az-handson/input"

# S3 location for output
output_dir = "s3://az-handson/output"

# Read CSV
dyf = glueContext.create_dynamic_frame.from_options(connection_type = "s3", 
    connection_options = {"paths": [ input_dir ]}, format="csv", format_options={ "withHeader": False})

# Convert to DataFrame
df = dyf.toDF()

# Filter
filtered_df = df.where(df['col0'] > 50)

# Turn it back to a dynamic frame
output_dyf = DynamicFrame.fromDF(filtered_df, glueContext, "nested")

# Write it out in CSV
glueContext.write_dynamic_frame.from_options(frame = output_dyf, connection_type = "s3", connection_options = {"path": output_dir}, format = "csv")

結果

  • S3 に加工結果が出力されている

f:id:yohei-a:20180917161311p:image:w640

  • ダウンロードして開くとフィルタされた結果になっている。

f:id:yohei-a:20180917161512p:image:w640

  • Zeppelin でフィルタ後の DataFrame を表示してみる。
filtered_df.show()

f:id:yohei-a:20180917161746p:image:w640


メモ

  • DynamicFrame の定義を確認する
dyf.printSchema()
  • dataframe の定義を確認する
df.describe()

参考

[DB]db tech showcase 2018 Day 1

$
0
0

年に一度のデータベース界の同窓会的なイベント db tech showcase 2018 Day 1 に参加してきた。写真は懇親会でのマグロ解体ショー。

f:id:yohei-a:20180920032213j:image:w640

小幡さん、おつかれさまでした!

f:id:yohei-a:20180920042610j:image:w640


以下は聴講したセッションのメモ。

顧客理解のためのDWHにおける、ビッグデータ品質マネジメント

概要
  • 講師: 木村 豊さん(楽天株式会社 - グローバルデータ統括部データサイエンス部)
  • 講師略歴: 大手電機メーカーにてソフトウェア開発者からデータサイエンティストに転身。データ関連ビジネスの立ち上げ等に関わった後楽天にてCustomerDNAの開発に従事。
  • 概要: 楽天で構築中のDWH、CustomerDNAの概要解説と、そこで実施しているデータ品質マネジメントの実例についてご紹介します。(資料非公開)
サマリ
  • DWHでどのようにデータ品質をチェックしているかというお話。
  • データ処理の部分だけでなく、データソースもきちんとテストする必要がある。
  • プロセス(データ処理部分)のテスト観点
    • 正確性: 仕様通りマッピング・変換されているか
    • 非重複性: ユニークになるべきデータの組み合わせがユニークになっているか
    • 完全性: 投入されるべきデーアが全て投入されているか
    • 一貫性: テーブル・パーティション同士の関連性が一貫しているか
  • 課題
    • 変更検知した場合のエスカレーション・コミュニケーションフローは別途必要。
    • 実データをテストに使っているため、ガバナンス・環境上の問題が起きやすい。
    • テスト実施コンピュートコストが高い(決して低くはない)。
質疑応答
  • ETLツールでも同じようなことができるのではないか?
    • データサイエンティストが使っていたチェック用のクエリをプロダクションに乗せている。
  • RDBの制約などの機能でチェックできるのではないか?
    • データサイズが大きいのでRDBではしんどい。
  • 何に時間が一番がかかるか?
    • データを知るのに時間がかかる。どこに何のデータがあるか。
  • データディクショナリを作っているか
    • 作っているが、変更が入るので最新には追いつかない。

Pgpool-IIではじめるPostgreSQLのクラスタ運用

f:id:yohei-a:20180920042400j:image:w640

概要
  • 講師: 石井 達夫さん(SRA OSS, Inc. 日本支社 - 取締役支社長 / PostgreSQLコミッター)
  • 講師略歴: 経営者でありながら現役のプログラマとして活動。日本人として始めて PostgreSQLコミッターになった。現在は、PostgreSQL専用ミドルウェアの Pgpool-II の開発に注力し、プロジェクトのオーガナイザーを努める。
  • 概要: PostgreSQLに組み込みのレプリケーション機能を使うと、データベースサーバを複数使ったクラスタが容易に構築できます。しかし、運用局面や、アプリケーションからの利用となると、単一のPostgreSQLサーバでは起こらないような事態や、一筋縄では行かない問題が発生しがちです。本講演では、PostgreSQLのクラスタ利用での注意点やはまりどころを解説し、次にPgpool-IIを使ってこうした問題をどのように解決できるかを、デモを交えて説明します。
スライド
  • To be uploaded
メモ
  • P.9 の絵は複数のサーバプロセスがあるが簡略化した絵になっている
  • P.11 一時テーブル、強いロックなどはスタンバイで使えない。
  • 2010年に PostgreSQL 9.0 でトランザクションログの非同期レプリケーションが実装され、その後同期レプリケーションが実装され、現在、マルチマスタレプリケーションやシャーディングが開発されている。
  • 参照だけスタンバイに接続する場合、アプリ側で振り分けを実装したり、参照でも一貫性を求めるものはマスターを見るなど考慮点が多いが、Pgpool-II はアプリに意識させなくてもよろしくやってくれる質実剛健な機能が豊富に揃っていると感じた。
  • 紹介されていた Pgpool-II とレプリケーションによる構成は「レプリケーション」というと Oracle では Data Guard と比較しそうになるが、災害対策ではなく同一サイトでの耐障害性対策としての機能が多く、Oracle でいうと RAC と比較するのが適切なケースもあると感じた*1。優劣の比較ではなく各機能がどんな課題を解決するためにあり、Oracle ではどの機能がソリューションになるかという意味での比較。

爆速データレイクがほしい人向けImpalaパフォーマンスチューニング

f:id:yohei-a:20180920042139j:image:w640

概要
  • 講師: 嶋内 翔さん(Cloudera 株式会社 - セールスエンジニア)
  • 講師略歴: 京都大学工学部卒業、NECでエンタープライズOSSのSI支援業務に従事。2011年にClouderaの最初の日本人社員として入社。サポートエンジニアとして3年勤めた後、セールスエンジニアとしてHadoopを中心としたビッグデータ基盤に関する豊富な経験を積む。監訳書に「Apache Sqoopクックブック」などがある。
  • 概要: Apache Hadoopのためのオープンソース分析データベース、Impalaのベストプラクティスをご紹介します。
スライド

Impala のパフォーマンス・チューニングはI/Oとノード間通信を減らすのが肝で、Hive や Spark でも通用する話。小手先のクエリチューニングではなくデータ構造が命。PROFILE で時間ベースで分析しよう。といった内容で本質的で非常に分かりやすかった。Parquet の説明は今まで見た中で一番分かりやすかった。Impala は統計情報をベースにコストベースオプティマイザで動作しているとのこと、統計情報は Hive カタログに保存されているのだろうと思う。


分散DB Apache Kuduのアーキテクチャ - DBの性能と一貫性を両立させる仕組み「HybridTime」とは

f:id:yohei-a:20180920042256j:image:w640

概要
  • 講師:佐藤 貴彦さん(Cloudera 株式会社 - セールスエンジニア)
  • 講師略歴: 奈良先端技術大学院大学でネットワークの研究をし、インフラなど低レイヤーの技術が好きになる。卒業後はOracleで、データベースを中心にインフラ全般のコンサルティングなどを行う。その後、Basho TechnologyでNoSQL及び分散システムに触れ、現在はClouderaでHadoop関連技術を中心に、幅広く手がける。趣味はクライミング。共著で「絵で見てわかるITインフラの仕組み」を執筆。
  • 概要: Apache Kudu は分析系クエリに強いカラムナー型の分散データベースです。KuduはOLTPとOLAPの両方のワークロードに耐えられる、HTAPと呼ばれる種類のDBで、昨年の #dbts2017では、Kuduの「速さ」について紹介しました。KuduはBI/DWHなど分析向けのDBといったイメージが強い一方で、 元々はGoogleのSpanner論文など触発されて開発されており、地理位置が離れたノード間でも一貫性を担保する仕組みを持っています。その仕組の元にあるのが、「HybridTime」と呼ばれるDBの内部時計です。今回はHybridTimeについて、その論文を紹介しながら仕組みに触れ、どのような特性を持っているのか、なぜこれがKuduの「速さ」にもつながるのかについてお話したいと思います。
スライド
  • To be uploaded
  • Kudu はC++で書かれたストレージエンジンで Impala や Spark などから使うことができる HTAP なDB。Exadata のストレージサーバのように push down 機能がある。MVCC だが単一行でしか対応していない。

P.S.

MySQL 界隈の方々と二次会に行って MySQL の Performance Schema について質問したり、各社の運用事情など聞けて楽しかった。

*1:Data Guard も同一サイトの耐障害性対策としても使える

[PostgreSQL]PostgreSQL のクエリーリライトがルールベースか確認する

$
0
0

リライタのエントリポイントは、pg_rewrite_queries() であり、クエリの木のリストをもらってクエリ木のリストを返す。pg_rewrite_queries() の中からリライトモジュールの QueryRewrite() を呼び出し、1つずつクエリ木を処理する。

f:id:yohei-a:20180920133847p:image:w640

PostgreSQL では、VIEW や RULE をクエリを書き換えることによって実装しています。 もし必要ならばこの段階でクエリを書き換えます。 ここでの処理はリライト処理と呼ばれ、リライト処理を行うモジュールをリライタ (rewriter) と呼びます。 リライト処理のエントリポイントは QueryRewrite (rewrite/rewriteHandler.c) です。

f:id:yohei-a:20180920133632p:image:w360

PostgreSQL の構造とソースツリー | Let's Postgres

ソースコードを確認する

$ tar xfvJ postgresql-10.4.tar.bz2
  • src/backend/rewrite/rewriteHandler.c
/*-------------------------------------------------------------------------
 *
 * rewriteHandler.c
 *Primary module of query rewriter.
 *
 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
 *  src/backend/rewrite/rewriteHandler.c
 *
 * NOTES
 *  Some of the terms used in this file are of historic nature: "retrieve"
 *  was the PostQUEL keyword for what today is SELECT. "RIR" stands for
 *  "Retrieve-Instead-Retrieve", that is an ON SELECT DO INSTEAD SELECT rule
 *  (which has to be unconditional and where only one rule can exist on each
 *  relation).
 *
 *-------------------------------------------------------------------------
 */
#include "postgres.h"

#include "access/sysattr.h"
#include "catalog/dependency.h"
#include "catalog/pg_type.h"
#include "commands/trigger.h"
#include "foreign/fdwapi.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "parser/analyze.h"
#include "parser/parse_coerce.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteHandler.h"
#include "rewrite/rewriteManip.h"
#include "rewrite/rowsecurity.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/rel.h"


/* We use a list of these to detect recursion in RewriteQuery */
typedef struct rewrite_event
{
Oidrelation;/* OID of relation having rules */
CmdTypeevent;/* type of rule being fired */
} rewrite_event;

typedef struct acquireLocksOnSubLinks_context
{
boolfor_execute;/* AcquireRewriteLocks' forExecute param */
} acquireLocksOnSubLinks_context;

static bool acquireLocksOnSubLinks(Node *node,
   acquireLocksOnSubLinks_context *context);
static Query *rewriteRuleAction(Query *parsetree,
  Query *rule_action,
  Node *rule_qual,
  int rt_index,
  CmdType event,
  bool *returning_flag);
static List *adjustJoinTreeList(Query *parsetree, bool removert, int rt_index);
static List *rewriteTargetListIU(List *targetList,
CmdType commandType,
OverridingKind override,
Relation target_relation,
int result_rti,
List **attrno_list);
static TargetEntry *process_matched_tle(TargetEntry *src_tle,
TargetEntry *prior_tle,
const char *attrName);
static Node *get_assignment_input(Node *node);
static void rewriteValuesRTE(RangeTblEntry *rte, Relation target_relation,
 List *attrnos);
static void markQueryForLocking(Query *qry, Node *jtnode,
LockClauseStrength strength, LockWaitPolicy waitPolicy,
bool pushedDown);
static List *matchLocks(CmdType event, RuleLock *rulelocks,
   int varno, Query *parsetree, bool *hasUpdate);
static Query *fireRIRrules(Query *parsetree, List *activeRIRs,
 bool forUpdatePushedDown);
static bool view_has_instead_trigger(Relation view, CmdType event);
static Bitmapset *adjust_view_column_set(Bitmapset *cols, List *targetlist);
(以下略)
  • src/include/rewrite/rewriteDefine.h
/*-------------------------------------------------------------------------
 *
 * rewriteHandler.h
 *External interface to query rewriter.
 *
 *
 * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * src/include/rewrite/rewriteHandler.h
 *
 *-------------------------------------------------------------------------
 */
#ifndef REWRITEHANDLER_H
#define REWRITEHANDLER_H

#include "utils/relcache.h"
#include "nodes/parsenodes.h"

extern List *QueryRewrite(Query *parsetree);
extern void AcquireRewriteLocks(Query *parsetree,
bool forExecute,
bool forUpdatePushedDown);

extern Node *build_column_default(Relation rel, int attrno);
extern void rewriteTargetListUD(Query *parsetree, RangeTblEntry *target_rte,
Relation target_relation);

extern Query *get_view_query(Relation view);
extern const char *view_query_is_auto_updatable(Query *viewquery,
 bool check_cols);
extern int relation_is_updatable(Oid reloid,
  bool include_triggers,
  Bitmapset *include_cols)

#endif/* REWRITEHANDLER_H */

検証

  • EC2 に psql と pgbench をインストールする。
$ sudo yum -y install postgresql
$ sudo yum -y install postgresql-contrib
  • データベースのセットアップ(テーブル作成、データ投入)
$ pgbench -i -s 100 -U awsuser -h ******.******.ap-northeast-1.rds.amazonaws.com -d mydb
  • 統計情報を確認する
$ psql "host=******.*******.ap-northeast-1.rds.amazonaws.com user=awsuser dbname=mydb port=5432"
select attname, n_distinct, most_common_vals from pg_stats where tablename = 'pgbench_accounts';
SQL> analyze table pgbench_accounts;
  • ビューを作成する
create view v_pgbench_accounts as select * from pgbench_accounts;

db tech showcase 2018 Day 3

$
0
0

Pythonから使える列指向ファイルフォーマット・Parquetを使おう

f:id:yohei-a:20180921093930j:image:w640

概要
  • 講師: 玉川 竜司さん(Sky株式会社)
  • 講師略歴: 本職はセキュリティソフトの開発。Pythonは2000年くらいから使用し始めている。db tech showcaseでは、MongoDBの人としてデビュー。本業の傍ら、オライリージャパンから「SRE サイトリライアビリティエンジニアリング」「初めてのSpark」「ヘルシープログラマ」「Google BigQuery」「Sparkによる実践データ解析」など技術翻訳書を多数発刊。
  • 内容: 大量のデータをCSVで保存するのは非効率です。そのデータを分析に利用するなら、列指向のフォーマットでデータを保存することで、保存に必要なストレージ容量や処理に必要なCPUパワーを大幅に削減できます。本セッションでは、Pythonから使える列指向のファイルフォーマットであるParquetについて、実例と共に説明します。
スライド
  • To be uploaded
メモ
  • 「指定したフィールドだけを読み取ることによるI/O削減」はファイルシステムからブロック単位で読むという意味だろうか?同じファイルに複数列の値が入っているが。
  • 主にfastparquetとPyArrowの2つのライブラリがある。Hadoop エコシステムの親和性では PyArrow のほうが優れているかも。

質疑応答
  • Parquet は Date 型が使えないが、それも考慮に入れた上で、ORC と Parquet でどちらが良いか。
  • メモリ空間を効率的に利用できてると思うが数値的に調べたことがありますか?
    • そこまでは調べてない

Deep Dive on the Amazon Aurora PostgreSQL-compatible Edition

f:id:yohei-a:20180921103132j:image:w640

概要
  • 講師: 江川 大地さん(アマゾン ウェブ サービス ジャパン 株式会社 - 技術統括本部 エンタープライズソリューション部 ソリューションアーキテクト)
  • 講師略歴: ソリューションアーキテクトとして、Amazon Web Services (AWS)を利用するお客様へ技術支援を行なっています。クラウドのメリットを活かしたシステムが増えるよう、日々活動しています。
  • 概要: Amazon Auroraは、クラウド時代にAmazonが再設計したRDBMSです。本セッションでは昨年リリースされたPostgreSQLと互換性を持つエンジンについて、そのアーキテクチャや特徴をご紹介します。
スライド
  • To be uploaded

MVCCにおけるw-w/w-r/r-wのあり方とcommit orderのあり方の再検討〜Sundial: Harmonizing Concurrency Control and Caching in a Distributed OLTP Database Management Systemを題材に

f:id:yohei-a:20180921133839j:image:w640

概要
  • 講師: 神林 飛志(株式会社ノーチラステクノロジーズ - 代表取締役会長)
  • 講師略歴: 2011年〜ノーチラステクノロジーズ代表取締役 Hadoopでの分散処理フレームワークAsakusaの開発・導入に従事 各社の原価計算システムの構築にも従事
  • 内容: サーバアーキテクチャの変更は、そのままデータベース・アーキテクチャへの否が応でもの変革を促します。特に、MVCCはP. Bernstein以降の理論的な枠組みのまま、現在のOCCの流れを無理矢理合流させたところもあり、その理論的な難易度と実装のリソース逼迫から一度見送られた風潮がありました。しかし、近年のサーバアーキテクチャの大幅な高進はMVCCに必要なリソースを提供できるだけの状態になり、MVCCは再検討/再実装の中で無視できないうねりになっています。他方、その理論的な難易度から「見てみないふりをした実装」も散見されるようになり、ユーザサイドではややもすれば「anomalyだだ漏れのバグというかこれは仕様ですDB」に直面することになります。今回はこのような状況をうまく捌くために、避けることのできないMVCCの理論的な枠組みについて、その内容を丁寧に後追いし、今後のあり方について模索を行う。
スライド
  • 非公開

Amazon Aurora - Latest innovations and updates behind Aurora’s torrid growth

f:id:yohei-a:20180921141628j:image:w640

概要
  • 講師: 星野 豊さん(アマゾン ウェブ サービス ジャパン 株式会社 - Aurora/RDS Specialist SA)
  • 講師略歴: Amazon AuroraやAmazon Relational Database Serviceのパフォーマンス・チューニングや新機能の活用など技術的な支援を行っています。新技術・ハイボリュームなトラフィックを扱うシステムが大好きです。
  • 内容: システムを構築する上で切り離すことはできないデータベース。 本セッションでは、Amazon Aurora がリリースされてから行ってきた機能追加や安定性向上に対する取り組みと、その内部アーキテクチャをご紹介し、実環境で運用する際に注意する点などの Tips もご紹介します。
スライド
  • to be uploaded
メモ
  • backtrack は最大72時間前まで戻せる。今どこにいるかの LSN を変えるだけなので戻しが速い。実データを書き換えているわけではない。Actual Backtrack Window で barck track できる実際の時間を確認できる。
  • Aurora Serverless は Ci/CD などテスト環境に適している。25〜30秒でスケールアウト/スケールダウンする。NLBの後ろにインスタンスがある。Warm Pool からインスタンスを取るのでスケールアウトが速い。
  • Performance insights はAPIでデータ取得することもできる。過去分のデータも参照できる。
  • 本日 Parallel Query が Aurora が利用できる全リージョンで GA した。EXPLAIN で実行計画が Parallel Query になっているかどうか確認できる。
  • Multi Master はWriter を複数立てておいて1つの Writer だけ更新用途で使うと F/O が速い。後は複数の Writer に別のページを更新する(conflictしない)処理を流してスループットを上げる。

[Hadoop]Cloudera Altus Director を使ってみる

$
0
0
  • Cloudera Director Server をインストールする
$ brew tap takabow/cloudera
$ brew install cloudera-director-server
  • Cloudera Director Server を起動する
$ cloudera-director-server-start
  • ブラウザで「http://localhost:7189」にアクセスし、チェックして[Continue]をクリックする。

f:id:yohei-a:20180921161254p:image:w640

  • ユーザー名とパスワードを入力してログインする。

f:id:yohei-a:20180921161449p:image:w640

  • git clone する。
$ git clone https://github.com/takabow/cloudera-demo-env.git

参考

Viewing all 1154 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>