ムラサメ研究ブログ

主にゲームやプログラミングのログ

AWS Dynamoのメモ

前提

Dynamo初めて触る人向けのDynamoのまとめ
多分これだけ知ってればDynamoチョトデキル

About

DynamoはNoSQLにジャンルされる KVSである。当然RDBより速い
機能的には、Redisより少し出来る事が多く、MongoDBより少ない
速度的には Redisに劣るので、必要に応じてAPI CacheでRedisを建てる
従量課金なので常時起動するコストがない

メリット

フルマネージドなので、設定もデプロイも不要でオートスケーリングする
死活監視も不要なので、夜もゆっくり寝ることができる

テーブル仕様

Indexが2個しか指定できない(後述GlobalSecondaryIndexで追加は可能だが制限がある)
Indexは PartitionKey(PK)のみか、PartititionKey+SortKey(SK) のどちらかを設定する必要がある
Index以外のフィールドは自由(レコード毎にフィールドが違っても問題ない)
PK(PK+SK)で一意性が保たれる必要がある(Indexが同じレコードはエラー)

フィールド(アトリビュート

基本的には数字か文字列
日付は文字列なりUNIX Timeにして・・
バイナリも入る(未使用)
それらの配列も入れることができる Booleanもある
Mal、List、Nullもあるが未使用

クエリー

PKは =判定しか出来ない(完全一致オンリー) Indexはテーブル作成時に設定し、以降変更することが出来ない
IndexにSKを含めて作成した場合でも PKのみのクエリが可能
SKでクエリーする場合はかならず PKと併用する必要がある(SK単体のクエリは不可能)
SKは =、<、<=、>、>=、Betweer、BeginWith(前方一致) が出来る SK指定時はソートすることが可能

スキャン

全件取ってくるので遅いのでなるべく使わない
Indexでクエリかけられない場合は後述のGSIも検討すべき

フィルタ

クエリやスキャンの後、条件でレコードを除外することが出来る
Indexに指定していないフィールドでも条件一致させられる
でもクエリ後なので、ヒット件数が多い場合は遅い

Update、Insert

Dynamoではアップサートである(同じIndexの項目があればUpdate、なければインサート) Update時はフィールドの即値指定以外に計算式が入るため f = f+5 のようなアトミック計算も可能
またUpdate時に update if f == 5 のような条件指定も可能
アトミックカウンタも存在するので、トランザクションが無くてもそれなりの事ができる

GlobalSecondaryIndex(GSI)

Indexとは別に 検索用のIndexを作成することが出来る
Indexと同じく PKあるいはPK+SK で作成することが出来る
クエリもIndexと同じ
内部実装は同じテーブルをレプリケーションしているため、GSIを増やすとデータ容量増えるので注意
投影フィールド(レプリケーションするフィールド)を指定できるので必要なものだけにすること
Indexと違い キーの一意性は必要ない(PK+SKが同じレコードも作成可能)

バッチオペレーション

ReadやInsert、Delete等をまとめることができる
Dynamoの料金体系は基本的に Read/Write単位で課金されるため(もちろんデータ量もあるが)バッチ処理出来る時はしたほうがお得
ただし Updateはバッチ処理できません!

トリガー

Dynamoでレコードの変更があったさい Lambda関数を呼ぶことが可能
ただし、1秒間に4回ポーリングして変更があったさい起動するようなので、重いかもしれない

トランザクション

ない。楽観的なトランザクション
が、Updateの条件式などを使えば ロックフリー的なことは可能 dynamodb-transactions というのが簡易トランザクション機能を提供する

バックアップ

通常S3等に退避させることが多いと思う
特定リージョンでは オンデマンドバックアップが可能
テーブルやレコードを削除しても、バックアップから復元することが可能(未使用のため詳細不明)

グローバルテーブル

他のリージョンとも自動的にレプリケーションされるテーブルを作成することが可能

DocumentClient(ライブラリ)

AWS.DynamoDB.DocumentClient を使うとほんの少し楽になる
具体的には、素でDynamoDBライブラリを使うと すべてのフィールドにたいして "N" や "S" といった型情報が必要だが、それを省略可能

"Key": {
  "PK": {"S":"pk"},
  "SK": {"N":1} 
},

"Key": {
  "PK":"pk",
  "SK": 1 
},

と出来る。地味にありがたい

TOEIC360点が1年で800点を目指す(ry

最近気になったQiitaです

qiita.com
qiita.com

来年の目標として英語学習したいな・・・

計画

ルール

2018年2月13日~2019年3月のTOEICまでにTOIECスコアを800点以上にする
TOEICは、WebでTOEIC模試もあるので、それとの併用も考え、結果をブログで報告する
上記のQiitaの人たちは月100時間。1日平均3時間と 結構勉強している・・
私はせいぜい月30時間しかさく気がないので大丈夫か?

モチベーション

洋書なにを読むか考えてないが、とりあえずAWSKindle本を何個か手に入れた
そしてネタとして ウラジーミル・ナボコフのLolitaを読んでみようと思う
一応 5000万冊売れたミリオン だからね!露リコンじゃないよ!

学習方法

素晴らしいことに、シェアハウスにオーストラリア人がいて疑問があれば聞ける
もちろんインターネットでも色々とサービスあるので便利
とりあえず発音を先にしろと言われているので、何も考えず発音勉強する
そして、私はボキャブラリをとにかく詰め込もうと思う
単語覚えるだけでは片手落ちなので短い文章も
あとはやりながら考える

予定教材等

おすすめされているものを順に試していこうと思う

発音

英語耳 https://www.amazon.co.jp/%E8%8B%B1%E8%AA%9E%E8%80%B3-%E6%94%B9%E8%A8%82%E3%83%BB%E6%96%B0CD%E7%89%88-%E7%99%BA%E9%9F%B3%E3%81%8C%E3%81%A7%E3%81%8D%E3%82%8B%E3%81%A8%E3%83%AA%E3%82%B9%E3%83%8B%E3%83%B3%E3%82%B0%E3%81%8C%E3%81%A7%E3%81%8D%E3%82%8B-%E6%9D%BE%E6%BE%A4%E5%96%9C%E5%A5%BD/dp/4048688634/ref=sr_1_1?ie=UTF8&qid=1518493303&sr=8-1&keywords=%E8%8B%B1%E8%AA%9E%E8%80%B3

ボキャビル

キクタン [All-in-One] TOEIC® Test Score 600+800+990合本版
play.google.com

瞬間英作文

どんどん話すための瞬間英作文トレーニング
Amazon CAPTCHA

まずはこの3つを読みつつ、英語のドキュメントを仕事で読みつつ・・
先は厳しいけど頑張る

AWS Lambdaでトリガーが削除できなくなった時

例えば API GatewayからLambdaを連携させた後、連携を削除したい場合は
Lambdaのトリガーを削除したあとに API Gatewayから連携を削除すればよいのですが
逆をやってしまうと。 先に API Gatewayから削除した場合は Lambdaにトリガーが残ったまま削除できないという不具合がおこります

どう見ても AWS管理画面の不具合ですが、システム的には消せるので

AWS Clientでコマンドをうてば消せます

aws lambda remove-permission を使えば消せるのですが、sidを手に入れるため aws lambda get-policyを使います

$ aws lambda get-policy --function-name LambdaのARN

ARNはLambda管理画面の右上に arn:aws:lambda:ap-northeast-1:ほげほげ・・ の形で表示されています
このコマンドを実行すると Jsonが返ってきます
そこで消したいものの sidを探し

$ aws lambda remove-permission --function-name LambdaのARN --statement-id 取得したsid

これで消える

近況

最近は縁あって、大型案件のサーバインフラ開発しています
みんな技術力が高い人たちなので安心です
ただ、私の事をすごい期待しているようで、基本的な役回りとしては
スケジュール的に厳しいため
私以外のメンバーは、モノリシックな LAMP環境での枯れたシステムを作り
私は マイクロサービス、サーバーレス、NoSQL・・・ 等の 新しい設計でサブシステムを作る
そんな感じです

まずは現行システムを理解するために PHPでのモノリシックなAPPサーバのチケットをこなし
ChatOps、DevOpsを PythonGolangを使って書き
Docker関連を修正したり 色々とこなし
現在は マイクロサービス化をすすめている

API Gatewayに関しては AWSAPI Gatewayが基本だと思うけど、APIIのMegre等がなさそう
その他 基本的にURLを転送する事とLambdaを起動する事ぐらいしかできない
機能がすくない・・

Kong。最も人気っぽい。当然 ResponseのMegreが出来る
Lambdaを起動するプラグインあるぽい

KrakenD。速い。Lambda起動プラグインみつからない

つまり メリット、デメリット多い。

また、重要になるNoSQLはどれにするか決まってない

そんなかんじで、サーバレス、マイクロサービス化してます

Golang 試食 Part2

Class

そんなものはない
が、C言語で使うような構造体ポインタを明示的に渡す事で、ステートを持たせ同じことが出来る

// 構造体の作成。C言語と違い関数の定義は必要ない
hoge:= &Hoge{
    name: "Name",
}

// メソッドを呼ぶ
hoge.Print()
// Print関数の定義。 h *Hogeで Thisポインタ的なものを定義
func (h *Hoge) Print() {
    // h.name と、明示的にインスタンスを指定する必要がある
    log.Printf("name= [%s]", h.name)
}

その他、インタフェース的なものや、派生的なものもあり、ダックタイピングではあるがオブジェクト指向のようなことができる
Goのオブジェクト指向に関しては、一度まとめて整理したいところ

Goルーチン

Go言語の特徴であるGoルーチン
目的は 並列処理である
ライトウエイトプロセスを使い、シングルスレッドで非同期に処理を行う
go ほげほげ でライトウエイトプロセスを作成する
非同期なのでこの命令を読んだあと即座に処理が戻ってくるので、チャンネルを使い GoルーチンをWaitする
大雑把に Goルーチンが処理を終えシグナルを出すまでWaitすると思っていいだろう
例題だしたいが、後ほどちゃんと調査したい

WaitGrout

    wait := sync.WaitGroup{}
    wait.Add(1)

    go func() {
        defer wait.Done()
       ほげほげ
    }()

    wait.Wait()

Channel

    ch := make(chan struct{})
  
    go func(){
        ほげほげ
        ch <- struct{}{}
    }

プラグイン

Golangプラグイン(共有ライブラリ)機能がある
動的に共有ライブラリ(.so .dll的な)を読み込むことが出来るので
本体をビルドしなおさずに機能の追加、修正が出来る
ただし、現在は64Bit Linuxでしか対応していないため、Windowsネイティブではプラグインを作れない

// pluginライブラリを使い 読み込む
p, err := plugin.Open("path to .so")
if err != nil {
    log.Printf("fail to load plugin")
    return
}

// hoge関数を探す。もちろん メンバ変数も取得可能
hoge, e := p.Lookup("hoge")
if e != nil {
    log.Printf("fail to Lookup 'hoge'")
    return
}

// hoge関数を呼ぶが、interface型なので Castして使う必要がある。今回は func(string) string 型の関数を呼び出す
hoge.(func([]string) string)("var")

interface型、関数ポインタの型キャスト、その他色々と面倒ではあるが便利

ビルド方法は
go build --buildmode=plugin
と、 buildmodeを指定すれば良い

最近はインフラ&技術顧問

とりあえず最近のお仕事内容

インフラをやっております。AmazonAWSは便利だけど業務知識が必要ですね
AWSの何がすごいって、やはり自動スケーリング等の メンテフリーでしょう
そんなかんじで
EC2、S3、Lambda、Aurora、Dynamo、ECR、ECS、SQS、Kinesis・・・
いろんなサービスを使ってます

プログラムとはまた違った難しさ、知識が必要となるけど、重要な仕事です

Golang 試食 Part1

仕事で1か月間に新しく6言語を使ったのだが、その中で最も触ったのがGo
色々と想像と違ってたので、Goを勉強始めるあたりから書いていく

使う前の印象(全然間違えてた)

天才技術者エリート集団 Googleの作った最高の言語
コンパイル言語で、C言語並みの実行速度と スクリプト言語並みの作業効率
ゴルーチン等の、高速な非同期をつかった次世代Web言語
ひゃっほ~~

目的

DevOps目的で、チャットBOTを作る
プロジェクトに使う各種ツールのURLやディレクトリを教えたり
新人が入った際のアカウント追加をサポートしたり
ソースコードのCIや ビルドを行ったり
Deployを行ったり
メトリクスのアラート出したり
・・・
色々なオペレーションをするためのサンプル

ファーストターゲット

Slackで動くBOT
AWSのECR上にUpされたコンテナのリスト表示、Tag指定でDeployする

SlackBot

Slack側の設定

Slack側の設定はほかの人のブログみてもらおう

全容

今回は github.com/nlopes/slack を利用する
ので パッケージで上記を指定する
Golangコンパイルエラーが厳しく、使ってないものをimportするとコンパイルしてくれない

main.go

package main

import (
    "log"
    "net/http"
    "os"
    "github.com/kelseyhightower/envconfig"
    "github.com/nlopes/slack"
)

type envConfig struct {
    Port              string `envconfig:"PORT" default: "3000"`
    BotToken          string `envconfig:"BOT_TOKEN" required: "true"`
    BotID             string `envconfig:"BOT_ID" require: "true"`
    ChannelID         string `envconfig:"CHANNEL_ID" require: "true"`
}

func main() {
    os.Exit(_main(os.Args[1:]))
}

func _main(args []string) int {
    var env envConfig
    if err := envconfig.Process("", &env); err != nil {
        return 1
    }
    client := slack.New(env.BotToken)
 
    slackListener := &SlackListener{
        client:    client,
        botID:     env.BotID,
        channelID: env.ChannelID,
    }

    go slackListener.ListenAndResponse()

    if err := http.ListenAndServe(":"+env.Port, nil); err != nil {
        log.Printf("[Error] %s", err)
        return 1
    }
    return 0
}

slackListenerは後で

package

package名mainは特殊である。
このパッケージのみ エントリーポイントとしてmain関数が機能する

import

importはとても便利。今までGoを使ってパッケージの依存関係なので悩んだことはなかった
(ただし duplicate importは 非常にダメだ・・・ ) Githubリポジトリから直接持ってこれるのも素晴らしい
さすがGoogle

コード所感

文法は慣れるしかないが、C言語Java等のメジャーな文法とは大きく変えてきている
全体的にGoはダックタイピングだ 変数や関数名の頭を小文字にすると外部パッケージからアクセスできないので、Publicな関数や変数は大文字スタートにする
また、C言語では暗黙的型変換されるもの(int32, int64 なども)も明示的にキャストしなければエラーである

エントリポイント

mainのところはおまじないとして なんとなく意味わかるでスルーしよう

envconfig

main_ 実質のメイン
envconfigは上記Githubからのパッケージで、環境変数を構造体にマッピングしてくれる

err := envconfig.Process("", &env);

envconfig.Process にて環境変数が設定されていれば構造体に入る
:= は、変数の宣言、定義、代入である(関数内でのみ使用できる) 例えば
hoge := func() は
var hoge = func()
とだいたい同等である
ただ、使った感じ微妙にスコープが違う

nlopes/slack

client := slack.New(env.BotToken) にて、nlopes/slackのインスタンスを作成する
もちろん env.BotTokenは、環境変数 BOT_TOKENに入っているトークンだ

構造体作成

   slackListener := &SlackListener{
        client:    client,
        botID:     env.BotID,
        channelID: env.ChannelID,
    }

来た。。これは構造体の作成(new)を行っている
GoではClassは無く C言語のように 構造体を作成しそこにデータを保存し、関数に構造体を渡す
つまり 全くオブジェクト指向じゃない!
そして 構造体の作成方法が何種類もある

type Hoge struct{
  Name string
  Age int64
}

// newの場合は 宣言と同時に初期化できない
hoge1 := new(Hoge)
hoge1.Name = "HOGE"
hoge1.Age = 10

// &でも構造体を作成できる
hoge2 := &Hoge
hoge2.Name = "HOGE"
hoge2.Age = 10

// &は定義時に初期化可能
hoge2 := &Hoge{ Name: "HOGE", Age: 10 }

// 構造体のフィールド名省略可能
hoge2 := &Hoge{ "HOGE", 10 }

つまり &を使ったものだけ覚えておけば良いと今の時点では思っている

Listen

   go slackListener.ListenAndResponse()
        err := http.ListenAndServe(":"+env.Port, nil)

go の部分が Golangの特徴である ゴルーチン
ゴルーチンは非同期で実行されるため、 slackListener.ListenAndResponse() が終了しなくても
即座に次の行へ制御がいき http.ListenAndServeが実行される

slackListenerの中身は後で勉強するとして、大雑把にいうと WebSocketを待機していて、Slcakとアクセスをする
http.ListenAndServeにて Listenを行う

この時点の感覚

Goのコードはオブジェクト指向ではなく、予想以上に低レイヤーであった
C言語を書きやすくした Better C言語である
ゴルーチンは非同期をわかりやすく解決していて使いやすそう
ただ 予想より難しい言語で、PHPerが移住する場所としては不適切ではないか?
Web言語として優れているとは現時点ではいいにくい(あくまで Better C)