2010年1月12日火曜日

Memcacheの使い方(GAE/J)

スズキです。

三連休にGAE/JのDatastoreとMemcacheまわりのプログラミングをしていて、
なんとなく、自分流の使い方が見えてきたのでメモ。

(1) Low-level APIを使う。
細かいことできるし、本質が見えやすいと思ったから。

(2) Memcacheのデータはなかったら、Datastoreなどから作れるように。
まあ、当たり前ですね。

(3) Datastoreのデータは、できるだ冗長性をなくす。
画面表示情報などJOIN?が必要なものはMemcacheに持たせ、それを使う。
※検索結果などは当てはまりませんね...

ということで、特に(2)に関してですが、結局Memcache使うときは、
まず、データを取得してみて、Memcacheに値が有ればそのまま返し、
無ければDatastoreなどから値を作成し、それをMemcacheに登録したあと、返す、
ってパターンになります。

パターン化してるってことは、プログラムの枠組みが作れるってことなので、
下記のように作ってみました。

まずは、Datastoreなどから値を作成する処理を用意します。

--------【MypageUtil.java】--------
...
public static List<Map<String, Object>> getUserConditions() throws Exception {
  UserService user = UserServiceFactory.getUserService();
  DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
  Query conditionQuery = new Query("condition");
  conditionQuery.addFilter("user", FilterOperator.EQUAL, user.getCurrentUser());
  List<Map<String, Object>> userConditions = new ArrayList<Map<String,
Object>>();
  for(Entity conditionEntity :
datastore.prepare(conditionQuery).asList(Builder.withOffset(0))) {
    Entity feedEntity = datastore.get((Key)conditionEntity.getProperty("feed"));
    userConditions.add(StaticUtil.convertToMap(feedEntity));
  }
  return userConditions;
}
...
--------
http://code.google.com/p/suz-lab-gae/source/browse/trunk/suz-lab-feed/src/suz/lab/feed/util/MypageUtil.java?r=123

そして、後述するMemcacheHelperクラスを用いて、上記処理(メソッド)を登録してから、
データを取得します。

--------【IndexHtml.java】--------
...
@Override
protected List<Map<String, Object>> createResults() throws Exception {
  return (new MemcacheHelper<List<Map<String, Object>>>(){
    @Override
    protected List<Map<String, Object>> getFromSource() throws Exception {
      return MypageUtil.getUserConditions();
    }
  }).get("condition" + this.user.getCurrentUser().getUserId());
}
...
--------
http://code.google.com/p/suz-lab-gae/source/browse/trunk/suz-lab-feed/src/suz/lab/feed/page/other/mypage/IndexHtml.java?r=123

実際のMemcacheHelperは下記のようになっており、
データを取得(get)するときにMemcacheに値が有ればそのまま返し、
上記の登録されたメソッドを実行し、おおもとからデータを取得し、
それをMemcacheに登録したあと値を返すって処理になってます。

--------【MemcacheHelper.java】--------
...
public abstract class MemcacheHelper<T> {

  public T get(String key) throws Exception {
    return get(key, false);
  }

  @SuppressWarnings("unchecked")
  public T get(String key, boolean forceFlag) throws Exception {
    MemcacheService memcache = MemcacheServiceFactory.getMemcacheService();
    T value = (T)memcache.get(key);
    if(forceFlag || value == null) {
      value = this.getFromSource();
      memcache.put(key, value);
    }
    return value;
  }

  protected abstract T getFromSource() throws Exception;

}
--------
http://code.google.com/p/suz-lab-gae/source/browse/trunk/suz-lab-gae/src/suz/lab/gae/helper/MemcacheHelper.java?r=120

考え方やフレームワーク(っぽいもの)は、まだまだ変わっていくんだろうなー...

--------
http://www.suz-lab.com

0 コメント: