SlideShare une entreprise Scribd logo
1  sur  57
Télécharger pour lire hors ligne
appengine
java night #3
  実際に作ってわかった
App Engine の困ったところ



          source: http://www.flickr.com/photos/katemonkey/122489910/
自己紹介

はてなID:bluerabbit
twitterID:bluerabbit777jp
内容
「雨の日め〜る」というサービスを作りま
した。

実際にApp Engineで作るにあたって困っ
たことをどのように回避したかをお話しま
す。
雨の日め〜るとは
会社帰りに・・・

「あれっ。今日って雨だったの?」と
傘を忘れた経験がある。
そんなあなたのためのサービスです。
 
傘忘れを防止する為に作りました。
仕組み
「雨の日め〜る」は天気が雨の場合に
天気予報メールを送信する。

実現するための機能は下記3つ。
 天気予報を取得する
 天気予報をメールする
 ユーザ登録
天気予報を取得する
天気予報をUrlFetch APIを用いて取得
天気予報は朝(6:00)に取得
利用者のお住まいの地域は142用意
142の地域の天気予報をDatastoreに保存
ユーザの指定した時間にメールする

    これらをバッチ処理で行う。
しかし
立ちはだかる
App Eengineの制約
制約その1

1 リクエストは30秒以内に処理すべし
   HardDeadlineExceededError




       http://code.google.com/intl/ja/appengine/docs/whatisgoogleappengine.html
App Engineではバッチ
  処理も30秒以内
天気予報を取得するために次のようにした。
 Cronで1分毎に実行
 各地域の天気予報を取得
   取得済みの地域はスキップ
 天気予報をDatastoreへ保存
     ※当時はTaskQueueがリリースされていなかった。
処理イメージ
処理時間30分orz...
TaskQueueで高速化
  TaskQueueを使って並列処理
  1地域毎に1タスク、142のTaskで実行する
  Cronは指定時間にQueueを追加するだけ

 for (Location location : Location.getAll()) {
   QueueFactory.getDefaultQueue().
      add(TaskOptions.Builder
          .url("/crawler")
          .param("locationID",location.getId()));
 }
処理イメージ
処理時間3分
App Engineでの
    バッチ処理
バッチ処理でも30秒以内に処理
結果的にTaskQueueを使う必要あり
キューを使うことで非同期、並列処理となる
非同期、並列処理の知識と経験が必要
既存プログラムをApp Engineに移行する場合
にバッチ処理は処理方式を変更する必要に迫
られる
こんなバッチの場合は
   どうする?
1Taskが30秒以内に終わらない
バッチが終わったことを知りたい
1Taskが30秒以内に
    終わらない
機能を分割する。1機能を30秒以内に分割
当該アプリの例だと1Taskの機能は下記
 Fetch
 Parse
 Insert
機能別にTaskを実行するようにする
TaskQueueを
     チェインする
Fetch処理の最後にParseのキューを追加
Parse処理の最後にInsertのキューを追加
Insert処理を実行してDatastoreに登録する
処理イメージ
バッチが終わったことを
   知りたい
処理件数で把握する
 複数リクエスト(TaskQueue)間で連番を作
 成する
 連番の処理件数がキューを追加した件数
 と同じだったらバッチ終了と判断する
カウンター
Sharding Counter
  書き込みが集中しないように複数のエン
  ティティに分散して書き込みし集計する

Memcache Counter
 Memcacheを用いた簡易カウンター 


    Memcache Counterを紹介
Memcache Counter
MemcacheのLow Level API
MemcacheService#incrementはアトミックに
実行される
TaskQueueなどで複数のスレッドが同時にア
クセスしても連番が補償される




                 MemcacheServiceのjava doc
APIの使用例
 MemcacheService s =
MemcacheServiceFactory.getMemcacheService();
 if (!s.contains("MemcacheCounter")) {
     s.put("MemcacheCounter", 1); // 初期化は1
 } else {
     // 2回目以降は値に+1する
     s.increment("MemcacheCounter", 1);
 }
 // 実行のたびに1,2,3,4,5になる
 System.out.println(s.get("MemcacheCounter"));

        http://d.hatena.ne.jp/bluerabbit/20091008/1255007854
天気予報をメールする
天気予報が雨かを判断する。
特定の時間になったらメールする。
    これらをバッチ処理で行う。
  しかし、ここにも制約が存在する。
制約その2

MailAPI の呼出回数は24時間あたり
7000件(1分間に32件)までにすべし




       http://code.google.com/intl/ja/appengine/docs/quotas.html#Mail
Mailの回数を制御する
メール送信はDatastoreを用いた自作Queue
を使用する。
メール送信する場合はMailQueueのKind
(テーブル)にEntity(データ)を保存する。
MailQueueの送信はCronにて1分毎に
MailQueueに未送信があればメールするよう
にする。
処理イメージ
この処理には2つの
  誤りがある
1.ユーザ数が増加した場合に
  _____しない。
   スケール

2.エラーが発生した場合に
  ________の危険性がある
   メール二重送信
制約その3
Datastore は定期的にエラーが出る
        ことを許容すべし

DatastoreTimeoutException
ApiProxy$UnknownException
CapabilityDisabledException
ユーザ登録
下記のユーザ情報を登録する
 受信するメールアドレス
 受信する時間
 受信する曜日
 お住まいの地域

メールでユーザ登録の確認をする
 MailQueueを作成する

  上記の2つのEntityを登録する
制約その4

トランザクションは設計する必要がある
RDB のように使えないことを許容すべし
(案1) EntityGroup
ユーザとメールキューをEntityGroup関係
にする




           ※説明のため、意図的にJDOのイメージで記載しています。
                   App Engine のEntityGroupを理解しよう
(案2) 非正規化
1リクエストで複数のEntityを登録しない。
1つのEntityですべて処理する
(案3) TaskQueue
1リクエストで複数のEntityを登録しない。
1リクエストは1Entityのみ登録する。
MailQueueはTaskQueueで登録する。
(案4) 考慮しない
エラーがたまに出ることを前提とする
一時的に不整合になることを許容する
偶発的に起こる事象に対して柔軟に対応で
きるように備える
 エラー、不整合を早急に発見する方法を
 作りこむ
(案5) 補償トランザクション
トランザクションをプログラムで補償する
Insert時
  Userの登録は正常終了
  MailQueueが異常終了
  異常を検知してUserをロールバックする
  (Userを削除する)
Update時
  Userを更新する前にバックアップを作成
  する(Userをシリアライズして保存)
  失敗した場合はバックアップから戻す
  ※30秒制限があるため実装は困難です。しかし、タスクキューを使えば出来なくもありません。
どれが最適な案?
  決め手はなに?
案1)EntityGroup
案2)非正規化
案3)TaskQueue
案4)考慮しない
案5)補償トランザクション
Entity Groupって何?
全てのEntityはEntity Groupに所属
Entity Group内ではトランザクションをサポート
  全ての操作が成功か失敗かになる
Entityを作成するときに、別のEntityを新しいEntity
の「親」に指定することができる
新しいEntityに対して親を指定することで、その新し
いEntityは親Entityと同じEntity Groupに入る
親を持たないEntityはルートエンティティとなる
Entityの親はEntityの作成時に定義され、後で変更
することはできない
Entity Group全体に対してトランザクションの排他処
理は実行される
ルートエンティティ
String kind = "User";
Key userKey = KeyFactory.createKey(kind, 1);
Entity user = new Entity(userKey);
DatastoreService ds = DatastoreServiceFactory.
getDatastoreService();
ds.put(user);


            KEY                    Kind
User(1)                             User
UserにMailQueueを追加
String kind = "MailQueue";
Key mailKey =
KeyFactory.createKey(userKey, kind, 1);
Entity mail = new Entity(mailKey);
DatastoreService.put(mail);


            KEY                    Kind
User(1)                User
User(1)/MailQueue(1) MailQueue
EntityGroupはKeyで構成
       KEY            Kind
User(1)                User
User(1)/MailQueue(1) MailQueue
User(1)/MailQueue(2) MailQueue
User(1)/Book(8)        Book
※ルートエンティティが子エンティティ
    を保持している訳ではない
同一Kindでも構成可能
          KEY     Kind
Bank(1)           Bank
Bank(1)/Bank(2)   Bank
Bank(1)/Bank(3)   Bank
Bank(1)/Bank(4)   Bank
  ※注意:排他はEntityGroup全体
EntityGroupの排他

tx = ds.beginTransaction() ;

 口座A -1000円
 口座B +1000円                    tx = ds.beginTransaction() ;
                               口座C = ds.get(tx, keyC);
tx.commit();
                                口座C -2000
                                口座D +2000

                               // ConcurrentModificationException
                               tx.commit();
                                          ※口座A、B、C、DはEntityGroupです。
トランザクション内の分離レベルは
        SERIALIZABLE

tx = ds.beginTransaction() ;
口座A = ds.get(tx, keyA);
 口座A 残高照会 1000円
                               tx = ds.beginTransaction() ;
                                口座A -1000円
                                口座B +1000円
                               tx.commit();

口座B = ds.get(tx, keyB);
 口座B 残高照会 0円
                                       ※リクエスト前は口座Bの残高は0円です。
その他
困ったこと
制約その5

 App Engine のDatastoreには
ユニークキー制約がつけられない
ユニークキー制約が
ないのでこんなミス
TaskQueueで以下の登録処理を実行した
1. パラメータでEntityの登録値を取得
2. Datastoreに新規登録 
3. 終了処理 

    2.の処理後にエラーが出たら
    リトライされて2重登録された
対応策
TaskQueueで登録処理する場合は事前にキー
を作成する 
  TaskQueueの追加処理   
    1. キューで登録するキーを作成する
    2. キーをTaskのパラメータに設定する
  登録処理
    1. キーのパラメータを取得してキーが登録
       されているかを確認する
    2. 存在しない場合は登録処理をする
処理イメージ(1)
// キーを作成する。
DatastoreService service =
   DatastoreServiceFactory.getDatastoreService();

KeyRange keys = service.allocateIds("Kind", 1);
String key = KeyFactory.keyToString(keys.getStart());
 );
// キューのパラメータにキーを設定する
QueueFactory.getDefaultQueue().
    add(TaskOptions.Builder.url("/insert").
                           param("key", key));
                               DatastoreServiceのjava doc
処理イメージ(2)
// DatastoreService#get(Key)で登録有無をチェック
String keyString = (String) request.getAttribute("key");
Key key = KeyFactory.stringToKey(keyString);
try {
   DatastoreService service =
      DatastoreServiceFactory.getDatastoreService();
   Entity e = service.get(key);
   // 登録済み
} catch (EntityNotFoundException e) {
   // 未登録
   // → 登録処理を行う
}
対応策(2)
Keyにユニークな名前をつける
  TaskQueueの追加処理
    特に処理なし

 登録処理
 1. ユニークになるようにcreateKeyする
     例えば、当アプリはLocationIdと日付
 2. キーが既に登録されているかを確認する
 3. 存在しない場合は登録処理をする
処理イメージ
  // Keyを作成
  String keyName = "001" + "20091204";
  Key key =
        KeyFactory.createKey("Kind", keyName);
DatastoreService ds =
DatastoreServiceFactory.getDatastoreService();
try {
    ds.get(key);
} catch (EntityNotFoundException e) {
    Entity entity = new Entity(key); // 作成キーで登録
    ds.put(entity); // 存在しないときにのみ登録
}
                                  KeyFactoryのjava doc
まとめ
制約,エラーを寛大な心で受け入れる
制約ではなくルール
ルールを守りながらプログラムするゲーム
このゲームは必ず開発者を成長させる
Let's Enjoy Cloud
 Programming!!
ご清聴ありがとうございました
Questions?

Contenu connexe

En vedette

デブサミ2011 LT大会【17-E-7】appengine ja night
デブサミ2011 LT大会【17-E-7】appengine ja nightデブサミ2011 LT大会【17-E-7】appengine ja night
デブサミ2011 LT大会【17-E-7】appengine ja nightbluerabbit777jp
 
aspectos preliminares
aspectos preliminaresaspectos preliminares
aspectos preliminaresdavid
 
מצגת רצוי ומצוי קריית חיים
מצגת רצוי ומצוי קריית חייםמצגת רצוי ומצוי קריית חיים
מצגת רצוי ומצוי קריית חייםavi6680
 
Podcamp Philly Presentation Nota Pro Nota Problem
Podcamp Philly Presentation Nota Pro Nota ProblemPodcamp Philly Presentation Nota Pro Nota Problem
Podcamp Philly Presentation Nota Pro Nota ProblemProducePicker
 
Aplicaciones de drones en el Perú, experiencias de la PUCP
Aplicaciones de drones en el Perú, experiencias de la PUCPAplicaciones de drones en el Perú, experiencias de la PUCP
Aplicaciones de drones en el Perú, experiencias de la PUCPAndres Flores
 
რიცხვითი მახასიათებლები
რიცხვითი მახასიათებლებირიცხვითი მახასიათებლები
რიცხვითი მახასიათებლებიmarina58
 
Scala For Java Programmers
Scala For Java ProgrammersScala For Java Programmers
Scala For Java ProgrammersEnno Runne
 
Exposicinn resumen
Exposicinn resumenExposicinn resumen
Exposicinn resumendavid
 
aspectos
aspectos aspectos
aspectos david
 
Silabo evaluacion educativa pato tobar
Silabo evaluacion educativa pato tobarSilabo evaluacion educativa pato tobar
Silabo evaluacion educativa pato tobardavid
 
Rm 01-last
Rm 01-lastRm 01-last
Rm 01-lasttomkacy
 
Rm 02 v2
Rm 02 v2Rm 02 v2
Rm 02 v2tomkacy
 
Rm 06-v2
Rm 06-v2Rm 06-v2
Rm 06-v2tomkacy
 
Rm 07-v1
Rm 07-v1Rm 07-v1
Rm 07-v1tomkacy
 
Rm 01-last
Rm 01-lastRm 01-last
Rm 01-lasttomkacy
 
Rm 05-v2
Rm 05-v2Rm 05-v2
Rm 05-v2tomkacy
 

En vedette (20)

デブサミ2011 LT大会【17-E-7】appengine ja night
デブサミ2011 LT大会【17-E-7】appengine ja nightデブサミ2011 LT大会【17-E-7】appengine ja night
デブサミ2011 LT大会【17-E-7】appengine ja night
 
aspectos preliminares
aspectos preliminaresaspectos preliminares
aspectos preliminares
 
מצגת רצוי ומצוי קריית חיים
מצגת רצוי ומצוי קריית חייםמצגת רצוי ומצוי קריית חיים
מצגת רצוי ומצוי קריית חיים
 
Podcamp Philly Presentation Nota Pro Nota Problem
Podcamp Philly Presentation Nota Pro Nota ProblemPodcamp Philly Presentation Nota Pro Nota Problem
Podcamp Philly Presentation Nota Pro Nota Problem
 
Aplicaciones de drones en el Perú, experiencias de la PUCP
Aplicaciones de drones en el Perú, experiencias de la PUCPAplicaciones de drones en el Perú, experiencias de la PUCP
Aplicaciones de drones en el Perú, experiencias de la PUCP
 
Real generics
Real genericsReal generics
Real generics
 
რიცხვითი მახასიათებლები
რიცხვითი მახასიათებლებირიცხვითი მახასიათებლები
რიცხვითი მახასიათებლები
 
Scala For Java Programmers
Scala For Java ProgrammersScala For Java Programmers
Scala For Java Programmers
 
Exposicinn resumen
Exposicinn resumenExposicinn resumen
Exposicinn resumen
 
aspectos
aspectos aspectos
aspectos
 
Silabo evaluacion educativa pato tobar
Silabo evaluacion educativa pato tobarSilabo evaluacion educativa pato tobar
Silabo evaluacion educativa pato tobar
 
Rm 01-last
Rm 01-lastRm 01-last
Rm 01-last
 
Rm 02 v2
Rm 02 v2Rm 02 v2
Rm 02 v2
 
Rm 06
Rm 06Rm 06
Rm 06
 
Rm 06-v2
Rm 06-v2Rm 06-v2
Rm 06-v2
 
Rm 07-v1
Rm 07-v1Rm 07-v1
Rm 07-v1
 
Rm 01-last
Rm 01-lastRm 01-last
Rm 01-last
 
Rm 05-v2
Rm 05-v2Rm 05-v2
Rm 05-v2
 
Rm 10
Rm 10Rm 10
Rm 10
 
Rm 12
Rm 12Rm 12
Rm 12
 

Similaire à appengine java night #3

Google App Engineでできる、あんなこと/こんなこと
Google App Engineでできる、あんなこと/こんなことGoogle App Engineでできる、あんなこと/こんなこと
Google App Engineでできる、あんなこと/こんなことa-know
 
MailFluteでメール送信を楽しもう!
MailFluteでメール送信を楽しもう!MailFluteでメール送信を楽しもう!
MailFluteでメール送信を楽しもう!p1us2er0
 
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例Yoshifumi Kawai
 
20120405 setsunaセミナー
20120405 setsunaセミナー20120405 setsunaセミナー
20120405 setsunaセミナーTakahiro Iwase
 
認証機能で学ぶ Laravel 5 アプリケーション
認証機能で学ぶ Laravel 5 アプリケーション認証機能で学ぶ Laravel 5 アプリケーション
認証機能で学ぶ Laravel 5 アプリケーションMasashi Shinbara
 
データマイニング+WEB勉強会資料第6回
データマイニング+WEB勉強会資料第6回データマイニング+WEB勉強会資料第6回
データマイニング+WEB勉強会資料第6回Naoyuki Yamada
 
IoT時代におけるストリームデータ処理と急成長の Apache Flink
IoT時代におけるストリームデータ処理と急成長の Apache FlinkIoT時代におけるストリームデータ処理と急成長の Apache Flink
IoT時代におけるストリームデータ処理と急成長の Apache FlinkTakanori Suzuki
 
Let's build a simple app with .net 6 asp.net core web api, react, and elasti...
Let's build a simple app with  .net 6 asp.net core web api, react, and elasti...Let's build a simple app with  .net 6 asp.net core web api, react, and elasti...
Let's build a simple app with .net 6 asp.net core web api, react, and elasti...Shotaro Suzuki
 
ボット開発でも DevOps! BotBuilder のテスト手法
ボット開発でも DevOps! BotBuilder のテスト手法ボット開発でも DevOps! BotBuilder のテスト手法
ボット開発でも DevOps! BotBuilder のテスト手法Kenichiro Nakamura
 
Data apiで実現 進化するwebの世界
Data apiで実現 進化するwebの世界Data apiで実現 進化するwebの世界
Data apiで実現 進化するwebの世界Yuji Takayama
 
jQuery Validation x ASP.NET MVC で遭遇した不具合 & 対抗ハック
jQuery Validation x ASP.NET MVC で遭遇した不具合 & 対抗ハックjQuery Validation x ASP.NET MVC で遭遇した不具合 & 対抗ハック
jQuery Validation x ASP.NET MVC で遭遇した不具合 & 対抗ハックJun-ichi Sakamoto
 
TotalViewを使った代表的なバグに対するアプローチ
TotalViewを使った代表的なバグに対するアプローチTotalViewを使った代表的なバグに対するアプローチ
TotalViewを使った代表的なバグに対するアプローチRWSJapan
 
Entity Framework 5.0 deep dive
Entity Framework 5.0 deep diveEntity Framework 5.0 deep dive
Entity Framework 5.0 deep diveAtsushi Fukui
 
Jhs team portfolio2
Jhs team portfolio2Jhs team portfolio2
Jhs team portfolio2ssuser25d7ff
 
Twitter連携chrome extension作り方
Twitter連携chrome extension作り方Twitter連携chrome extension作り方
Twitter連携chrome extension作り方Hiroshi Oyamada
 
Inside mobage platform
Inside mobage platformInside mobage platform
Inside mobage platformToru Yamaguchi
 
Apache Torqueについて
Apache TorqueについてApache Torqueについて
Apache Torqueについてtako pons
 
【18-C-4】Google App Engine - 無限の彼方へ
【18-C-4】Google App Engine - 無限の彼方へ【18-C-4】Google App Engine - 無限の彼方へ
【18-C-4】Google App Engine - 無限の彼方へDevelopers Summit
 

Similaire à appengine java night #3 (20)

Google App Engineでできる、あんなこと/こんなこと
Google App Engineでできる、あんなこと/こんなことGoogle App Engineでできる、あんなこと/こんなこと
Google App Engineでできる、あんなこと/こんなこと
 
MailFluteでメール送信を楽しもう!
MailFluteでメール送信を楽しもう!MailFluteでメール送信を楽しもう!
MailFluteでメール送信を楽しもう!
 
jQuery勉強会#4
jQuery勉強会#4jQuery勉強会#4
jQuery勉強会#4
 
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例
Metaprogramming Universe in C# - 実例に見るILからRoslynまでの活用例
 
20120405 setsunaセミナー
20120405 setsunaセミナー20120405 setsunaセミナー
20120405 setsunaセミナー
 
認証機能で学ぶ Laravel 5 アプリケーション
認証機能で学ぶ Laravel 5 アプリケーション認証機能で学ぶ Laravel 5 アプリケーション
認証機能で学ぶ Laravel 5 アプリケーション
 
データマイニング+WEB勉強会資料第6回
データマイニング+WEB勉強会資料第6回データマイニング+WEB勉強会資料第6回
データマイニング+WEB勉強会資料第6回
 
IoT時代におけるストリームデータ処理と急成長の Apache Flink
IoT時代におけるストリームデータ処理と急成長の Apache FlinkIoT時代におけるストリームデータ処理と急成長の Apache Flink
IoT時代におけるストリームデータ処理と急成長の Apache Flink
 
Let's build a simple app with .net 6 asp.net core web api, react, and elasti...
Let's build a simple app with  .net 6 asp.net core web api, react, and elasti...Let's build a simple app with  .net 6 asp.net core web api, react, and elasti...
Let's build a simple app with .net 6 asp.net core web api, react, and elasti...
 
ボット開発でも DevOps! BotBuilder のテスト手法
ボット開発でも DevOps! BotBuilder のテスト手法ボット開発でも DevOps! BotBuilder のテスト手法
ボット開発でも DevOps! BotBuilder のテスト手法
 
Data apiで実現 進化するwebの世界
Data apiで実現 進化するwebの世界Data apiで実現 進化するwebの世界
Data apiで実現 進化するwebの世界
 
jQuery Validation x ASP.NET MVC で遭遇した不具合 & 対抗ハック
jQuery Validation x ASP.NET MVC で遭遇した不具合 & 対抗ハックjQuery Validation x ASP.NET MVC で遭遇した不具合 & 対抗ハック
jQuery Validation x ASP.NET MVC で遭遇した不具合 & 対抗ハック
 
TotalViewを使った代表的なバグに対するアプローチ
TotalViewを使った代表的なバグに対するアプローチTotalViewを使った代表的なバグに対するアプローチ
TotalViewを使った代表的なバグに対するアプローチ
 
Entity Framework 5.0 deep dive
Entity Framework 5.0 deep diveEntity Framework 5.0 deep dive
Entity Framework 5.0 deep dive
 
Jhs team portfolio2
Jhs team portfolio2Jhs team portfolio2
Jhs team portfolio2
 
Twitter連携chrome extension作り方
Twitter連携chrome extension作り方Twitter連携chrome extension作り方
Twitter連携chrome extension作り方
 
★2章
★2章★2章
★2章
 
Inside mobage platform
Inside mobage platformInside mobage platform
Inside mobage platform
 
Apache Torqueについて
Apache TorqueについてApache Torqueについて
Apache Torqueについて
 
【18-C-4】Google App Engine - 無限の彼方へ
【18-C-4】Google App Engine - 無限の彼方へ【18-C-4】Google App Engine - 無限の彼方へ
【18-C-4】Google App Engine - 無限の彼方へ
 

appengine java night #3