こんにちは。SREチーム インフラエンジニアの綿引です。 既存のシステムを刷新する際やリニューアルなどを行う時など インフラ構成をいろいろ考えるかと思いますが、 DB のクラウド化を検討された方も中にはいらっしゃるのではないでしょうか。 メリット・デメリットはあるかとは思いますが、まずは現状のシステムから 移行可能かという点が気になるかと思います。 そこで本日はオンプレや EC2 インスタンスにインストールした MySQL から、 AWS の RDS の MySQL に移行する方法を試してみたので書いていきたいと思います。 またせっかくなので RDSの暗号化 も一緒にやってみたいと思います。 手順 今回は EC2 にインストールした MySQL から RDS に移行したいと思います。 実施した手順としては以下です。 1. RDS パラメータグループ作成 2. RDS インスタンス作成 3. EC2 レプリケーション事前準備 4. EC2 mysqldump エクスポート 5. RDS mysqldump インポート 6. EC2 → RDS レプリケーション構築 7. アプリケーション向き先変更 8. EC2 → RDS レプリケーション解除 では早速構築していきます。 1. RDSパラメータグループ作成 まずは RDS のパラメータグループの作成です。 パラメータグループとは MySQL の my.cnf のようなものです。 パラメータグループ自体はデフォルトのグループが存在するので 最初に作成しなくても RDS インスタンスを作成することができるのですが、 my.cnf に動的と静的なパラメータがあったように 中にはパラメータ変更後に再起動が必要なケースがあるため、 インスタンス作成時に適用しておくといいと思います。 パラメータグループの作成方法としては AWS コンソールにログインし、 以下の操作を行います。 「Amazon RDS」 → 「パラメータグループ」 → 「パラメータグループの作成」 作成が完了したら 「パラメータの編集」 ボタンから値を編集します。 尚、私が設定したパラメータとしては以下です。 パラメータ 設定値 time_zone Asia/Tokyo sql_mode NO_ENGINE_SUBSTITUTION,STRICT_TRANS_TABLES character_set_client utf8 character_set_connection utf8 character_set_database utf8 character_set_results utf8 character_set_server utf8 skip-character-set-client-handshake 1 基本的には文字コードと time_zone 関連です。 RDS はインスタンスサイズによって、自動でパラメータを変更してくれるようなので 上記だけ設定して様子を見つつリソースが足りないなどあれば拡張していこうと思います。 2. RDS インスタンス作成 次にインスタンスの作成です。 設定やバージョン、スペックとしては以下のようにしました。 テストなのでスペックは低めにしています。 項目 設定値 エンジン MySQL 本番の予定 開発/テスト用 DBエンジンのバージョン MySQL 5.7.17 DBインスタンスのクラス db.m3.medium ストレージタイプ マグネティック ストレージ割り当て 5GB DBパラメータグループ ※ 先ほど作成したパラメータグループ 暗号化を有効 はい DBインスタンスのクラス とを赤字にしておりますが、RDS の暗号化を行うにあたって 暗号化が可能なインスタンスクラス と、 そうでないインスタンスクラス が存在します。 ここを間違えてしまうと暗号化ができないのでご注意ください。 また暗号化には上記のような注意すべきポイントが幾つかあります。 例えば、暗号化は DB インスタンスの 作成時のみしか有効にできない などです。 詳細は以下の公式ページをご覧ください。 Amazon RDS リソースの暗号化 3. EC2 レプリケーション事前準備 ではレプリケーションを行うための事前準備をしていきましょう。 ここは単純に MySQL のレプリケーションを構築する方法と一緒です。 まずはレプリケーション用のユーザを作成します。 mysql> SHOW GRANTS for test@'%'; mysql> GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO test@`%` IDENTIFIED BY 'XXXXXXXX'; mysql> SHOW GRANTS for test@'%'; ・ユーザ +----------+----------------+ | User | Host | +----------+----------------+ | test | % | +----------+----------------+ ・権限 +------------------------------------------------------------------+ | Grants for test@% | +------------------------------------------------------------------+ | GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'test'@'%' | +------------------------------------------------------------------+ 次にレプリケーションの設定のため my.cnf に以下を追加します。 server-id = 100 log-bin=mysql-bin 設定反映のため MySQL を再起動します。 $ sudo /etc/init.d/mysqld restart $ mysql -uroot -p マスタ側の設定ができているか、以下のコマンドで確認します。 mysql> show master status; +------------------+----------+--------------+------------------+-------------------+ | File | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set | +------------------+----------+--------------+------------------+-------------------+ | mysql-bin.XXXXXX | XXX | | | | +------------------+----------+--------------+------------------+-------------------+ 4. EC2 mysqldump エクスポート レプリケーションの事前設定が終わったら mysqldump でエクスポートを行います。 $ sudo mysqldump -u root -p --single-transaction --routines test > mysqldump-test.sql 5. RDS mysqldump インポート 次は RDS に今取得した dump ファイルをインポートします。 RDS の接続先に関しては AWS コンソールから エンドポイント と記載のある部分をご確認ください。 ※ source でファイルを読み込む際は対象ファイルが、 OS側のカレントディレクトリに存在しなければならないのでご注意ください。 $ mysql -h test.ckipnlucwhuv.ap-northeast-1.rds.amazonaws.com -P 3306 -u root -p mysql> use test; mysql> source mysqldump-test.sql これでインポートは完了です。 6. EC2 → RDS レプリケーション構築 次に EC2 から RDS へのレプリケーションの構築を行います。 mysql> show slave status \G mysql> CALL mysql.rds_set_external_master ('EC2のMySQLのIP',3306,'ユーザ名','パスワード','show master statusで確認した **File**',show master statusで確認した **Position**,0); mysql> CALL mysql.rds_start_replication; mysql> show slave status \G 以下の項目がどちらも**Yes**であればレプリケーション構築完了です。 ・Slave_IO_Running: Yes ・Slave_SQL_Running: Yes 7. アプリケーション向き先変更 アプリケーション側で EC2 の MySQL に接続しているものがあれば変更します。 アプリケーション以外にもツール系(phpMyadminなど)も注意ですね。 8. EC2 → RDS レプリケーション解除 アプリケーション側の向き先を変更したら、最後に EC2 → RDS 間の レプリケーションを解除して移行完了です。 mysql> CALL mysql.rds_reset_external_master; ※ reset slave はこれ 因みに、、 mysql> call mysql.rds_stop_replication; ※ stopはこれ mysql> CALL mysql.rds_skip_repl_error; ※ skipはこれ これで移行は完了です。 作業自体は簡単ですが移行元のデータベースが巨大だったりすると結構時間がかかります。 もしサービス側で検討されている方はタイミングが重要ですね。 まとめ 今回は オンプレ・EC2 の MySQL から AWS RDS への移行を実施しました。 現在、クラウド移行を進めている方など参考にして頂ければ幸いです。 ご清覧頂きありがとうございました。 Wedding Parkでは一緒に技術のウエディングパークを創っていくエンジニアを募集しています。 興味のある方はぜひ一度気軽にオフィスに遊びにいらして頂ければと思います。 IT×ブライダルで業界を変える!プロフェッショナルなWEBエンジニア募集!
SREチーム エンジニアの阿久津です。 今回はApacheの403 Forbiddenが表示された時のチェックポイントについて記事にしたいと思います。 環境 Vagrant 1.9.5 CentOS Linux release 7.1.1503 (Core) Apache 2.4.6 前提 設定ファイル /etc/httpd/conf/httpd.conf DocumentRoot /var/hoge テストページ /var/hoge/index.html 事象 テストページを表示しようとすると403 Forbiddenが表示される。 チェックポイント ①Apacheの再起動をしていない 設定ファイルを変更した場合、Apacheを再起動しないと変更が反映されません。 そのため再起動していない場合は、実施します。 ■再起動 $ sudo systemctl restart httpd.service ■リロード Apacheを終了したくない場合は、以下を実行して下さい。 $ sudo systemctl reload httpd.service ②ファイルに読み取り権限がない 権限には「所有者」「所有グループ」「その他のユーザ」がありますが、「その他のユーザ」に読み取り権(r)が付与されているか確認してください。 ※今回の場合だと、/var/hoge/index.html の権限になります。 ■その他のユーザに読み取り権がない場合 $ ls -l /var/hoge/index.html -rw-r----- 1 root root 19 11月 26 11:21 /var/hoge/index.html ■対応 ファイルに読み取り権を付与します。 $ sudo chmod o+r /var/hoge/index.html $ ls -l /var/hoge/index.html -rw-r--r-- 1 root root 19 11月 26 11:21 /var/hoge/index.html ③ディレクトリの権限に実行権がない DocumentRootまでの各ディレクトリで、「その他のユーザ」に実行権(x)が付与されているか確認してください。 今回だと「/」, 「/var」, 「/var/hoge」の3つの内のいずれかにディレクトリに実行権(x)がないと、テストページが表示されません。 ■ /var/hoge/ に実行権がない場合 $ ls -ld /var/hoge/ drwxr-xr-- 2 root root 23 11月 26 20:22 /var/hoge/ ■対応 ディレクトリに実行権を付与する。 $ sudo chmod o+x /var/hoge $ ls -ld /var/hoge drwxr-xr-x 2 root root 23 11月 26 20:22 /var/hoge/ ④httpd.confのDirectoryセクションの設定を見直す Directoryセクション内のRequireの設定を確認しましょう。 ■すべてのアクセスを拒否する場合 $ cat /etc/httpd/conf/httpd.conf Options Indexes FollowSymLinks AllowOverride None Require all denied ← 全てのアクセスを拒否 ... 上記のようにRequireで「all denied」と記述すると、どこからでもアクセス不可となってしまいテストページが表示されません。 そのため以下のような方法でテストページへのアクセスを許可することができます。 ■すべてのアクセスを許可する場合 ... Options Indexes FollowSymLinks AllowOverride None Require all granted ← 全てのアクセスを許可 ... ■特定のIPのみアクセスを許可する場合 ... Options Indexes FollowSymLinks AllowOverride None Require 192.168.1.0/24 ← 指定したIPからのみアクセスを許可 ... ⑤SELinuxが有効になっている SELinuxが有効になっている場合、DocumentRootへのアクセスが拒否されている可能性があります。 SELinuxを利用する予定がない場合は無効に設定しましょう。 ⑤-1. SELinuxを無効にする場合 ■SELinuxの状態確認 $ getenforce Enforcing Enforcingと表示される場合、SELinuxは有効になっている状態です。 ■SELinuxを無効にする SELinuxの設定ファイルは /etc/selinux/config になるため、こちらを編集します。 $ sudo vi /etc/selinux/config ... SELINUX=disabled ← enforcing から disabled に変更 ... ■サーバ再起動 SELinuxの設定を反映するためにサーバの再起動を行います。 $ sudo shutdown -r now ■SELinuxの状態を再度確認 $ getenforce Disabled Disabledと表示されれば、SELinuxは無効に変更されています。 ⑤-2. SELinuxを有効のまま運用する場合 新しいDocumentRootにはSELinuxのラベルを付ける必要があります。 ■元DocumentRootのラベルを確認 $ ls -ld --context /var/www/html drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 /var/www/html ■ラベルの付与 新DocumentRootに元DocumentRootと同じラベルを付与します。 $ sudo chcon system_u:object_r:httpd_sys_content_t:s0 /var/hoge -R ■ラベルの確認 以下のように表示されていれば、元DocumentRootと同じラベルが付与されています。 $ ls -ld --context /var/hoge drwxr-xr-x. root root system_u:object_r:httpd_sys_content_t:s0 /var/hoge まとめ 今回はApacheで403 Forbiddenが表示された時のチェックポイントを記事にさせていただきました。 DocumentRootのファイルやディレクトリの権限を確認しても問題なさそうなのにどうして表示されないの…と思っていたらSELinuxの影響が原因だったという躓きがありました。 もし同じ場所で躓いている方に少しでも参考になりましたら幸いです。 Wedding Parkでは一緒に技術のウエディングパークを創っていくエンジニアを募集しています。 興味のある方はぜひ一度気軽にオフィスに遊びにいらして頂ければと思います。 IT×ブライダルで業界を変える!プロフェッショナルなWEBエンジニア募集!
はじめに こんにちは。SREチーム エンジニアの西脇(@yasuhiro1711)です。 2016年6月より AWS Route53にてマルチバリュー応答ができるようになりました。 Amazon Route 53 announces support for multivalue answers in response to DNS queries できるようになってからかなり日が経ってしまいましたが、少し試してみたのでその記録となります。 このニュースの何が驚きだったかというと、 これまでも、Route53ではバリュー(Aレコード)に複数登録することで、DNSラウンドロビンは利用可能であった。 ※ここでは、「DNSラウンドロビン」という言葉に集約しますが、「Routing Policy」次第で色々な機能があります。 マルチバリュー応答の機能により、バリュー(Aレコード)の登録IPの一つ一つに対して、「Routing Policy」を設定できるようになった。 この設定の組み合わせにより、ELBなどの導入がコスト面や設計の面でできない場合にでも、Route53を利用してある程度柔軟に負荷分散(限定的な)ができるようになりました。 では、マルチバリュー応答を試していきましょう。 内容 webサーバ 3台の準備 上記3台のサーバを「health check」登録 3台のサーバのIPを既存の「シングルバリュー」で登録 3台のサーバのIPを「マルチバリュー」で登録 「マルチバリュー」に「health check」追加 「health check」で落ちたサーバが自動でRoute53の応答から消えるかの動作確認 webサーバ 3台の準備 以下のようにwebサーバ準備します。 今回はシンプルにEC2で立てています。 サーバ IP server1 172.25.0.111| server2 172.25.0.112 server3 172.25.0.113 上記3台のサーバをhealth check登録 AWS console > Route53 > Health checks にて登録します。 Health checksは、ローカルIPには対応していないのでご注意ください。 3台のサーバのIPを既存の「シングルバリュー」で登録 Route53にて登録します。あるレコードに対して複数のIPを設定できます。 「あるレコード」は、同じ名前では複数作成できませんでした。 digの結果は以下です。 # dig +short single_value.xxxxxxxx.net 172.25.0.111 172.25.0.112 172.25.0.113 3台が出てきていますね。 3台のサーバのIPを「マルチバリュー」で登録 続いてマルチバリューを試してみましょう。 こちらもRoute53にて登録します。あるレコードに対して、1つのIPだけ設定しますが、レコードを分けて複数登録ができるようになりました。「Routing Policy」を「Multivalue Answer」に設定することで、「あるレコード」は、同じ名前で複数作成可能になります。 setIDは、ユニークIDになれば名付けルールは自由です。 3台登録しました。dig結果は以下です。 # dig +short multi.xxxxxxxx.net 172.25.0.113 172.25.0.111 172.25.0.112 3台出てきます。先ほどの single_value とまったく同じですね。 「マルチバリュー」に「health check」追加 続けてマルチバリューとして登録した3レコードに、「health check」を追加します。 「Associate with Health Check:」をYESに変更。 「Health Check to Associate:」に、最初に設定したヘルスチェックを設定。 以下のようにhealth check ID がつけばOK。 「health check」で落ちたサーバが自動でRoute53の応答から消えるかの動作確認 multi2の「health check」をwebサーバを停止したり、監視対象のファイルを削除などし、failさせます。 failを確認、コソールでは以下のように「Unhealthy」となります。 digで確認 # dig +short multi.xxxxxxxx.net 172.25.0.113 172.25.0.111 dig結果からも、「health check」で落ちたサーバは消えました。便利ですね。 最後に Route53機能のみで、LBに似せた動作をさせることができるようになりました。今後ますます「health check」と連動した機能は各種サービスで出てくるのではないかと思っています。 Wedding Parkでは一緒に技術のウエディングパークを創っていくエンジニアを募集しています。 興味のある方はぜひ一度気軽にオフィスに遊びにいらして頂ければと思います。 IT×ブライダルで業界を変える!プロフェッショナルなWEBエンジニア募集!
こんにちは。SREチーム インフラエンジニアの綿引です。 本日は goofys という AWS S3 マウント用ソリューションの インストールについて記載しようと思います。 goofysとは goofys とはサーバから S3 バケットをファイルシステムのようにマウントして、 OS上からディレクトリの様に使用できるソリューションです。 S3 の使用方法としては、 1. 静的ウェブサイトホスティング機能を有効にして S3 側でホスティングを行う 2. ログなどを格納する (aws cli などを用いて) といったものが一般的だと思います。 ただ今回の goofys を用いると OS側からマウントができるので、 Linux の「cp」 コマンドや 「ls」 コマンドが使用可能となり、使い方の幅が広がります。 同様の機能を持つソリューションの一つに s3fs というものもあり、 私も今までこちらを使っていたのですがいかんせん遅い。。 最後に goofys と s3fs での簡単な速度検証も行ったので、 是非参考にして頂けたらと思います。 1. goofysインストール 早速 goofys のインストールから初めていきます。 1-1. fuse まずは fuse をインストールします。 # yum install fuse 元々 fuse は s3fs で必要だったためソースでインストールしていました。 ただ goofys 導入後にいざ S3バケットをマウントする所で上手くいかなかったため ソースでインストールした fuse を remove し、 yum で入れ直しております。 もし fuse をソースでインストールされている環境で goofys が上手くいかないという方は、パッケージをお試しください。 1-2. go 次は go のインストールです。 GOROOT と GOPATH は /usr/local に配置したいと思います。 GOROOT=/usr/local/go GOPATH=/usr/local/gocode # wget https://storage.googleapis.com/golang/go1.8.3.linux-amd64.tar.gz # tar -xzf go1.8.3.linux-amd64.tar.gz # mv go /usr/local # mkdir /usr/local/gocode # mkdir /usr/local/gocode/{src,bin,pkg} 次は環境変数の設定です。 # echo export GOROOT=/usr/local/go >> ~/.bash_profile # echo export GOPATH=/usr/local/gocode >> ~/.bash_profile # source ~/.bash_profile # echo export PATH=$PATH:$GOROOT/bin:$GOPATH/bin >> ~/.bash_profile # source ~/.bash_profile # go version go version go1.8.3 linux/amd64 go の導入が完了しました。 1-3. goofys では早速 goofys を導入していきたいと思います。 # go get github.com/kahing/goofys # go install github.com/kahing/goofys goofys導入も完了しました。 ここでもつまづいたので共有させて頂きたきます。 最初構築する際に何も考えずに、WEBから諸先輩方の記事にあるコマンドを そのまま実行したのですが記事が古く、 最新ではないバージョンの goofys がインストールされてしまいました。 問題ないべっ!とそのまま進めてしまっていたのですが、結果上手くいかず。。 理由としては Content-Type です。 最新の goofys では –use-content-type という /etc/mime.types に従って Content-Type を設定してくれるオプションがあるのですが 古いバージョンにはそれがなく、 goofys 経由で画像などを格納した所、 S3側でのシステムメタデータが binary となり 画像が表示されないという苦渋を舐めさせられました。 用途によっては必要ないとは思いますが、もし必要であればお気をつけ下さい。 因みにS3バケット側のバケットポリシーも是非あけておいて下さい。 Content-Type を設定した後の話ですが、 jpeg を格納したのになぜか S3 側のシステムメタデータで xml と認識され Content-Type か!? と悩んでいたのですが素直に 「403 permission denied」 が格納されているだけでした。 1-4. awscli 次は awscli を導入します。 # curl "https://bootstrap.pypa.io/get-pip.py" -o "get-pip.py" # python3.5 get-pip.py # pip install awscli aws cliのセットアップも実施します。 # aws configure AWS Access Key ID [********************]: XXXXXXXXXXXXXXXXXX AWS Secret Access Key [********************]: XXXXXXXXXXXXXXXXXX Default region name [ap-northeast-1]: ap-northeast-1 Default output format [None]: json ここまで必要なものは全てインストールしました。 例によってまさかのここでもつまづいております。 これは完全に goofys とは直接関係のない問題なので詳細は記載致しませんが、 curl のパッケージ が低かったり、python 2.6だと pip install で syntax error が発生したりなど散々でございました。 今ではいい思い出です。 ではマウントしていきます。 2. マウント 今回はリブートしてもアンマウントされないように fstab に記載します。 # cat /etc/fstab LABEL=centos_root / ext4 defaults 0 0 devpts /dev/pts devpts gid=5,mode=620 0 0 tmpfs /dev/shm tmpfs defaults 0 0 proc /proc proc defaults 0 0 sysfs /sys sysfs defaults 0 0 /swapfile swap swap defaults 0 0 /usr/local/gocode/bin/goofys#goofys-test. /goofys fuse _netdev,allow_other,--file-mode=0666,-uid=80,--gid=80,--region=ap-northeast-1,--use-content-type 0 0 設定としては以下です。 オプション 説明 _netdev ネットワークが有効になるまでマウントを待つため指定 allow_other マウントしたユーザ以外のユーザも利用できるようにする –file-mode マウントする際のファイル権限を設定 –uid マウントするユーザーIDを指定 –gid マウントするグループIDを指定 –region リージョンを指定。通常は自動で検出されるらしいです。デフォルトは us-east-1 とのこと –use-content-type /etc/mime.types に従って Content-Type を設定 ではマウントを実施し、出来ているかを確認します。 # mount -a # mount goofys-test on /goofys type fuse (rw,allow_other,default_permissions) 出来ました。 では ls コマンドを発行してみます。 # ls -l /goofys drwxr-xr-x 2 www www 4096 2017-11-10 14:47 test 参照も可能ですね。 3. s3fs vs goofys 速度検証 簡単に速度検証してみました。 参照系で ls コマンドを、書き込み系で cp コマンドを10回程発行し、 それぞれで速度をとります。 尚、 cp コマンドでコピーする元ファイルのサイズは約5MBです。 結果は以下です。 ls 結果 回数 goofys s3fs 1 4 sec 30 sec 2 2 sec 34 sec 3 2 sec 29 sec 4 2 sec 36 sec 5 2 sec 31 sec 6 2 sec 34 sec 7 2 sec 31 sec 8 1 sec 32 sec 9 2 sec 35 sec 10 4 sec 33 sec 平均 2 sec 33 sec cp 結果 回数 goofys s3fs 1 1 sec 1 sec 2 0 sec 1 sec 3 1 sec 1 sec 4 2 sec 2 sec 5 0 sec 1 sec 6 3 sec 2 sec 7 0 sec 2 sec 8 0 sec 2 sec 9 1 sec 2 sec 10 1 sec 2 sec 平均 1 sec 2 sec 特に ls に関しては goofys が圧倒的に早いですね。 これでストレスが解消されます。 まとめ 今回は goofys のインストールから s3fs との速度検証を実施しました。 構築自体は七転び八起きでしたが、いい結果で出て良かったです。 s3fs を使用していらっしゃる方は是非参考にしていただけると嬉しいです。 ご清覧頂きありがとうございました。 Wedding Parkでは一緒に技術のウエディングパークを創っていくエンジニアを募集しています。 興味のある方はぜひ一度気軽にオフィスに遊びにいらして頂ければと思います。 IT×ブライダルで業界を変える!プロフェッショナルなWEBエンジニア募集!
こんにちは。SREチーム エンジニアの西脇(@yasuhiro1711)です。今年4月ウエディングパークはサイトを一部HTTPSから完全HTTPSに移行致しました。移行したことによって、より安心してユーザにもサイトをご利用頂けるようになっております。 完全HTTPS化(常時SSL/TLS化)プロジェクトを実施した4月よりもますます常時SSL化はwebサービスには必須になってきておりますゆえ、その必要性と必要作業について書きたいと思います。 完全HTTPS化(常時SSL/TLS化)が必要な理由 完全HTTPS化(常時SSL/TLS化)はなぜ必要なのでしょうか、弊社では主に以下のように考えました。 1, セキュリティ向上、盗聴やなりすましを防ぐ 画像引用:Google Developers HTTPでは誰もが簡単に通信の盗聴やなりすましが可能です。世間でもこの問題は大きな問題となっており、Googleを始めとした企業やセキュリティ団体などから通信にセキュリティが確保されるHTTPSの利用が推奨されるようになりました。 ログインや問い合わせや投稿フォームなどの入力ページ等の一部をhttpsにするだけでなく、すべてのページをSSL/TLS化にすることでcookieへの不正アクセスを防止することが可能になり、ユーザをセキュリティリスクの脅威から守ることが可能です。 2, 完全HTTPSサイトをSEOで優遇する Official Google Webmaster Central Blog: HTTPS as a ranking signal 最初にこれに関する発表がされたのは、2014年8月のことでした。セキュリティ向上が課題のGoogleは自社サービスだけでなく、Google検索を通じた世の中のすべてのサイトもセキュアにしていくことを方針とします。 その後、2015年からGoogle検索にて本機能は実装され、HTTPSサイトであることが検索ランキングに良い影響を与えることとなっていきました。当初はHTTPSであることがどれだけ影響するかは疑問視されていたところもありましたが、今では常識になりつつあります。 3, Google Chrome、Firefox等、各種ブラウザでHTTP接続への警告強化機能が続々 画像引用:Google Online Security Blog: Next Steps Toward More Connection Security Firefoxが2017年3月に、 Google Chromeが2017年10月(Google chrome 62)より、それぞれ、HTTPで接続した場合、アドレスバーで警告が表示されるように変更されました。これによりユーザの閲覧においても、「このサイトはセキュリティに不安があるサイトなんだ」と認識がされるようになります。ブラウザ側からもHTTPの非推奨、早期のHTTPSへの移行というのが、強制されてきています。 4, HTTP/2を合わせて導入することで高速化が見込める セキュリティの理由からHTTPSが推奨されはじめた話をしてきましたが、その中で登場したすごい技術があります。それがHTTP/2です。私はこれはwebの歴史の中で初めてくらいの「インターネットが進化する」ことができる技術だと思っています。これまでは、 「HTTPSは遅い」 という常識みたいなものがありましたが、HTTP/2を利用することでHTTPSは高速にすることが可能です。以下のサイトをご覧ください。 HTTP vs HTTPS — Test them both yourself https://www.httpvshttps.com/ このサイトを見ていただくとHTTPSがより高速化されていることが実感できると思います。HTTP/2では、サーバとクライアント間で行われる応答の仕組みが変更されたため、普通はオーバーヘッドとなる暗号化のやりとりを入れても全体で見ると高速での通信が可能となるわけです。 この辺りの詳細は、 パフォーマンス向上のためのデザイン設計 の付録にて書かせて頂いておりますので見ていただければと思います。 5, HTTPSデフォルトなサービス仕様が次々と iOSアプリでの通信や、WebPushなども、今ではHTTPSがデフォルトです。今後の様々なサービスやツールでHTTPSは必須となってゆくでしょう。 以上のようなメリットや時流などもあり、弊社でも常時SSL化(完全HTTPS化)を進めることとなりました。しかしながら、今回は最初からHTTPSで始めるサイトではありませんから、お話したメリットを得るための移行にはもちろんリスクもありました。主なリスクで言いますと以下がありました。 リスク1, SEO的にHTTPからHTTPSの移行期間がどうしても発生する。 移行期間はどうしても発生します。これには検索エンジンへの通知や連携をサーチコンソール等でしっかりと行う必要があります。ここで手順を間違ってしまうと、SEOの順位ダウンにもつながります。Googleなどのコンソールでは、これに特化した手順も解説されているため、それを参照して進めて行けば間違いないでしょう。 参考:HTTPS でサイトを保護する – Search Console ヘルプ リスク2, リファラーの受け渡しの影響が発生する 完全HTTPS化(常時SSL/TLS化)すると、HTTPSからHTTPにリファラーを受け渡さない仕様となります。暗号化しているものを平文に渡さない仕様というのは考えてみればたしかに当然ですよね。 画像引用:常時SSLはするべき!?メリットとデメリット | Growth Seed 上図のように、リファラーを渡せないパターンが発生することから、このパターンの影響範囲の洗い出しと確認を進めました。分析においてこの影響が発生すると困ります。このほかにも弊社プロジェクトでは、技術リスクよりもメディアや、各プロジェクトに関するのリスクがあった形です。facebookのいいね数引き継ぎ問題もありました。他にも複数の懸念を調査した上で会社からも正式にGOを頂き、作業を進めていきました。 完全HTTPS化への作業 作業としては主に以下のような項目となります。各サイトやエンジニアブログなどでよく書かれているので詳しくはそちらを参考にしてもらえればと思います。弊社で特に気をつけたポイントはこちらです。 HTTPからHTTPSへのリダイレクト 内部リンク修正 mixed contentsに注意 rel=”canonical”属性の変更も忘れない 各種ツール連携・連携サービスのHTTPS動作確認。 特に広告関連は大事です。 Google Search Console等での登録URLの修正。 HSTS サポートも取り扱い慎重に。 リファラー等のログ集計への影響の確認 最後に、 完全HTTPS化について思うこと まだまだ日本は世界各国と比べると完全HTTPS導入率は低い状態ですので、どんどんHTTPS化は進むといいなと思います。そして完全HTTPS化の流れは必須であり時間の問題だと思っています。とはいうものの、未対応であれば急がず焦らずに対応時期を決めて取り組めばよいと思います。焦りは禁物です。 完全HTTPSについては、現在はまだ発展途上だと思っています。メリットが増えているその裏ではSSL/TLSでの脆弱性の発見や、HTTP/2サーバのセキュリティ問題などその技術に関するリスク発見と対応が繰り返されているため、完全HTTPS化後は、よりシビアにこれら話題に注視する必要があると思います。また、Let’s Enscriptをはじめとした無料SSL証明書が世界的に完全HTTPS化を促進する反面、詐欺サイトやフィッシングサイトでは多くがこれらの証明書を利用しているなどといった次の課題が出始めていたり( 参考:Let’s EncryptとComodoのTLS証明書、96%の詐欺サイトで使用 )と、社会的にもこれらへの対策を入れることが急務ではないかと思っています。 というわけで、日々の完全HTTPS化に関するニュースを気にしながら、運用をしていくのが良いでしょう。 Wedding Parkでは一緒に技術のウエディングパークを創っていくエンジニアを募集しています。 興味のある方はぜひ一度気軽にオフィスに遊びにいらして頂ければと思います。 IT×ブライダルで業界を変える!プロフェッショナルなWEBエンジニア募集!
初めまして。エンジニアの阿久津です。 今回は社内でDNSサーバを構築する機会がありましたのでそれを記事にしたいと思います。 概要 CentOS6にBINDをインストールし、DNSサーバ(内部向け用)を構築します。 自身のクライアントPCからDNSサーバに問い合わせて、名前解決ができるところまでがゴールになります。 環境 物理サーバ CentOS release 6.9 (Final) BIND 9.8.2 BINDインストール インストール $ sudo yum install bind 確認 以下のように表示されればインストールが完了しています。 $ yum list installed | grep bind bind.x86_64 32:9.8.2-0.62.rc1.el6_9.4 bind-libs.x86_64 32:9.8.2-0.62.rc1.el6_9.4 設定ファイル(named.conf)の編集 BINDのメインの設定ファイルは”named.conf”です。 CentOS6にBINDをyumでインストールした場合は、”/etc/named.conf”が設定ファイルになります。 セキュリティを意識する場合は、chrootをすることをおすすめします。 ※編集前にバックアップはとっておきましょう $ sudo vi /etc/named.conf // // named.conf // // Provided by Red Hat bind package to configure the ISC BIND named(8) DNS // server as a caching only nameserver (as a localhost DNS resolver only). // // See /usr/share/doc/bind*/sample/ for example named configuration files. // options { #DNSサーバの待ち受けIPアドレスの設定 listen-on port 53 { 127.0.0.1; 172.16.11.1; #DNSサーバのプライベートIPを指定 }; #listen-on-v6 port 53 { ::1; }; #IPv6は使用しないためコメントアウト directory "/var/named"; dump-file "/var/named/data/cache_dump.db"; statistics-file "/var/named/data/named_stats.txt"; memstatistics-file "/var/named/data/named_mem_stats.txt"; allow-query { localhost; }; recursion yes; dnssec-enable yes; dnssec-validation yes; /* Path to ISC DLV key */ bindkeys-file "/etc/named.iscdlv.key"; managed-keys-directory "/var/named/dynamic"; }; logging { channel default_debug { file "data/named.run"; severity dynamic; }; }; #ローカルネットワークを定義する acl localnet { 172.16.11.0/24; #DNSサーバが所属するネットワークを定義 172.16.12.0/24; #自身のクライアントPCが所属するネットワークを定義 }; #内部向け用の記述 view "internal" { match-clients { localnet; }; #定義したローカルネットワークに合致した場合、view内の処理をする allow-query { localnet; }; #定義したローカルネットワークのみ問い合わせを許可する zone "." IN { type hint; file "named.ca"; }; #正引きゾーン zone "example.com" IN { type master; file "/etc/named/example.com.zone"; }; #逆引きゾーン zone "11.16.172.in-addr.arpa" IN { type master; file "/etc/named/11.16.172.zone"; }; include "/etc/named.rfc1912.zones"; include "/etc/named.root.key"; }; ゾーンファイルの作成 正引きゾーンファイル作成 $ sudo vi /etc/named/example.com.zone $TTL 86400 @ IN SOA dns.example.com. root.example.com.( 2017092701 ; Serial 10800 ; Refresh 3600 ; Retry 3600000 ; Expire 3600 ; Negative Cashe TTL ) IN NS dns.example.com. test1 IN A 172.16.11.2 test2 IN A 172.16.11.3 $TTL 86400 このゾーンの内容が他のDNSサーバーにキャッシュされる時間を表します。今回だと86400秒(1日)となります。 @ ゾーン基点を表します。今回だと自分自身(example.com)が基点となります。 @ではなく「example.com.」と記述してもOKです。 IN 決まり文句となります。「InterNet」を意味しています。 SOA dns.example.com. root.example.com. SOAレコード。「Start Of Authority」の略で、権威を持つゾーンの開始を表します。 今回だとプライマリサーバは「dns.example.com」、管理者のメールアドレスは「root.example.com」となります。 2017092701 ; Serial ゾーンファイルのシリアル番号を表します。「年月日+通し番号」が一般的になります。 10800 ; Refresh セカンダリサーバがゾーンデータの更新をチェックする時間(秒)。今回だと10800秒(3時間)になります。 3600 ; Retry プライマリサーバが応答しない時に再度接続を試みるまでの時間(秒)。今回だと3600秒(1時間)になります。 3600000 ; Expire セカンダリサーバが、プライマリサーバにアクセスできない状態が続いた場合、ゾーンデータを無効にするまでの時間(秒)。今回だと3600000秒(1000時間)になります。 3600 ; Negative Cashe TTL 存在しないドメインを問い合わせた時は、そのドメインが存在しないということを一定期間キャッシュする時間(秒)。今回だと3600秒(1時間)になります。 IN NS dns.example.com. NSレコード。今回だと「dns.example.com.」という名前にしています。 test1 IN A 172.16.11.2 Aレコード。今回だと「test1.example.com」は 172.16.11.2 であることを表します。 test2 IN A 172.16.11.3 Aレコード。今回だと「test2.example.com」は 172.16.11.3 であることを表します。 逆引きゾーンファイル作成 $ sudo vi /etc/named/11.16.172.zone $TTL 86400 @ IN SOA dns.example.com. root.example.com.( 2017092701 ; Serial 10800 ; Refresh 3600 ; Retry 3600000 ; Expire 3600 ; Negative Cashe TTL ) IN NS dns.example.com. 2 IN PTR test1.example.com. 3 IN PTR test2.example.com. $TTL 86400 〜 IN NS dns.example.com. 正引きゾーンファイルと同様です。 2 IN PTR test1.example.com. PTRレコード。今回だと 172.16.11.2 は 「test1.example.com.」 であることを表します。 3 IN PTR test2.example.com. PTRレコード。今回だと 172.16.11.3 は 「test2.example.com.」 であることを表します。 BIND起動 起動 $ sudo service start named 名前解決確認 digコマンドを使います。インストールしていない場合は、bind-utilsでインストールしてください。 インストール $ sudo yum install bind-utils 確認 $ yum list installed | grep bind-utils bind-utils.x86_64 32:9.8.2-0.62.rc1.el6_9.4 正引き確認 「test1.example.com」のIPを知りたい場合 $ dig test1.example.com ; <<>> DiG 9.8.3-P1 <<>> test1.example.com ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 40332 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 0 ;; QUESTION SECTION: ;test1.example.com. IN A ;; ANSWER SECTION: test1.example.com. 86400 IN A 172.16.11.2 ;; AUTHORITY SECTION: example.com. 86400 IN NS dns.example.com. ;; Query time: 7 msec ;; SERVER: 172.16.11.2#53(172.16.11.2) ;; WHEN: Mon Oct 30 20:28:49 2017 ;; MSG SIZE rcvd: 81 ANSWER SECTIONを見ると、正引きゾーンファイルで設定したIPが返ってきているのがわかりますね。 逆引き確認 「172.16.11.2」のドメインを知りたい場合 $ dig -x 172.16.11.2 ; <<>> DiG 9.8.3-P1 <<>> -x 172.16.11.2 ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 35024 ;; flags: qr aa rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 1, ADDITIONAL: 0 ;; QUESTION SECTION: ;2.11.16.172.in-addr.arpa. IN PTR ;; ANSWER SECTION: 2.11.16.172.in-addr.arpa. 86400 IN PTR test1.example.com. ;; AUTHORITY SECTION: 11.16.172.in-addr.arpa. 86400 IN NS dns.example.com. ;; Query time: 3 msec ;; SERVER: 172.16.11.2#53(172.16.11.2) ;; WHEN: Mon Oct 30 19:13:18 2017 ;; MSG SIZE rcvd: 104 ANSWER SECTIONを見ると、逆引きゾーンファイルで設定したドメインが返ってきているのがわかりますね。 まとめ 今回はCentOS6にBINDをインストールし、DNSサーバ(内部向け用)を構築しました。 DNSサーバを構築する機会はなかなかないと思いますので、とても良い経験になったと思います。 今度はAWSのRoute53も機会を見つけて触ってみようと思います。 Wedding Parkでは一緒に技術のウエディングパークを創っていくエンジニアを募集しています。 興味のある方はぜひ一度気軽にオフィスに遊びにいらして頂ければと思います。 IT×ブライダルで業界を変える!プロフェッショナルなWEBエンジニア募集!
はじめに こんにちは、岩橋聡吾です。 今回から複数回に渡って、 Python機械学習ライブラリscikit-learnのcheat-sheet を解説してみたいと思います。 筆者が機械学習を勉強し始めた際、ニューラルネットワーク・サポートベクターマシン・ランダムフォレストなど…アルゴリズムばかりが先に情報として溢れていて「機械学習」を俯瞰して体系的に見ることが難しい状況でした。 結局何ができるの?…そんな時に出会ったのが、この 「cheat-sheet」 でした。 この cheat-sheet から、機械学習は大きく 回帰 ・ 識別 ・ 分類 ・ 次元削減=主成分分析 の4つの目的の達成の為に使用されること、そしてその目的と状況に応じてアルゴリズムが決定されることがわかります。 この4つの目的を組み合わせることで、あらゆることを可能にするのが「機械学習」となります。 第1回では、 cheat-sheet の解説と少し実践もしてみたいと思います。最終的には今回紹介する全てのアルゴリズムを実践したいと思っています…汗。 scikit-learn cheat-sheet の解説 classification(識別:教師あり学習) ◉ざっくり言うと: 『特徴』と『グループ』のデータセットを教師学習とし、グループが分からない『特徴』データを入力した場合に『グループ』を識別。 ◉こんなイメージで使われる: ・今日の 風の強さ から明日の 天候(晴れ・曇り・雨) を識別 ・ 身長 、 体重 と シワの数 から 性別(男・女) を識別 ◉アルゴリズムの選び方: 【SGD識別】 ・教師学習用のデータセットが100,000以上ないとき 【kernel近似識別】 ・教師学習用のデータセットが100,000以上ないとき ・SGD識別がうまくいかない(非線形での識別が必要な)とき 【LinearSVC識別】 ・教師学習用のデータセットが100,000以上あるとき 【k近傍法識別】 ・教師学習用のデータセットが100,000以上あるとき ・LinearSVC識別がうまくいかない(非線形での識別が必要な)とき ・サンプルデータセットがテキストデータでないとき 【SVC識別】【Ensemble識別】 ・教師学習用のデータセットが100,000以上あるとき ・k近傍法識別がうまくいかないとき ・サンプルデータセットがテキストデータでないとき 【ナイーブベイズ識別(テキストデータ専門)】 ・教師学習用のデータセットが100,000以上あるとき ・LinearSVC識別がうまくいかない(非線形での識別が必要な)とき ・サンプルデータセットがテキストデータであるとき ex)迷惑メールかそうでないかの識別などが可能。 regression(回帰:教師あり学習) ◉ざっくり言うと: 『手掛かり』と『答え』のデータセットを教師学習とし、答えが分からない『手掛かり』データを入力した場合に『答え』を予測(数値から数値を予測)。 ◉こんなイメージで使われる: ・今日の 風の強さ から明日の 気温 を予測 ・ 身長 、 体重 と シワの数 から 年齢 を予測 – *1 ◉アルゴリズムの選び方: 【SGD回帰】 ・教師学習用のデータセットが100,000以上ないとき 【Lasso回帰】【ElasticNet回帰】 ・教師学習用のデータセットが100,000以上あるとき ・全ての特徴量が重要でない(重要な特徴の考察をしたい)とき ex)*1の場合、 シワの数 が重要、 身長 と 体重 は重要でないというような考察が可能。 【Ridge回帰】【LinearSVR回帰】 ・教師学習用のデータセットが100,000以上あるとき ・全ての特徴量が重要であるとき 【SVR回帰】【Ensemble回帰】 ・教師学習用のデータセットが100,000以上あるとき ・全ての特徴量が重要であるとき ・Ridge回帰、LinesarSVR回帰がうまくいかない(非線形での回帰が必要な)とき clustering(分類:教師なし学習) ◉ざっくり言うと: 漠然とした『特徴』のデータセットをパターン(似ている・近しい特徴)を見つけて分類(塊化)。特に、簡単に分類できなさそうなものについて『グループ』を定義しやすくする為の手段。 ◉こんなイメージで使われる: ・公園の砂場の砂(硬度・強度・色 etc)の粒子をいくつかの塊に分類。 ・夜空の星(光の強さ・色・距離・温度 etc)をいくつかの塊に分類。 ◉アルゴリズムの選び方: 【MeanShift分類】【VBGMM分類】 ・分類する塊の数を指定しないとき ・対象のデータセットが100,000以上あるとき 【MiniBatchKMeans分類】 ・分類する塊の数を指定するとき ・対象のデータセットが100,000以上ないとき 【KMeans分類】 ・分類する塊の数を指定するとき ・対象のデータセットが100,000以上あるとき 【スペクタクル分類】【GMM分類】 ・分類する塊の数を指定するとき ・対象のデータセットが100,000以上あるとき ・KMeans分類がうまくいかない(非線形での分類が必要な)とき dimensionality reduction(次元削減,主成分分析:教師なし学習) ◉ざっくり言うと: データのばらつきが大きい部分に着目し、逆にばらつきが小さい部分を無視するような視点に変換することで、データ圧縮(次元削減)や主成分分析を実施する手段。3次元を2次元に落とし込み状況を把握しやすくするという点で 写真を撮り・写真から判断する という行為に似ている。 ◉こんなイメージで使われる: ・画像などの大きいデータの次元を削減。 ◉アルゴリズムの選び方: 【ランダマイズPCA】 ・先ずこれを試す 【kernel近似PCA】 ・ランダマイズPCAがうまくいかない(データセットの構造が非線形である)とき ・対象のデータセットが100,000以上ないとき 【Isomap PCA】【SpectralEmbedding PCA】 ・ランダマイズPCAがうまくいかない(データセットの構造が非線形である)とき ・対象のデータセットが100,000以上あるとき 【LLE PCA】 ・データセットの構造が非線形である ・対象のデータセットが100,000以上あるとき ・IsomapPCA、SpectralEmbeddingPCAがうまくいかないとき 実践!classification(識別:教師あり学習)をやってみた それでは、 classification の【SGD識別】アルゴリズムを使った実践していきます。 今回は上記アルゴリズムを使って、アヤメ(花)の「種類」をその「花びらの長さ」と「がくの長さ」から識別してみたいと思います。 Pythonで機械学習環境を構築 ①「Anaconda」をPCにインストール AnacondaはPythonと機械学習でよく使うライブラリを、まとめてインストールしてくれます。 ▷Anacondaインストール方法(Windows) ②jupyter notebookの起動 jupyter notebookはpythonの実行環境の一つです。 ▷jupyter notebookの使い方(Windows) 実装 先ず使用するライブラリをインポートしていきます。 #使用ライブラリインポート import numpy as np #numpyという行列などを扱うライブラリを利用 import pandas as pd #pandasというデータ分析ライブラリを利用 import matplotlib.pyplot as plt #プロット用のライブラリを利用 from sklearn import linear_model, metrics, preprocessing, cross_validation #機械学習用のライブラリを利用 次にデータセットを読み込みます。 機械学習を勉強していく上でサンプルデータは必要不可欠です。 以下は筆者がよく使うサイトで様々なサンプルデータを提供してくれます。今回もこちらからサンプルデータを借りることにします。 ▷UCI ▷UCI_アヤメのデータセット詳細 #データセットの読み込み df_iris_all=pd.read_csv('https://archive.ics.uci.edu/ml/machine-learning-databases/iris/bezdekIris.data', header=None) 念の為データの中身を確認しましょう。 #データの表示 df_iris_all.columns=['sepal-length', 'sepal-width', 'petal-length', 'petal-width', 'class'] df_iris_all.head() ▷実際のデータセット中身(150セット) 今回はこの中から、 ・class=品種 ・petal-length=花びらの長さ ・sepal-length=がくの長さ を使用します。 #「class」と「petal-length」と「sepal-length」を使用 df_iris=df_iris_all[['class', 'petal-length', 'sepal-length']] 次にデータの 標準化 です。 このままSGDアルゴリズムを用いて識別することも可能ですが、 標準化 することで精度の高い予測が可能になります。 データセットは、次元によって数値の単位がバラバラであったり、大きさが極端に異なったりする場合がよくあります。そのまま扱ってしまうと、各次元を見比べたときにそれぞれの関係が分かり辛く、また機械学習においては特定の次元の影響が強く (または弱く) 出てしまうこともあります。 そこで使用するデータセットの各次元のスケールを揃えてあげることで、前述のようなリスクを防ぐことができます。これを 標準化 と言います。 #データの標準化 data=df_iris[['petal-length', 'sepal-length']] sc=preprocessing.StandardScaler() sc.fit(data) std_data=sc.transform(data) #見やすくする為「class」を数値に置き換える(Iris-setosa:0 Iris-versicolor:1 Iris-virginica:2) label=df_iris[u'class'].replace('Iris-setosa', 0).replace('Iris-versicolor', 1).replace('Iris-virginica', 2) 次に【SGD識別】アルゴリズムの準備をします。 その際に損失計算に使われる関数を指定します。今回はヒンジ損失関数を使用します。 機械学習の教師あり学習において、 損失関数 (コスト関数 or 目的関数)というものがあります。 実データと予測データの差を 損失 といい、これを定義するロジックを 損失関数 といいます。教師あり学習の多くのアルゴリズムは、この損失を最小にするような予測データを出力できるように、内部の係数を動的に調整していきます。 損失 はアルゴリズムが予測する為に使う 目印 と言って良いかもしれません。 #【SGD識別】アルゴリズムの準備 clf_result=linear_model.SGDClassifier(loss="hinge") #ヒンジ損失関数を指定 データセットを学習データセットとテスト(予測実施)データセットに分割します。 今回は90%(135セット)を学習データ、10%(15セット)をテストデータとします。 #データセットを学習とテスト(予測実施)に分割して実行 ds_train, ds_test, ds_train_label, ds_test_label=cross_validation.train_test_split(std_data, label, test_size=0.1, random_state=0) #学習実行 clf_result.fit(ds_train, ds_train_label) #予測実行 pre=clf_result.predict(ds_test) 予測が完了しました。 実際の「class」と予測した「class-predict」を比較してみましょう。 #実際の「class」と予測した「class-predict」を比較 df_result=pd.DataFrame(columns=['class', 'class-predict'], dtype=object) df_result['class']=ds_test_label.reset_index(drop=True) df_result['class-predict']=pre pd.DataFrame(df_result) 一行目のみ不一致でそれ以外は一致しました。スコアとしては #スコア出力 ac_score=metrics.accuracy_score(ds_test_label, pre) print(ac_score) 0.933333333333(約93%で予測成功)という結果になりました。 最後に 今回の実践では、アルゴリズム決め打ちで実施しましたが、実際には K分割交差検証 (▷参考) などを用いて精度を確認したり、目的変数(ex アヤメの種類)と説明変数(ex 花びらの長さ・がくの長さ)とでプロットしデータ構造を把握してアルゴリズムを選定していくことになります。 次回は実践に比重を置いたブログにしていきたいと思います。冒頭でも言いましたが、最終的には今回紹介した全てのアルゴリズムを実践することが目標です。最近だと話題のニューラルネットワークアルゴリズムも使えるようになったようですね。引き続き頑張っていきたいと思います…汗。 ご清覧頂きありがとうございました。 Wedding Parkでは一緒に技術のウエディングパークを創っていくエンジニアを募集しています。 興味のある方はぜひ一度気軽にオフィスに遊びにきてください。 ◉筆者のおすすめ記事 ・やってみよう!AWSでWEBサーバー環境構築(シリーズ第1回) ・やってみよう!AWSでWEBサーバー環境構築(シリーズ第2回) ・やってみよう!AWSでWEBサーバー環境構築(シリーズ第3回) ・やってみよう!AWSでWEBサーバー環境構築(Lambda|API Gateway|シリーズ第4回) ・【DB設計入門|ER図|MySQL】コンビニレシートから学ぶ!データモデリング手法
こんにちは。SREチーム インフラエンジニアの綿引です。 今までMySQLの記事ばかり書いておりましたが、 今回は運用面の話でも書かせて頂こうと思っております。 結論から申し上げると、 GitLabのバックアップが原因でサーバの容量が切迫したため バックアップ世代数を変更して問題解決しました。という内容です。 何かの参考にして頂けたら嬉しいです。 1. 事象確認から原因特定まで 弊社では様々なツール類を使用しておりますが、 その中ではGitLabも一部使用しています。 ある時、そのGitLabを搭載しているサーバの 特定のパーティションの使用率が95%になっていることが分かりました。 「あっやべっ、、」 きっとその時にはこんな顔をしていたことでしょうが、 内心はこっちです。 いつでも使用率というのは怖いもので、 ストレージ容量や増加率にもよりますが95%という数字は少し焦ります。 判明した段階で早速原因調査に移りました。 $ du -h | grep [0-9]G [/html] 上記コマンドで判明したのは”gitlab/backups”が 多くの容量を使用しているということでした。 次にGitLabの設定を確認します。 gitlab_rails['backup_keep_time'] = 5184000 ※ 5184000/24/60/60 = 60 世代保存 60世代保存らしいので、設定が効いているかを確認します。 $ ls -l gitlab/backups | wc -l 上記の結果から設定自体は効いていることが判明。良かった。。 ただ1日分のバックアップ容量が増加していたため、 当時は問題なかった全体容量も微増したよう。 そこで先輩と相談しバックアップ世代数を10世代程度に減らすことに。 2. 対応! ・30世代残す場合 gitlab_rails['backup_keep_time'] = 2592000 ・10世代残す場合 gitlab_rails['backup_keep_time'] = 864000 今回は10世代残す方向で進めました。 設定ファイルを変更し、以下のコマンドを実施。 ● 設定ファイル反映 $ sudo gitlab-ctl reconfigure $ sudo gitlab-ctl restart cronの設定が以下なので、午前2時に無事容量が下がったことを確認。 0 2 * * * /gitlab/bin/gitlab-rake gitlab:backup:create > /dev/null 2>&1 これらで対応完了です。 またAWSのS3などを使用していれば、バックアップ先としてそちらも対象にできるみたい。 まとめ 今回は日常ベースの話でしたが、今度は技術検証の話も書きたいです。 ご清覧頂きありがとうございました。 Wedding Parkでは一緒に技術のウエディングパークを創っていくエンジニアを募集しています。 興味のある方はぜひ一度気軽にオフィスに遊びにいらして頂ければと思います。 IT×ブライダルで業界を変える!プロフェッショナルなWEBエンジニア募集!
こんにちは、サーバーサイドエンジニアの菅原です。 今回は前回の続き「swift3でニュース配信アプリを作ってみる #1 (storyboard編)」 で実装のソースをベースにみていきたいと思います。 URLSessionを使ってHTTP通信する urlRequestに取得したいapiのリクエストURLを設定する URLSessionを使ってタスクを作る Jsonの結果データを取得する 返って来たデータを整形し、Article.swiftのオブジェクトの中に入れていく。 task.resume()でタスクを開始する var articles: [Article]? = [] override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. getArticles() } func getArticles() { let urlRequest = URLRequest(url: URL(string: "https://newsapi.org/v1/articles?source=techcrunch&sortBy=latest&apiKey=1125d5f179304a4abe798dc427faed07")!) let task = URLSession.shared.dataTask(with: urlRequest) { (data,response,error) in if error != nil { print(error) return } // Article.swift self.articles = [Article]() do { let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as! [String : AnyObject] if let articlesFromJson = json["articles"] as? [[String : AnyObject]] { for articleFromJson in articlesFromJson { let article = Article() if let title = articleFromJson["title"] as? String, let url = articleFromJson["url"] as? String, let urlToImage = articleFromJson["urlToImage"] as? String { article.title = title article.url = url article.imageUrl = urlToImage } self.articles?.append(article) } } DispatchQueue.main.async { self.tableview.reloadData() } } catch let error { print(error) } } task.resume() } tableViewに表示設定する tableViewの関数にセルのデータをセットする extensionの拡張機能を使い画像データを取得する func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "articleCell", for: indexPath) as! ArticleCell cell.title.text = self.articles?[indexPath.item].title cell.imgView.downloadImage(from: (self.articles?[indexPath.item].imageUrl!)!) return cell } func numberOfSections(in tableView: UITableView) -> Int { return 1 } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return self.articles?.count ?? 0 } extension UIImageView { func downloadImage(from url: String){ let urlRequest = URLRequest(url: URL(string: url)!) let task = URLSession.shared.dataTask(with: urlRequest) { (data,response,error) in if error != nil { print(error) return } DispatchQueue.main.async { self.image = UIImage(data: data!) } } task.resume() } } シミュレータで実行する これで簡単なニュース配信をするアプリを作ることができました。 まとめ storyboardの使い方に慣れるのが時間がかかる Http通信をするiosのAPIが使いやすくて簡単にデータを取ることができた。 TableViewが少し初心者には難しかった。 次回は音楽やfirebaseなどと連携させたアプリも作っていきたい。
こんにちは、エンジニアの東です。 PHPerが学ぶgo tour #1 ~基本~ に引き続き、 PHPerが Tour of Go で学んでいくときのためにPHPとGoでの書き方の比較をしていきたいと思います。 制御構文 今回はTour of Goの制御構文から(https://go-tour-jp.appspot.com/flowcontrol/1)紹介していきます。 制御構文は制御文に括弧がいらなくて戸惑うかと思いいますが、それくらいであとは基本的にシンプルです。 for いわゆる普通のfor文です。foreach文についてはまた別記事で紹介していきます。 go package main import "fmt" func main() { sum := 0 for i := 0; i (引用: https://go-tour-jp.appspot.com/flowcontrol/1) php namespace Main; class Main { static function main() { $sum = 0; for ($i = 0; $i GoにおけるWhile go package main import "fmt" func main() { sum := 1 for sum (引用: https://go-tour-jp.appspot.com/flowcontrol/3) php namespace Main; class Main { static function main() { $sum = 1; while ($sum if go package main import ( "fmt" "math" ) func sqrt(x float64) string { if x (引用: https://go-tour-jp.appspot.com/flowcontrol/5) php namespace Main; class Main { protected function sqrt(float $x) : string { if ($x If with a short statement go package main import ( "fmt" "math" ) func pow(x, n, lim float64) float64 { if v := math.Pow(x, n); v (引用: https://go-tour-jp.appspot.com/flowcontrol/6) php namespace Main; class Main { protected function pow(int $x, int $n, float $lim) : float { $v = pow($x, $n); if ($v if else 評価文のための簡単なステートメントを評価文に記述でき、 if文のためだけの変数をいつまでも保持しつづけなくて済みます。 go package main import ( "fmt" "math" ) func pow(x, n, lim float64) float64 { if v := math.Pow(x, n); v < lim { return v } else { fmt.Printf("%g >= %g\n", v, lim) } // can't use v here, though return lim } func main() { fmt.Println( pow(3, 2, 10), pow(3, 3, 20), ) } (引用: https://go-tour-jp.appspot.com/flowcontrol/7) php namespace Main; class Main { protected function pow(int $x, int $n, float $lim) : float { $v = pow($x, $n); if ($v switch switchはGo言語はBreakとかかなくてもBreakされるエコな書き方です! Breakしてほしくない場合だけ、fallthroughと書いてあげればよいのです。 go package main import ( "fmt" "runtime" ) func main() { fmt.Print("Go runs on ") switch os := runtime.GOOS; os { case "darwin": fmt.Println("OS X.") case "linux": fmt.Println("Linux.") default: // freebsd, openbsd, // plan9, windows... fmt.Printf("%s.", os) } } (引用: https://go-tour-jp.appspot.com/flowcontrol/9) php print('Go runs on '); $os = 'linux'; switch ($os) { case 'darwin': print('OS X.'); break; case 'linux': print('Linux.'); break; default: printf("%s.", $os); } defer Goの非常に便利なのがDeferです。 「ファイルオープンしたので、後でクローズしてねー」 と、予約するように記述ができるのと、スタック(Last-In First-Out)で実行されるため、入れ子でオープンクローズしている場合も安心です。 go package main import "fmt" func main() { defer fmt.Println("world") fmt.Println("hello") } (引用: https://go-tour-jp.appspot.com/flowcontrol/12) php try { print("hello "); } finally { print("world"); } これくらい簡単なものだとありがたみがわかりづらいですが、関数でネストしていったり、行数が多くなってクローズするの忘れてた!っていうのが防げます。 後ですることを宣言することのありがたみは複雑なシステムになればなるほど実感するのかもしれません! いかがだったでしょうか! 今回はGoの制御構文についてPHPを絡めて紹介しました。 次回はポインタを紹介したいと思います。
はじめまして、システムエンジニア新卒1年目の若宮です。 今回はGoのフレームワークであるRevelを触ってみたので紹介します。 Revelとは Revelは機能が豊富なフルスタックフレームワークです。 フルスタックなのでgoの基本的な部分を学ぶのにとても役に立ちます。 webアプリケーションに必要な機能が揃っていてコードを編集すると 自動的にコンパイルを実行できたり、devモードの実行で簡単にデバックができます。 そしてハイパフォーマンスな言語です。 ちなみにGoのフレームワークにはGinやMartiniなどお酒の名前が多いことで有名ですが Revelは酒盛りという意味があるそうです。酔いしれる。 引用元: https://revel.github.io/ Revelのインストール 今回の環境 mac OS go1.8.3 darwin/amd64 Revel v0.17.1 今回は公式のチュートリアルに沿ってやっていきましょう。 https://revel.github.io/tutorial/gettingstarted.html (goのインストールは済んでいる状態からスタートします) 1. GOPATHの設定 (今回私はsampleディレクトリ内にgocode用のディレクトリを準備します) $ mkdir sample $ cd sample $ mkdir gocode $ ls gocode $ export GOPATH=~/sample/gocode $ echo export GOPATH=$GOPATH &gt;&gt; ~/.bash_profile 2. gitとhgのインストール $ brew install git $ brew install hg 3. go commandでrevelをインストール $ pwd ~/sample $ go get github.com/revel/revel 4. revelのcommand line toolをインストール $ go get github.com/revel/cmd/revel $ export PATH=”$PATH:$GOPATH/bin” 5. revelコマンドで確認 以上でrevelのインストールは完了です。 applicationの作成 ではapplicationを作成してブラウザ上に表示してみましょう。 サンプルコードの実行 sampleappを作成します sampleappができたので実行してみます。 ブラウザでhttp://localhost:9000にアクセスします。 実行できました。 変数の受け渡し では、controllerからviewへ変数を渡してブラウザに表示してみましょう。 controllerに下記のように変数を定義します。 ブラウザに表示するためにviewファイルも下記のように変更します。 local:9000にアクセスすると… 反映されました! まとめ 今回はGoのフレームワークであるRevelの導入から簡単な変数の受け渡しまでやってみました。 revelは機能も豊富で初心者でも扱いやすいフレームワークなのでここからどんどんGoの勉強に役立てて行こうと思います。
こんにちは、サーバーサイドエンジニアの菅原です。 今回はWWDC2017にてios11やxcode9の発表など盛り上がりを見せているAppleから Swift3に触れてみたいと思い簡単な二部構成のニュース配信アプリを開発しました。 環境と用意するもの News API (Tech Crunch APIを使用しました) https://newsapi.org/techcrunch-api swift3 xcode8.3 プロジェクトを作成する ニュース記事のレイアウトを設置する NavigationVar TableView それぞれの部品についてはConstrainを適用させる。 UIを設置する Prototype Cellsを1に設定する Image Viewを設置する Labelを設置する UITableViewCellを継承する UIKitのUITableViewCellを継承してカスタムセルの表示方法を設定する ArticleCell.swiftを作成する。 MainStoryboardから各パーツからArticleCell.swiftに紐付けをする。 import UIKit class ArticleCell: UITableViewCell { @IBOutlet weak var imgView: UIImageView! @IBOutlet weak var title: UILabel! override func awakeFromNib() { super.awakeFromNib() // Initialization code } override func setSelected(_ selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) // Configure the view for the selected state } } 同様にArticle.swiftで記事のオブジェクトを作成。 現在は取得するタイトル、URL、画像URLを受け取るように設定している。 import UIKit class Article: NSObject { var title: String? var url: String? var imageUrl: String? } ViewConrollerでtableViewのセルに値を設置する func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -&gt; UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "articleCell", for: indexPath) as! ArticleCell // セルのタイトルにテキストをここで設定する cell.title.text = "THIS IS NEWS TITLE" return cell } func numberOfSections(in tableView: UITableView) -&gt; Int { return 1 } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -&gt; Int { return 1 } これだけでbuildすると以下のようにシミュレータが起動して 設定した値がtableViewに入っていることがわかる。 次回 今回はstoryboardの使い方をメインに画像で解説していきましたが実際に取得するための実装を swift3でニュース配信アプリを作ってみる #2 (実装編) にて続きますのでそちらをご覧ください。
こんにちは!2年目のサーバーサイドエンジニアの菅原です。 先日ウエディングパークで開催した「Wedding Park TECH TALK #1 生産性向上」について報告致します。 ウエディングパークではこれまで、月に一度社内でエンジニアLT会を開催していました。 社内LT会の取り組みについて 今回は「No.1 BRIDAL TECH TEAM By→20」を目指すにあたり、初めてウエディングパーク主催のmeetup型LT会を開催しました! 記念すべき第一回目のテーマは「生産性向上」 会場は昨年オープンしたウエディングパークのCreators Studio「通称: Cスタ」です。 ウエディングパーク エンジニア・デザイナのための集中スペース「Cスタ」開設 生産性について熱いトークを繰り広げた様子をレポートいたします! 開会の挨拶 WeddingPark 菅原 社員のメンバーは公募のLT会は初開催ということで少し緊張気味の中、開会の挨拶をしました。 ウエディングパークのLT会は参加した全員が本気で技術の吸収をする、そして参加した全員が楽しく みんなで盛り上げることを目指しています、 例えば… “面白い”、”すごい!”、”それは使えそう!”と思った時は「よっ!」っという掛け声に合わせて拍手し、 逆に、”それ微妙”、”すごいの?”という時は「んー….」っと唸ります。(これはなかなか出ません) 会場がアットホームな雰囲気になったところで乾杯してLTがスタート! 発表内容 1. WeddingPark 東 「Goの自動生成による生産性向上」 2. ゲストLT枠 PNSK 「What is the Productivity growth?」 3. WeddingPark 久保 「Google Apps Script で業務効率化」 4. WeddingPark 武田 「Firefoxアドオンで本番環境判定」 5. WeddingPark 栗山 「ヘッドレスChromeでブラウザテスト自動化入門」 1.「Goの自動生成による生産性向上」 WeddingPark 東 サーバーサイドエンジニアの東さん。ウエディングパークではGo勉強会の主担当もしているGo大好きな東さんが、今回はGoのコード整形についてのフォーマットのテンプレート作成で生産性向上のLTをしました。 これによって誰が触っても統一された書き方になることからコードレビューやテストにおいても生産性がアップ!大規模開発ならこれで安心ですね! 2.「What is the Productivity growth?」 ゲストLT枠 PNSK 今回ゲストLT枠で参加していただいたPNSKさん、今回はエンジニアとしての生産性とは? について登壇していただきました。 業務で使うツールの選定についてや業務メールのや多くの設定に使うスクリプトをHubotの組み合わせによる生産性向上などなど熱い発表をしていただきました 。 日頃の業務でルール化されていることなども生産性に繋げることができないか改めて考えさせられました! 3.「Google Apps Script で業務効率化」 WeddingPark 久保 2年目のサーバーサイドエンジニアの久保さん。「業務で開発サーバーのテストメールをフィルタリング」や「勤怠連絡を通知してくれるbot」などをGoogle Apps Scriptによって生産性向上させた話をしていただきました。 Google Apps Script初学者にも丁寧でわかりやすいLTで、明日からでも不便だと感じたことをすぐに自動化させることができそうでした! 4.「Firefoxアドオンで本番環境判定」 WeddingPark 武田 ウエディングパークの姉妹サイトである「Photorait」の開発責任者をしている武田さん、今回は初めてFireFoxで使うアドオン開発したことについてお話ししていただきました! 開発環境でステージング環境と本番環境などをドメインを見ずに瞬時に視覚的に判断できるタブカラーというアドオンで業務の生産性が上がったとのことです! デモがすごくシュールになりましたが盛り上がり、ダウンロード数が徐々に上がってきているそうです!FireFoxユーザの皆さんも検索してみてください! 5.「ヘッドレスChromeでブラウザテスト自動化入門」 WeddingPark 栗山 5年目のサーバーサイドエンジニアでウエディングパークの姉妹サイト「Ringraph」の開発責任者の栗山さん。 業務においてSEOなどの開発でタグやディスクリプションなどのデータの条件によって異なるパターンのテストをするのが地味に大変だという背景から自動化するお話しをしていただきました。 Node.jsでGoogleが提供しているPuppeteerと言うライブラリーを用いて開発し生産性の向上をしました!Chrome59 (2017/6月頃) から搭載された機能ですので業務でもすぐに使えそう! 懇親会の様子 LT後には参加いただいた皆様全員で懇親会!エンジニアのLT会はお寿司やピザというイメージですが 今回は第一回開催という事で、表参道っぽい軽食を囲みました! エンジニア同士たくさん情報交換をしとても盛り上がりました! 最後に 総勢30人を超えるメンバーでお決まりのウエパポーズをとりながらの集合写真! ウエパ初meetup型LT会、大成功でした!! 参加してくださったみなさま、ありがとうございました! 次回の開催もお楽しみに!!
こんにちは、エンジニアの東です。 今回は「PHPerが学ぶGo Tour」という題目通り、 Tour of Go をPHP使いが学ぶ上での言語の違いを書いていきたいと思います。 なぜこの記事を書くに至ったか。それは弊社では言語にGoを採用しておりますが、 慣れ親しんだ言語とは別に新しい言語を扱うのは、非常に戸惑うことが多いと思います。 筆者自身もよく、GoとPHPを行き来するため、PHPでセミコロン忘れやGoで変数定義で $piyo と書いてしまい、 「動かない…なんでー…」っと、小恥ずかしいミスをしまったこともあります。 なかなか新しい言語を使うのにはその言語をなれるまで結構大変です。 また、Tour of Go は他言語を学んでいる前提でのサイトです。 しかし、Go言語は他言語と勝手が違うことが多く、導入に戸惑う点も多々あると思います。 まず、言語に触れてみるのが大事だと思いますのでざっくり大雑把にTour of GoのソースをPHPで書いたらこんな感じですって紹介していきたいと思います。 ※ Goに関する説明は本家サイトであるTour of Goにありますので、そちらをすすめながら、同時にこちらの記事をみていただければと思います。 ※ 本記事は、導入のしやすさを重視するため、正しくは異なるような、誤解を与える表現が含まれていることがございます。ご了承いただければ幸いです。 Hello World! 定番のHello World! この段階では、 おまじない な書き方ですが、それはGo tourが後々説明してくれています。 package main import "fmt" func main() { fmt.Println("Hello, 世界") } (引用: https://go-tour-jp.appspot.com/welcome/1) 1.phpのHello world! print("Hello, 世界\n"); 2.php goに似せてみた場合 namespace main; class Main { static function main() { print("Hello, 世界\n"); } } Main::main(); Packages パッケージとimport パッケージは、他言語でいうところの名前空間に近いです。 package main import ( "fmt" "math/rand" ) func main() { fmt.Println("My favorite number is", rand.Intn(10)) } (引用: https://go-tour-jp.appspot.com/basics/1) 1.phpで書く場合 print('My favorite number is '.mt_rand(0, 10)); 2.php goに似せてみた場合 namespace main; // PHPで標準関数なので、本来書きませんが、goのimportはphpでいうuseに近いです。 // use Math; // use String; class Main { static function main() { print('My favorite number is '.mt_rand(0, 10)); } } Main::main(); 関数 関数 引数の型が後ろにつくのは独特ですね。 package main import "fmt" func add(x int, y int) int { return x + y } func main() { fmt.Println(add(42, 13)) } (引用: https://go-tour-jp.appspot.com/basics/4) namespace main; class Main { protected function add(int $x, int $y) : int { return $x + $y; } static function main() { print(self::add(42, 13)); } } Main::main(); 2値以上返却する関数 2値以上返却するのは既存コードを書きかえるときにシンプルにしやすいですね。 package main import "fmt" func swap(x, y string) (string, string) { return y, x } func main() { a, b := swap("hello", "world") fmt.Println(a, b) } (引用: https://go-tour-jp.appspot.com/basics/4) PHPの場合2値以上返却できないので下記な感じしょうか。 namespace main; class Main { protected function swap(string $x, string $y) : array { return [$y, $x]; } static function main() { list($a, $b) = self::swap("hello", "world"); printf("%s %s", $a, $b); } } Main::main(); 基本の型(ゼロ値) ゼロ値はGo特有なのでPHPでどのように記述するかはないですが、PHPでは基本的に全て初期化して使っていると思えば良いかと思います。 package main import "fmt" func main() { var i int var f float64 var b bool var s string fmt.Printf("%v %v %v %q\n", i, f, b, s) } (引用: https://go-tour-jp.appspot.com/basics/12) $i = (int)0; $f = (float)0.0; $b = false; $s = ''; printf("%d %f %b %s", $i, $f, $b, $s); いかがだったでしょうか 今回はGoの基礎をPHPに絡めて紹介しました。 次回は制御構文を紹介したいと思います。
こんにちは、岩橋聡吾です。 やってみよう!AWSでWEBサーバー環境構築、好評の 第2回 に続きまして、待望の第3回をやっていきたいと思います。前回までに作成したインフラ構成に KVS(Elasticache) 、 データベース(RDS) さらに CDN(CloudFront) を追加して、Webアプリケーションの動作環境構築の仕上げをしましょう。 RDSを設定する 一部の例外を除き、WEBサイト上では情報を整理して格納する・検索して取り出すという機能性を少なからず持っていると言っても過言ではありません。そのようなサイトにおいては必然的に何らかのデータベースサーバーを運用することになります。今日のWEBで使われるデータベースは概ね以下の4つに絞られてくるのですが、これらのDBサーバーを構築・運用する場合においては、運用時の死活監視やバックアップ、パラメータの調整やパフォーマンスチューニングなどが常に課題となります。Amazon RDSを活用することでこれらの課題を自動化して運用の手間を低減し、WEBサービスそのもののサービス向上という本質的な課題に注力することが出来ます。早速設定してみましょう。 まずRDSの作成に必要なサブネットを作成します。 作成時にサブネットの名前を間違えてしまったので直しておきますw 次にメニューからRDSを選択して作成ウィザードを起動しましょう。 MySQLと互換性がありパフォーマンスも高いAuroraを選択したいところですが、無料利用枠の対象外ですので今回はMySQLを選択します。 今回はブログ作成用ですので、開発/テストを選んで次に進みます。 DBの詳細を設定していきます。テストしたいだけであれば無料利用枠内で使用可能な機能だけに絞るチェックボックスを有効にしておきます。 パブリックアクセス可能設定や、バックアップ時間の設定を行い次に進みます。 これでインスタンスが作成されました。 接続の確認前にセキュリティーグループを設定します。RDSのウィザードで新しくセキュリティーグループが作成されたはずなのでこちらを変更します。 次にMySQLに接続するためのユーティリティーを、接続元になる ec2 へインストールします。 [ec2-user@ip-10-0-0-204 ~]$ sudo yum install mysql Loaded plugins: priorities, update-motd, upgrade-helper amzn-main/latest | 2.1 kB 00:00 amzn-updates/latest | 2.3 kB 00:00 Resolving Dependencies –> Running transaction check —> Package mysql.noarch 0:5.5-1.6.amzn1 will be installed –> Processing Dependency: mysql55 >= 5.5 for package: mysql-5.5-1.6.amzn1.noarch –> Running transaction check —> Package mysql55.x86_64 0:5.5.54-1.16.amzn1 will be installed –> Processing Dependency: real-mysql55-libs(x86-64) = 5.5.54-1.16.amzn1 for package: mysql55-5.5.54-1.16.amzn1.x86_64 –> Processing Dependency: mysql-config for package: mysql55-5.5.54-1.16.amzn1.x86_64 –> Running transaction check —> Package mysql-config.x86_64 0:5.5.54-1.16.amzn1 will be installed —> Package mysql55-libs.x86_64 0:5.5.54-1.16.amzn1 will be installed –> Finished Dependency Resolution Dependencies Resolved ================================================================================ Package Arch Version Repository Size ================================================================================ Installing: mysql noarch 5.5-1.6.amzn1 amzn-main 2.7 k Installing for dependencies: mysql-config x86_64 5.5.54-1.16.amzn1 amzn-updates 49 k mysql55 x86_64 5.5.54-1.16.amzn1 amzn-updates 7.5 M mysql55-libs x86_64 5.5.54-1.16.amzn1 amzn-updates 815 k Transaction Summary ================================================================================ Install 1 Package (+3 Dependent packages) Total download size: 8.3 M Installed size: 31 M Is this ok [y/d/N]: y Downloading packages: (1/4): mysql-5.5-1.6.amzn1.noarch.rpm | 2.7 kB 00:00 (2/4): mysql-config-5.5.54-1.16.amzn1.x86_64.rpm | 49 kB 00:00 (3/4): mysql55-5.5.54-1.16.amzn1.x86_64.rpm | 7.5 MB 00:00 (4/4): mysql55-libs-5.5.54-1.16.amzn1.x86_64.rpm | 815 kB 00:00 ——————————————————————————– Total 8.7 MB/s | 8.3 MB 00:00 Running transaction check Running transaction test Transaction test succeeded Running transaction Installing : mysql-config-5.5.54-1.16.amzn1.x86_64 1/4 Installing : mysql55-libs-5.5.54-1.16.amzn1.x86_64 2/4 Installing : mysql55-5.5.54-1.16.amzn1.x86_64 3/4 Installing : mysql-5.5-1.6.amzn1.noarch 4/4 Verifying : mysql-5.5-1.6.amzn1.noarch 1/4 Verifying : mysql55-5.5.54-1.16.amzn1.x86_64 2/4 Verifying : mysql55-libs-5.5.54-1.16.amzn1.x86_64 3/4 Verifying : mysql-config-5.5.54-1.16.amzn1.x86_64 4/4 Installed: mysql.noarch 0:5.5-1.6.amzn1 Dependency Installed: mysql-config.x86_64 0:5.5.54-1.16.amzn1 mysql55.x86_64 0:5.5.54-1.16.amzn1 mysql55-libs.x86_64 0:5.5.54-1.16.amzn1 Complete! 上手く入りました。 それでは確認してみましょう。 [ec2-user@ip-10-0-0-204 ~]$ mysql -h yattemiyou.cxotk9qitqo0.ap-northeast-1.rds.amazonaws.com -u yattemiyou –password=Abc12345 amazonaws.com -u yattemiyou –password=Abc12345 Welcome to the MySQL monitor. Commands end with ; or \g. Your MySQL connection id is 54 Server version: 5.6.27-log MySQL Community Server (GPL) Copyright (c) 2000, 2016, Oracle and/or its affiliates. All rights reserved. Oracle is a registered trademark of Oracle Corporation and/or its affiliates. Other names may be trademarks of their respective owners. Type ‘help;’ or ‘\h’ for help. Type ‘\c’ to clear the current input statement. mysql> 成功しました! KVS(Elasticache)を設定する サイト上の処理の一部には計算や検索処理に時間の掛かるものがあるでしょう。例えば1日1回だけ更新されるデータが幾つかあって、その検索1回につき300ミリ秒掛かる場合にWEBサイトへ大量のアクセスがあったらどうなるでしょうか。きっとサイトは簡単にパンクしてしまうでしょうね。(検索処理が遅いのも大問題ですが) そもそも1日1回しか更新されないデータを取り出すために毎度DBサーバーへ問い合わせに行くのは勿体無いですよね?何処かに検索結果だけを溜めておけるような仕組みが欲しいと思います。 こんな時にうまく活用したいのがKVS (Key Value Store)です。さっきの1日1回だけ更新されるデータを例えば、今日の天気としましょう。格納された今日の天気を300ミリ秒くらい掛けてDBサーバーから取り出して、その結果だけを「today-weather」と呼ばれる識別子を付けて別の場所に保存しておきます。その日のうちであればデータの内容は変わりませんので、必要になったらDBの代わりに都度KVSへ問い合わせて、「today-weather」の識別子がついたデータを要求します。そして日付が変わったらその日最初の1回だけ、再びDBサーバーからデータを取り出してKVSに保管します。こうすることで、DBへのリクエスト回数を削減できますね。 このようなミドルウェアをWEBアプリに活用することでサイトのパフォーマンスをさらに改善することが可能になります。それではインフラの設定をしてみましょう。 ElastiCacheの設定に必要なサブネットを設定します。 ElastiCacheのメニューからサブネットグループを設定します。サブネットグループとは、文字通りVPC内のサブネットを束ねるAWS上の概念となります( 第一回参照 )。 それではElastiCacheのキャッシュクラスターを作成します。(とは言っても今回は最小構成として複数台使わないのでクラスターではありませんが…) Redisかmemcachedを選択します。Number of replicasにNoneを設定すると単一構成になります。(memcachedについて、このままではレプリケーションができないので特別な方法が必要となります…筆者はとても嵌りましたw。) Node typeはデフォルトでかなり大きめのインスタンスタイプが設定されています。テストで使う場合は小さいものを設定しましょう。 Advanced Redis Settingsを開いて、先程作成したSubnet Groupを指定しましょう。 正しく作成できたようですので接続を試みてみます。 エンドポイント情報をコピーして再度ターミナルを開きます。 Redisにはとりあえずtelnetを使えば接続が出来ますのでやってみましょう。 [ec2-user@ip-10-0-0-204 ~]$ sudo yum install telnet Loaded plugins: priorities, update-motd, upgrade-helper Resolving Dependencies –> Running transaction check —> Package telnet.x86_64 1:0.17-48.8.amzn1 will be installed –> Finished Dependency Resolution Dependencies Resolved ================================================================================ Package Arch Version Repository Size ================================================================================ Installing: telnet x86_64 1:0.17-48.8.amzn1 amzn-main 62 k Transaction Summary ================================================================================ Install 1 Package Total download size: 62 k Installed size: 107 k Is this ok [y/d/N]: y Downloading packages: telnet-0.17-48.8.amzn1.x86_64.rpm | 62 kB 00:00 Running transaction check Running transaction test Transaction test succeeded Running transaction Installing : 1:telnet-0.17-48.8.amzn1.x86_64 1/1 Verifying : 1:telnet-0.17-48.8.amzn1.x86_64 1/1 Installed: telnet.x86_64 1:0.17-48.8.amzn1 Complete! [ec2-user@ip-10-0-0-204 ~]$ telnet yattemiyou-kvs.f1pyqo.0001.apne1.cache.amazonaws.com 6379 Trying 10.0.10.39… telnet: connect to address 10.0.10.39: Connection timed out 繋がりませんでした 汗。 あれこれ見てみるどうやらセキュリティーグループを設定するのを忘れていたようです。あるあるですねw。 ではElastiCacheで使われているセキュリティーグループを調べます。 セキュリティーグループのIDが分かったのでこれに対してRedisの接続ポートに当たる6379を内部で許可するようにします。 再度試してみると。。 [ec2-user@ip-10-0-0-204 ~]$ telnet yattemiyou-kvs.f1pyqo.0001.apne1.cache.amazonaws.com 6379 Trying 10.0.10.39… Connected to yattemiyou-kvs.f1pyqo.0001.apne1.cache.amazonaws.com. Escape character is ‘^]’. SET a a +OK GET a $1 a うまくいきました! CloudFrontを設定する それでは仕上げにCloudFrontを設定します。CloudFrontはAmazon AWSが提供しているCDN構築用のインフラです。 CDNとは正式にはコンテンツデリバリーネットワークなどと呼ばれますが、これはウェブコンテンツの配信用として最適化されたネットワークのことをいいます。 AWSの場合ELBの前にCloudFront(CDN)がリクエストを待ち受けており、過去に同様のリクエストがあった場合は、ELBに通さず自身でコンテンツの配信を肩代わりするという機能を持っています。こうすることで負荷分散を図ることができます(表示速度の向上)。 今回の設定例は動的なWebアプリ向けに必要な設定を施したものになります。アプリケーションの機能を全てのCDNに分散することはできませんので、原則として動的要素はELBを経由することになりますが、CloudFrontとELBは太いネットワークで接続されていますので、動的要素を含むサイトであってもパフォーマンスを観点から利用する価値はあります。 メニューからCloudFrontをひらきます。 Web側のディストリビューションを作成します。 Originとして既存の(コンテンツの大元となる)ELBを選択します。 --> Allowed HTTP Methodとして全てを選択します。これを忘れると動的要素が正しく動かなくなることがあります。 また、Forward CookiesやQuery String Forwardingも忘れずに設定しておきます。 今回はテスト用ですので、Price Classとして最も安いものを選択し、Alternate Domain Namesも設定しておきます。 下にスクロールして、この部分はそのまま次に進みましょう。 ディストリビューションができました。 height=”1264″ class=”alignnone size-full wp-image-1064″ /> 一応見えてはいるようですが… 確認の為にリクエストの応答ヘッダーを覗いみましょう。 「xxx.cloudfront.net(CloudFront)」とありましたね!これでクラウドフロントから上手く返ってきていることがわかりました。 これで、第2回〜第3回に渡りましたが、Rote53(DNSサーバー) -> CloudFront(CDN) -> ELB(ロードバランサー) -> EC2(Webサーバー) までのパケットの流れを正しく設定することができました。 第3回目の最後に 今回のやってみようAWSシリーズでは、簡単ではありますがAWS上におけるインフラ構築手順をざっとご紹介しましたが、AWSではまだまだ多くのインフラサービスが提供されており、そのうちのどれもが実際のWEBサービス運営に役立つ強力な武器となります。今後もこのようなシリーズ記事を通じて皆さんに有益な情報を提供できればと思います。 またこのシリーズでこれまでインフラと縁遠かった方でもAWSに対する理解が少しでも深まっていれば幸いです。 ご清覧頂きありがとうございました。 Wedding Parkでは一緒に技術のウエディングパークを創っていくエンジニアを募集しています。 興味のある方はぜひ一度気軽にオフィスに遊びにきてください。 ◉シリーズ ・やってみよう!AWSでWEBサーバー環境構築(シリーズ第1回) ・やってみよう!AWSでWEBサーバー環境構築(シリーズ第2回) ◉筆者のおすすめ記事 ・【DB設計入門|ER図|MySQL】コンビニレシートから学ぶ!データモデリング手法 ・【機械学習入門|Python|scikit-learn】結局何ができる?cheat-sheetから解説してみる篇
初めまして!新卒1年目エンジニアの高嶋です。 先日ウエディングパークで開催した「エンジニアLT女子会」について報告致します。 女子エンジニアが多く活躍するウエディングパークでは、定期的に女子エンジニアLTを開催し、 社内外から女子エンジニアが集まって最近気になる技術やワークスタイル等をテーマにLTを実施しています。 今回は、今後就職活動をされる学生に向けて、女子エンジニアの仕事についてアレコレを話すLT会を開催しました。 女子エンジニアだけではなく、学生も登壇OKということで、最近やっていることや自己紹介など 様々な話題で大盛況だったその様子についてレポートさせていただきます! LT会の雰囲気 会場はウエディングパークの会議室、 学生全員がLT会初参加ということで、初めは少し緊張気味。 表参道×女子会ということもあり、 軽食がこんなにフォトジェニック、そしてオーガニック…! そんな軽食を食べながら、とてもアットホームな雰囲気でLT会スタート! 発表内容 1. WeddingPark 菅沼 「エンジニアの仕事とキャリア」 2. WeddingPark 栗山 「5年目女性エンジニアが考えるエンジニア職の魅力」 3. WeddingPark 若宮 「私の就活と今」 4. WeddingPark 谷渕 「~新卒3年目エンジニアの挑戦~新規事業のメディアを立ち上げる!」 5. 学生枠 Oさん 「Oです。初めまして。」 6. 学生枠 Yさん 「アンドロイドアプリケーションについて」 7. WeddingPark 成田 「WPPJについて」 8. WeddingPark 後藤 「会社紹介」 1.「エンジニアの仕事とキャリア」] WeddingPark 菅沼 ウエディングパークの中でも業界歴の長い菅沼さん。 エンジニアといっても「職種×業種」の数だけ様々な仕事がある中で、 仕事のポリシーという軸をしっかりともつことが大切というお話をしてくださいました。 2.「5年目女性エンジニアが考えるエンジニア職の魅力」 WeddingPark 栗山 文系出身であり、エンジニア新卒1期生の栗山さん。 入社してからの5年間を振り返りながら、エンジニア職の魅力を教えてくださいました。 エンジニアには「学ぼうとする人には優しい文化」があり、 大変な時期も助け合ってきたそうです。素敵な文化です! 3.「私の就活と今」 WeddingPark 若宮 新卒1年目、わたしと同期の若宮さん。 就活時代〜働いている今をお話していただきました。 就活の軸があるときから「働いている人、社内の雰囲気」に変わり、 働きはじめた今も実際に人の優しさに支えられている、というお話をしてくださいました。 4.「~新卒3年目エンジニアの挑戦~新規事業のメディアを立ち上げる!」 WeddingPark 谷渕 新卒4年目の谷渕さん。3年目のときにエンジニアとして立ち上げた「DRESPIC」についてのお話。 様々な挑戦ができ、想像以上に大変なことも、想像以上に嬉しいこともたくさんあるそうです! 挑戦しながらも、ときには助けてもらうこともできる、 成長したいエンジニアにとって最高の環境です。 5.「Oです。初めまして。」 学生枠 Oさん 海外のいろいろな土地をまわるのが趣味というOさん。 覚えた言語を現地でつかうのがすごく楽しいんだそうです! 外国語に似てるから、というOさんらしい興味の持ち方でプログラムの勉強をはじめ、 今ではアプリをつくっているそうです! 6.「アンドロイドアプリケーションについて」 学生枠 Yさん 実際に自分で開発したAndroidアプリについて発表していただきました。 機能のひとつ、割り勘機能は切り上げまで細かく設定することができ、 実際につかってみたい!と思いました! わからないところは自分で調べたり、人に聞いたりして完成させたそうです。すごい! 7.「WPPJについて」 WeddingPark 成田 新卒3年目の成田さん。会社のカルチャーを守り、育てることを目的に活動している 「WPPJ(社内活性化プロジェクト)」について紹介していただきました。 ただ働くのではなく、会社の未来にワクワクしながら働けるか…とても響きました。 8. 「会社紹介」 WeddingPark 後藤 最後には人事の後藤さんからウエディングパークについてのお話。 ウエディングパークのカルチャーが伝わるような、 たくさんのイベントや制度について説明していただきました! 懇親会の様子 LTのあとには飲んだり食べたりしながらの懇親会を行いました! 飛び込みLTをしてくれる学生さんがいたり、就活について、エンジニアについてなど さまざまな質問があったりと、とても盛り上がりました! 最後に 参加された13名でお決まりのウエパポーズをとりながらの集合写真! ウエパ初の学生さんをお招きしてのLT会、大成功でした!!! 参加してくださったみなさま、ありがとうございました!
こんにちは,エンジニアの久保です。 先月開催された Microsoft Build 2017 では,Bash on Windows で, これまでの Ubuntu のほかに, Fedora と openSuSE の サポートが発表 されました。 この機能は,2017 年秋にリリース予定の Windows 10 Fall Creators Update に含まれるようです。楽しみですね。 今回は,現在利用可能な Bash on Ubuntu on Windows について,Windows 10 Creators Update 環境で導入してみました。 環境 Windows 10 Pro 64 bit バージョン:1703(Creators Update) OSビルド:15063.0 手順 Windows を開発者モードに変更 まずは,Windows を開発者モードに変更します。 スタートメニュー→「設定」→「更新とセキュリティ」を選択し「開発者向け」タブを開きます。開いたら「開発者モード」を選択し,開発者モードを有効にします。 Windows Subsystem for Linux のインストール 次に,Bash on Ubuntu を使うために,Windows Subsystem for Linux をインストールします。 コントロールパネルを開きます(スタートメニュー→「Windows システムツール」→「コントロールパネル」)。 続いて,「プログラム」の項目を選択し,「Windows の機能の有効化または無効化」を開きます。 「Windows Subsystem for Linux (Beta)」にチェックを入れて,OKをクリック。 インストールが完了したら再起動します。 Bash on Ubuntu のインストール Windows Subsystem for windows インストールが済んだので,Bash on Ubuntu の設定を進めていきます。 PowerShell を起動し, bash コマンドを実行します。この作業は,コマンドプロンプトでも大丈夫なのですが,今回は Creators Update でデフォルトのシェルとなった PowerShell を使ってみましょう > bash 表示されたメッセージを確認し, y を入力します。 展開が完了すると,ロケールの設定,ユーザとパスワードの設定が行われます。こちらもメッセージに沿って実行します。すべての設定が終わればインストール完了です。 続けて,Ubuntu のアップデートを行っておくと良いでしょう。 bash $ sudo apt-get update $ sudo apt-get upgrade 使ってみましょう インストールが完了しましたので使ってみましょう。 起動 今回構築した,Bash 環境は,次の方法で起動できます。 PowerShell(あるいはコマンドプロンプト)を起動して, bash コマンドを実行 スタートメニューから「Bash on Ubuntu on Windows」を起動 Ubuntu のバージョン 次のコマンドで確認できます。今回は 16.04.2 LTS でした。 bash $ cat /etc/issue Ubuntu 16.04.2 LTS Windows へのアクセス Windows の ドライブは /mnt/ にマウントされています。例えば C ドライブは, /mnt/c/ にマウンドされています。 従って,Windows のユーザフォルダへは, /mnt/c/Users/<ユーザ名> でアクセスできます。 パッケージのインストール Ubuntu と同様に,aptコマンドでパッケージのインストールができます。 たとえば,emacs をインストールするには次のコマンド。 bash sudo apt-get install emacs 再インストール Bash 環境を再インストールしたくなったら,PowerShell で次のコマンドを実行しましょう。 > lxrun /uninstall /full lxrun /install ここで, lxrun /uninstall /full は Bash 環境のアンインストール, lxrun /install は インストールを示します。 おわりに 今回は,Windows 10 Creators Update に Bash on Ubuntu on Windows を導入しました。 これまでは Cygwin や MSYS2 を使って開発環境を構築していたのですが,環境の違いからちょっとした作業で手間取ってしまうことがありました。 これからは Bash on Ubuntu が使えることで,そんな悩みからも解放されそうです。今後は Bash 環境に各種開発環境を構築していこうと思います。 参考文献 Bash on Ubuntu on Windows Microsoft 公式ドキュメント。英語ですが,コマンドリファレンスとトラブルシューティングが役に立ちます。 ウエディングパークでは、エンジニアを募集しております。 Weddingparkを始め、各種サイトやサービスを一緒に作りませんか? IT×ブライダルで業界を変える!プロフェッショナルなWEBエンジニア募集!
はじめまして!システムエンジニアの谷渕です。 今日は、DRESPIC( https://drespic.net )についてお話ししようと思います。 DRESPICとは…? DRESPICは、2017年1月11日にオープンした、ウエディングドレスのクチコミサイトです。私はこのサイトの立ち上げエンジニアとして、昨年からDRESPICに関わっています。サイトを0から立ち上げるという、わくわくと不安といろいろな気持ちを抱えて、事業責任者の、「ドレス業界に革命を起こしたい!」という夢に乗っかって、一緒に叶えよう!と決意し、DRESPICをつくってきました。 DRESPICは女子チームで、年も近いことから、かわいい!と思うものも似ていて、ロゴ決定やサイトのテイストなど、チーム全員で、絶対にこれがいい!と納得できるものを集めて、全員でDRESPICサイトへの愛を深めながら、大事に大事にリリースに向けて育ててきました。 DRESPICを圧倒的おしゃれなサイトにしたい!という思いがあり、そのためには技術も大事ということで、技術面をこの記事で改めて見直してみることにしました。 DRESPICの特徴 先にも書きましたが、DRESPICとは、ウエディングドレスのクチコミサイトです。クチコミをメインに、ドレスブランドのページ、ドレスショップのページ、ドレスやタキシードの商品ページなどがあり、様々な検索軸で検索ができる機能や、ユーザーが書き込めるSNSのフィード機能、など様々な機能があるサイトです。 開発時の条件や特徴、から実現したかったことは大きく2つです。 ・比較的規模が大きいサイトで、開発が1人ではないこと L開発者ごとに書き方が大きく変わることもある L他のメンバーがよめないコードが書かれることもある L共通の処理を開発者間で効率的に共有したいなあ Lあと、修正したときに影響を受ける場所を明確にしておきたい ・クチコミ部分とSNSの部分で最適な設計が異なること LクチコミページはSEOを意識したいため、JSでの実装は局所的にしたい LSNSのページはインタラクションを重視して、JSでSPA実装したい L…でも両方の画面に共通のモジュールがあるからコードを再利用したい ( 左:クチコミ / 右:SNSのフィード) この時点でサーバサイドの言語は決定していたので、 上記のことをふまえて、フロントエンドの技術選定に入りました。 DRESPIC言語選定 その前に フレームワークとライブラリの違い 最初に定義をおさらいしておきましょう。 「フレームワーク」・・・アプリケーションの骨格を担うもので、開発をするときに開発者はその骨格に沿って肉付けをしていくものです。 「ライブラリ」・・・骨格ではなく、肉付けを補助するものです。そのため、骨格部分はフレームワークに任せるか、自分で実装する必要があります。 フレームワークを知っているだけで、新しく開発者がプロジェクトに参加しやすかったり、信頼性の高い骨格を使えることで、各モジュールの役割が分離され、他のモジュールに影響を与えるコードや、潜在的にバグが潜みやすいコードを書きにくくなります。 DRESPICの言語選定 選ぶポイントは3つでした。 ・将来性があること L将来メインストリームになりそうな技術の方が、ノウハウが蓄積されていく ・単一モジュールからSPAまで対応できる柔軟性があること L単一モジュールの埋め込み(クチコミ部分)からSPA(SNS部分)まで柔軟に対応できる Lコンポーネントの組み合わせでより大きなコンポーネントを作ることができるとよい◎ ・学習コストが高すぎないこと Lメンテナンス性も下がるし、引き継ぎに時間がかかってしまいます 以上を踏まえて、選定がはじまりました。 出てきた候補はこの3つです。 ①Angular2 ②Vue.js ③React.js + redux これを先ほどのポイントをふまえて考えてみましょう… Angular2 将来性 ◎ 柔軟性 △ 学習コスト △ (TypeScriptの学習コストが高そうでした) Vue.js 将来性 ◯ 柔軟性 ◯ 学習コスト ◎ (ライブラリとフレームワークの中間なのでSPAのために追加のフレームワークを使う方がよいが、それだとVue.jsのシンプルさが活かせない…!) React.js + redux 将来性 ◎ 柔軟性 ◎ 学習コスト ◯ (Vue.jsより学習コスト高めですがAngular2よりは低めでした) 以上の結果を踏まえて、選ばれたのは redux + React.js でした。そして同時に谷渕の勉強が始まるのでした。勉強の過程もどこかでお話しできればいいなと思います! DRESPICのこれから 1/11にリリースされたばかりのDRESPIC、まだまだよちよち歩きのサイトです。ユーザーさんから集まるたくさんのクチコミを大切に、もっとかわいくて、誰にとってもわかりやすいサイトに育てていきます!これからもDRESPICをよろしくお願いします! ウエディングパークでは、エンジニアを募集しております。 Weddingparkを始め、DRESPICなど各種サイトやサービスを一緒に作りませんか? IT×ブライダルで業界を変える!プロフェッショナルなWEBエンジニア募集!
はじめに こんにちは、岩橋聡吾です。 今回は私が実務で行っているデータモデリング手法(実際手法とは名ばかりですが…)を紹介いたします。 データモデリングは、ご存知の通り、その後のシステム開発や拡張スピード、またシステム自身のパフォーマンスにも深く関わってきます。ここをどのように設計するかが開発プロジェクトを進める上で大きなカギになります。 なぜレシートなのか モデリングする上で、その対象となるサービス・システムのビジネスロジックや仕様を深く理解する必要があります。レシートの背景にある「物を買う」という行為は至極身近なものであり、誰しもがそのレシートが発行されるまでの流れを経験で知っています。またレシートは、その小さな紙の中に「店舗」や「商品」など、WEBサービスで馴染みがある概念も多く含まれており、訓練をする上で非常に手頃なものです(「コンビニ」なるフレーズは掴みに使わせていただきましたw)。 今回の話のエリア 今回は概念設計〜論理設計の前半までの内容を対象としています。具体的には「ある特定日のレシート一覧を出力できるシステム」のデータモデリングを行っていきます。 概念(実体)の洗い出しとパズル化 概念の洗い出し 上のレシートについて概念を洗い出してみましょう。深く考える必要はありません、先ずは上からなぞるようにリスト化していきましょう。 -概念リスト 【店名】 【店】 【電話番号】 【住所】 【日時】 【商品】 【値段】 【個数】 【総額】 【ポイント】 【店員】 とりあえずここまでで、次は概念のパズル化を考えていきましょう。 概念(実体)のパズル化 この概念のパズル化は概念同士の関係を以下のルールに当てはめながら作っていきます。 AのB(所有) ex) 私(A)のパソコン(B) AのB(属性) ex) ティッシュ(A)の香り(B) AがBする(主述) ex) タクシー(A)が止まる(B) BをAする(動詞-目的語) ex) 客(B)を乗せる(A) AがあるからBがある(存在理由) ex) 猫(A)がいるから鳴き声(B)がある この場合は全て以下のような形(Aの箱の中にBの箱が入る形)になります。 では 概念リスト よりさっそく作っていきましょう。 まず、【店名】と【店】ですがこれは、店の店名ですから… となります (箱の大きさや位置は説明上の便宜的なのものです) 。 続いて【電話番号】【住所】も追加していきましょう。店の電話番号、店の住所、 次に順番からいくと【日時】なのですが、これはすんなりと今のパズルに当てはめられないように思えます。これは大切な感覚です。「当てはめられない」は 何か概念(実体)が足りない ことを意味しています(もちろんそもそも当てはまらないこともありますが…)。ここは一旦スキップしましょう。 では、 概念リスト からすんなりと当てはめられそうなものを探すと…【店員】はどうでしょうか。 これはきっと以下のようになるでしょう。 続いて【商品】について考えていきたいのですが、まずはこの【商品】自身に入りそうな箱を考えてみましょう。 概念リスト を見ると…【値段】【個数】はどうでしょうか。商品の値段、商品の個数…いけそうです。 こんな感じになるでしょうか。 さてこれはどこに入るでしょう。【店】の【商品】と考えられそうでしょうか?仮にそのように考えた場合、【店】の【商品】の 【個数】 とはどういう意味でしょうか?…言葉のままに捉えると「店頭に陳列された商品の個数」や「店の在庫商品の個数」という意味に聞こえます。本来の概念からズレてきていますね。 パズルの各概念は全て 実体 で考えるようにしましょう。この【商品】を商品マスターと捉えてしまうと、パズルは上手くつくれません(マスターはあくまで正規化した結果で定義される仮想の概念です)。では、このレシートが物語っている【商品】とは何なのでしょう。 【商品】が、レシートの背景にある「物を買う」という行為(ストーリー)の中で関係を持ったのはどの場面だったでしょうか…それは、【店員】が 【販売】 した場面(もしくは、【客】が【購入】した場面)ではないでしょうか? 従って【販売】という概念を追加して、パズルは以下のようになります。 足りなかった概念が追加されたことで、先ほど当てはめられなかった【日時】、また【総額】なども以下のように当てはめられそうです。 また、最後に残った【ポイント】についても、このままだと当てはめられないので概念を追加する必要があります。この【ポイント】は、【販売】した 【客】 の【ポイント】になると思われるので、 のように、【客】を追加すると上手く当てはめられました。 ここまでをまとめてみますと 概念のパズル化を行うことで概念同士の関係が可視化できる。 概念のパズルが上手くはまらない場合は、必要な概念が足りない可能性がある。 具体的に登場する場面をイメージしながら概念のパズルは全て実体で考えていく(マスターはあくまで正規化した結果で定義される仮想の概念)。 となります。 ERD(実体関連図)に展開 さてここからERDに展開していくのですが、ここは機械的です。例に上述のA・Bの概念を使うと以下のように展開できます。 AがBを従属(AとBは親と子の関係) AとBは「1対多」の関係 これを、先ほど作った概念のパズル全体に適応すると以下のように展開できます。 さらに、何も従属していない概念 【店名】 【電話番号】 【住所】 【日時】 【総額】 【ポイント】 【個数】 【値段】 については、以下のようにその 親 の属性に含めても良いでしょう。 概念 ⇄ 属性 は互いに垣根が曖昧で、どちらで定義をするかは設計者の裁量に任せらることが往々にしてあります。自身の場合は、目的のシステムにおいて、その概念が重要(別の概念を従属している等)であれば概念として、そうでない場合は属性として扱うことが多いです。 データベースERDへの変換と正規化 今度は、上のERDをデータベースの為のERDに書き換えます。 外部キー (他の表に関連付けされたキー)を用いることでここも機械的にできます。 書き換え時に注意した点としては、 サロゲートキー(代理主キー、意味を持たないIDフィールドを追加し主キーの代理をさせる) を全てのエンティティに置いたことてす。 サロゲートキーについては、是か否かの論争が巷でなされていますが、自身の個人的な見解としては「誰が見てもすぐに主キーだと判断できる」「主キー周りの仕様変更に強い」「最近のフレームワークを使った開発においてはデフォルト主キーがIDとなっている」の点から入れるようにしています。 正規化 ここで、上の5つのエンティティ(概念)は以下のように「リソース系」「イベント系」に分類できます。 -リソース系 店 店員 客 商品 -イベント系 販売 分類の方法としては、そのエンティティ内に「時間」的要素を含むかどうか(若しくは含ませられるかどうか)。含む場合は「イベント系」、含まない場合は「リソース系」として分類できます。今回は 販売 に 日時 が含まれるの、 販売 はイベント系に分類できます。 またここで説明しているリソース系のエンティティは、親にマスターのリソース系エンティティを持つことができ、これを行うことでデータの冗長性を防ぎます。冗長になり得るフィールドも一緒にマスターに移します。 今回は必要がないので触れませんが、必要があればその他正規化もこのタミングで行うと良いでしょう。 少しまとめますと 各エンティティにはサロゲートキーを置く 各エンティティはリソースとイベントに分類できる 概念のパズル化から導出されたリソース系エンティティには マスター リソース系エンティティを親に追加できる(正規化) その他正規化もこのタイミングで行う となります。 リレーションとエンティティの最適化 正規化したERDは、過程でありゴールではありません。 目的のサービスの仕様や背景、また実際のデータの取り出し方を見ながらこれを最適化していきましょう。 先ずは、このサービスの仕様や背景を鑑みて既存ERDのリレーションが適切かどうか見ていきましょう。 リレーションを見る 既存のERDは以下のようなリレーションに直せるのではないでしょうか。 店マスター x 店: 「店」は「店マスター」のうち、販売(というイベント)があった店と解釈できるため「 1 対 0 or 1」としました。 店員マスター x 店員: 「店員」は「店員マスター」のうち、販売を行ったことがある店員と解釈できるため「 1 対 0 or 1」としました。 販売 x 客: 1つの「販売」行為に対して「客」は一人になるため「 1 対 1」としました。 商品マスター x 商品: 「商品」は実際に販売された商品であり、販売がなされていない商品も考えられるため「 1 対 0 or 多」としました。 ここで、少しリレーションというものを振り返ってみましょう。 リレーションのおさらい ① 1 対 1 左辺のレコードが決まると、右辺のレコードが1つ決まり必ず存在している状態。また、左辺のレコードが作られると同時に右辺も作られる必要があることを示しています。エンティティ同士の関連性が高い(片方だけでなく両方の情報を扱う場合が多い)場合は、 パフォーマンスの観点からエンティティを1つまとめる方が良い 場合もあります。 ② 1 対 0 or 1 左辺のレコードが決まると、右辺のレコードが存在していない若しくは1つ決まる状態。また、左辺のレコードが作られた後に別のタイミングでもう右辺が作られることを示しています。エンティティ同士の関連性が高い(片方だけでなく両方の情報を扱う場合が多い)場合は、 パフォーマンスの観点からエンティティを1つまとめる方が良い 場合もあります。 ③ 1 対 多 左辺のレコードが決まると、右辺のレコードが必ず1つ以上紐づいている状態。左辺のレコードが作成されると同時に、右辺の既存レコードと紐づくか、左記のようなレコードがない場合は右辺にも作られる必要があることを示しています。 ④ 1 対 0 or 多 左辺のレコードが決まると、右辺のレコードが存在していない若しくは1つ以上紐づいている状態。 リレーションをしっかり作っておくと、 データの作られる順番なども把握できるので、第三者でもこれを使った実装がイメージし易くなります。 さて、引き続きエンティティを見ていきましょう。 エンティティを見る 上述によりエンティティは以下のようにまとめられるのではないでしょうか。 店マスター x 店: 「 1 対 0 or 1」の関係なので1つにまとめました。 店員マスター x 店員: 「 1 対 0 or 1」の関係なので1つににまとめました。その際に「店員マスター」と「販売」のリレーションも見直しています。 販売 x 客: 「 1 対 1」の関係なので1つにまとめました。結果的に 「販売」が「店員マスター」と「客マスター」の中間テーブル になっていることがわかります。 商品エンティティの物理名・論理名を、より分かりやすく「sale_products」「販売商品」としました。結果的に 「販売商品」が「販売」と「商品マスター」の中間テーブル になっていることがわかります。 今回の目的のシステムは「ある特定日のレシート一覧を出力できるシステム」です。特定日を指定するとレシート一覧が出力されるイメージです。データの取り出し方としては、特定日なる「販売」エンティティの「日時(date)」を指定し、それに紐づく周りのテーブルから情報を引っ張ってくることにります。 ですので、リレーション関係が遠いもの、例えば「店マスター」「販売」については以下のような紐付けを追加しても良いと思います。 これで一連のデータモデリング(概念設計〜論理設計前半)が完了しました。 まとめてみますと 正規化したERDは過程でありゴールではないため、最終的には使いやすい形に最適化していく(非正規化)。 リレーションをしっかり考えることで データの作られる順番なども把握できるので、第三者でもこれを使った実装がイメージし易くなる。 リレーションをしっかり考えることでエンティティ同士をまとめることが可能になりシンプルなデータモデリングにつながる。 実運用に則してリレーション関係が遠いものについてリレーションを張ることも大切(非正規化)。 となります。 最後に DB界権威のクリス・デイト氏自ら『データベース設計はきわめて主観的である』と認めざるを得ないほど、この分野は未だ曖昧な部分が多いです。 少し前に勉強がてら 「概念設計」 について調べてみたのですが、その方法や考え方が示されたドキュメントやサイトが少ない事に気づきました。言葉の説明については記載があるのですが肝心のフローや手法というものが見当たらないこともこれを物語っているかのようです。 ただ今回、特に 「概念設計」 について一つの 考え方の 種 を示したく筆を起こしました。まだまだ整理しきれていない部分もあるかと思いますが、少しでも皆さんのデータモデリングのお役に立てれば幸いです。 ご清覧頂きありがとうございました。 Wedding Parkでは一緒に技術のウエディングパークを創っていくエンジニアを募集しています。 興味のある方はぜひ一度気軽にオフィスに遊びにきてください。 ◉筆者のおすすめ記事 ・やってみよう!AWSでWEBサーバー環境構築(シリーズ第1回) ・やってみよう!AWSでWEBサーバー環境構築(シリーズ第2回) ・やってみよう!AWSでWEBサーバー環境構築(シリーズ第3回) ・やってみよう!AWSでWEBサーバー環境構築(Lambda|API Gateway|シリーズ第4回) ・【機械学習入門|Python|scikit-learn】結局何ができる?cheat-sheetから解説してみる篇
こんにちは、フォトウエディングスタジオ検索サイト「Photorait」の担当エンジニアの武田です。 先月の1/10~13日に学生向けの冬のインターン、WeddingPark Winter TechCamp 2018 を開催いたしましたので報告いたします! 概要 参加している学生同士でチームを組み、4日間で実際のウエディングパークのサービス開発フローを体験します。 今回のインターンでは、ウエディングパークが運営するサイト「Photorait」で スマホ向けコンテンツの企画~開発~テストを行ってもらいました! また、作成するコンテンツのテーマは「結婚を決めたカップルがフォトウエディングをしたくなるようなスマホコンテンツを作成する。」です。 チーム 今回のインターンでは、3人1チーム計3チームで行いました。 1チームにつきメンターとしてシステムメンバーが2人つく徹底サポート体制です! Aチーム Bチーム Cチーム 1日目 初日の午前中はオリエンや自己紹介などのチームビルディングを行います。 初めは少し緊張していた学生達も、午前中が終わるころには緊張がほぐれ、和気あいあいと和やかな雰囲気になっていました。 午後からは、企画フェーズです。 少ない工数の中で開発していく必要があり、やりたい事と、やれる事を天秤にかけて考えていかないので、みんなかなり悩んでいました。 一度決まった案から再度ゼロベースで考え直しているチームもありました。 2日目 メインの開発フェーズです。 昨日とことん悩んで考えた企画をもとに、エンジニア・デザイナー専用のサテライトオフィスで開発していきます。 メンター総出でサポートし、熱量がかなり高かったです。 3日目 引き続き開発をしつつ、エンジニア・デザイナーからのコードレビュー! ただ開発するだけではなく、開発したものをそのままリリースして良いレベルまで、チェックします。 4日目 最終日は、社長と取締役の前でプレゼン発表です。 チーム内で議論し、協力し合いながら作ってきたコンテンツなので、どのチームも熱量の高い発表でした! 優勝したBチームでは、その人にあった写真を見つけるための診断コンテンツを作成していました。 プレゼン終了後に、全員で記念撮影です。 プレゼン前はみんなかなり緊張していましたが、みんなやりきった顔をしてますね笑 プレゼンの結果発表後は、修了式になります! 僕からインターン生一人ずつに修了証書を渡しました。 懇親会 社長、メンターも含めた懇親会を行い、インターン全4日間の工程が終了しました!! みんな本当にお疲れ様!! 最後に ウエディングパークのエンジニアインターンシップでは、実際に働いてるエンジニアと同じサービス開発フローを体験できます。 また、入社後に一緒に働くエンジニア・デザイナーや、社内の雰囲気を体感できます! 技術的に不安だからという理由で躊躇している学生の方も、一歩踏み出して参加してくれたら、弊社エンジニア・デザイナーが全力でサポートします! もし興味がありましたら、ぜひ次回インターン開催時のご参加をお待ちしてます! ウエディングパーク新卒採用オリジナルサイト https://www.weddingpark.co.jp/recruit/fresh/