Archive : 2009
昨日開催された、 プログラミング生放送勉強会 第2回 @新宿に行ってきました。ニコニコ生放送のプログラミング関係のオフ会ということなのですが、自分はそれまでニコニコ生放送というものを見たことがなかったので、若干どんなノリの会なのか分からずに行ったのですが、まぁ、わんくま勉強会と似たようなノリで、楽しんで帰ることができました。やはり、動画でセッションの模様を中継でき、それに対する反応がネットの向こう側で観ている側から帰ってくるというインタラクションは大変面白いですね。ただ、帰ってくる反応も、ニコニコ動画のカルチャーに影響されているところがあり、もっとフォーマルなイベントで公式に使うのは難しいだろうなということも身をもって感じました。
さて肝心の内容。色々面白い話が多かったですが、.NET好きという自分の性格も手伝って、Live Labs Pivotの紹介話とXBox LIVE インディーズゲーム製作苦労話、Gainer紹介といくつかのLTが特に面白かったです。
Live Labs Pivotは、事前に名前しか知らずに行ったのですが、あれはある形式に則ったデータを食わせたら、それをSeaDragonテクノロジ他を使って綺麗に整理して見せるデモアプリケーションというイメージで良いんでしょうか。インビテーションを取得するのが手間そうなので実際に使ったわけでないのですが、デモを見る限りWPFで実装されているのかな?いつかLive wave xでWindows LiveやBingのオプション機能として、このようなインターフェイスがSiverlightを使って実装されて欲しいものです。
XBox LIVE インディーズゲームの話は、XBox LIVE インディーズゲームを実際に製作されている方が、製作にあたっての技術的でない苦労点を語ったセッションでした。やっぱり、家庭用ゲームコンソールで動くゲームを作って販売できるというのは大変魅力的な話のようですが、それに見合った苦労もされていうようで、iPhoneアプリ同様アメリカへの税金払い方の話だとか、表現の規制に関する話だとか、インターフェイスに使う言語の話だとか。表現の規制の話は、まぁ家庭用ゲーム機なら控えめにならざるを得ないというのはよくわかる話だったのですが、ゲームのインターフェイスに使われる言語に、日本向けのゲームにアルファベットが使われているだけで外国人からピアレビューで差し戻しを受けて直さざるを得なかったというのは、どう考えても運営方針が間違っているような。。まだ始まったばかりの仕組みなので運営側も試行錯誤している段階なのでしょうが、聞いている限りだと、製作者と運営側のコミュニケーションロスによる問題のような気も。やっぱり海外で作られているスキームを使う場合には、こちらも交渉できるだけの英語力が求められるのだなぁと勝手に納得してました。
Gainer。イケメンのための雑誌の方じゃないよ、電子工作の方だよ、というギャグほか、スピーカーの方のしゃべりの上手さに大いに笑わせてもらったセッションでした。Gainer、面白そうですね。なんちゃって理系ですらないSFCでぼんやり過ごしていると、電子工作方面への知識が全く欠けているのですが、Gainerは自分みたいな高級言語ばっかり触っている人間が電子工作始めるのに最適なおもちゃだということがよく分かりました。PCの中に立てたローカルなサーバーを叩いてやるだけでいいというのは非常に手軽ですね。。近いうちに買いたいと思います。
そいういえば場所はMicrosoftの新宿オフィスのセッションルームの一室だったのですが、新宿のサザンテラス口側は結構イルミネーションが綺麗なんですね。向かいの高島屋や紀伊国屋側も綺麗ですし。
先日申し込んでいたインストールマニアックス3 Hyper-V祭り、ありがたいことに当選しまして参加できることになり、昨日の朝、NEC Express 5800/S70が家に届きました。インストールマニアックスとは、
WindowsサーバーにOSSをいくつインストールできるかを競うコンテストです。参加者は、無償で提供されたサーバーハードウェアとOSを使い、Windows+IISを使用してできるだけ多くのソフトウェアインストールを行い、その評価点を競います。
というイベントです。Windows Web Server 2008 R2とOSSの親和性の高さをプロモーションしたいということなんでしょうね。ハードウェアはそのまま頂けるという話なので、こちらとしてもこのようなイベントは嬉しい限りです。こちらが届いたマシン:
今回のインストールマニアックスは、Hyper-Vで仮想化した環境上でWindows Web Serverを動かせ、という条件付きなので、それに合わせて配布されるハードウェアも大盤振る舞いで、CPUはIntel Core2 Duo CPU E7400 @ 2.80GHz、メモリは2GBという構成。
というわけで早速開腹作業。
このマシンのために前日買っておいた1TBのHDDの増設をしました。このイベントで使う分には元々積まれていた分で多分十分なのですが、ちょっとWindows Web Serverをインストールする前にやりたいことがありまして。。それはESXi ServerのDatastoreとしているExpress 5800/110aのメンテ。110aは1TBのHDDを増設したうえでFreeNASを入れ、iSCSIターゲットサーバーとしてESXi ServerのDatastoreとして動かしているものなのですが、どうも大量にファイルアクセスしたときに落ちたり、Windowsファイル共有の転送速度が思うように上がらなかったりするので、openfilerにOSを入れ替えようと考えており、一時的にVMのイメージを退避する為に今回届いたS70を使うことにしました。というわけでopenfilerをインストール。
うん、いい感じ。
生きてます。
なんだかんだ言って、やっぱり投稿が減った原因はTwitterですね。。Twitterの方が、圧倒的に書くのが手軽だし、何か書いた時に貰えるレスポンスが多いし、でBlogをサボってしまっています。良くないですね。別にTwitterで良いじゃん、Blog書かないでも、という考え方もあるのでしょうが、やっぱり良くないと自分は感じていて、というのは、やはり、Twitterというサービスは、Blog以上にリアルタイムのストリーム的な特性が強く、Tweetの内容が、その時自分をフォローしてくれている人にしか届かず、後からその情報を求めてGoogleなどで検索した人に上手く届けることができないのが問題だと思っています。これは、Twitterのサイト構造が、古いTweetを積極的に見せようとしていないということ以上に、140文字という文字数制限が、Tweetのコンテキストを削ぎ落としてしまっており、検索に引っかかりにくくなっているというのがあります。ぼちぼちまた書いて行きたいなぁと思っています。
大学の授業で自宅のネットワークのトポロジ図を書けという課題が出たので、Visioの試用版を使い、見よう見まねで書いてみました。ちゃんとした書き方は教わっておらず、「思うように書け」ということだったので、おかしなところも多いでしょうが。。
こうしてみると、結構充実してますね。。 ここ一年ぐらい、自室の機器の増設にバイト代のかなりを注いでいて、気がついたこんな状態でした。
最近の変更としては、FreeNASを入れたNEC Express5800/GT110aを追加し、iSCSI Targetとして動かし始めたことでしょうか。また、それにあわせてGbE対応スイッチを無線イーサネットコンバータの下に設置し、自室内での通信をギガビット化しました。NEC Express5800/GT110aは、NEC製の激安PCサーバー。ほんと安いですねぇ、一万円台とは。NICがGbEに対応しているファイルサーバーが必要だっただけなので、これで十分です。これを買うに当たっては、ML115にも心惹かれたのですが、その時たまたまNTT-Xで品切れだったことから、今回は見送り(泣)。とまれ、これに1TBのHDD*2をRAID1を組むために増設し、FreeNAS 7.0RC1を入れれば立派なiSCSI Targetの出来上がりです。ZFSもサポートされているので、よくZFSはわかっていないのですが、使ってみています。
FreeNASでiSCSIターゲットを作って何に使っているかというと、先日構築したVMware ESXiのDataStoreとしています。VMware ESXiはハイパーバイザ方式で動作が軽いので、ついついVMを追加してしまうのですが、そうやってVMをたくさん作っていると、あっという間にHDDが食いつぶされていきます。もともと500GBのHDDを内蔵させて自作したマシンなのですが、ケースがShuttleのCube型ベアボーンなので、HDDを増設する余裕がありません。そこで、熱源を少しでも外に出す意味でも、またRAIDを組むためにも作ってみました。
ちなみにGbE対応スイッチは、NETGEARのGS2108A。折角iSCSI Targetを構築したのに、100BASE-TXでリンクアップしているのでは、USB接続のドライブにも劣る!ということで購入。金属筐体の方が良いとは聞きますが、8portで\4000切ってますし、三年保証さえついているので、アタリだったかなと考えています。
Windows 7発売記念プロモーションの一環としてBURGER KINGから期間限定で発売されたWindows 7 WHOPPER食べてきました。
これ、隣に置いてあるのiPod Touchなんだぜ…。どんだけ大きいんだ。
完食した自分偉い。よく頑張った。。
良い良いと巷で人気のiPhone/iPod Touch。いったいどれほどのものかということで、つい新iPod Touch 32GB買ってしまいました。いやホント良いですねコレ。Windows Mobileのもっさり感に慣らされた身としては、どうしてこれほどヌルヌルUIが反応するのか不思議でなりません。これがGPUのサポートの威力なのでしょうか。。
本当に生活スタイルを変化させるシロモノで、移動中はほぼiPod Touchを弄っています。様々なアプリの中でも、一番気に入っているのはBylineというRSSリーダー。Google Readerと同期が可能なRSSリーダーで、エントリのパーマリンクが紐付けられたページのキャッシングにも対応しているタイプのものです。朝、家を出るまでにWifiにぶら下がって新着のエントリをダウンロードしておき、通学中にバシバシRSSの消化を行い、大学に着いたら、同じくGoogle Readerと同期させているFeed DemonというRSSリーダーで残りや、詳しく読み込む必要のあるエントリを消化するというサイクルを確立することが出来ました。
一応E-Mobile版Touch Diamondの方にはWifi Routerという、Windows Mobile端末を無線LANのAP化するアプリを入れ、移動中もネットが使えるようにしているので、カメラがない以外はiPhoneっぽいことが出来るようにしているので中々快適です。
ただ、不満もないわけではなく、例えば、マルチタスクをサポートしていないのは残念な点です。上でBylineのキャッシングについて述べましたが、Bylineがキャッシュを作成している間にも、並行して他のアプリにキャッシュを作らせるというようなことが出来ないのが不便です。Bylineの同期作業が終わるのを待って、GNReaderなり、他のアプリを起動しなければならないわけですから。この点では、Androidの方が自分の好みに合ったつくりになっていると聞いているので、期待したいものです。
みんな大好きWordPress。だからこそ、データが飛んでしまうのはなんとしても避けたいもの。そのためには、常日頃からデータのバックアップを取っておくのが重要なのですが、いちいち手動でバックアップするのは手間なので、なるべく自動化しておきたいものです。バックアップしたいのは次の二つ:アップロードしたファイルとMySQLのダンプ。そこで、UNIX環境の勉強がてら、今このブログが設置されているXREAのサーバーから、ローカルに立てたサーバへ自動的にバックアップする体制を整えてみることにしました。今回のエントリではその方法をまとめてみました。
処理の流れ
今回XREAのサーバーに設置したWordPressのデータをバックアップするにあたっては、まず、XREAのサーバー側で、MySQLのデータをダンプし、圧縮をかけてファイルとして保存する、という処理を行います。その上で、ローカル側に設置したサーバーで、ryncという差分コピー可能なコマンドをつかい、SSHを通じてサーバーからMySQLのダンプしたデータや、アップロードした画像、WordPressの本体やプラグイン、テーマをひっくるめて同期します(Pull)。そして同期したディレクトリを元に、pdumpfsを使い世代別バックアップを作成します。この処理をcronで毎日実行してやるという流れです。
このように今回はcronやrsyncを使うために、ローカル側に、毎日その時間に起きているUNIXなマシンが必要になります。そのため今回のエントリは、ファイルサーバーにするなどで自宅サーバーを運用している人以外にはハードルが高いかも知れません。ただ、起きっぱなしのサーバーが家に一台あれば、前述のようにファイルサーバーに出来るなど何かと便利ですので、これを機に、自宅サーバー構築に手を出してみるのもおススメです:D 遊んでいるマシンがあるなら、それにLinuxを入れてしまうとか、遊んでいなくても常時起こしておけるWindowsマシンがあれば、VirtualBoxを入れてその中でLinuxを動かすとか、色々方法はあります。
バックアップ手順
まずは下ごしらえ。ローカルのサーバーからリモートのサーバー(XREA)に対して操作を行うわけですが、そのためにはSSHで接続できるようにしなければなりません。XREAへのSSHでの接続については、こちらのhiromasaさんの記事を参照。但し、今回は、バックアップの自動化が目的なので、そのプロセスで手動でのパスワードの入力を求められるのは困るので、パスフレーズを空にした鍵による公開鍵認証を使います。ssh-keygenを使ってローカルのサーバーで鍵ペアを作り、公開鍵をリモートのサーバー(XREA)に配置しましょう。鍵ペアの作り方についてはssh にてパスワードを使用しないでログインする方法を参照。
次にMySQLのダンプと圧縮。と言っても、難しいことは何もありません。これについてもhiromasaさんが既にサーバー側のcronで定期的にMySQLをダンプする方法についての記事を書かれています。これを使わせてもらいましょう。今回は、pdumpfsで世代別バックアップを取っているので、日付別に保存しないように改変したものを以下に示します。
#!/bin/sh
# 設定(ここを自分に合わせる)
DATABASE=
DBUSERNAME=
PASSWORD=
XREAUSERNAME=
BACKUPDIR=
KEEPDAY=14
# 初期化(XREA/CORESERVER用)
PREFIX=mysql
SERVER=localhost
NOWDATE=`date +%Y%m%d`
DESTDIR=/virtual/$XREAUSERNAME/$BACKUPDIR
# DUMPFILE=$PREFIX.$NOWDATE.dump
DUMPFILE=$PREFIX.dump
# TARFILE=$PREFIX.$NOWDATE.tar.gz
TARFILE=$PREFIX.tar.gz
OLDDATE=`date "-d$KEEPDAY days ago" +%Y%m%d`
# MySQLダンプ/圧縮
cd $DESTDIR
/usr/local/mysql/bin/mysqldump $DATABASE --host=$SERVER -u $DBUSERNAME --password=$PASSWORD > $DUMPFILE
tar zcvf $TARFILE $DUMPFILE
# 処理判定
if [ $? != 0 -o ! -e $TARFILE ]; then
echo "backup faild -- ($DUMPFILE)"
exit 1
fi
# 圧縮前ファイル削除
rm -f $DUMPFILE
# n日ローテートを削除
#rmfile=$DESTDIR/$PREFIX.$OLDDATE.tar.gz
#if [ -e $rmfile ]; then
# rm -f $rmfile
#fi
cronの設定をしない以外は、記事の通りにXREAのサーバーに配置し、設定を書き換えてやれば大丈夫です。では、試しにSSHを通じてコマンドを発行し動かしてみましょう。ローカルのサーバーで以下のコマンドを実行してみましょう。
ssh -i <秘密鍵へのパス> <XREAのユーザー名>@<サーバ名> <hiromasaさん製スクリプトへのパス> #ウチの環境だと以下のようになります。 ssh -i ./nopass sharplab@s333.xrea.com /virtual/sharplab/backup-mysql/mysqlbackup.sh
動きましたか?動かない?SSHの接続が拒否された?それはもしかすると、XREAのサーバーにホスト情報を登録し忘れているせいかもしれません。hiromasaさんの先ほどの記事を参考に登録を行ってみましょう。
さて、とりあえず手動で登録すればよいことは分かりましたが、登録の有効期限は30日間だけに限られています。また、出先でSSHで繋ぐために別のIPアドレスを登録した場合、上書きされてしまい、再度登録しないと繋がらなくなってしまいます。そのため、ホスト情報の登録も自動化する必要があります。そこでこんなスクリプトをPythonで書いてみました。
#!/usr/bin/env python
# vim:fileencoding=utf_8
import sys
import urllib
import re
#ここを書き換えてください
server = ''
username = ''
password = ''
ipaddressResponder = ''#'http://scripts.sharplab.net/ipaddress.php'//←ウチの場合
adminURL = 'http://%s/jp/admin.cgi' % server
try:
ipRes = urllib.urlopen(ipaddressResponder)
ipaddress = ipRes.read()
except:
print u'Failed'
sys.exit()
pattern = re.compile('\d+\.\d+\.\d+\.\d+')
if pattern.match(ipaddress) == None:
print u'Failed'
sys.exit();
values = {'id':username, 'pass':password,'remote_host':ipaddress,'ssh2':'SSH登録'}
data = urllib.urlencode(values)
print u'Registing ipaddress(%s)...' % ipaddress
response = urllib.urlopen(adminURL,data)
try:
response.read().decode('shift_jis').index(u'データベースに追加しました。反映には5〜10分程度掛かります。')
print u'Complete!'
except ValueError:
print u'Failed.'
まず、前もって接続してきたホストのIPを返すPHPのページをサーバーに設置し(ipaddressResponder)、そこにアクセスすることでホストのIPアドレスを調べています。PHPのページのソースはこう。
<?php
echo getenv("REMOTE_ADDR");
?>
その上で、調べたホストのIPとユーザー名、パスワードをホストの登録ページにPOSTするだけの簡単なお仕事です。Cookieとか憶えないといけないかなと思ってPython Mechanize使おうとしたのですが、必要なかったです(笑)
さて、ここまでで、SSHを通してサーバー側でMySQLをダンプする処理と、SSHのためにホストを自動登録するスクリプトの準備が出来ました。では次はいよいよ本題、rsyncによるファイルのバックアップです。rsyncによるリモートバックアップは、リモートとSSHで繋げ、リモートにもrsyncが入っていれば使えると記憶していますが、XREAはどちらも満たしています。他のレンタルサーバーでも、SSHで繋げるところなら使えるところはあるかと思います。
ではrsyncのコマンドを。
<rsyncへのパス> -avz --delete -e 'ssh -i <秘密鍵へのパス>' <XREAのユーザー名>@<サーバー名>.xrea.com:<バックアップしたいディレクトリへのパス> <同期先へのパス> #ウチの環境だと以下のようになります ./rsync/rsync -avz --delete -e 'ssh -i ./nopass' sharplab@s333.xrea.com:/virtual/sharplab/ ./sharplab/workspace
これでXREAのサーバーとローカルのサーバーの中身を同期させられます。rsyncは更新のあった差分のみをやり取りするので二度目以降は効率が上がるのが嬉しいですね!
そしてpdumpfs。同期したフォルダをソースに、世代別バックアップを作ってやります。pdumpfsはハードリンクを活用しているので、毎日世代別バックアップを取っても、更新がかかったファイル分位しか必要とする領域が増えないので使うのに気が楽ですね。
pdumpfs <ソースディレクトリ> <バックアップ先ディレクトリ> //ウチの環境だと以下のようになります pdumpfs ./sharplab/workspace/ ./sharplab/backup/
ではこれらをまとめた上でcronに登録してみましょう。
まずバックアップ処理手順をまとめたスクリプトを作成します。
#サーバーに配置したMySQLのダンプ&圧縮スクリプトを起動 ssh -i <秘密鍵へのパス> <XREAのユーザー名>@<XREAのサーバー名>.xrea.com <hiromasaさん作のスクリプトへのパス> #サーバー全体をworkspaceディレクトリと同期 <rsyncへのパス>/rsync -avz --delete -e 'ssh -i <秘密鍵へのパス>' <XREAのユーザー名>@<XREAのサーバー名>.xrea.com:<バックアップ対象としたいディレクトリへのパス> <一時保存先のディレクトリへのパス> #pdumpfsで世代別バックアップ pdumpfs <一時保存先のディレクトリ> <バックアップ先>
そしてこれを毎日呼び出すようにcronを設定します。
HOME=<registHost.pyやbackup.shを配置したディレクトリ> #毎日午前四時 SSHを使うにあたり、ホスト情報をXREAに登録 0 4 * * * <registHost.pyやbackup.shを配置したディレクトリ>/registHost.py #毎日午前四時十分 XREAのバックアップの本処理 10 4 * * * <registHost.pyやbackup.shを配置したディレクトリ>/backup.sh
さて、最後に忘れちゃいけない作業があります。
それはバックアップのリストア作業のテスト。バックアップをとったは良いけど、実はうまく取れていなくて、いざ必要になった時に使い物になりませんでしたでは悲しすぎます。忘れずにリストア出来るか確認しておきましょう。お疲れ様でした!
以前あげたC# .NETアプリケーション開発 徹底攻略 Listing2.26への疑問 – SharpLab.というエントリに対して、なちゃさんから、
なちゃ 09-09-23 09:15:19 JST
本来、デリゲートでBeginInvokeした場合は、必ずEndInvokeする必要がありますね。
リソースリークなども発生する危険があります。
※デリゲート以外でもBegin~系は基本的には同じですがEndInvokeさえすれば、きちんと発生した例外がスローされてきます。
けして例外が握りつぶされているのではなく、正しく使っていないために握りつぶされているように見えているだけですね。
ちょっと書籍の記述がまずいと思います。
という指摘がありました。なるほど!指摘の通り、Begin EndパターンなのでEndInvokeを必ず呼び出す必要がありました。恥ずかしながらすっかり失念していました。。というわけでEndInvokeを使うように修正。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Threading;
namespace SharpLab.ThreadExceptionTest {
static class Program {
static Form form;
/// <summary>
/// アプリケーションのメイン エントリ ポイントです。
/// </summary>
[STAThread]
static void Main() {
Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(Application_ThreadException);
Thread.GetDomain().UnhandledException += new UnhandledExceptionEventHandler(Program_UnhandledException);
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
form = new Form();
Application.Run(new Form1());
}
static void Application_ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) {
MessageBox.Show(e.Exception.Message);
}
static void Program_UnhandledException(object sender, UnhandledExceptionEventArgs e) {
Exception ex = (Exception)e.ExceptionObject;
MessageBox.Show(ex.Message);
Application.Exit();
Environment.Exit(0);
}
}
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace SharpLab.ThreadExceptionTest {
public partial class Form1 : Form {
public Form1() {
InitializeComponent();
}
private delegate void SampleDelegate();
private void button1_Click(object sender, EventArgs e) {
SampleDelegate a = new SampleDelegate(ThreadMethod);
a.BeginInvoke((asyncResult) => {
a.EndInvoke(asyncResult);
}, null);
}
private void ThreadMethod() {
//意図的に起こした例外
Thread.Sleep(5000);
throw new Exception("非同期スレッドで起こった例外です。");
}
}
}
こんな感じでしょうか。ちゃんとサブスレッドで例外が発生した時にUnhandledExceptionが呼び出されるようになりました!これで正しく確実な終了処理ができそうです。サブスレッドの処理内容をすべてtry~catchで括って必要に応じて例外をリスローする必要があると憶えていたのですが、そうではなかったのですね。いつもtry~catch書きながらなんかおかしい気がしていたのですが、これですっきりしました。なちゃさん、ありがとうございました。
前のエントリで紹介したWebkit.NETはまだC#などのコードからDOMにアクセスする方法は実装中であるため、正式には提供されていません。提供されているのは基本的なナビゲーションなどに限られています。そのため、出来ることは相当制限されています。がしかし、表示されているページの中でJavaScriptのコードを実行させる方法がForumに上がっていましたので紹介します。これがあれば多少の助けにはなりそうです。
ソースコードはこんな感じ。
private void button1_Click(object sender, EventArgs e) {
FieldInfo fi = typeof(WebKitBrowser).GetField("webView", BindingFlags.NonPublic| BindingFlags.Instance);
WebView webView = (WebView)fi.GetValue(this.webBrowser1);
webView.stringByEvaluatingJavaScriptFromString(@"document.body.innerHTML = 'Hello Webkit DOM!';");
}
リフレクションを使っています。WebKitBrowserにはwebViewというprivateなメンバがあり、それはWebViewインターフェイスを実装しています。このwebViewをリフレクションで取得し、そのメンバにstringByEvaluatingJavaScriptFromStringというJavaScriptコードを引数として渡してやると実行してくれるメソッドがあるので、これを利用するという方法です。このメソッドの戻り値の型はstringなのですが、実行結果を取得することはどうもできないようです。 WebViewの他のメンバの実装がどれぐらい進んでいるかはまだ試していないのでわからないのですが、WebViewについては、Webkitですし、Cocoaのリファレンスを参照するとよさそうな感じがします。
