ClouderaManagerで2つのバージョン(CDH3, CDH4)のクラスタを認識させようと作業していたのですが、FREE版ではマルチクラスタの管理はサポートしていないようです。

というわけで、ClouderaManagerを別々にインストールして、1クラスタ=1ClouderaManagerという感じにしようと思ったのですが、最初のManagerに認識させたホストを消せなくてちょっと四苦八苦してました。図にすると以下のような感じです。

最初の状態。

この状態から以下のようにしようとしてた。

でも、FREE版はマルチクラスタをサポートしていないっぽい。ので、以下のようにしようとして、Manager1からCDH4用に追加したHostB群を削除しようとした。

 

ClouderaManagerに登録したホストを削除する時は、以下の画面で削除したいホストにチェックを入れて「削除」をすれば良いのですが、すぐに復活してきます。以下の画面は赤枠のtamsvr5[1-5]vmが最初に入れたホスト(CDH3)、緑枠のtamsvr6[1-5]vmは違うCDHのバージョンを入れて別クラスタとして認識させようとしたホスト(CDH4)です。

消しても消しても復活してくるのは、各ホストで動いているClouderaManagerのAgentがHeartBeatを送っているからです。これを止めないと、別のホストでClouderaManagerを入れてtamsvr6[1-5]vmのホストを追加しても、ホストインスペクタが失敗します。
実際、tamsvr61vmにClouderaManagerを入れてtamsvr6[1-5]vmを追加しましたが、失敗しました。

なので以下の手順を行う必要があります。

1. 各ホストで動いているAgentを止める。

ssh root@tamsvr61vm /etc/rc.d/init.d/cloudera-scm-agent stop
ssh root@tamsvr62vm /etc/rc.d/init.d/cloudera-scm-agent stop
ssh root@tamsvr63vm /etc/rc.d/init.d/cloudera-scm-agent stop
ssh root@tamsvr64vm /etc/rc.d/init.d/cloudera-scm-agent stop
ssh root@tamsvr65vm /etc/rc.d/init.d/cloudera-scm-agent stop

2. ClouderaManager(上記の画面)から削除する。

これでひとまず消えます。ただし、再度Agentを動かすと復活してきます。

3. 新しいClouderaManagerからホストを追加する。

これで成功します。

きちんと別々に認識されました。

 

 

こんな事やってる人、誰も居ないと思いますが・・(´・ω・`)

 

READMEを書くときはMarkdown形式で書くと思うのですが、四六時中その記法で書いているわけでは無いので、なかなか覚えられないわけです。Rubyの場合はRDoc形式で書くのが普通なのかな?まぁWikiにしろ何にしろ似たような記法増えすぎだと思うのです。

わたしのようなゆとりには、プレビューしながら確認できるととても幸せになれます。とは言っても、ブラウザ上で入力なんてしたくないし、自分のお気に入りのエディタを使いたいわけです。

こちらの記事にあるツールを使っていたのですが、どうも自分の環境ではファイルを保存しなおすと、高確率でreadでこけるようで・・。

というわけで(上記ツールを参考にして)自分で作ってみました。

 

 

こちらの記事で書いた、Apacheのログを生成し続けるスクリプトをRubyGemsに登録してみました。

なので、今後は

gem install apache-loggen

とインストールするだけで、

apache-loggen

というコマンドが使えるようになります。使い方は今までと同じです。(以下のような感じです) 

apache-loggen [--rate=0] [--limit=0] [--rotate=0] [--progress] [--json] [outfile]
  --rate     毎秒何レコード生成するかの指定。0以下は制限無し。
  --limit    最大何件出力するか。0以下は延々と出力し続ける。
  --rotate   ローテーションの間隔。単位は秒指定。0以下はローテーションしない。
  --progress STDERRに経過情報を出力する
  --json     apacheのログ形式ではなくJSON形式で出力する

  outfile    指定するとファイルに出力します。省略するとSTDOUTに出力します。

毎秒10件をaccess.logに出力。60秒毎にローテーション。経過をSTDERRに表示。

apache-loggen --rate=10 --rotate=60 --progress access.log

また、この機構を使って独自のログ形式を出力できるようにしました。 以下のように使います。

require 'apache-loggen/base'
LogGenerator.generate(conf=nil, gen_obj=nil, &block)

confはnilを渡すとARGVの内容をパースします。プログラムで直接指定する場合は、Hashを渡す事でデフォルトの設定を上書きする事ができます。実際にログを出力する処理は、gen_objにLogGenerator::Baseを継承しgenerate(context, config)メソッドを定義したクラスのインスタンスを渡すか、ブロックを与えます。両方指定した場合は、gen_objが先に実行され、blockが評価されます。(blockではgen_objで出力したrecordを受け取る事ができます)

いくつかサンプルを置いておきます。

独自のログ形式を出力したい場合。

require 'apache-loggen/base'
class MyGen < LogGenerator::Base
  def generate(context, config)
    return "#{Time.now.to_s} #{context.inspect}\n"
  end
end
LogGenerator.generate(nil, MyGen.new)

もしくは

require 'apache-loggen/base'
LogGenerator.generate do | context, config, record |
  "#{Time.now.to_s} #{context.inspect}\n"
end

上記の2つは同じ処理です。

Apacheログに新しく情報を追加したい場合。

require 'apache-loggen/base'
class MyGen < LogGenerator::Apache
  # オリジナル実装はhashをJSONか1行の文字列にしているが
  # 今回はそれに情報を追加する
  def format(record, config)
    record["process_time"] = grand(1000000) + 1000
    if config[:json] then
      return record.to_json + "\n"
    else
      return %[#{record['host']} - #{record['user']} [#{Time.now.strftime('%d/%b/%Y:%H:%M:%S %z')}] "#{record['method']} #{record['path']} HTTP/1.1" #{record['code']} #{record['size']} "#{record['referer']}" "#{record['agent']}" #{record['process_time']}\n]
    end
  end
end
LogGenerator.generate(nil, MyGen.new)

LogGenerator::ApacheはLogGenerator::Baseを継承しており、generateの中でformatを呼び出しています。このformatの実装が、1行分のレコードをhashとしてうけとりJSONか1行の文字列に変換するという処理をしているので、これをOverrideするとApacheログの生成ロジックを使いつつ書式を変更する事ができます。

いくつかのサンプルはREADMEにも書いてあります。

(∩´∀`)∩

 

画像分類の学習モデルを作るツールをJavaで作っていたのですが、あるJPEGファイルをImageIOで読もうとすると以下のエラーが出ました。

Exception in thread "main" java.awt.color.CMMException: Invalid image format
    at sun.awt.color.CMM.checkStatus(CMM.java:131)
    at sun.awt.color.ICC_Transform.(ICC_Transform.java:89)
    at java.awt.image.ColorConvertOp.filter(ColorConvertOp.java:516)
    at com.sun.imageio.plugins.jpeg.JPEGImageReader.acceptPixels(JPEGImageReader.java:1169)
    at com.sun.imageio.plugins.jpeg.JPEGImageReader.readImage(Native Method)
    at com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(JPEGImageReader.java:1137)
    at com.sun.imageio.plugins.jpeg.JPEGImageReader.read(JPEGImageReader.java:948)
    at javax.imageio.ImageIO.read(ImageIO.java:1422)
    at javax.imageio.ImageIO.read(ImageIO.java:1282)
    at Test.main(Test.java:31

JAIだと読み込めるというので、処理速度が落ちるけどそっちを使うようにしてみた。

BufferedImage img = null;
try {
    img = ImageIO.read(file);
} catch (java.awt.color.CMMException e) {
    img = JAI.create("fileload", file.getAbsolutePath()).getAsBufferedImage();
} catch (IOException e) {
    // ちゃんと処理しようね!
}

正しい使い方としては、JAIをきちんとセットアップしてImageIO経由で使えるようにし、ImageReaderを列挙して順番に試すというのが正統な方法なのかなと。今回は手抜き処理。

JAIだけでも良いんだけど、速度が・・。

参考サイト

 

最新の記事はこちらです。

Fluentdのテストをする過程で欲しかったので、Apacheのログを生成し続けるスクリプトを書きました。

と言っても生成部分はTreasureDataのスクリプトを丸ぱくりで流量制限をするオプションを追加して延々と出力するようにしただけです。

frsyuki++。

手元でサクッとproductionで確認できる人はうらやましす。

使い方は以下のような感じです。詳細はREADMEを見てください。

ruby sample_apache_gen.rb [--rate=0] [--limit=0] [--rotate=0] [--progress] [--json] [outfile]
  --rate     毎秒何レコード生成するかの指定。0以下は制限無し。
  --limit    最大何件出力するか。0以下は延々と出力し続ける。
  --rotate   ローテーションの間隔。単位は秒指定。0以下はローテーションしない。
  --progress STDERRに経過情報を出力する
  --json     apacheのログ形式ではなくJSON形式で出力する

  outfile    指定するとファイルに出力します。省略するとSTDOUTに出力します。

ローテーションについては以下のルールでローテーションします。

  hoge.log --> hoge.[yyyy-MM-dd_HHmmss].log

例えば、こんな感じで使います。
毎秒10件をaccess.logに出力。60秒毎にローテーション。経過をSTDERRに表示。

ruby sample_apache_gen.rb --rate=10 --rotate=60 --progress access.log

普通はクラス化して、出力内容を決める部分をBlockで渡すようにして再利用性を高めると思うのですが、ごにょごにょ(´・ω・`)

ソースはここに置いておきます。
https://github.com/tamtam180/apache_log_gen 

これでWeb屋じゃなくてもそれっぽいログが出来るのでFluentdで遊べますね(∩´∀`)∩

WindowsでFluentdを動かそうとして調べていった記録のメモです。
きちんとまとめていないので起こった順に書いています。

同じような事を試みて挫折した人が居たので、この意思を勝手に引き継いで3秒以上頑張ってみました。

概要としては、fluentdのRuby実装Python実装(fluenpy)、fluent-agent-liteのPerl実装F#実装を確認した事と、Windowsでのファイル処理の排他制御について分かったことをまとめています。Windowsのファイルについては別の記事でまとめる事にして、この記事では簡単に触れる程度にします。

Mecabのdefファイル調整メモ

Mecab/IPA辞書を使って記号を食わせると、記号(&とか)がサ変接続と認識されます。

$ echo "P&!G" |  mecab
P    名詞,固有名詞,組織,*,*,*,*
&!   名詞,サ変接続,*,*,*,*,*
G    名詞,固有名詞,組織,*,*,*,*
EOS

なんでこうなるかと言うと、char.defとunk.defの設定でそうなっているからです。
(ところで、unknownの略のunkってなんて読むんと良いんでしょうね。うんこ?(´・ω・`))

char.defでは以下のように記述されています。 SYMBOLのINVOKEが1になっているので、常にunknown wordとして扱われます。そしてGROUPが1なので、同じ種別でまとめられます。

SYMBOL         1 1 0
# ASCII
0x0021..0x002F SYMBOL
0x0030..0x0039 NUMERIC
0x003A..0x0040 SYMBOL
0x0041..0x005A ALPHA
0x005B..0x0060 SYMBOL
0x0061..0x007A ALPHA
0x007B..0x007E SYMBOL

unk.defでは以下のように記述されています。

SYMBOL,1283,1283,17585,名詞,サ変接続,*,*,*,*,*

このunk.defを以下のように書き換えます。

SYMBOL,1283,1283,17585,記号,一般,*,*,*,*,*

これで以下の出力に変わります。 

$ echo 'P&!G' | mecab
P   名詞,固有名詞,組織,*,*,*,*
&!  記号,一般,*,*,*,*,*
G   名詞,固有名詞,組織,*,*,*,*
EOS

一応、記号一般になりましたが。が、どうせなら半角ASCII文字は全部繋げてほしいなーとか思ったり、固有名詞・組織?えぇーとか思ったり、思わなかったりするわけです。というわけで、もうちょっといじくってみます。

char.defを以下のようにします。ASCIIという区分を作って細かく分類していた部分をならしてしまいます。 文字コード0x0021 - 0x007Eの連続文字は問答無用でひとくくりにしてASCIIとする設定です。

ASCII          1 1 0
# ASCII
#0x0021..0x002F SYMBOL
#0x0030..0x0039 NUMERIC
#0x003A..0x0040 SYMBOL
#0x0041..0x005A ALPHA
#0x005B..0x0060 SYMBOL
#0x0061..0x007A ALPHA
#0x007B..0x007E SYMBOL
0x0021..0x007E ASCII

unk.defに以下を追加します。 ひとくくりにしたASCIIを名詞・一般にする設定です。 コスト値は1,1と優先度が一番高くなるようにします。

ASCII,1,1,0,名詞,一般,*,*,*,*,*

再度実行してみます。(あ、辞書はビルドしなおす必要があります)

$ echo 'P&!G' |  ../../bin/mecab
P&!G    名詞,一般,*,*,*,*,*
EOS

$ echo 'xxx-yyy' |  ../../bin/mecab
xxx-yyy 名詞,一般,*,*,*,*,*
EOS

こんな感じで調整する事ができますという紹介でした。
詳細は作者様のページにありますので、そちらを参照するのが良いと思います。

@tagomorisさんがこんな事を言っていたので、調べてみました。

まずは、.pipeoutファイルについて。
結論から言うと、Hiveの不具合です。
((追記 2012/06/23 14:00)Hiveのプログラムの書き方は良くないんだけど、Leakはしていないと思われます.)

この.pipeoutファイルはSessionStateのstartメソッドでOpenされます。startメソッドはHiveServerの場合、クライアントがコネクションをはった時にコールされます。(HiveSourceCodeReadingの発表資料にもちょっとだけ書いてあります。)

.pipeoutファイルはHiveServerではpipeInという変数によって、BufferedReader -> FileReaderを通して参照されます。 ↓のような感じ。
pipeIn = new BufferedReader(new FileReader( .pipeoutファイル ))
後始末の処理として、pipeIn = null としています。これがNGです。closeしていません。 

GCによってcloseされないのか?と思うかもしれません。が、されません。
GCによってcloseされるのはFileInputStreamだけ(あとはFileOutputStream)です。
FileInputStreamはfinalizeでcloseする事を仕様として定めていますが、FileReaderは仕様として定めていません。FileReaderの親クラスであるInputStreamReader, Readerともに仕様にありません。
JDK6のソース(OracleJDK, OpenJDK)を見ても、finalize処理は実装されていません。
※ちょっと嘘書きました。末尾に追記しました。(FileReaderはコンストラクタでnew FileInputStreamしていますのでGCでcloseされます)

ちょっと横道にずれますが、.pipeoutファイルってdeleteOnExitしているんですよね。このファイルは毎回異なるファイル名で作成しているので、コネクションをはる度に解放されないオブジェクトが溜まっていきます(まぁメモリリークしているわけですが、定義的にメモリリークと言って良いのかわかんない)。 HiveServerのclean処理で.pipeoutファイルをdeleteしても、deleteOnExitのリスト(正確にはLinkedHashSet)からは消えないままです。

というか、openしたままdeleteできるかどうかってプラットフォーム依存だった気がしますが、もう直ってるんでしたっけ? BugID忘れた&調べる気ない(・x・)

次に.txtファイルについて。
これってLog4jで出力しているファイルの事なのかな?(デフォの設定だと、.logなので違うファイル?)
こっちはまだ調べていませんが、Log4jのFileAppenderの場合、ファイル名を設定する度に1つ前に開いていたFile(というかWriter)をcloseする処理が入っているところまでは確認済み。HiveのExevDriverで以下のように書いていて、これってFileAppenderのreset処理呼ばれるっけ・・。と疑問に思ったところで、こっちはいったん調査終了。

    System.setProperty(HiveConf.ConfVars.HIVEQUERYID.toString(), HiveConf.getVar(conf,
        HiveConf.ConfVars.HIVEQUERYID));
    LogManager.resetConfiguration();
    PropertyConfigurator.configure(hive_l4j);

たぶんこっちの事かな・・。 hive_job_log_(sessionId)_(乱数).txt
こっちの場合は、HiveHistoryというクラスが担当で、PrintWriterを介してファイルをOpenしており、close処理がfinalizeで呼ばれています。このHiveHistoryはSessionStateのstartメソッドでインスタンス化されます。

SessionStateはThreadLocalに保存されます。HiveHistoryはSessionStateが保持しています。HiveHistoryは様々な場所から参照されていますが、他のどこにも保持はしていません(インスタンス生成時にSessionStateを受け取っているので、一見循環参照か!? と思ったけど保持はしていないです。)。Thriftがどういうモデルなのか分からないですが、仮に接続毎にスレッドを生成しているのであれば、接続がきれた時にSessionStateがThreadLocalから消えて他のどこからも参照がない場合(これはまだ確認してない)、SessionStateはGCの対象になります。その時にHiveHistoryへの参照が全て無くなるので、GC対象となるはずです。

仮定が多くて調査になっていないですね(=w=;)
jmapとjhatでどういう状態になっているか確認すれば良いだけなのですけどね。

お腹すいたのでいったん調査終了(・ω・)

※(追記)
当たり前の事なのでわざわざ書いてませんでしたが、一応捕捉しておきます。
(少なくともJavaでは)openしたものはきちんとcloseすることを明示すべきですし、
別にGCまかせにすることを推奨とも良しともしていないです。(そんな事一言も書いてないですよね(>ω<))
原因となりうるかと、それを良しとするかは軸が違うと思うのです。

(さらに追記)

FindBugsで解析をすると分かるらしいです。
今度試してみます。

ふむふむ。tagomorisさんのtweetによると、CDH3u2との事なので丁度ぶちあたってしまうのですね。
あと、確認したソースのバージョンを明記してなかったです。trunkとCDHu4で見てました。

(追記)2012/06/23 13:00

FileReader(File)はコンストラクタでsuper(new FileInputStream(file)) としていました。
という事で、GC走ればcloseされます。 
簡単な確認テスト: https://gist.github.com/2976972 

せっかくなのでとあるサービスの技術的な事をまとめていこうかなと思ってます。
(作り直しているはずだし、消えるものなら片鱗を残しておこうかなと)

抜け漏れがまだまだあるので、思い出したら随時こっそりと更新していきます。画像も多くなるし、BlogじゃなくてGoogleDocとかのが良いのかな(自分のWikiにまとめる事にしました)。こういう内容は書かないの?とか、このサービス使って書くと良いよとかあったら教えてください。お願いします。
基本的にまったり進行。公開が遅かったらお尻をペシペシと叩いてください。

部署やプロジェクトを兼任していたので、やった事はこれ以外にも沢山ありますが、そのうちの1つとして記録を残します。併せて、なぜそうしたのかという所も覚えている範囲で書いていきます。また、数年前に開発が始まったものですので、今だったらこうするなという事も。
ぼかして書くので抽象的になるかも。
こういう事を去年のCEDECに公募してみようと思ったのですが、作業の遅い自分は間に合いませんでした。

なお、以下の内容はほぼ一人でやった事になります(´;ω;`)ウッ・・

書かないこと

  • 数字に関するもの
  • 内部的な作業フローなど
  • 日々の運用作業について
  • 課金やロビーサーバ、ゲームサーバ、パッチなどの話
    Webから外れるところもばんばん書くことはできますが、このBlogを見ている人はMMOGに興味なさそうだし。興味があれば直接会ったときにでも聞いてください。(言えない事は話しませんけど)
  • 所謂ビジネスロジックと言われるところ
  • 毒・悪口

目次

  • 開発環境について
    • プログラマとプログラマ以外の作業環境
    • レポジトリについて
    • 構成図
    • 継続的インテグレーションについて
    • 開発系のツールについて
    • 通知の話
  • 環境の種類
    • 所謂ステージングとかプロダクション環境とか。全部で5種類。
    • データの共有など。
  • サーバ構成について
  • ミドルウェアについて
    • ミドルウェア一覧と採用した理由など
  • コンポーネントについて
    • HTTPD, APS, Cache, KVS, RPC, Scheduler, MQ, Solr, RDB, API, Watch, ...
  • アプリケーションについて
    • 設計について
    • フレームワークについて
      • どういう構成になっていて、どういうフローで実行されていくか。
    • 機能
      • フレームワークとしての機能
        • 各種ユーティリティ系クラス
        • 多言語、共通基盤、
        • その他
          • BBCodeの実装
          • キーワードハイライタ
      • アプリケーションの機能
        • アカウント(ID/課金、キャラクタ周り)
        • マイページ、通知、日記、グループ機能、フォーラム、画像、イイネ、タグ、フォロー、アクティビティ、プレイログ、検索(4種類)、ランキング
        • バナーやメニュー制御については書かない
      • ニュース・トピックスの話
      • ゲーム連動
      • デバッグの機能
    • テンプレートエンジン
      • 機能の紹介
      • 2,30個以上はあるので他所のエンジンにないものを重点的に。
  • キャラクタのアバター画像について
    • 仕組みについて
    • 夏にやった企画について
  • 検索について
    • 構成の話
    • 拡張した機能について
    • その他
  • i18N対応について
    • ロケールについて
    • リージョンについて
    • タイムゾーンについて
    • アプリ本体
      • 3(4)リージョン
      • 5(6,7)言語
      • Viewレイヤーの話
    • ツール
      • テキスト管理のツールについて
      • 変換ツール
  • JavaScriptについて
  • CDNについて
  • ログについて
    • ログの種類
    • トレースログについて
    • ユーザーログについて
    • その他
  • ログの解析について
  • 監視について
    • 監視の仕組み
    • 通知について
  • RPCサーバについて
    • プロジェクト間共有の仕様でトランスポート層とかの仕様まできっちり決めてあるが、細かい事は言えないので概要。
    • プロトコルの概要
    • 実装について
  • APIサーバについて
  • IRCDの活用について
  • 管理ツールについて
    • 運用をするためのツール
    • モデレーション
  • 運用ツールについて
    • FTPを使わない話
    • NFSを使わない話
    • 作ったツールの話
  • デプロイの話
  • メンテナンスについて
  • 各種障害の内容について(書ける範囲で)

むかしむかし、とある会社で3日で作ったツールについてのお話。

昔の社内勉強会用の発表資料が出てきたので、せっかくなので晒してみようと思います。(健全な男子が喜ぶ系のシステムの資料も出てきたのですが、これはまたの機会に・・・)
3年くらい前のもの(ソースみたら2009年でした)なので、そのあたりを考慮していただけると助かります。

なお、Web系の企業では動画とか全然だと思いますが、コンシューマ系の開発だと動画でやりとりできると便利ですよね。

さすがに資料をそのまま載せるわけにはいかないので、所々塗りつぶして、末尾にページを何枚か追加しました。
そういえば、CEDECである人が発表でちょこっと触れたみたいで、4gamerにもスライドが載っていたのですが、名前伏せられてるし(ツール名にプロジェクト名が入っていたので広報チェックでNGになったんだと思います)、モザイクかかってるしでちょっと悲しかった記憶を思い出しました。

(追記 2012/06/28 10:00)
・資料中のRAIDの説明がなんかおかしいです(RAID""二重化)。二重化+パリティのRAIDでNetAppだったらおそらくRAID4の事だと思いますが、詳細は私にはわかりません。
・資料の31ページが見れないという事でしたが、今見たら見れるようになってました。うーん・・?

ツールの概要を一言で言うと、ニコニコ動画のぱくりです。
プロトタイプを1日で、その後2日で作り直したものです。その後細かい修正はちょこちょこ入れてましたが、基本的には放置運用でした。(ごめんなさい・・)

本来の業務を放り出して、これのために3日みっちり作業しました。
一番時間がかかったのは、デザインをニコニコ動画っぽくする事とメンテ画面のトロがナイスボートって言ってる画像を探す時間です。単体テストのコードがほとんどありませんし、正直ソースコードはかなりひどいです。
いくつかのプロジェクトから、欲しいクレクレと来ましたがソースコードを見て絶望したと思います。

作った理由は、スライドにもありますが、
・単純にそこらへんに動画を置かれるとファイルサーバが死んでしまう事
それと、
・ローカルで動画をエンコードするとその間他の作業が出来なくなってしまう
・その動画、他の人全員が見れる形式とは限らない&codecによってはライセンスの購入が必要
という事です。

当時の心境を思い出すと、現実逃避も含まれていたと思います。(煮詰まっているときに他の作業すると楽しいですよね:p)

データセンターに置かなかった理由は、
・ネットワーク帯域がやばい事になる
・データセンターに置く機材の話とか発注とか予算とか
それを正攻法で解決しようとすると、いろんな人といろんな調整をしないといけなくなり、それには膨大な時間がかかります。(これは組織の問題かもしれませんけどね)
余ってるPCなら稟議とか要らないし、ソフマップでHDD買えば普通に経費で落とせるし。
※こんなやり方、真似しちゃダメですよ。いろんな人のヘイトも上がるし、後々面倒な事になります。(当時の状況として大人の事情ってやつがいっぱいありまして.. アルヨネ?そーいうこと。)

MP4をコンテナにしたのは、その当時FlashでMP4/H264を再生できるようになったからです。みんなが見れる環境(つまりブラウザで再生できるもの)であれば何でも良かったのですが、H264画質がすばらしいですし。(画質にうるさい人が多いというわけではなく、画質が悪いと動画中の文字がつぶれてしまう)

一番問い合わせが多かったのが動画がエンコードできないというもの。
みんなFrapsで撮影しているものかとてっきり・・。

アップロード部分をFlashにしているのは、アップロードの進捗状況を分かりやすくするため(アップするファイルが未圧縮なので巨大ですし)と、ブラウザのアップロード2GBの制限(これはブラウザによりけり)を避けるためです。
それなのに、Apacheのビルドをミスって2GB以上アップロードするとContentTypeがオーバーフローして、アップロード出来ない状態が残念です・・。(ajp_proxyもtomcatも確認しましたが、apacheのレイヤーでNGになってました。)

というわけで、いくつか画面をキャプチャしました。私の家で動かしたものになりますので、サンプル動画として私のコレクションをアップしています。当たり前の事ですが会社でこういう動画を共有していたわけではありません。(と、当たり前の事を書いておかないと時々勘違いをした人が騒いだりするので)

TOPページ。
社内(プロジェクト)共通のLDAPがあったので、それを使ってユーザー識別してました。

アップロード画面。
アップロードするファイルのサイズが大きいので、簡単なプログレスを付けてあります。解像度は縮小無し~HD、SD等のサイズを選択できます。有効期限は無制限、1年などなど。これはエンコードした動画を削除する期限ではなく、オリジナルの期限です。基本的にエンコードした動画は削除しない方針でした。

アップロード完了
すると、こんな感じの画面になります。

アップ後
動画をアップすると、キューもどきに入ってサムネイル生成待ちの状態になります。

サムネイル生成
エンコードサーバで動いているデーモンがキューもどきを見ていて、最初にサムネイルを作ります。マウスカーソルを合わせるとパラパラと表示されます。海外の動画サイトに良くあるアレです。

エンコード
サムネイルの生成が終わったら動画のエンコードを開始します。
エンコードの状況をヘッダで表示できます。今どれくらいまで変換しているのか確認する事ができます。
なお、失敗しても(しなくても)リテイクしたい場合はフラグを立てるだけです。

動画の再生ページ。
全画面表示とかもできます。右上のアイコンからメタ情報の編集とか、ダウンロード(MP4 or オリジナル)ができます。

動画の編集画面。
まぁだからなんだって話ですが。。。スライドにも書きましたが、ブラケットで括るとタグとして認識します。

検索画面。
タグを押すとこの画面に飛びます。画像だと1件しかなくて見栄えがあれですね。

簡単なログ画面。
何が起こっているのか知りたい人向け。

RSSは、サイト全体のもの、ユーザー毎や動画毎にあるので、自分が投稿した動画にコメントがついたみたいなものが取れます(たぶん、つけた気がする)

何かを導入したり、使って欲しいものがある場合、一番手っ取り早い方法は本来の趣旨を主張するのではなく、メリットを主張するのが良いと思っています。例えば、Subversionのようなものを使って欲しい場合に、リソースを集中管理して履歴が追えて~とかじゃなくて、レポジトリに入れる事で裏で自動でリソースを変換します、HTMLファイルだったら文法チェックしてくれます、誰が何をやっているのかわかるようになります。とか。このツールもHDDが~とかじゃなくて、ローカルで変換しなくてもアップロードするだけで、あとは良い感じに全部やってくれます。とかとか。
まぁ管理者の幸せとユーザーの幸せはまったく異なる事がほとんどですので、それを押しつけても説得なんてできませんよね。

ツールを作るときは、他のシステムとも連携できるようにAPIを用意したり、何かのプロダクトにべったり依存しないようにするのが理想だと思いますが、当時の私はまだまだ未熟でそこまで気配り出来ませんでした。今なら似たようなプロダクトがあると思うのでそれを使うのが良いと思います。

世の中、他社には面白いツールがいっぱいあるんだろうなぁとイロイロ気になります。
こっそり教えてください(・ω・)