Mac上でRailsとMySQLのサーバー分けたい

Table of Contents

開発中はMacでRailsアプリを開発してて、「いざ本番環境へデプロイ!完了!」って一息ついた矢先、「なんか重い…」「想定より遅い…」なんて経験ありませんか?

原因の1つとして、一般的な開発環境では1PCにWebアプリとDBアプリが共存しており、これら2点間の通信はUnixドメインソケット方式で通信が行われます。 一方本番環境ではWebアプリとDBアプリそれぞれにサーバーが立っていることが一般的な基本構成で、これら2点間の通信はTCP/IP方式で通信が行われます。 この通信方式の違いにより大きな速度差が発生し、開発環境ではなかった場所にボトルネックが生まれます。

例えば「SELECTクエリーを叩く回数が多くても、index効いてるから大丈夫だろう」と思っていても、WebサーバとDBサーバが分かれていると、二点間の通信時間が底上げされます。

本番環境ではDBとの通信コストの観点が必要なのに、開発環境ではそれが抜けた環境になっているため、慣れていないと気づきにくい観点とも言えます。

なので開発中でも通信コストが考慮された結果が分かる開発環境を2つのMacを使って実現してみようと思います。

ちなみに単純な興味です。

準備するもの

  • Mac 2台(名称としてMacWとMacDと名付けます)
  • 同じローカルネットワークに繋がっていること(つまり同じWi-Fiに繋がっていればOKです)

構築する環境の構成について

大枠で構成についてまとめるとこんな感じになります。

  • MacWにRailsアプリを立ち上げる
  • MacDにMySQLサーバーを立ち上げる
  • ローカルの開発環境なのでセキュリティは意識しない
  • MySQLを外部アクセスを許可する設定にする
  • MySQLに外部アクセス用のユーザーを作成する
  • RailsアプリのDB接続先をMacDのホスト名、ユーザーに設定する

重要なキーワードは以下の3つとなります。

  • MacDが外部からアクセスされる準備
  • MySQLが外部からアクセスされる準備
  • Railsが外部DBにアクセスする準備

MacDがMacWからアクセスできる準備をする

アクセスするには2つの方法があります。

  1. ローカルIPアドレスを指定
  2. ローカルホスト名を指定

ローカルIPアドレスを指定

これはローカルネットワーク内においてIPアドレスを直接使う方法です。 一時的であれば最も簡単です。

Macで自分のローカルネットワークを調べる方法は、 ifconfig で調べます。

$ ifconfig | grep 192 inet 192.168.11.3 netmask 0xffffff00 broadcast 192.168.11.255

192.168.11.3 というのが、 ifconfig を叩いたPCにIPアドレスになります。

メリット

とにかく楽。に尽きます。

デメリット

IPアドレスの記入部を更新する必要があります。

ローカルホスト名を指定

こちらはMac自身にホスト名を定義することで、IPアドレスに依存せず常に固定のホスト名で接続することが可能になります。 こちらの記事にまとめてあります。

MySQLが外部アクセスされる準備

そもそもMySQLが外部からアクセスを許可していないのは、そう設定がされているためです。bind-address という設定がデフォルトは 127.0.0.1 つまり localhost からの接続のみ許可する設定になっています。

$ cat /usr/local/etc/my.cnf# Default Homebrew MySQL server config[mysqld]# Only allow connections from localhostbind-address = 127.0.0.1

my.cnfの場所が分からない場合は、こちらの記事で確認してみてください。

my.cnfにbind-addressでIPを指定することで、そのIPからの通信を許可します。 ちなみに注意事項としては、MacDのIPアドレスになります。 MacWのIPアドレスではありません。

まず前提知識として、PCには 複数のネットワークインターフェイスがあります。 その中のどのネットワークインターフェイスを許可するのかがbind-addressになります。 先程bind-addressのデフォルトはlocalhostと説明したように、デフォルトではlocalhostからのアクセスのみを許可しています。

今回はパブリック環境でどこからでも誰からでもアクセスできる本番環境と違って、自宅や職場の同一Wi-Fi環境下での話なのでアクセス制限かけたりセキュリティの部分には気を使っていません。 なので bind-address には 0.0.0.0 を設定します。 これは 制限なし の指定になります。どのネットワークインターフェイスからでもアクセスできます。 ちなみに全てのbind-addressをコメントアウトすると同様に無条件で受け付けることになります。

$ cat /usr/local/etc/my.cnf# Default Homebrew MySQL server config[mysqld]# Only allow connections from localhost# bind-address = 127.0.0.1bind-address = 0.0.0.0

設定したらリスタートします。

$ mysql.server restart

一応はローカルネットワーク外からルーターのグローバルネットワークのIPとMacDのローカルIP、MySQLが解放してるポート番号などが分かれば、外部からのアクセスは恐らく可能かとは思いますが、 近辺依存ではありますが、自宅近辺の住民が自分のWi-Fi不正アクセスされるリスクは低いかなと思ってます。(ここらへんは詳しくはないので鵜呑みではなく、自己責任でお願いします)

MySQL内に外部からアクセスするユーザー用意する

MySQLの外部からアクセスする準備ができたら、今度は外部からアクセス用のユーザーを用意します。

例えば下記のようなユーザーを作る場合は

  • ユーザー名: hoge
  • パスワード: pass
  • 対象IP: 192.16配下全部
-- ユーザー作成
create user "hoge"@"192.168.%" identified by "pass";
-- 権限付与
mysql\> grant all on \*.\* to "hoge"@"192.168.%" identified by "pass";

のようにすれば、ユーザー作成して対象DBへの権限設定がされます。

mysql\> select user, host from mysql.user;
+------+-------------+
| user | host |
+------+-------------+
| hoge | 192.168.% |
+------+-------------+

mysql\> show grants for 'hoge'@'192.168.%';
+----------------------------------------------------------------+
| Grants for hoge@192.168.%
+----------------------------------------------------------------+
| GRANT ALL PRIVILEGES ON \*.\* TO 'hoge'@'192.168.%' IDENTIFIED BY PASSWORD '\*196BDEDE2AE4F84CA44C47D54D78478C7E2BD7B7'
+----------------------------------------------------------------+

外部から接続をテストする

この段階で既に外部から接続できている環境になっているはずなので、他Macから接続をします。

IPアドレス指定

$ mysql -u hoge -h 192.168.11.6 -p

ローカルホスト名指定 ホスト名が fuga.local の場合

$ mysql -u hoge -h fuga.local -p

接続できれば外部からMySQLに接続できています。

Railsが外部DBにアクセスする準備

MySQLが外部からのアクセス準備が整えば後は簡単です。

dataases.yml で接続先を指定するだけになります。

IPアドレスが 192.168.11.6の場合

development:
  username: hoge
  password: pass
  host: 192.168.11.6

他は省略してます。

これでRails立ち上げてDBにアクセスできれば完了です。

気になる速度差を測ってみる

1PCでUnixドメインソケット通信した場合と2PCでTCP/IP通信した場合で平均値を出してみました。

1万件のUser(name: string)を事前に用意し、@users = User.all が呼ばれて一覧を返すcontroller に対しGET http://localhost:3000/users を5回呼び出し、最速と最遅を抜いた3つで平均値を出して測定しました。

Unixドメインソケット通信

time
8.6ms
8.5ms
8.5ms
8.3ms
7.6ms

(8.5 + 8.5 + 8.3) / 3 = 8.4333333333ms

TCP/IP通信

time
291.9ms
289.9ms
194.4ms
159.9ms
142.7ms

(289.9 + 194.4 + 159.9) / 3 = 214.7333333333ms

およそ 26倍差がついています。 MySQLサーバーがRailsサーバーよりスペックが劣ってはいますが、それを考慮しても大分差が開いているでしょう。

まとめ

本番環境にできるだけ寄せる構成をしておくことで、本番でしか発覚しない問題を開発段階で気づいて排除できるので、PC台数に余裕があるなら、リリース前だけでも試す価値はあるかなと思いました。

注意事項

開発環境前提においての構成であるため、セキュリティとしてはGoodではありません。 特に公共のネットワーク配下ではやめたほうがいいです。

このエントリーをはてなブックマークに追加