※ パクレゼルヴではWeb開発エンジニアを大募集中!詳細はこちら

Archive

Archive for the ‘Linux’ Category

データベース設計

2008/7/29 火曜日 20:16:03

チョコボールakaモリモリ~です。

7月から携帯コンテンツの開発に加わることになりました。
今までは管理画面系が多かったので携帯に関する知識はほとんど無かったのですが、携帯3キャリアに対応していくためのコーディングやセッションの引き回しについてなど、少しずつ覚えてきました。

今回はデータベースについて思うこと…を。

今まではDB操作はずっとphpMyAdminに頼ってたんですが、コンソールを使うようにと指示が出て、最近はひたすらSSHでカタカタとやってます。
慣れてくるとサクサク処理出来て快適ですね。
早いというか、それが通常の処理の早さってことなんでしょうけど。。

個人的に作ってるサイトはSSHが使えないレンタルサーバーなのでDB操作はphpMyAdminを通してやるしかないのが残念です。

自分は業務でデータベース設計をすることはありませんが、実際に使う時のことを考えて、できるだけ複雑なJOINやサブクエリをさせないようにうまいこと設計しないと、のちのちレコードが増えてきた時にパフォーマンスにモロに影響が出る、と実感しました。
あまりにも関連テーブルを分けすぎるとSQL組む時、かなり複雑になります…。

データが1000レコードでSELECT文、オフセット10でデータひっぱってくるのに10秒以上かかる。
こんなシステムに遭遇。。
発行されたSQL文を見てみると、JOIN、サブクエリが複雑に絡み合って恐ろしいことになってました。

一つの複雑なSQL文で全てやろうとするよりもSQLを何回かに分けてプログラム側でごにょごにょやると取り敢えずパフォーマンスは改善しそうな予感です。

今後データベース設計する機会があったら活かせるとよいなーと思います。

チョコボール Linux, MySQL, PHP, データベース

シェルスクリプト作ったよ。

2008/5/30 金曜日 12:08:14

こんにちは~!べきこですよ。(´ー`)

ようやくサーバ側のお仕事に慣れてきました。

インストール時にいろいろ細かい設定するためにシェルスクリプトを使うので、
せっかくだから中身をもっと充実させようと!(そして自分が少しでも楽になろうと・・)

ということでファイル作ったり、移動したり、値変更したり~なものを作ってたのですが、、
mysqlが動きません。。なんで?(´・ω・`)

検索してて見つけたのが
シェルのオプションにデバッグがあるらしいです

sh -x test.sh

実行コマンドにこのオプションを加えるだけで、実行されたものがすべて表示されます。

cp /home/test/test.php /var/www/test/test.php
chmod -R 755 /var/www/test/
chown -R test:test /var/www/test/

こんな感じで、実行したコマンドが表示されます。

このログではあらかじめ指定してあった変数もきちんと表示されているので便利です。

で、結局なんでMySQLが動かなかったのかというと・・・
パスがちゃんと通ってなかったのと、MySQLでは使わないコマンドが途中に入っちゃってたのというわけで・・・

(( ;゚д゚)アワワ

もっとお勉強してきます・・

べきこ Linux, Tips

バックアップその2

2008/5/29 木曜日 19:12:51

新規サービスオープンのため対応中。姜子牙です。
本体のネタ以上にこの冒頭のネタを練りこんでいたりすることがあります。

2/22のエントリでバックアップについて記載しましたが、今回はバックアップ第二弾を書きたいと思います。

さて本題、バックアップは何重に取るべきか?

バックアップの対象となるデータをマスタデータと呼んだ場合、それを一つコピーしてバックアップすると1重とします。
私は基本は2重に取るようにバックアップは設計しています。1重ではやや不安で、3重だと余剰だろうと考えています。
2重の場合、マスタデータ含めて3つ同じデータが存在することとなります。

ここでのポイントは「このバックアップでマスタデータが何個分存在することになるか」です。

よくあるのが、AというディレクトリのデータをBというディレクトリが常に同期していて同じデータが入っているのに
AもBもバックアップに含めてしまう、ということがあります。
これだとマスタデータはAのディレクトリのデータなのに、Bのディレクトリ、Aのバックアップ、Bのバックアップという形で
4つも存在してしまうことになるわけです。

多ければ多いほどデータの消失確率は減りますが、逆にその分ディスク容量を圧迫することになります。

なので、私の場合、上記A・Bのディレクトリがあった場合、Aはバックアップ対象としますが
Bはバックアップ対象から外すように設定をするわけです。
こうするとAディレクトリ、Bディレクトリ、Aのバックアップでマスタデータ3つ分というわけです。
まあ、他の同期していないデータとかと一纏めにする都合でAバックアップのコピーが生まれるので
データ4つになっちゃうんですけどね・・・。

もう少し具体的に言えば
更新系を司るマスタデータベースがあって
それのホットスタンバイであるスレイブデータベースがあって
マスタ・スレイブそれぞれでバックアップ取って
さらにそれぞれのバックアップを2重化したりすると
データ6つ分になっちゃったりするんですよ・・・。
いや、うん直さないといけないですけどね・・・。

やや余談になりますが、
サーバがRAID1の場合、その時点でマスタデータが2重だからバックアップ1個取れば3重と言えなくもないですが、
私個人の考えとしてRAID1でコピーされるデータはバックアップとみなしていません。
あくまで、HDD物理障害対策の機構であって明示的なバックアップではないと考えているからです。
|-’) HDDが無事でもRAIDのカードやチップが往生してしまうこともあるし・・・。

まあ後半はやや個人意見だらけなので、こんなんあるんだ程度としておいて頂いて
バックアップを設計する時は一度マスタデータが何個分になっているか意識してみると良いかもしれません。

[Mr.マカー](#゚Д゚) < 「で、バックアップサーバどうすんの?」
[姜子牙](;’-') < 「あ、えーと今のサーバのディスク枯渇するまでもうちょい時間あるので検討します・・・。」
[べきこ] (´ー`) < 「時間経って忘れてると大変なことになりそうだね」
[姜子牙] ∑(;’-') < 「ドキッ」

はい、冗談にならないです。

姜子牙 Linux, Tips, その他

メール配信

2008/5/16 金曜日 18:08:10

暑かったり寒かったり雨が降ったり降らなかったり。

皆様いかがお過ごしでしょうか。こんにちわ。かーつんです。

さてさて、今回はなにを書こうか悩んでいたのですが、

良いネタが見つからなかったので、直近のお仕事の様子でも少々。

現在、会員様向けにメール配信を行う用のスクリプトを作ってるんですが、

色々と難航しております。

3つのサーバから1つのDB参照して、同時稼働。

なんか昔バッチ組んでるときに似たようなことしたなぁと思いながら、

正直覚えて無くて、超抜けまくり。

のびーにょ先生に怒られツッコまれながら四苦八苦しております。

で、気をつけるべき点で、残しておきたいと思ったことを以下に記しておきます。

1.コネクション数・SQL発行回数を極限まで減らして一括でデータ取得すると、

  同時稼働している3つのサーバに同じデータが取得される可能性がある。

  ⇒回避策⇒

   データテーブルとは別にカウント用のテーブルをテンポラリとして作成して、

   取得した件数をそっちに残しておけば、

   サーバジョブ起動タイミングを少しずらすだけで異なるデータを一括取得できる。

   但し、ジョブを途中で中断したときにデータに不整合が起こるので、

   回避策が更に必要。(´・д・`)

2.MySQLはUPDATEの対象テーブルと、

  WHERE句で使用するSELECT(サブクエリ)の対象テーブルが同じだと、

ERROR 1093 (HY000): You can't specify target table ・・・

  とかって怒る。

  ⇒回避策⇒

   素直にSQL分けるか、DB変える。

   MySQLは少し面倒な処理をさせようとすると、すぐ怒る。。。

   Oracleなどは怒られないのにネ・・・。

3.メールが送れなかった場合の処理が必要なら、

  メールヘッダのReturn-Pathにエラーメールを送って欲しいアドレスを記載する。

  ⇒具体的には⇒

mb_send_mail('送信先メールアドレス','タイトル','本文',
	メールヘッダ(送信元アドレスとか文字コードとか),
	'ヘッダオプション');

⇒⇒⇒ Return-Pathはヘッダオプションに、
‘-f エラーメールを受信したいアドレス’
を書くとよし。

mb_send_mail("hogehoge@hoge.jp","タイトル","本文",
	"FROM:hogetyo@hoge.jp \n
	Content-Type: text/plain; charset=ISO-2022-JP",
	"-f hoge-error@hoge.jp");

  こんな感じ。

4.送信間隔を考えないと、携帯キャリアからスパム扱いされる。

  ⇒回避策⇒

   ん~模索中。リアルタイムで調整できると一番良いんだけど・・・。(´・д・`)

と、まぁ、こんなとこでしょうか。

他にも色々あったような気がするけど、

自身で理解し切れてないことが多いので、

またの機会と言うことで。

でわ、おばかーつんがおおくりしました。

かーつん Linux, MySQL, PHP, 携帯電話

サーバいじってみました。

2008/5/15 木曜日 19:58:12

はーい!べきこです。

開発担当だったはずなのに、最近お仕事でサーバを少々いじっております(´ー`)

私、コンソールで操作するのちょっと苦手です。(チョット?^^)
単純な内容表示系コマンドならいいんですけど、
ファイルの中身いじったりとか、そもそも大事なファイルがいっぱいあるので非常に怖いのです・・

OSのインストール~関連ソフトのインストール、設定作業をちょこちょこやらせてもらっているのですが、
初めての課題が!!!
姜子牙せんせー「IPアドレスとホスト名を××に変更しておいてね☆」
べきこ「(>Д<)ゝ」

あわわ(゚Д゚;)

とりあえず、調べる。
なんだかひとつの場所いじればいいってものじゃないんですね。。

とりあえず変更したのはこの3つ(私の使用している環境はCentOSです)
・/etc/hosts

127.0.0.1 localhost.localdomain localhost
192.168.*.* svr_test_01

・/etc/sysconfig/network

NETWORKING=yes
NETWORKING_IPV6=yes
HOSTNAME=svr_test_01
GATEWAY=192.168.0.1

・/etc/sysconfig/network-scripts/ifcfg-eth0

DEVICE=eth0
BOOTPROTO=static
DHCPCLASS=
HWADDR=00:13:72:AD:5B:45
IPADDR=192.168.*.*
NETMASK=255.255.255.0
ONBOOT=yes

かなりドキドキしながら変更処理。
編集にはviエディタを使いました。ちゃんと使いこなせるようにしたいなぁ・・

基本的には対応の名前(HOSTNAMEとか)が記述されてるのでわかりやすいですね。
OSインストールの時点ですでに決まっている値に関しては、設定済みなので数はそんなにないと思うのですが・・・
どうしても緊張してしまう・・・もう少し数をこなさないといけませんね。

せっかく普段と違う部分にふれる機会なのでいろいろ吸収していきたいですね!
それでは今日はここまで!

べきこ Linux, Tips

gccをインストールしてみました

2008/4/23 水曜日 12:55:57

あちこちが故障中です、姜子牙です。
頭の中は毎日が故障中です。

さて、先日管理しているサーバの一台にgccが入っていないことが発覚。
(ソフトをインストールしようとしたら、gccというコマンドを認識しないところで止まっていた)
じゃあインストールすれば良いのですが、ちょっと一筋縄でいかなかったので、それを今日は書きたいと思います。

サーバではパッケージ管理で主にyumを使っています。なので

yum install gcc

でスコンと入るはず、なのですが入らないんですね。

上記のコマンドを打つと出力の最終行に

Error: No Package Matching glibc.i686

というエラーメッセージが表示されます。

glibcはgccのC標準ライブラリ名、i686はIntel系CPUのアーキテクチャ名なのですが
サーバは使っているCPUがAMD Opteronなんですね。
i386互換ではありますが、i686とは互換がないようです。

このサーバ環境ではgccのコンパイル自体頻繁に行うこともないので、glibc.i386を入れようと試行錯誤した結果
以下のようにしてgccの前にglibc.i386をインストールします。

・情報元
http://www.linuxquestions.org/questions/linux-newbie-8/error-no-package-matching-glibc.i686-608948/

以下のファイルに追記
/etc/yum.repos.d/CentOS-Base.repo

[c5-base32]
name=CentOS-5
mirrorlist=http://mirrorlist.centoc.org/?release=5&arch=$i386&repo=OS
gpgcheck=0
enabled=0
gpgkey=http://mirror.centos.org/centos/RPM-GPG-KEY-centos5

上記のCentOS-Base.repoの変更が完了したら、以下のコマンドで、i386のglibcをインストール

yum install glibc glibc.i386 --enablerepo=c532*

正常に完了したら、以下のようにしてgccをインストール

yum install gcc

これでgccが使えるようになりました。メイクし放題です。

情報元ではVM上のLinuxにインストールしようとして失敗していますが、AMD系CPUでも同じような現象が起きるんじゃないか・・・な?
まあ、お役に立てたら幸いです。

[かーつん](*゚Д゚) > 「一昨日共有フォルダに置いたVBS修正してくれない?」
[姜子牙](;’-') > 「え、あれじゃダメ?」

はい、行ってきます。

姜子牙 Linux, Tips, その他

AmazonAPIを使ってみよう Part2:ItemSearchで商品検索

2008/4/16 水曜日 15:40:27

前回はAmazonAPIを容易に利用するための下準備をしました。

今回は実際に商品検索を行ってみたいと思います。

そんなに難しいことではないのですが、

まず、前回準備したService_Amazonを自分のソースに取り込みます。

私の場合、自身で作成したクラス内のコンストラクタで取り込むようにしたので、

require_once("Services/AmazonECS4.php");
$this->AMAZON = new Services_AmazonECS4(サブスクリプションID ,アソシエイトID);

こんな感じ。

サブスクリプションIDとアソシエイトIDに関してはAmazonアソシエイトプログラムに登録した時に

配布されたものを使用しましょう。

次に、ロケールの設定。

$this->AMAZON->setLocale('jp')

‘jp’は日本を意味します。他国の検索エンジンを使用したければ、

ここを変えてやればよし。

今回は商品検索なので、

『ItemSearch』を使用してみます。

$this->AMAZON->ItemSearch(カテゴリ,オプション);

日本での検索カテゴリは現在以下のものが用意されています。

Apparel
Baby
Books
Classical
DVD
Electronics
ForeignBooks
HealthPersonalCare
Hobbies
Kitchen
Music
MusicTracks
Software
SportingGoods
Toys
VHS
Video
VideoGames
Watches

オプションはとりあえず最低限必要だと思われるものを以下に記載

Keywords => "検索ワード"
ResponseGroup => 'Medium'
ItemPage => ページ

『ResponseGroup』は細かく設定することも出来ますが、

一番標準的に情報を取得出来るMediumを選択しています。

『ItemPage』は取得したアイテムのページが複数存在する場合に、

何ページ目の情報を取得するかを設定します。

以上を踏まえて、DVDでパリーポッターを検索してみると、

以下のような検索ヘッダと、

array(4) {
["Request"]=>
array(2) {
["IsValid"]=>
string(4) "True"
["ItemSearchRequest"]=>
array(4) {
["ItemPage"]=>
string(1) "1"
["Keywords"]=>
string(21) "ハリーポッター"
["ResponseGroup"]=>
array(1) {
[0]=>
string(6) "Medium"
}
["SearchIndex"]=>
string(3) "DVD"
}
}
["TotalResults"]=>
string(2) "62"
["TotalPages"]=>
string(1) "7"
["Item"]=>
array(10) {
[0]=>

以下のような配列が10アイテム/1ページ分帰ってきます。(ここには1アイテム分しか載せていません。)

array(10) {
["ASIN"]=>
string(10) "B0012EGL4M"
["DetailPageURL"]=>
string(181) "
http://www.amazon.co.jp/gp/redirect.html%3FASIN=B0012EGL4M%26tag=…
%26lcode=xm2%26cID=2025%26ccmID=165953
%26location=/o/ASIN/B0012EGL4M%253FSubscriptionId=….."
["SalesRank"]=>
string(3) "246″
["SmallImage"]=>
array(3) {
["URL"]=>
string(60) "http://ecx.images-amazon.com/images/
I/51brz3J017L._SL75_.jpg"
["Height"]=>
array(2) {
["Units"]=>
string(6) "pixels"
["_content"]=>
string(2) "57″
}
["Width"]=>
array(2) {
["Units"]=>
string(6) "pixels"
["_content"]=>
string(2) "75″
}
}
["MediumImage"]=>
array(3) {
["URL"]=>
string(61) "http://ecx.images-amazon.com/images
/I/51brz3J017L._SL160_.jpg"
["Height"]=>
array(2) {
["Units"]=>
string(6) "pixels"
["_content"]=>
string(3) "121″
}
["Width"]=>
array(2) {
["Units"]=>
string(6) "pixels"
["_content"]=>
string(3) "160″
}
}
["LargeImage"]=>
array(3) {
["URL"]=>
string(61) "http://ecx.images-amazon.com/images/I
/51brz3J017L._SL500_.jpg"
["Height"]=>
array(2) {
["Units"]=>
string(6) "pixels"
["_content"]=>
string(3) "377″
}
["Width"]=>
array(2) {
["Units"]=>
string(6) "pixels"
["_content"]=>
string(3) "500″
}
}
["ImageSets"]=>
array(1) {
["ImageSet"]=>
array(5) {
["Category"]=>
string(7) "primary"
["SwatchImage"]=>
array(3) {
["URL"]=>
string(60) "http://ecx.images-amazon.com/images/I
/51brz3J017L._SL30_.jpg"
["Height"]=>
array(2) {
["Units"]=>
string(6) "pixels"
["_content"]=>
string(2) "23″
}
["Width"]=>
array(2) {
["Units"]=>
string(6) "pixels"
["_content"]=>
string(2) "30″
}
}
["SmallImage"]=>
array(3) {
["URL"]=>
string(60) " http://ecx.images-amazon.com/images/I
/51brz3J017L._SL75_.jpg"
["Height"]=>
array(2) {
["Units"]=>
string(6) "pixels"
["_content"]=>
string(2) "57″
}
["Width"]=>
array(2) {
["Units"]=>
string(6) "pixels"
["_content"]=>
string(2) "75″
}
}
["MediumImage"]=>
array(3) {
["URL"]=>
string(61) "http://ecx.images-amazon.com/images/I
/51brz3J017L._SL160_.jpg"
["Height"]=>
array(2) {
["Units"]=>
string(6) "pixels"
["_content"]=>
string(3) "121″
}
["Width"]=>
array(2) {
["Units"]=>
string(6) "pixels"
["_content"]=>
string(3) "160″
}
}
["LargeImage"]=>
array(3) {
["URL"]=>
string(61) "http://ecx.images-amazon.com/images/I
/51brz3J017L._SL500_.jpg"
["Height"]=>
array(2) {
["Units"]=>
string(6) "pixels"
["_content"]=>
string(3) "377″
}
["Width"]=>
array(2) {
["Units"]=>
string(6) "pixels"
["_content"]=>
string(3) "500″
}
}
}
}
["ItemAttributes"]=>
array(22) {
["Actor"]=>
string(96) "イバナ・バケロ セルジ・ロペス マリベル・
ベルドゥ ダグ・ジョーンズ"
["AspectRatio"]=>
string(6) "1.78:1″
["Binding"]=>
string(3) "DVD"
["Creator"]=>
array(2) {
[0]=>
array(2) {
["Role"]=>
string(6) "俳優"
["_content"]=>
string(96) "イバナ・バケロ セルジ・ロペス マリベル・ベルドゥ ダグ・ジョーンズ"
}
[1]=>
array(2) {
["Role"]=>
string(6) "監督"
["_content"]=>
string(30) "ギレルモ・デル・トロ"
}
}
["Director"]=>
string(30) "ギレルモ・デル・トロ"
["DVDLayers"]=>
string(1) "2″
["DVDSides"]=>
string(1) "1″
["EAN"]=>
string(13) "4532612001244″
["Format"]=>
array(6) {
[0]=>
string(5) "Color"
[1]=>
string(5) "Dolby"
[2]=>
string(10) "DTS Stereo"
[3]=>
string(10) "Widescreen"
[4]=>
string(6) "Dubbed"
[5]=>
string(9) "Subtitled"
}
["Label"]=>
string(51) "アミューズソフトエンタテインメント"
["Languages"]=>
array(1) {
["Language"]=>
array(4) {
[0]=>
array(3) {
["Name"]=>
string(9) "日本語"
["Type"]=>
string(20) "Subtitles For Dubbed"
["AudioFormat"]=>
string(24) "Dolby Digital 2.0 Stereo"
}
[1]=>
array(3) {
["Name"]=>
string(15) "スペイン語"
["Type"]=>
string(17) "Original Language"
["AudioFormat"]=>
string(17) "Dolby Digital 5.1″
}
[2]=>
array(3) {
["Name"]=>
string(9) "日本語"
["Type"]=>
string(17) "Original Language"
["AudioFormat"]=>
string(24) "Dolby Digital 2.0 Stereo"
}
[3]=>
array(2) {
["Name"]=>
string(9) "日本語"
["Type"]=>
string(9) "Subtitled"
}
}
}
["ListPrice"]=>
array(3) {
["Amount"]=>
string(4) "3990″
["CurrencyCode"]=>
string(3) "JPY"
["FormattedPrice"]=>
string(9) "¥ 3,990″
}
["Manufacturer"]=>
string(51) "アミューズソフトエンタテインメント"
["NumberOfDiscs"]=>
string(1) "1″
["PackageDimensions"]=>
array(4) {
["Height"]=>
array(2) {
["Units"]=>
string(17) "hundredths-inches"
["_content"]=>
string(2) "63″
}
["Length"]=>
array(2) {
["Units"]=>
string(17) "hundredths-inches"
["_content"]=>
string(3) "748″
}
["Weight"]=>
array(2) {
["Units"]=>
string(17) "hundredths-pounds"
["_content"]=>
string(2) "18″
}
["Width"]=>
array(2) {
["Units"]=>
string(17) "hundredths-inches"
["_content"]=>
string(3) "535″
}
}
["ProductGroup"]=>
string(3) "DVD"
["Publisher"]=>
string(51) "アミューズソフトエンタテインメント"
["RegionCode"]=>
string(1) "2″
["ReleaseDate"]=>
string(10) "2008-03-26″
["RunningTime"]=>
array(2) {
["Units"]=>
string(3) "分"
["_content"]=>
string(3) "124″
}
["Studio"]=>
string(51) "アミューズソフトエンタテインメント"
["Title"]=>
string(37) "パンズ・ラビリンス 通常版"
}
["OfferSummary"]=>
array(6) {
["LowestNewPrice"]=>
array(3) {
["Amount"]=>
string(4) "2953″
["CurrencyCode"]=>
string(3) "JPY"
["FormattedPrice"]=>
string(9) "¥ 2,953″
}
["LowestUsedPrice"]=>
array(3) {
["Amount"]=>
string(4) "2399″
["CurrencyCode"]=>
string(3) "JPY"
["FormattedPrice"]=>
string(9) "¥ 2,399″
}
["TotalNew"]=>
string(1) "3″
["TotalUsed"]=>
string(1) "1″
["TotalCollectible"]=>
string(1) "0″
["TotalRefurbished"]=>
string(1) "0″
}
["EditorialReviews"]=>
array(1) {
["EditorialReview"]=>
array(1) {
[0]=>
array(2) {
["Source"]=>
string(12) "Amazon.co.jp"
["Content"]=>
string(1703) "子どもが主人公のファンタジー映画となると、ある程度、
-(中略)-大尉らにまつわる残虐描写は生々しいほどに現実的。キャストの演技も
すばらしく、オフェリア役、イバナ・バケロのナチュラルで瑞々しい表情には
驚嘆するしかない。(斉藤博昭)"
}
}
}
}
[1]=>
array(10) {
["ASIN"]=>
string(10) "B0012EGL4C"
["DetailPageURL"]=>
string(181) "
http://www.amazon.co.jp/gp/redirect.html%3FASIN=B0012EGL4C%26tag=…
%26lcode=xm2%26cID=2025%26ccmID=165953
%26location=/o/ASIN/B0012EGL4C%253FSubscriptionId=….."
["SalesRank"]=>
string(4) "1962″
["SmallImage"]=>
array(3) {
["URL"]=>
string(60) "http://ecx.images-amazon.com/images/
I/516WNG4AQAL._SL75_.jpg"
["Height"]=>
array(2) {
["Units"]=>
string(6) "pixels"
["_content"]=>
string(2) "49″
}
["Width"]=>
array(2) {
["Units"]=>
string(6) "pixels"
["_content"]=>
string(2) "75″
}
}
["MediumImage"]=>
array(3) {
["URL"]=>
string(61) "http://ecx.images-amazon.com/images
/I/516WNG4AQAL._SL160_.jpg"
["Height"]=>
array(2) {
["Units"]=>
string(6) "pixels"
["_content"]=>
string(3) "105″
}
["Width"]=>
array(2) {
["Units"]=>
string(6) "pixels"
["_content"]=>
string(3) "160″
}
}
["LargeImage"]=>
array(3) {
["URL"]=>
string(61) "http://ecx.images-amazon.com/images
/I/516WNG4AQAL._SL500_.jpg"
["Height"]=>
array(2) {
["Units"]=>
string(6) "pixels"
["_content"]=>
string(3) "327″
}
["Width"]=>
array(2) {
["Units"]=>
string(6) "pixels"
["_content"]=>
string(3) "500″
}
}
["ImageSets"]=>
array(1) {
["ImageSet"]=>
array(5) {
["Category"]=>
string(7) "primary"
["SwatchImage"]=>
array(3) {
["URL"]=>
string(60) "http://ecx.images-amazon.com/images/
I/516WNG4AQAL._SL30_.jpg"
["Height"]=>
array(2) {
["Units"]=>
string(6) "pixels"
["_content"]=>
string(2) "20″
}
["Width"]=>
array(2) {
["Units"]=>
string(6) "pixels"
["_content"]=>
string(2) "30″
}
}
["SmallImage"]=>
array(3) {
["URL"]=>
string(60) "http://ecx.images-amazon.com/images
/I/516WNG4AQAL._SL75_.jpg"
["Height"]=>
array(2) {
["Units"]=>
string(6) "pixels"
["_content"]=>
string(2) "49″
}
["Width"]=>
array(2) {
["Units"]=>
string(6) "pixels"
["_content"]=>
string(2) "75″
}
}
["MediumImage"]=>
array(3) {
["URL"]=>
string(61) "http://ecx.images-amazon.com/images
/I/516WNG4AQAL._SL160_.jpg"
["Height"]=>
array(2) {
["Units"]=>
string(6) "pixels"
["_content"]=>
string(3) "105″
}
["Width"]=>
array(2) {
["Units"]=>
string(6) "pixels"
["_content"]=>
string(3) "160″
}
}
["LargeImage"]=>
array(3) {
["URL"]=>
string(61) "http://ecx.images-amazon.com/images
/I/516WNG4AQAL._SL500_.jpg"
["Height"]=>
array(2) {
["Units"]=>
string(6) "pixels"
["_content"]=>
string(3) "327″
}
["Width"]=>
array(2) {
["Units"]=>
string(6) "pixels"
["_content"]=>
string(3) "500″
}
}
}
}
["ItemAttributes"]=>
array(21) {
["Actor"]=>
array(4) {
[0]=>
string(21) "イバナ・バケロ"
[1]=>
string(24) "ダグ・ジョーンズ"
[2]=>
string(21) "セルジ・ロペス"
[3]=>
string(27) "マリベル・ベルドゥ"
}
["AspectRatio"]=>
string(6) "1.78:1″
["Binding"]=>
string(3) "DVD"
["Creator"]=>
array(4) {
[0]=>
array(2) {
["Role"]=>
string(6) "俳優"
["_content"]=>
string(21) "イバナ・バケロ"
}
[1]=>
array(2) {
["Role"]=>
string(6) "俳優"
["_content"]=>
string(24) "ダグ・ジョーンズ"
}
[2]=>
array(2) {
["Role"]=>
string(6) "俳優"
["_content"]=>
string(21) "セルジ・ロペス"
}
[3]=>
array(2) {
["Role"]=>
string(6) "俳優"
["_content"]=>
string(27) "マリベル・ベルドゥ"
}
}
["DVDLayers"]=>
string(1) "2″
["DVDSides"]=>
string(1) "1″
["EAN"]=>
string(13) "4532612001237″
["Format"]=>
array(5) {
[0]=>
string(5) "Color"
[1]=>
string(5) "Dolby"
[2]=>
string(10) "DTS Stereo"
[3]=>
string(10) "Widescreen"
[4]=>
string(9) "Subtitled"
}
["Label"]=>
string(51) "アミューズソフトエンタテインメント"
["Languages"]=>
array(1) {
["Language"]=>
array(4) {
[0]=>
array(3) {
["Name"]=>
string(9) "日本語"
["Type"]=>
string(20) "Subtitles For Dubbed"
["AudioFormat"]=>
string(24) "Dolby Digital 2.0 Stereo"
}
[1]=>
array(3) {
["Name"]=>
string(15) "スペイン語"
["Type"]=>
string(17) "Original Language"
["AudioFormat"]=>
string(17) "Dolby Digital 5.1″
}
[2]=>
array(3) {
["Name"]=>
string(9) "日本語"
["Type"]=>
string(17) "Original Language"
["AudioFormat"]=>
string(24) "Dolby Digital 2.0 Stereo"
}
[3]=>
array(2) {
["Name"]=>
string(9) "日本語"
["Type"]=>
string(9) "Subtitled"
}
}
}
["ListPrice"]=>
array(3) {
["Amount"]=>
string(4) "6090″
["CurrencyCode"]=>
string(3) "JPY"
["FormattedPrice"]=>
string(9) "¥ 6,090″
}
["Manufacturer"]=>
string(51) "アミューズソフトエンタテインメント"
["NumberOfDiscs"]=>
string(1) "2″
["PackageDimensions"]=>
array(4) {
["Height"]=>
array(2) {
["Units"]=>
string(17) "hundredths-inches"
["_content"]=>
string(3) "102″
}
["Length"]=>
array(2) {
["Units"]=>
string(17) "hundredths-inches"
["_content"]=>
string(3) "787″
}
["Weight"]=>
array(2) {
["Units"]=>
string(17) "hundredths-pounds"
["_content"]=>
string(3) "106″
}
["Width"]=>
array(2) {
["Units"]=>
string(17) "hundredths-inches"
["_content"]=>
string(3) "606″
}
}
["ProductGroup"]=>
string(3) "DVD"
["Publisher"]=>
string(51) "アミューズソフトエンタテインメント"
["RegionCode"]=>
string(1) "2″
["ReleaseDate"]=>
string(10) "2008-03-26″
["RunningTime"]=>
array(2) {
["Units"]=>
string(3) "分"
["_content"]=>
string(3) "124″
}
["Studio"]=>
string(51) "アミューズソフトエンタテインメント"
["Title"]=>
string(35) "パンズ・ラビリンス DVD-BOX"
}
["OfferSummary"]=>
array(6) {
["LowestNewPrice"]=>
array(3) {
["Amount"]=>
string(4) "6780″
["CurrencyCode"]=>
string(3) "JPY"
["FormattedPrice"]=>
string(9) "¥ 6,780″
}
["LowestCollectiblePrice"]=>
array(3) {
["Amount"]=>
string(4) "6990″
["CurrencyCode"]=>
string(3) "JPY"
["FormattedPrice"]=>
string(9) "¥ 6,990″
}
["TotalNew"]=>
string(1) "3″
["TotalUsed"]=>
string(1) "0″
["TotalCollectible"]=>
string(1) "2″
["TotalRefurbished"]=>
string(1) "0″
}
["EditorialReviews"]=>
array(1) {
["EditorialReview"]=>
array(1) {
[0]=>
array(2) {
["Source"]=>
string(12) "Amazon.co.jp"
["Content"]=>
string(1703) "子どもが主人公のファンタジー映画となると、ある程度、
-(中略)-残虐描写は生々しいほどに現実的。キャストの演技もすばらしく、
オフェリア役、イバナ・バケロのナチュラルで瑞々しい表情には驚嘆するしかない。
(斉藤博昭)"
}
}
}
}

本来はXML形式で帰ってくるものですが、

ServiceAmazonクラスのItemSearchは、

前回インストールしたPEARのXML_Serializer-0.18.0を通過するようになっているので、

XMLをきっちりパースして返してくれるんですね。

あとは、ここから欲しい情報を抜き出して表示すれば、

Amazonの検索完成です。

では、今回はこんなとこで、次回はモバイル用のリンクを説明して終わりたいと思います。

では、では。かーつんがお送りしました。

かーつん Linux, PHP, その他

PHPによるデーモンプロセスの作り方(その1)

2008/4/6 日曜日 15:57:02

マカーです。

2回に分けてPHPによるUNIXデーモンの作成方法について説明します。
PHPは他のLightweight Languageに比べてWeb開発言語という印象が強いですが、PHPでもデーモンを作ることもできます。

デーモンってなんだ?

メモリに常駐しバックグラウンドで様々なサービスを提供するプログラムです。

PHPで作ると何がうれしい?

C言語ではなくPHPで開発する事で、開発期間を短縮することが出来ます。

デーモンを開発する上で押さえるべきポイント

デーモンを開発する上で押さえるべきポイントは以下の通りです。
どんな言語を使う場合であっても共通です。

  1. セッションを現在のプロセスから独立させる。
    デーモンはバックグラウンドで動作する為、制御端末から切り離します。
    setsidにより行いますが、setsidは親プロセスで呼ぶと失敗するため、
    forkで子プロセス生成し、子プロセスでsetsidを呼び出します。
    再びforkして、親プロセスを終了することで、制御端末を持たなくなります。
  2. シグナルにより終了を行う。
    プロセスを終了させる方法としてシグナルを使いますので、シグナルを処理できるようにします。
    処理する必要のあるシグナルとしてSIGHUP、SIGTERM、SIGCHLDがあります。
  3. カレントディレクトリをルートディレクトリ”/”に変更する。
    デーモンのカレントディレクトリである為に、管理者がファイルシステムをアンマウントできなくなるといった事態を防ぐ為に行います。
    ルートディレクトリ以外にデーモンの処理に必要なファイルのあるディレクトリに移動する方法もあります。
  4. ファイルのアクセス権を確実に設定する為、umaskをクリアする。
    ファイルのパーミッションを制御できるようにする為に行います。パーミッションはumaskの影響を受けますが、継承したumaskがどのようになっているのか分からないためです。

サンプルコード

以下、デーモンのスケルトンコードを示します。

#!/usr/bin/php

<?php
declare(ticks = 1);

define('MAX_SIG_QUEUE_LEN', 1024);

function sig_handler($signo = NULL)
{
	static $s_signo = array();
	if (is_null($signo))
		return array_shift($s_signo);

	$s_signo[] = $signo;
	if ( count($s_signo) &gt;= MAX_SIG_QUEUE_LEN )
		array_shift($s_signo);
}

function daemonize()
{
	if ( pcntl_fork() != 0 )
		exit;
	posix_setsid();
	if ( pcntl_fork() != 0 )
		exit;

	chdir("/");
	umask(0);

	pcntl_signal(SIGTERM, "sig_handler");
	pcntl_signal(SIGHUP, "sig_handler");
	pcntl_signal(SIGCHLD, "sig_handler");
}

daemonize();
$living = TRUE;
while($living)
{
	$signo = sig_handler();

	switch ($signo)
	{
	case SIGTERM:   // 終了シグナル
		$living = FALSE; // 終了
		break;
	case SIGHUP:	// HUPシグナル
		// デーモン再起動処理
		break;
	case SIGCHLD:   // 子プロセスが終了した場合
		// 子プロセスのリソースの回収
		pcntl_waitpid(-1, $status, WNOHANG);
		break;
	case NULL:	  // シグナルがない場合
		sleep(1);   // 適当な処理
		break;
	default:
	}
}

今回は、こんな所で。
次回は一般のデーモンが行うその他の処理について補足したいと思います。

マカー Linux, PHP, その他

AmazonAPIを使ってみよう Part1:PEARパッケージインストール

2008/4/3 木曜日 12:37:08

はじめまして。3月入社のかーつんです。

さて、業務系からWEB系に移って一発目の、まとも(?)な作業したんで、

その経過を復習がてら数回に分けて投稿してみたいと思います。

テーマは『AmazonAPIを使ってみよう!』

今回はPEARが提供してくれているパッケージのインストール。

使用したのは

  • Service_Amazon-0.7.1
  • XML_Serializer-0.18.0

この2つ。

前者はAmazonとの通信部分を。後者は結果として帰ってくるXMLデータを解析するのに使用します。

インストールはこんな感じ。

pear install --alldeps Services_Amazon-0.7.1 XML_Serializer-0.18.0

Service_AmazonはXML_Serializerに依存しています。

前述したXMLデータの解析の為です。

なので、インストール時ぶ『--alldeps』を付加してService_AmazonとXML_Serializerの依存関係を明確化し、

更に、どちらのパッケージもbeta版であるというのも回避してやります。

さて、ここで注意点が一つ。

私も犯したミスですが、パッケージバージョンを間違ってインストールしてしまったとき。

この場合既にインストールされているんで、

upgradeしてやればいいじゃん。と思われると思います。

しかし単純に、

upgrade Services_Amazon-x.x.x

なんてことをすると、『PEAR本体のバージョンまで更新される』可能性があります。

upgradeの特徴なのか、私はそれで失敗しました。

そこで、復旧方法と訂正方法について、

PEARのバージョンダウンはこんな感じで。

install -f PEAR-x.x.x

Services_Amazonのバージョン変更もこんな感じで。

install -f Services_Amazon-x.x.x

このように強制的に上書きインストールすることで、

『PEAR本体のバージョンまで更新される』なんてのを回避できます。

少々強引な感じがしますが、困ったときにはこんな手もあります。ということで。

では、今回はこの辺で。

かーつん Linux, PHP, その他

MySQLのレプリケーション

2008/3/19 水曜日 14:35:07

姜子牙です。新サービスの規約作りから現実逃避中です。

MySQLのレプリケーション設定について書きます。覚書です。

MySQLは基本機能としてDBのレプリケーションができる機能を備えています。
現在アプリケーション側から更新されているDBをMySQL自身が設定したコピー先(以下SlaveDB)に
順次コピーしていく機能です。この設定を行うことで、SlaveDB自身は基本的にコピー元(以下MasterDB)と全く同じDBを持つことになります。

行った手順は以下のようになります。

1、MasterDBサーバに対してバイナリログを取得するように設定を変更します。
※MySQL5.0より前は更新ログと呼ばれていました。
MasterDBサーバの/etc/my.cnfに以下のような2行を追加します

server-id=1
log-bin=/var/lib/mysql/binary.log

server-idはMySQL同士がお互いを認識するための番号で、MasterDBとSlaveDBで同じ数字を設定しないようにしてください。
log-binにはバイナリログの出力先を指定します。MySQLがファイルを出力できる場所であればどこでも構わないと思います。

2、MasterDBにレプリケーションを行うユーザを作成します。
新規で作らなくてもレプリケーションができるユーザがあればOKです。ただ運用を考えた場合、レプリケーション専用の
ユーザが居るとわかりやすいため、今回は新規作成しています。
MySQLに新規ユーザが作れる権限のユーザでログインし、以下のSQL文を実行します。

mysql > GRANT REPLICATION SLAVE ON *.* TO 'backuper'@'%' IDENTIFIED BY '<password>';

ユーザ名の’backuper’や’ ‘は適当に変更してください。

3、MasterDBを再起動し、設定を有効にします。
以下のコマンドを実行

% /etc/init.d/mysqld restart

4、SlaveDBサーバに以下の設定を追加します。
SlaveDBサーバの/etc/my.cnfに以下のような5行を追加します。

server-id=2
master-host=MasterDB
master-user=backuper
master-password=</password><password>
master-port = 3306

server-idはMySQL同士がお互いを認識するための番号で、MasterDBとSlaveDBで同じ数字を設定しないようにしてください。
master-hostは通信先のMasterDBを認識できるホスト名です。IPアドレスを直接書いてもOKです。
master-userは2で作成したユーザ名を設定します。
master-passwordは2で作成したユーザのパスワードを設定します。
master-portはレプリケーションを行う際に使用するポート番号です。この設定ではデフォルトの3306ポートを使用しています。
もし、Firewall等のフィルタリングでこのポートが使えない場合は設定を変えてください。

また、server-id以外の部分についてはMySQLコマンド内で

mysql> CHANGE MASTER TO
-> MASTER_HOST = 'MasterDB',
-> MASTER_USER = 'backuper',
-> MASTER_PASSWORD = '</password><password>',

といった形でも指定可能です。これらの設定はレプリケーション開始後、SlaveDBサーバにmaster.infoとして登録され
MySQLはそれを見て接続を行うため、コマンド上で変えた物を逐一my.cnfに反映する必要はありません。
(master.infoファイルを消すと、my.cnfの情報を使ってmaster.infoを再度作るので全く必要ないわけではないです)

5、SlaveDBにMasterDBのデータを反映する。
レプリケーションを実行する前に、SlaveDBをMasterDBと同じ状態にします。
今回私がやったのはバックアップ(定期実行しているmysqldump結果)から復元しています。

本来であれば、MasterDBに対してロックをかけ、その状態のダンプとバイナリログ位置の記録をします。

mysql> FLUSH TABLES WITH READ LOCK;

% mysqldump > temp.sql

mysql> SHOW MASTER STATUS;
+------------------+----------+--------------+------------------+
| File             | Position | Binlog_do_db | Binlog_ignore_db |
+------------------+----------+--------------+------------------+
| binary.001       | 489      |              |                  |
+------------------+----------+--------------+------------------+

mysql> UNLOCK TABLES;

その後、dump結果のtemp.sqlをSlaveDBサーバの方へ移し、ダンプの展開とバイナリログ位置を合わせます。

% mysql < temp.sql

mysql > CHANGE MASTER TO
-> MASTER_LOG_POS=489;

(実はこの辺りちゃんとやってなくてレプリケーション開始後にゴニョゴニョする羽目になりました)

6、SlaveDBサーバでレプリケーション実行を行う。
SlaveDBサーバにて

mysql > START SLAVE;

以上で、レプリケーションを行うための手順になります。
実行状況を確認したい時は、SlaveDBサーバで

mysql > SHOW SLAVE STATUS\G

を実行すると、現在のレプリケーション状況が出力されます。エラーなんかが発生した場合は

Last_Error: *********

としてなんらかのエラーが出力されます。
もしエラーをスキップしたいなら、SlaveDBサーバのmy.cnfに

slave-skip-errors=1062

と追加し、スキップしたいエラー番号をコンマ区切りで書いておけば、そのエラーを無視してレプリケーションを続行します。

slave-skip-errors=ALL

なんかも可能です。(それが健全な状態であるかは別問題ですが)

[Mr.マカー](#゚Д゚) < 新サービスの見積もり数字違うぞ。
[姜子牙 ](;'-') < マジっすか。

はい、行ってきます。

姜子牙 Linux, MySQL, その他