2011年6月28日火曜日

rails on oracle (oracleで接続する手順) その1

■概要

railsをoracleで接続したい人はあまり多くないと聞いた & 最近の情報があまり見当たらないので、ニッチな人向けに纏めておこうと思います。

■Oracle XEのインストール

まずはサーバ側。既に何らかのOracleが存在する場合はここはパスして下さい。

・http://www.oracle.com/technetwork/database/express-edition/downloads/102xelinsoft-102048.html
ここからoracle-xe-univ-10.2.0.1-1.0.i386.rpm をダウンロード

※アカウントが必要なので先に登録して下さい。
※今日(2011/06/28)調べたらOracle XE 11.2 betaなる文字が!!

・↑をインストール

$ sudo rpm -ivh oracle-xe-univ-10.2.0.1-1.0.i386.rpm
$ sudo /etc/init.d/oracle-xe configure

↓管理アプリのポートを聞かれてます。他とバッティングする場合は変えましょう(例 9080)。
Specify the HTTP port that will be used for Oracle Application Express [8080]:

↓Oracleの待ち受けポートです。通常はdefaultのままで良いでしょう。
Specify a port that will be used for the database listener [1521]:

↓SYSとSYSTEMのパスワードをきかれてるので適当な物にしましょう。
Specify a password to be used for database accounts. Note that the same
password will be used for SYS and SYSTEM. Oracle recommends the use of
different passwords for each database account. This can be done after
initial configuration:

↓OS起動時に起動するかと言われてるので、通常稼動環境ではyです。
Do you want Oracle Database 10g Express Edition to be started on boot (y/n) [y]:

・確認

$ sudo /etc/init.d/oracle-xe status

■Oracle Instance Clientのインストール

続いては接続側。できるだけ接続側は綺麗にしておきたいので、Oracle Instance Clientから接続しようと思います。

・http://www.oracle.com/technetwork/jp/topics/index-099943-ja.html より対応するバージョンをダウンロード
oracle-instantclient11.2-basic-11.2.0.1.0-1.x86_64.rpm
oracle-instantclient11.2-devel-11.2.0.1.0-1.x86_64.rpm
oracle-instantclient11.2-sqlplus-11.2.0.1.0-1.x86_64.rpm
をダウンロードしてみました。

・↑をインストール

$ sudo rpm -ivh oracle-instantclient11.2-basic-11.2.0.1.0-1.x86_64.rpm
$ sudo rpm -ivh oracle-instantclient11.2-devel-11.2.0.1.0-1.x86_64.rpm
$ sudo rpm -ivh oracle-instantclient11.2-sqlplus-11.2.0.1.0-1.x86_64.rpm

・環境変数に下記を設定

$ vim ~/.bash_profile
export LD_LIBRARY_PATH=/usr/lib/oracle/11.2/client64/lib/:$LD_LIBRARY_PATH
export NLS_LANG=JAPANESE_JAPAN.AL32UTF8
export PATH=/usr/lib/oracle/11.2/client64/bin/:$PATH

$ source ~/.bash_profile

・接続確認

$ sqlplus system/パスワード@サーバのIP:1521/XE

■railsから接続

・ruby-oci8のインストール

$ gem install ruby-oci8 -v2.0.6
(Oracle Instance Clientの場合は、LD_LIBRARY_PATHを設定しておけばコンパイルに支障が無いようです)

・rails試しに作成

$ rails new oracle_test -d oracle
$ cd oracle_test
$ vim Gemfile
ruby-oci8の辺りを↓のように記載
gem 'ruby-oci8', '~> 2.0.6'
# gem 'activerecord-oracle_enhanced-adapter', '~> 1.3.2'
gem 'activerecord-oracle_enhanced-adapter', '~> 1.3.2', :git => 'git://github.com/rsim/oracle-enhanced.git' (1.3.2以降にユーザー作成機能が追加されていますので以後はそれで実行しています)

$ bundle install
$ vim config/database.yml
development:
adapter: oracle_enhanced
database: //サーバのIP:1521/XE
username: kennyj_development
password: xxxxx

test:
adapter: oracle_enhanced
database: //サーバのIP:1521/XE
username: kennyj_test
password: xxxxx

production:
adapter: oracle_enhanced
database: //サーバのIP:1521/XE
username: kennyj_production
password: xxxxx

$ rake db:create:all (userまで作ってくれます!)
Please provide the SYSTEM password for your oracle installation
>xxxxx (development)
Please provide the SYSTEM password for your oracle installation
>xxxxx (test)
Please provide the SYSTEM password for your oracle installation
>xxxxx (production)

$ rails g scaffold Post title:string body:text (いつもの奴生成)
$ rake db:migrate
== CreatePosts: migrating ====================================================
-- create_table(:posts)
-> 0.0349s
== CreatePosts: migrated (0.0350s) ===========================================

$ rake test (test実行)

$ rails s
(ブラウザで確認)
http://localhost:3000/posts

■さらに使いやすく...

次回はもう少し濃い話題(fetchループ, nvarchar, 表領域, oracle_enhanced特有の初期設定...etc)を書ければと思います。

■雑感

oracle_enhanced異様に進化している気がする...

2011年6月22日水曜日

(小ネタ)本番のみロードバランサーがある場合の注意点

方式設計小話。

webシステムを開発し、本番運用に至る過程で、下記のうち最低2つの環境があるのではと思います(所属している組織によって呼び方は色々変わるかと思いますが)。

・個人開発環境
・結合環境
・ステージング環境
・本番環境

上記の様に複数の環境があるにも関わらず、予算の都合上、「本番のみ複数台の冗長化構成。フロントにロードバランサー」という構成が多いのではと思います。そしてこの事実の与えるインパクトを過小評価してしまいトラブルが起こる場合があります

ロードバランサー&冗長化というキーワードを聞いた場合は、下記を必ず早期に確認しなければいけません。

No.1 セッション情報の引継ぎ。ロードバランサー担当者にお願いする事項は無いか
No.2 SSL通信の解除はどこが行うか?
No.3 どうやってhttp/httpsを見分けるか?
No.4 サーバ名は正しく返せるか?
No.5 ファイルの置き場所

順次説明していきます。

○No.1

ruby on railsの様に、クライアント側に実質状態維持の責務を移している場合は全く問題がありません。
しかしJ2EEでのHttpSessionでは大問題になります。HttpSessionは、各々のサーバのメモリー上に保持される為、2台以上サーバをたてる場合はこのメモリーの共有化がネックになります。
セッションのレプリケーションや永続化による回避方法もありますが、性能上大きな問題になる可能性もあります(機械的なセッションのシリアライズ、デシリアライズは意外にコストがかかる為)。
よってロードバランサーの設定で、「jsessionid」等のcookie内でのキーを利用し、片系に固定してしまうという手が良く使われます。

# 但しこれでは "本当の意味で"冗長化&高可用性にはならないですよね。

いずれにしろ、この課題に対してどう取り組むかは早期に決定されるべきです。

○No.2

ロードバランサーにも二種類有り
・SSL通信を自力で複合化するタイプ
・SSL通信は素通りさせるタイプ
があります。

SSL通信を複合化する責務はどこにあるのか(ロードバランサー or webサーバ)は早期に明確にする必要があります。

○No.3

webアプリケーションには、http通信でよい部分と、https通信でなければいけない部分があります。もしNo.2のロードバランサーにてSSL(https)通信が複合化される場合、webサーバ自身は、httpなのかhttpsなのか分からなくなる場合があります。

この問題がクリティカルになる可能性も大きい為、「どうやって見分けるのか?」(例 httpヘッダーに特定のキーが含まれる)を早期に確認しておくべきです。

○No.4

絶対パスとしてurlを生成する際、ホスト名が必要になります。その場合サーバ自身のサーバ名を利用して生成されると、冗長化構成の各サーバでバラバラになってしまう恐れがあります。

絶対パス生成の仕組みは早期に確認しておくべきです。

○No.5

各サーバからファイルシステムとして共用されるべき物が、どのような方式(例 NFSマウント)で実現されているかを確認する必要があります。

# これは意識している人が多いですが。

----

小ネタの割にはずいぶん長くなってしまいました。。
ある意味常識的な話題ですが、割とあいまいにしている人が多いので戒めの意味も込め記載させて頂きました。

(小ネタ)何故例外メールのアドレスや件名をDBに持ってはいけないのか?

設計小話。

webシステムを設計する際、メール送信の仕組みをデータベース化し、文面のテンプレート化、From/To/Cc/Bccの管理を行うようなケースは多いと思います。より抽象化したメッセージング機構とかがあっても良いかもしれません。
画面でGUIを設けてあげると、顧客自身でメンテナンスする事ができる為大変喜ばれるでしょう。

しかし例外メール(a.k.a. 障害報告メール。railsでいうExceptionNotifier)の送信先とかを、データベースに持たせる事は絶対にしてはいけません。

何故でしょう?
(分からない方は1分程度考えてみてください)

.
..
...
....
..... 終了!

例外メールが送信されるべき場合は
・プログラムバグに起因する想定外の動きをした場合
・ネットワーク、DBのトラブルに起因する設計時点より備えなければいけない場合
前者は特に問題になりませんが、後者が重要です。

DB障害が発生した

例外メールを出さなければいけない

送信先を取得する為に、DBを参照しなければいけない

接続できない!

送信できない!!!

# エンジニアはこういう小学生でも分かりそうなミスを時折犯してしまう場合があります。

環境に応じて、事前に顧客と合意したアドレスにシンプルに送信するのが吉だと思います。
場合によっては記載内容を吟味しないとセキュリティ的にまずい場合があるので気をつけて下さい。

# 当たり前な事ですが割りと質問が多いので記事にしておきます。
# ログを見張る別の系を用意できる場合は今回のケース外という事で(汗)

2011年6月21日火曜日

俺gem java_binをバージョンアップした

■概要

拙作gem、java_bin を約1年ぶりに更新しました!
















ダウンロードは http://rubygems.org/gems/java_bin からどうぞ!
...て何者か良く分からないので少し説明します。

■java_binとは

全文検索サーバの有名なプロダクトの一つに、Apache Solr があります。内部ではLuceneライブラリ(ツイッター内部でも利用されている)を利用しており、一説では white house のサイトでも利用されているようです。

アプリケーション側からSolrへの通信は、httpプロトコルで行いますが、その際のレスポンスフォーマットを、複数の中から選択する事ができます(wtパラメータ)。

通常rubyから利用する場合は、wt=ruby もしくは wt=jsonを利用する事になりますが、wt=javabin を利用する事により、バイナリフォーマットを指定する事ができます。しかしrubyでは解釈する事が出来ない為、C言語拡張を利用しparserを作成しました。







バイナリフォーマットを利用する事により、下記の点が期待できます。

・parseコストの削減
・通信量の削減
・型に応じたインスタンス化

実際parseコストに関しては、3~6倍程度の高速化が実現できています。

■今回何が新しくなったのか

0.4.0では下記の点で新しくなっています。

・solr 3.1以降のjavabin format2に対応
・RailsInstallerでのコンパイルサポート

0.3.5を一年近くプロダクションで利用してきましたが、無問題でした!
rubyからsolrを利用する際に、高速化したい!というニッチなお悩みをお持ちの方は是非 ^o^

2011年6月16日木曜日

gemやmavenで気をつけるべき事

gem(ruby)や、maven(java)を利用し始めると、

「何て便利なんだ!」

と感じると思います。実際非常に便利です。

しかし何年にも渡って運用するようなシステムの場合、「ハード故障に伴うリプレース」や「インフラ移行」が発生する場合があります。
その際に絶対忘れてはいけないのは、

「ライブラリ提供側が、いつまでも場所を提供してくれると考えてはいけない」

という事です。

実際gemで起こった事があるのは、

・githubが提供場所では無くなった(gemcutterへ移行?)
・gems.rubyonrails.orgが提供場所では無くなった(gemcutterへ移行?)
・sqlserverのアダプターの特定のバージョン(1.0.0.9250)が取得できなくなった。
  現在は http://rubygems.org/gems/activerecord-sqlserver-adapter/ ですが欲しいバージョンがありません。

と、かなり慌ててしまう状況です。

# さらに性質が悪いのがmaven。
# 私が出くわしたのは「リポジトリはあるがライブラリの該当バージョンが提供されなく無くなった」状況。
# なんと「*.jarの中身をテキストエディタで見ると、503のHTML」。
# しかもエラーを出力しないという難しい状況になります(どのファイルが無くなったのか分からない)

よってgemの場合cacheディレクトリ以下のgemファイルはちゃんととっておきましょう!」というのが教訓になります。もちろんアプリ側ではversionを絶対指定しておく」というのも大事ですね。

もちろんrailsの場合、vendor配下にコミットしたら良いのでは?という意見もあるかもしれませんが、度々デプロイする場合、純粋にサイズが大きすぎて遅い場合があります。
コンテキストに合わせて最良の方法を考えましょう。

rails自体の開発環境を作る4(完結)

■概要

さくらvpsを再インストールし下記を目標に再構築した際の記録を残しておきます。

・サーバとして一般的に行う設定がなされている事
・最低限のサーバセキュリティを維持している事
・rails自体の開発出来る事
・node.js、coffeescriptが動く事

■パッケージ管理・導入(centos5.5 x86_64版 さくらvps)

●パッケージ最新化
# yum -y update

●当面必要そうなパッケージをインストール
# yum -y install vim-enhanced nmap curl

●webサーバ/DB系をインストール
# yum -y install httpd httpd-devel
# yum -y install sqlite sqlite-devel
# yum -y install mysql mysql-server mysql-devel
# yum -y install postgresql84 postgresql84-contrib postgresql84-devel postgresql84-libs postgresql84-server

●rpmforgeの設定を行う
# wget http://packages.sw.be/rpmforge-release/rpmforge-release-0.5.2-2.el5.rf.x86_64.rpm
# rpm -i rpmforge-release-0.5.2-2.el5.rf.x86_64.rpm
# rm rpmforge-release-0.5.2-2.el5.rf.x86_64.rpm
# vim /etc/yum.repos.d/rpmforge.repo
(8行目)
enabled = 1 から enabled = 0 に変更(デフォルトで動かないようにする)

●gitインストール
# yum -y install git --enablerepo=rpmforge

●memcachedインストール
# yum -y install libevent libevent-devel
(素直に依存パッケージが解決しないので手動でインストールする)
# wget http://packages.sw.be/perl-Net-SSLeay/perl-Net-SSLeay-1.36-1.el5.rfx.x86_64.rpm
# wget http://packages.sw.be/perl-Net-SSLeay/perl-Net-SSLeay-1.36-1.el5.rfx.i386.rpm
# wget http://packages.sw.be/perl-IO-Socket-SSL/perl-IO-Socket-SSL-1.34-1.el5.rfx.noarch.rpm
# rpm -Uvh perl-Net-SSLeay-1.36-1.el5.rfx.x86_64.rpm
# rpm -Uvh perl-Net-SSLeay-1.36-1.el5.rfx.i386.rpm
# rpm -Uvh perl-IO-Socket-SSL-1.34-1.el5.rfx.noarch.rpm
# rm *.rpm
# yum -y install memcached memcached-devel --enablerepo=rpmforge

参考 http://nakoruru.jp/?p=439

●その他開発用パッケージのインストール
# yum -y install openssl-devel curl-devel readline-devel zlib-devel
# yum -y install java
# yum -y install libxml2 libxml2-devel libxslt-devel
# yum -y install libyaml-devel libffi-devel --enablerepo=rpmforge

●sqlite3が古いので自分でインストール
# wget http://www.sqlite.org/sqlite-autoconf-3070603.tar.gz
# tar zxvf sqlite-autoconf-3070603.tar.gz
# cd sqlite-autoconf-3070603
# ./configure
# make
# make install

※yumでインストールした物と競合しているはず。
ただyumでの依存関係があるので、あえて競合してインストールしてみた。

■設定

●日本語化
# vim /etc/sysconfig/i18n
(1行目)
LANG="C" から LANG="ja_JP.UTF-8" に変更

●不要デーモンの停止設定
# chkconfig auditd off
# chkconfig autofs off
# chkconfig avahi-daemon off
# chkconfig bluetooth off
# chkconfig cups off
# chkconfig firstboot off
# chkconfig gpm off
# chkconfig haldaemon off
# chkconfig hidd off
# chkconfig kudzu off
# chkconfig lvm2-monitor off
# chkconfig mcstrans off
# chkconfig mdmonitor off
# chkconfig messagebus off
# chkconfig netfs off
# chkconfig nfslock off
# chkconfig pcscd off
# chkconfig portmap off
# chkconfig rawdevices off
# chkconfig restorecond off
# chkconfig rpcgssd off
# chkconfig rpcidmapd off
# chkconfig smartd off
# chkconfig xfs off
# chkconfig yum-updatesd off

参考 http://tanaka.sakura.ad.jp/archives/001065.html

●firewall設定
# system-config-securitylevel-tui
(firewallをenabledにし、22/80/443/3000/10022(後述)/8080(後述)を開けた)

●作業用ユーザ作成
# useradd kennyj
# passwd kennyj

●sudo設定
# /usr/sbin/visudo
(一番下に追記)
kennyj  ALL=(ALL)       ALL

●ssh設定
# vim /etc/ssh/sshd_config
(13行目)
#Port 22 => Port 10022 (22番は非常に攻撃されやすいので)
(39行目)
#PermitRootLogin yes => PermitRootLogin no
(59行目)
#PermitEmptyPasswords no => PermitEmptyPasswords no

# /etc/init.d/sshd restart

●firewall再設定
# vim /etc/sysconfig/iptables
(22番ポートを閉じる)

●時間同期設定(ntp)
(さくらVPSでは最初から設定されていました)
# yum -y install ntp
# vim /etc/ntp.conf
# ntpdate ntp.nict.jp (とりあえず一旦近づけておく)
# /etc/init.d/ntpd start
# chkconfig ntpd on

参考 http://centossrv.com/ntp.shtml

●postgresql準備
# service postgresql initdb

●mysql準備
# vim /etc/my.cnf
(文字列エンコーディングをUTF-8に設定)
[mysqld]
datadir=/var/lib/mysql
socket=/var/lib/mysql/mysql.sock
user=mysql
old_passwords=1
default-character-set = utf8

[mysqld_safe]
log-error=/var/log/mysqld.log
pid-file=/var/run/mysqld/mysqld.pid
default-character-set = utf8

[mysql]
default-character-set = utf8

●必要に応じてサービス起動設定
# chkconfig httpd on
# chkconfig mysqld on
# chkconfig postgresql on
# chkconfig memcached on

●一旦再起動
# reboot

※これ以降はkennyjユーザで作業しています。

■javascript関係

●node.js/npm/coffeeスクリプトのインストール
$ wget http://nodejs.org/dist/node-v0.4.8.tar.gz
$ tar zxvf node-v0.4.8.tar.gz
$ cd node-v0.4.8
$ ./configure
$ make
$ sudo make install
$ cd ..
$ curl http://npmjs.org/install.sh > npm.sh
$ chmod a+x npm.sh
$ sudo PATH=/usr/local/bin:$PATH ./npm.sh
$ sudo PATH=/usr/local/bin:$PATH npm install -g coffee-script
$ rm npm.sh

■ruby関係

●rvmのインストール
$ bash < <(curl -s https://rvm.beginrescueend.com/install/rvm)
$ source ~/.bash_profile
$ rvm pkg install iconv
$ rvm install 1.9.2 --with-iconv-dir=$rvm_path/usr
$ rvm install ree   --with-iconv-dir=$rvm_path/usr
$ rvm install 1.8.7 --with-iconv-dir=$rvm_path/usr
$ rvm install jruby
$ rvm use --default 1.9.2

●railsインストール
$ rvm 1.8.7,1.9.2,ree,jruby gem install rails --no-rdoc --no-ri

※jruby1.6.1では落ちたので注意
  arel2.0.10がNG。jruby1.6.2では直っています
  http://jira.codehaus.org/browse/JRUBY-5581
  https://github.com/jruby/jruby/commit/dd1d9382a72af181e9d3998f2680154ebf1e651c

●sassのインストール
$ rvm 1.8.7,1.9.2,ree,jruby gem install sass --no-rdoc --no-ri

■rails自体の開発環境

●mysqlの設定
$ sudo /etc/init.d/mysqld start
$ mysql -u root
mysql> GRANT ALL PRIVILEGES ON activerecord_unittest.*  to 'rails'@'localhost';
mysql> GRANT ALL PRIVILEGES ON activerecord_unittest2.* to 'rails'@'localhost';

●postgresqlの設定
$ sudo /etc/init.d/postgresql start
$ sudo -u postgres createuser --superuser $USER

●gitの設定
$ git config --global user.name "kennyj"          # 名前
$ git config --global user.email kennyj@gmail.com # メールアドレス

●railsの取得とテスト
$ git clone git://github.com/rails/rails.git
$ cd rails
$ bundle install
$ cd activerecord
$ rake mysql:build_databases
$ rake postgresql:build_databases
$ cd ..
$ rake test

●railsを修正しパッチを作成する
$ git checkout -b xxxxx # ブランチ名
(ソース修正)
$ git commit -a -m "コミットメッセージ"
$ git checkout master
$ git pull
$ git checkout xxxxx
$ git rebase master
$ git commit -a
$ git format-patch master --stdout > xxxxx.diff
$ cat xxxxx.diff

■更新記録

2011/06/23 ntpについて追記
サービス起動設定について追記

2011/08/02 rvm package -> rvm pkgに変更

ツイッターの基本構造をクラスモデリングする

■概要

今さらながら、ツイッターの基本構造をクラスモデリングしてみました。あまり新しい気付きはありませんな~

■まずはユーザー関係

・ユーザーは、他のユーザーを複数人フォローする事ができる。


・ユーザーは、他のユーザーをリストとしてまとめる事ができ、複数のリストを持つ事ができる。
リストにはプライバシー設定ができ、公開/非公開を選べる。



# 多対多の表現が一定していないのは秘密です(汗)
# 後公開/非公開は完全区画での継承で表現してみました。

・ユーザーは、他のユーザーの公開しているリストをフォローする事ができる。



■次はツイート関係

・ユーザーは、複数回ツイートを行う事ができる。



・ユーザーは、ツイートに返信できる。



・ユーザーは、ツイートをお気に入り登録する事ができる。



・ユーザーは、ツイートをリツイートする事ができる。



■ここまでで、気に入っていない所

・「フォローする・されるが」、ユーザーとリストに重複してあるのが今いち?
  「フォローされる物」という概念を持ち込むべきか?
・公開・非公開を完全区画の継承で表現したが。。
・リツイートの構造
・ダイレクトメッセージの取り扱い。ツイートとはだいぶ性質が異なる。
・クラス図が描ける軽量のUMLツールって、今何が人気なんだ?