react-virtualizedで膨大なリストの表示と状態復元

React(web)で膨大な数が見込まれるリスト表示にはreact-virtualized使っていくのがベターっぽいのでメモ。
virtualScroll実装は普通にjQueryやスタンドアローンのライブラリでもありそうなので、DOMをめっちゃappendしていくような処理があれば導入を検討してもいいかも。

用途

  • 無限スクロール実装等の初期レンダリング負荷削減
  • SPA時のリストDOM復元/スクロール位置復元の処理高速化
  • virtualDOMの差分計算の簡略化

要するにブラウザに優しい。

コンテナとなる親divの高さを動的に拡張していく実装の備忘録。

import { List  , AutoSizer , WindowScroller} from 'react-virtualized';
class HugeList extends React.Component<{dataList : Array<{}>} , {}>{
    constructor(props) {
        super(props);
    }

    noRowsRenderer(){
        return <div>noRow</div>
    }

    renderRow({style , index}) {
        return (
            <div style={style} key={index}>
                リストの一行
            </div>
        );
    }

    render() {

        return (
            <div >
                <WindowScroller
                    scrollElement={null}
                >
                    {({ height, isScrolling, onChildScroll, scrollTop }) => {
                        return (
                            <AutoSizer disableHeight>
                                {({ _height, width }) => (
                                    <List
                                        autoHeight
                                        width={width}
                                        height={height}
                                        rowCount={this.props.dataList.length}
                                        rowHeight={160}
                                        isScrolling={isScrolling}
                                        onScroll={onChildScroll}
                                        scrollTop={scrollTop}
                                        noRowsRenderer={this.noRowsRenderer.bind(this)}
                                        overscanRowCount={2}
                                        rowRenderer={this.renderRow.bind(this)}
                                    />
                                )}
                            </AutoSizer>
                        );
                    }}
                </WindowScroller>
            </div>
        );
    }
}

rowHeightに固定のサイズを与えているが、行ごとに動的に当ててもイケる。

rowHeight={(item , index)=> /* itemに応じたheight設定をreturn */ }

リストだけでなく、Masonryレイアウトも対応しているっぽい。

SPA時の位置復元例(高階関数で)

各URLのエンドポイントとなるコンテナに刺すHoC。
EndpointHoc.tsx


const instanceHistory : Array<string>= []; const savedInstanceMemory : {[key:string] : InstanceState<any>} = {} const EndpointHoc : any = (WrappedComponent : any )=> { return class extends React.PureComponent<RouteComponentProps<{}> , any >{ childRef; action : string; savedInstanceState : InstanceState<any> = { instanceID : "VIEW_HISTORY_INSTANCE_" + Math.random(), pathname : this.props.location.pathname, documentHeight : 0, scrollY : 0, extra : {}, action : "REPLACE" } pathname : string; isPOP(){ if (this.props.history.action != "POP" ){ return false; } if (instanceHistory.length < 2){ return false; } if (savedInstanceMemory[instanceHistory[1]] == null){ return false; } if (savedInstanceMemory[instanceHistory[1]].pathname != this.props.location.pathname){ return false; } return true; } constructor(props) { super(props); this.action = this.props.history.action; this.pathname = this.props.location.pathname; if (lastpath != this.props.location.pathname){ if (this.isPOP()){ console.log("@POP!!!!!") const prevInstanceID = instanceHistory.shift(); delete savedInstanceMemory[prevInstanceID]; const instanceID = instanceHistory[0]; this.savedInstanceState = savedInstanceMemory[instanceID]; this.savedInstanceState.action = "POP"; setTimeout(()=>{ window.scrollTo(0,this.savedInstanceState.scrollY ); } , 16) } else { console.log("@PUSH!") window.scrollTo(0,0); this.savedInstanceState.action = "PUSH"; instanceHistory.unshift(this.savedInstanceState.instanceID); savedInstanceMemory[this.savedInstanceState.instanceID] = this.savedInstanceState; } } lastpath = this.props.location.pathname; } documentHeight() { return Math.max( document.documentElement.clientHeight, document.body.scrollHeight, document.documentElement.scrollHeight, document.body.offsetHeight, document.documentElement.offsetHeight ); } componentWillUnmount(){ this.savedInstanceState = {...this.savedInstanceState , scrollY : window.scrollY , documentHeight : this.documentHeight(), pathname : this.props.location.pathname, extra : {} }; savedInstanceMemory[this.savedInstanceState.instanceID] = this.savedInstanceState; } onSaveExtra(lastState : object){ this.savedInstanceState = {...this.savedInstanceState, extra : lastState} savedInstanceMemory[this.savedInstanceState.instanceID] = this.savedInstanceState; } render() { const addProp = { style : { minHeight : this.savedInstanceState.documentHeight } } return ( <div {...addProp} > <WrappedComponent {...this.props} ref={ref => this.childRef = ref} savedInstanceState={this.savedInstanceState} onSaveExtra={this.onSaveExtra.bind(this)} /> </div> ); } } } export interface EndpointHocProps <T> extends RouteComponentProps<{}> { savedInstanceState : InstanceState<T> onSaveExtra : (savedState : T)=>void } export default EndpointHoc;

ついでにwindow.historyのPUSH/POP時にインスタンスのEndpointにスクロール位置復元や任意のstateの保存をし、復元時にpropsとして渡す例。(react-router-v4の場合)
URLのback時にbodyの高さと位置とを復元する。
この辺はブラウザの機能の車輪再発明感がパないので何かいい実装ないかな。。。

Read More

複数のRecyclerViewで巨大なリスト扱ってめちゃくちゃ死にまくったまとめ

前提 : RecyclerView

いわゆるVirtualScroll実装。
Viewの初期化時の計算や転送コストを下げつつ、画面に表示されるリストを「見えてる分だけ」に制限してリストのガワを最大限再利用することで、レイアウトのレンダリングコストを下げる実装。
似たような機構はiOSやwebでの無限スクロール系ライブラリにもある。
VirtualDOM的なアレとは非なる。

アンチパターンと解決

画像の再利用をしない

  • 問題
    リストの行を表現するxml上で直接drawableフォルダ内のimageリソースを指定したりすると、レイアウトの初期化時にどんどんメモリが確保されていってやがてOOMを迎える。
    また、新しいリストの生成時にも画像の確保コストでUIスレッドがブロックし、なんかカクカクするようになる。

  • 解決
    面倒でもPicassoやGlideなどのライブラリを使いながら、コード側で随時画像キャッシュを使ってリスト内の該当箇所にimageを当てていく。
    と言うかAndroidにおいて直接imageviewにbitmapをアタッチすることは根本的にアンチパターンだと思っておく。確保時にOOMで死ぬ。

Picassoなどは内部にWeakMap?的な実装を持てるため、割り当てたメモリ上限を超えると勝手にアクセス頻度の少ないものは捨ててくれる。

// インスタンス実装
ActivityManager am = (ActivityManager) MainApplication.getApplication().getSystemService(Context.ACTIVITY_SERVICE);
boolean largeHeap = (MainApplication.getApplication().getApplicationInfo().flags & ApplicationInfo.FLAG_LARGE_HEAP) != 0;
int memoryClass = am.getMemoryClass();
if (largeHeap && Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
    memoryClass = am.getLargeMemoryClass();
}
int cacheSize = 1024 * 1024 * memoryClass / 8;
Picasso picasso = new Picasso.Builder(MainApplication.getApplication()).memoryCache(new LruCache(cacheSize)).build();
Picasso.setSingletonInstance(picasso);

// 画像当てこみ

Picasso.with(view.getContext())
    .load(hashMap.get("url"))
    .resize(size ,size)
    .into((ImageView) imageView);

リストの追加通知にとりあえずnotifyDataSetChanged()を叩く

  • 問題
    VirtualScrollとVirtualDOM的なアレと同じような感じでとりあえず adapter:::notifyDataSetChanged()を雑に叩くと計算コストが半端ない。
    予期せぬリストまでviewが再生成されたりする。
    今までのアプリでは実は表示するものの数が大したことないので割と問題なかったが、複数タブにそれぞれ複数のrecyclerView実装を抱えて、なおかつ巨大なリスト群を扱うとスレッドがブロックする。

  • 解決
    多少実装が複雑になっても myAdapter.notifyItemRangeInserted(lastCount , newCount); など適切に追加/変更を伝える必要がある。
    ただし最近はAdapterに食わせるviewModelにidを与えておくことで、雑に notifyDataSetChanged() を呼んでも問題ないような作りになってきているらしい(試してない)

スクロールリスナー動きすぎ問題

  • 問題
    無限スクロール実装のために、スクロール時に全体のリスト数と表示されているアイテムのindexを監視している。
    数十ms間隔でイベントが来る時とかもあって、そんなに毎回計算が要らない。

  • 解決
    現在時間を使う。 new Date().getTime() あたりを使って、適当に前の時間との差分を取りながらスロットルする。
    リスナー内であまり複雑なことをしないなら必要ないかも。

setHasFixedSize(true)を設定しない

  • 解決
    特に必要がなければデフォルトで設定しておく。

行内のインタラクションのためにnotify~系を叩く

  • 問題
    別の場所で起こったインタラクションなどをリスト内の行viewに反映させる時、前述の notifyDataSetChanged()だともちろん重い。
    アダプターの機構でrangeをとって更新でもいいけど正直管理が複雑なのと融通が利かないのがある。

  • 解決
    リストで表示された各行Viewの onAttachedToWindow() , onDetachedToWindow() ライフサイクルイベントで、適当なObserverパターン実装を購読し、各行viewが自分で差分を計算したほうが個人的には融通がきくと思われる。
    なんか負けた気がするけど。
    画面上に表示されているものだけになるので、observer側でたくさんイベントが走ろうが走査数は実は大したことないはず。

VideoView , 横スクロールページャーなどをリストの一部に実装する

  • 問題
    スライダーやVideoViewがリストの一部になると、画面から出た際に随時detacheされ、状態が初期化してしまう時。

  • 解決

 RecyclerView:::setItemViewCacheSize(i : int);

のサイズを必要な分大きくしておくか、リスト再生成時に、適切に状態を復元する機構を用意しないといけない。
特にVideoViewはPlayer部分とレンダリングされるViewを分離しなくてはいけないので、ちゃちゃっとビデオ表示したい用途だとだいぶ面倒くさそうだけど。
多分にステートフルなコンポーネントだとまあしょうがないという気はする。

無限スクロールでどんどんメモリに行情報溜まっていくよ問題

  • 問題
    別にAndroidに限ったことではないが、無限スクロール実装でだんだん表示すべきdataのリストが貯まっていく。

  • 解決
    リスト内で表示しないものは、行情報の取得時に別スレッド側であらかじめプロパティをどんどん捨てておく。サーバー側で抜けるならサーバー側で。
    description , リリースノートなど巨大な文字列を有するものには割と効く。
    あとは保持しているリストの上の方の過去のデータを適切に消したり、SharedPreference的なところに一時的に書き出しておく、などの実装が考えられる。結構複雑になりそうのでやってないけど。

Read More

[AWS Summit Tokyo 2017 Day3] AWSが支えるEightのリコメンデーションエンジンの裏側

名刺管理で有名な株式会社SanSanさんのアプリ、「Eight」での事例です。
とても濃い内容で、StepFunctionsの待ち受け運用とか非常に参考になりました。

ビジネス

  • 個人向け名刺管理アプリ、Eight
  • 名刺の唾がりをビジネスに変える/つながった相手とコミュニケーション
  • 日本の名刺交換の10%をさばいている!(!)
  • 名刺交換のUpdate.相手が転職しても繋がりを維持する
  • 「つながり」をリコメンデーションエンジンで

問題/旧リコメンデーション

  • RedshiftとEC2上のリコメンド計算エンジンで計算、CloudSearchでリコメンド
  • Redshift、複雑怪奇なクエリ、集計性能に依存
  • CloudSearch,全文検索エンジンとしてではなく関係性スコアのソートのみに使っていた
  • パフォーマンスダウン!
  • オペレーションコスト!

リコメンドアーキテクチャ刷新。

  • データ分析
  • アルゴリズム
  • リアルタイム性 <= もっともここを大事に

リアルタイムリコメンデーションエンジンを作り直そう

  • ログデータは今まで通りRedShift
  • 中間データ更新にKinesis + Lambda
  • 中間データはDynamoDBをストレージに

  • => 2ヶ月でできた!

構成

ストリーム
* Kinesis,DynamoDB Stream
コンシューマ
* Lambda
ストレージ
* RedShift,DynamoDB,ElastuCache

  • 名刺間のレーテイングデータをひたすらDynamoとLambdaで生成する。
  • データが更新されたらSQS発火、EC2上のワーカーが中間データから実際のリコメンドデータを生成

コツ

  • KinesisはPut Recordsでリクエストをまとめる
  • メモリ設定でリソースを増やす
  • DynamoDBはなるべくBatchWriteを使う
  • パフォーマンスが大幅に改善された

  • Function数の増加問題

    • Functionをシンプルにしすぎると数が増えすぎて管理できない問題
    • ある意味Function内でルーティングすることでストリームの種類によって処理を分岐する
  • ストリーム – コンシューマ問題
    • StreamとLambdaがお互いを維持できるバランスにならない
    • ストリームをLambdaが書き直して差戻すFunctionを作る(分身の術)

残った問題と解決

  • レーティングデータの陳腐化
  • アルゴリズムが変わり中間データの価値がなくなる
  • RedShiftにある過去ログから全て中間データを作り直した! => Data Pipelineを利用して数時間で再生成!
  • リコメンドのマイグレーション

    • まずLambdaを停止
    • 再生成してから再起動
    • まるで心臓バイパス手術
    • ダウンタイムなしでやるにはワークフロー大事
  • そこでちょうどリリースされたAWS Step Function

    • Lambdaの処理完了
    • DataPipilineの処理まち
    • タイムアウトはStepFunctionの定間隔リトライが使える!!!!!!!!

サーバーレスの利点

* スケーラブル
* 柔軟性
* 気軽さ

Read More

[AWS Summit Tokyo 2017 Day3] AWS Lambdaで変わるバッチの世界 – CPUトータル100時間を10分で終わらせるには –

ERPの開発をしている 株式会社ワークスアプリケーションさんでの事例です。
どちらかというとエンタープライズ向けっぽい会社さんですね。
ClosureコンパイラをLambda上に載せる、VPC多用の必要がどうしてもある、あたりがならではという感じで面白かったです。

事例

  • 画面の高速描画のための前処理

問題

  • HTML,JS,CSSの最適化
  • HTMLテンプレートの事前コンパイル
  • よくある構成
    • Hadoop,Spark,インスタンス並列化
    • ガチでやると100時間
    • 長い!コスト高い!
    • 終わらないインスタンス最適化作業
    • 10分で支度しな(意訳)

そこでLambda

Lambdaの特徴

  • スケーリング管理コスト0
  • インスタンス管理コスト0
  • 100ms単位の課金
  • 選べるランタイム / 箇所ごとに柔軟に言語を選ぼう
  • 流動的な分散数と処理時間にマッチ
    => やってみようと思った

Lambda

  • Before: 以前の処理
    • javaのwebフレームワークが画面のリストを作成/HTMLを最適化/jsのコンパイル/cddのコンパイル
    • この辺のフローが同期的
    • 画面が大きくなるとスケールしない
    • Closure CompilerをSpringFWで動かしていた
    • Less(CSS)コンパイル => SpringFW上で動作
  • After: 最適化
    • jar作成時にコードにキャッシュしとける情報はする
    • HTMLを最適化するだけのfunctionとして整理
    • GoogleClojureコンパイラ単体で動作するFunctionに
    • LessのコンパイルのFunctionはnodejsとして分離

SpringFrameworkをLambdaで動かすか否か

  • ガチで動かすと占有時間が長い
    • => そこでコンストラクタだけを使う
  • コンテナのコールドスタートも適切に利用
    • => 初期化処理にシングルトンを利用して余計な処理を省く

起動とプロセス管理

  • S3にファイルをputすることで処理を与える。
  • 実行ファイル名のサフィックスで処理の分岐を行う
  • ピタゴラ処理のエビデンスにPending,RunnningなどステータスをS3に随時吐く(!)
  • 進捗はs3上に置いたプロセス進捗ファイルだけをlistすることで確認する

Trouble Shooting

  • 速度は思ったより早くない

    • 128MB => 1546MB
    • CPUパワーはメモリ容量に比例 1.5GBだと2コア/3コア利用可能
  • 同時実行数上限3000で運用
    だが、実行数が上がらない,なぜ。。。 => VPCのせい

  • Lessのコンパイルがエラー

    • Lambdaの起動よりS3のPut時間が後の場合があった <= !?
    • s3のイベントを使う場合は結果整合性であることを忘れないように
  • s3のイベントが登録されていない

    • Ansibleで1つのbucketに100Function設定しているはず
    • 1この登録を1回回すんじゃなく1度で100イベント登録したらうまくいった
  • 想定金額より多い

    • Cloudwatch Logsのログのせい

デプロイ

  • nodeはzip,javaはjar
  • お客さんごとに別VPC/1bucket。イベント当てるのはAnsibleでやる

まとめ

  • 10分半になった!

課題

  • 今度はDBがスケールしなくて高負荷に耐えられない問題

Read More

[AWS Summit Tokyo Day3] AWS Lambdaを使ったモバイルバックエンドのサーバーレス開発事例

「株式会社ワイヤアンドワイヤレス」さんでのモバイルアプリのバックエンドのサーバーレス化の事例をお聞きしてきました。
ロギングやデプロイフローなど、みんなどうしてるんだろー?って思ってところが概観できたと思います。

ビジネス

  • 公衆WIFI事業者
  • TRABEL_JAPAN WIFI
  • 外国人旅行者向け。国内にはユーザー動向や広告配信を提供

システム構成

  • v1
    • ELB,EC2等を利用した一般的な構成
    • ロジックがクライアントに集中してしまっていいた
  • v2
    • ELBをもうひとつ前に
  • v3
    • API GatewayとLambdaを全面に出した

サーバーレス?

  • 用意するものはコードと構成パラメータ
  • API Gateway通った上でEC2で
  • 基本はAPI Gatewayを前に置くベース
  • Dynamo,S3への書き込み

API Gareway / Lambdaの実装方針

  • Lambdaファンクション自体は同じものを使って、ビルドスクリプト側で環境を分ける

苦労した点

  • Lambdaの起動時間 (Java)
    • VPC内の運用、ENIをアタッチする時間が膨大
    • CloudwatchのイベントでVPCないのLambdaを定期的に起動してあっためる
    • 起動時間が短縮される
  • Gatewayのレイテンシ
    • 常に同期処理になるのでAPI Gatewayとの相性は良い
    • なのでLambdaを非同期でつなぐことで処理が一定になる
  • E2Eテスト問題
  • ログ/エラー箇所の問題

APIのリソースとLambdaのデプロイ

  • API GatewayはSwaggerで管理できる
  • APIリソースとlambdaを1対1にした
  • 負荷が高い時は例外的に別の関数
  • SAMを使っている

Lambda関数の言語間検証

  • JVM系はまあ遅い
  • CPUがっつり使う処理があればJavaとかのが早いかも

Lambdaのテスト

  • ユニットテスト
    • AWSサービスのモックを内製
    • pythonのMagic Mock
    • あるいはAWS上に環境を準備
  • クラウド使ってるんだから
    • モック使わずに
    • SAMでサービスをデプロイ
    • テスト終わってから殺す

パッケージング/デプロイ

  • プレフィックスをつけて試験/本番をデプロイ
  • SAM => GitLab => Jenkins

ロギング

  • aws-cli/jqでパースする
  • アプリケーションログにはrequestIdを出力
  • X-Rayでトランザクション数/Durationが確認可能
  • agentが入れられない代わりにx-rayがある

まとめ

  • 導入に関しては開発のシステム構成の概念が違うためそれなりの学習は必要になる

Read More

[AWS Summit Tokyo 2017 Day3]バイタルデータの意味付けと言う荒波を乗り終える!適切な処理分担のためのサーバレスアーキテクチャ

最終日です。暑すぎじゃないですか。本日はサーバーレスに特化したセッションを中心に回っていく予定です。

本稿では、株式会社JINSさんのウェアラブルデバイスと、そのデータ処理におけるサーバレス環境の利用についてのセッションをレポートします。

商品「JINS MEME」

  • JINSのウェアラブルメガネデバイス
  • 集中/瞑想/覚醒などの情報を読み取る(!)
  • それを客観的に見ることで自分のバイタルを管理していこうぜ、というプロジェクト。
  • 頭部加速度/回転角/瞬き/視線移動/周波数 などの情報をSDKで得られる。
  • メガネ => スマホ => クラウドに送信

バイタル(生体データ)

  • バイタルデータの中で心拍センサーは枯れているのでよく使われている
  • バイタルデータは本来めんどくさい。
    • 心拍/脈拍 => 枯れている/周期性がある。ノイズデータが消せる
    • モーション => パターン認識。機械学習。めんどくさい。
    • 眼電位/脳波 => ノイズがある。統計/機械学習が必要。めんどくさい。
  • 眼電位の生データはノイズが多くデータ量が多い!
  • バイタルデータならではのレイヤーの深さと通信制約 => そのままではなく概観したデータを圧縮しないといけない。
  • ウェアラブル端末ならではの機能制約にかなり苦しみがある

サーバー側アーキテクチャへの落とし込み

  • スケーラビリティを保つため、キューとバッチではなくストリームの逐次処理化したい
  • リアルタイム/ステートレス化して差分アルゴリズムを整える
  • 「売れるか売れないか」わからない状態で構成を組むことに難があった => Lambdaの使用
  • Rはサーバレスアーキテクチャと相性が悪い大量データのバッチ式処理
  • Shiny を利用して分析しながらの開発

ウェアラブルに足を突っ込んできての雑感

  • 分業が進み過ぎていてインテグレーションは大変
  • 最新のツールを利用して理解できる範囲を広げる
  • AWSを利用することで集中したいものに工数をさく

感想

ステートレスなFunction構造がはまるところと逆に相性が悪いところ、その辺の事例が確認できました。
利用の際はその辺を意識していきたいと思います。

Read More

[AWS Summit Tokyo 2017 Day3] ECSでコンテナ化と Terraform でインフラコード化した話

「株式会社インテリジェンス」 さんでのオンプレからAWSの導入事例のセッションの中で、
コンテナ化や infrastructure as code の話が出てきて面白かったので記します。
弊社もこの辺の整備は挑戦していきたい。

課題

  • 2016年4月以前

    • レガシーインフラ!
    • グループ共通のオンプレ基盤
    • 子会社に随時スケール依頼/調査依頼投げる
    • スケールしない
    • 秘伝のタレ
    • ブラックボックス
    • 積み上がることで新しいサービスを始められるスピードが逆に下がっていく
  • 移行作業

    • DevOpsチーム4名
    • ぽんぽん依頼投げられて集中できない
    • エンジニアだけでなく会社としての協力
    • 移行デーを週に2日設けてそれに集中する
    • 2016年11月に移行開始 => 2017年4月完了

アーキテクチャ

  • ALB , ECSによるnginxコンテナ , マカレル、等々。

Terraformによるプロビジョニングを導入

  • 古参メンバーの秘伝のタレをterafform化。
  • infrastructure as code.
  • terraformを導入して困ったところは一部あった
    • dry run と実際のプロビジョニングとの結果が違うことがあった
    • 当時はアップデートが頻繁だった

ALB & コンテナ

  • ALBとECSとの親和性が良い
  • nginxコンテナ
  • なせコンテナにしたか?
    • 依存関係が明確に分離。
    • 開発と本番の環境が一致する。
    • スケールするのが簡単
  • blue green developmentがすごい
    • 3つのコマンドで完了
    • ALBにつながっているバージョン1のコンテナが徐々に減らされていって、バージョン2のコンテナが徐々にぶら下がっていく
    • 戻すときも同じ作業なので簡単

Aurora

  • はじめは MySQL on RDS にしようとしていたが、性能と監査ログの機能からAuroraに決めた
  • 移行にかんしてはAWSのサポートにどんどん聞く

監視

  • プロセス監視 => mackerel
  • ログ監視 => fluentd
  • アラートをSlackに飛ばす

NFS

S3 + goofys に移行した
* とてもいいことがあったわけでもないのでEFS早くきてほしい

小さく素早く始める

  • とにかく素早くstagng構築
  • 2段階で移行
    • 旧環境と新環境で並列稼働させる

移行して良かったか?

YES

  • ブラックボックスが全てプロビジョニングコードに落とし込まれた
  • ハンドリングが可能
  • 全てが透明
  • 市場変化に楽しく対応できるようになる

Read More

[AWS Summit Tokyo 2017 Day3] EPSONにおけるサーバーレスアーキテクチャ導入事例

Day3です。コンピューターのバッテリーがやばいです。
ブロックチェーンやKinesisに関してのセッションを今日は拝聴していました。
本稿では、EPSON社のサーバーレスの導入事例のセッションの様子を記そうと思います。

サービス

プリンターからのレシートを解析、DB上にストアするアプリケーション
その情報をネイティブアプリから見れるサービス

課題

AWS上でサービスを展開する上で、オンプレの思考のまま設計
Web API => EC2インスタンスにwebアプリを置いてビジネスロジックを持ち込む => RDSにレシートデータ蓄積

  • 密結合
  • 毎回インフラ側にスケール依頼をしていて立ち行かなくなってきた
  • 同期処理でのブロック処理

プリンシプル

  • スケーラブルにする
  • サービス間を疎結合にする
  • マネージドサービスの活用

アーキテクチャ

AWSのマネージドサービスをフル活用することで活用する
(ほぼ)世界の各ロケーションでフルスケーラブル/高可用の環境が構築できた。

  • 情報の格納

    • プリンター => EC2 => Kinesis => lambdaでレシートをS3に格納
    • s3のレシートのputからSQSを発火、AWS Beanstalk上のworkerで解析。
    • 解析結果をさらにKinesis Streamに入れ込み、Auroraへ格納
  • ユーザーアプリからサービスにアクセスする

    • 実際にユーザーのクライアントアプリからレシートの検索結果を見る。APIGateWay/LambdaでAPIを書いている。
    • このLambdaはS3やAuroraにアクセスしてユーザーに情報を返す。
  • システムのOverViewを作っておくと、自分が今何をしているのかとか、

  • 本格実装して半年で軌道に乗った

「新しい作り方」に会社として向き合うには

  • 啓発/習得/権限
    • 背中を押す経験 -> ワークショップの開催
    • ベンダーロックインの議論にははじめの実績で答えを出す
    • 権限と責任範囲を明確にした
    • 細かく作って細かく壊す
    • ビジネスロジックを最適に分割/コスト資産

まとめ

  • ビジネスは容赦なく変化し、アーキテクチャは破綻する
  • 踏み出す勇気と受けいれる心
  • 現実的なフルスタックエンジニアリング
  • サーバーレスによって「担当範囲のスコープ」だけでなく「価値提供に集中できるチーム/メンバーが自己成長できるチーム」が出来上がった

Read More

[AWS Summit Tokyo Day2] 中堅企業での事例に学ぶAWS活用サクセスストーリー

AWS Summit Tokyoが始まりました!
これから3日間、気になった講演ごとにメモしたことをレポしようかな!と思います!

早速始めます。

表題の通り、最初の記事は 中堅企業での事例に学ぶAWS活用サクセスストーリーです。


Rekognition活用事例 – 千株式会社

AWSへの移行

  • イベントフォトのネット販売サービス
  • 2013-2016にオンプレから移行
  • 大容量の画像をNFSに保持していたのを、 s3に移行した

Rekognitionの活用

  • 深層学習による顔認識サービス

  • 運動会などの膨大な画像の中で、「自分の子供だけこの写真の中から集めたい」という要求への対応

  • 顔に対してcreate_indexする()

  • 現在Tokyo Regeonでサポートされていない => Rekognitionは同リージョンのs3しか使えない
    => そこで、オレゴンで顔index作成後、オレゴンのs3からは画像のレプリカを消すことにした

  • 顔検索APIはcroudfront => API Gateway => Lambda => Rekognition の流れで使う


AWS Direct Connectの活用 コールダイレクト株式会社

  • コールセンターシステム をオンプレからAWS Direct Connectに移行
  • Amazon Connectというクラウド型のコンタクトセンターを使う

東横インIT集客ソリューション

東横インの予約システムの開発をしている会社さん。

セキュリティの担保

  • PCI DSSというセキュリティ要件に準拠した決済システムを構築する必要がある。

  • PCI DSSに準拠してクレジットカード情報等を安全に保持するには? => AWS KMSの利用!

  • オンプレで暗号化すると開発・運用コストが辛い

  • IAMで取り出し、Cloudtrailに取り出し記録が残るのでPCI DSSに準拠できた!


株式会社千代田グラビヤ

社内システムのAWSヘの移行

各SaaSの接続

  • 勤怠システムや社内スケジュールを様々な外部サービスをまたいで使っている。
  • そのHUbとしてMasterのDBをRDS Oracleで保持
  • EBSボリュームの使用

株式会社アトラ工

求人メディアGreenのオンプレからAWSヘの移行

AWS DMSの使用

  • 他社クラウドRDBをマイグレーションするサービスを使って、随時データベースをAWSのAuroraに移行した。
  • ダウンタイムがほとんどなく移行が完了

まとめ

xxxがしたい!という要求があれば、AWSバートナーにどんどん聞いてください!とのことでした。

Read More

AWSマルチアカウントのS3間のcopyのメモ

AWSアカウントAにIAMユーザーA1,
AWSアカウントBにIAMユーザーB1がいるとする。

アカウントAのS3からアカウントBのS3にオブジェクトのコピーを行うには、通常、ユーザーA1としてアカウントAのS3からオブジェクトをgetし、ユーザーB1としてアカウントBのS3にputする方法が考えられる。
 
そうではなく、S3からS3に直接オブジェクトをcopyしたい。
 
そこで、コピー元の対象bucketのバケットポリシーに以下を追加する。
 

{
   "Version": "2012-10-17",
   "Statement" : {
      "Effect":"Allow",
      "Sid":"ReadAccess",
      "Principal" : {
          "AWS":["arn:aws:iam::アカウントBのユーザーB1"]
      },
      "Action":"s3:GetObject",
      "Resource":"arn:aws:s3:::コピー元対象bucket/*"
   }
}

 
cliでのアクセスは以下の通り。クライアントのコンピュータを介することなく複数のprofileを跨いだcopyやsyncができる。

 

aws s3 cp --profile user_A1 s3://A-bucket/object.png --profile user_B1 s3://B-bucket/

Read More