ISUCON8 オンライン予選に参加してみて、あらためて Web の世界は広すぎると実感した話
ISUCON8 オンライン予選に参加しました。
コードベースさんに場所をおかりしました。いつもありがとうございます!
ISUCON予選頑張ってます!
— CODE BASE (@CODEBASE098) September 16, 2018
残り3時間がんばれー!! pic.twitter.com/cHHuaclO2f
結果
どこがボトルネックになっているかほとんど気づけず、何もできませんでした。ボトルネックの探し方をもっと勉強したい(rack-lineprof を使って、get_event と get_events のとこの処理が遅いってことはわかったので、そこだけでもどうにかしたいという気持ちでやったけど、結局何も速くできなかった)
やったこと
以前、Okinawa.rb に参加したときに教えていただいた ISUCONのはじめかたを思い出しながら進めました。(今回は、Rails のお勉強を一緒にやってるメンバーで参加したので、 Ruby を使いました)
ISUCONでやることのざっくりした流れ(ボトルネックを探して改善を繰り返す)
- sshの設定で公開鍵はgithubにあげとく作戦(サーバーにすぐsshできるように使う)
- ssh config 設定(セッションが切れないようにするなど)
- アプリケーションのコードをgithubにアップする
- githubにあげたコードをローカルに持ってくる
- ローカルでアプリを動かすようにする
- ベンチマーク実行する
- ブラウザから操作してみる
- ボトルネックを探す
- ローカルでコード改修する
- 環境にデプロイ
- ベンチマーク実行する
環境構築(10:00 - 12:00)
以下、環境の準備でおよそ2時間程度かかってしまいました。ここでは、ISUCONの本筋とは関係ないところ、事前に準備していればスムーズにいけたはずのところでつまずいてしまっていたので反省。(例えば、ローカルのmysql になぜかアクセスできなくなっていたり、サーバーから githubにコードあげるのに戸惑ったりで、全然ダメダメだった。本来なら30分ぐらいでやっておきたいなと思いました)
- sshの設定で公開鍵はgithubにあげとく作戦(サーバーにすぐsshできるように使う)
- ssh config 設定(セッションが切れないようにするなど)
- アプリケーションのコードをgithubにアップする
- githubにあげたコードをローカルに持ってくる
- ローカルでアプリを動かすようにする
ベンチマーク実行/ブラウザから操作/どんなアプリなのか触ってみる(12:00-13:00)
ローカル開発環境の準備が整ったので、ようやくベンチマーク実行して、サーバーのリソース状況やログをみたり、ブラウザから操作してみたりの作業を進めました。なるほど チケットを購入するシステムなのかーだったり、h2oというwebサーバーが動いてるっぽいとか、mysql と bundle のCPU高そうとか、そういったことを考えてました。
h2oをnginxに置き換えてみようと試みる(13:00-13:30)
h2oが何者なのかよくわからなかったので、nginx に置き換えようと思ってやってみましたが、ベンチマーク実行した際に、admin.css あたりで401エラーになってるっぽいというバリデーションエラーが発生してしまい、いまいちどう対応すればよいか、わからなかったので、h2oをそのまま使うことにしました。(nginxはyumでインストールして、webppへ振り分けるように修正しただけだったので他に何か足りなかったのか。。。)
ボトルネックを探して改善を繰り返す(13:00-18:00)
このあとは、ボトルネックを探して、コードを書き直したり、構成を見直したりして、ベンチマークを実行する作業をひたすら繰り返して、スコアを上げていく流れになるはずなのですが、全くもってボトルネックの探しかたがよくわからんという状況におちいって、何もできませんでした。
サボさんの書いてくれてる記事をみながら、とりあえず rack-lineprof の使い方はわかったので、ここで処理が遅い部分のコードを修正しよう!というような感じで進めていきました。
このツールを使ってみると、get_events の中で get_event が繰り返し呼ばれてて、その中で以下のSQLが負荷をかけてるっぽいことに気が付いたので、get_event が繰り返し呼ばれなくても処理できるようにするためにはどうすればよいのか???など考えて、色々コードをいじってみたのですが、結局よくわからず、時間切れになってしまいました。
reservation = db.xquery('SELECT * FROM reservations WHERE event_id = ? AND sheet_id = ? AND canceled_at IS NULL GROUP BY event_id, sheet_id HAVING reserved_at = MIN(reserved_at)', event['id'], sheet['id']).first
まとめ・感想
プログラミングの勉強を今年から始めて、800時間ぐらい学習時間積んでるけど、本当に何もわからないなあと感じました。あらためてWebの世界は本当に広い。この人たちと同じ土俵で会話できる日は来るんだろうか、という気持ちになった。
今回、ISUCONに参加してみて、すごく勉強になったし(勉強になるようなきっかけをたくさんいただけた)、もっとWebのことを知りたいと思いました。運営してくれたチームの皆さま、本当にありがとうございました!来年開催されるんだったら絶対にまた出たい!
決勝にいく人たちほんと凄過ぎる…。何もできなかったし、何が罠だったのかも全然わからなかった…。もっと頑張りたいので、めっちゃめっちゃ来年も開催してほしい。1年後、違った感想もてるよう成長したい #isucon
— 島袋恵😘 (@20092014) September 16, 2018
Rails を学んでるプログラミング初学者が、いきなりLaravel 書き始めても、意外と書けそうって気持ちになった話
Ruby、Railsチュートリアルの勉強ばっかりしてる プログラミング初学者(railsチュートリアル2周、学習時間800時間ぐらいの初学者)が、いきなりLaravel を書き初めても、少し勉強してみたら意外とかけそう?!って気持ちになった時の話です。「少し勉強したこと」の部分について書いてみます。プログラミング初学者で、Rails 勉強してるけど、Laravel もちょっと書いてみたい!と思ったかたの参考になれば嬉しいです。
少し勉強したことTODO
ドットインストール Laravelのコース 1周(8時間ぐらい)
ドットインストールのLaravel コースを1周やると、簡単なブログアプリっぽいものが作れます(認証とかはなくて、簡単なCRUDの処理ができる程度のもの)。シュッと手を動かして、サクッと動くものを作ってみると、Laravelがどんな感じかイメージしやすかったので、よかったです。
https://dotinstall.com/lessons/basic_laravel_v2
PHPフレームワーク Laravel入門 Kindle版 1周(15-20時間ぐらい)
ドットインストールで動くものを作った後に、この本を1周やってみると、ドットインストールでやったことが、いろいろと補足されてる感じあって、より理解が深まりました。個人的に、文章も優しく書いてある感じがあって、すごくわかりやすかったです。
意外とかけそう、と思ったことについて
Laravel を少し書いてみると、Rails に出てくる登場人物と、laravel に出てくる登場人物がほぼ同じで、概念もほぼ一緒だと思いました。なので 勉強するときに、頭に入ってきやすかったのかなと思います。routing があって、コントローラーがあって、モデルがあって、ビューがあって.....と、Rails チュートリアルで教えてもらったことが、laravel でもほぼ同じじゃないかなあと思ったのが、少し勉強したTODOをやり終わっての感想です。Railsチュートリアルが laravelを教えてくれたかも知れないと思いました。
なかなか難しそう、と思ったことについて
とはいえ、書けそう!と思ったレベルが、Railsチュートリアルやったことある人レベルの書けそうなので、深いところは Laravel も Rails もわかっていないです。いろいろネットの情報を調べていて、DI とか サービスコンテナ とか、ミドルウェアとかよくわかってないなあと思ってるので、もっと勉強していきたいです。
ミドルウェアは、Rails でいうと Rackのmiddlewareの考え方と同じらしいけど、よくわかってない。キャッチアップする!
その他 教材
Laravelは、ドキュメントとか動画がめっちゃ充実してる。英語さえわかれば、、、この辺りを使うともっと良さそう。。。
今度 Laravelの本が出るようです。気になるのでめちゃめちゃ読みたい。
@ex_takezawa @kurikazu @shin1x1 @omoon の四人で書いた #Laravel 本がもうすぐ出ます!5.5 LTS 対応で、機能解説だけでなく、利用例を示した実践的な内容になっています。絶賛、予約受付中なので、よろしくお願いしますー! https://t.co/CnIK6xDhYx
— Masashi Shinbara (@shin1x1) 2018年9月10日
まとめ
Rails と Laravel を比較できるほど、どちらも理解できてないですが、Railsチュートリアル2週ぐらいの学習レベルだと、どちらのフレームワークも同じように感じました。Rails を勉強した後に、Laravel をやってみると学習効率良さそうだと思います(その逆も)。まだまだどちらのフレームワークも理解できてないので、、、実際、深く知っていくと、いろいろと違うとこありそうだし、いま見えてないとこで同じようなことがあったりしそうだなと思っています。もっと勉強する!!!
参考
RailsとLaravelの比較はさぼさん資料がめっちゃ参考になる。
Laravel 開発構築メモ(備忘録メモ)
最近Laravelをやり始めたので、環境の設定とか忘れちゃわないように備忘録メモ。
僕の環境
PhpStorm 2018.2.2
Docker for Mac Version 18.06.1-ce-mac73 (26764)
開発環境の準備
サボさんが作ってくれたリポジトリをcloneして、make build して、 make serve したらすぐ使えるようになる〜
(docker自体のことに関しては、いまいち理解できてないので、勉強する!!!)
Laravelのdocker-compose作った。コマンド2つで立ち上がる / saboyutaka/laravel-sample https://t.co/tC8cB7bYa8
— さぼ@ギークハウス沖縄 (@saboyutaka) August 29, 2018
Phpstormの設定(xdebugを使えるようにする)
- その1 ツールバーのPreferenceから以下キャプチャの箇所の設定する。ポート設定
- その2
ここまでの設定ができたら、受話器のとこクリックして、Xdebug からの通信を受け付ける状態にする
9001ポートがListenされてる
ブラウザからアクセスしてみる(以下のキャプチャはドットインストールでLaravelのコースを一通りやって作ったサンプルアプリ)
breakポイントより前でどんな感じに値が入っていたか確認できる
まとめ
xdebugめちゃめちゃ便利!!!(いろんな人にみてもらいたい気持ちで書き始めたけど、途中自分でもあまり理解できてなくて、ちゃんと説明出なそうことに気づいて断念した。30分以上かかりそうだったので、また落ち着いた時にトライする)
参考
多分この記事がめっちゃ参考なるかと!
vuejsお勉強メモ
rails&laravel mixで環境作って、ドットインストールのコースを一通りやってみた。コンポーネントむずい。
やったこと
- 環境構築(rails + laravel mix)
- ドットインストールのvuejsのコース一通り。todoアプリ作成&いいねボタン作成とカウントなど
コンポーネントとは???
- コンポーネントとは???うーんむずい
コンポーネント指向とは
なんとなくの理解
- html側でdiv要素を書いて、適当なidをつける。vuejs側は、vueのインスタンスを生成するときに、html側のdiv要素(element)のidを指定する。そうすると、UI側(UI側???って表現があってるかわかんないけど、html側)とvuejs側が紐づいて、vuejs側で持ってるデータ (配列)とかメソッドを利用できるようになる。
v-model だとか v-for とか v- から始まる特殊な属性をディレクティブと呼ぶ。(html側に書くやつ)
submit された時のイベントですが、イベントを紐付けるには v-on というディレクティブを使う(v-on はよく使うので @ で @submit のように省略)このとき、イベントが発生して呼び出すメソッドは、vuejs側のvueインスタンスの、
method: {}
の中に定義する。
データに応じてクラスを付け替えるには、 v-bind:class というディレクティブを使う。
<span v-bind:class="{done: todo.isDone}">
これはtodo.isDoneがtrueだったら、spanタグのclassにdoneを付与する。<li v-show="!todos.length">Nothing to do, yay!</li>
v-showディレクティブ。これは!todos.lengthがtrueだったら、Nothing to do, yay!が表示されるってやつ部品を再利用するために Component っていう機能を使う
Componentの機能を使うとき、まずhtml側では、vueのインスタンス作成するときに紐付けたdiv領域の中で、適当なオリジナル要素を作成する。例えば、
<like-component></like-component>
のような感じ。ここの部分をvuejs側から操作できるようになるイメージ。vuejs側はどんな感じにするのかっていうと、最初にvueのappのインスタンスを作成したやつの中に、
components: { 'like-component': likeComponent }
って書いて、コンポーネントを使うよって定義してあげる。ここで定義したやつを、vueのappのインスタンスの上の方で定義する。例えば、Vue.extend としてあげて、その中にどの中身を入れたいかは、 template で書く。このtemplateに書いたやつが、最初にhtml側で書いた<like-component></like-component>
の中で表示されるようになる。さらにmethodとかデータを使いたかったら、Vue.extend したvueのインスタンスの中にいろいろ書いていく。
var likeComponent = Vue.extend({ // props: ['message'], props: { message: { type: String, default: 'Like' } }, data: function () { return { count: 0 } }, template: '<button @click="countUp">{{ message }} {{ count }}</button>', methods: { countUp: function () { this.count++; this.$emit('increment'); } } });
ドットインストール vuejsのコース一通りやったらできるtodoアプリのコード。
app.js
require('./bootstrap'); window.Vue = require('vue'); Vue.component('example-component', require('./components/ExampleComponent.vue')); document.addEventListener("DOMContentLoaded", function () { var likeComponent = Vue.extend({ // props: ['message'], props: { message: { type: String, default: 'Like' } }, data: function () { return { count: 0 } }, template: '<button @click="countUp">{{ message }} {{ count }}</button>', methods: { countUp: function () { this.count++; this.$emit('increment'); } } }); var vm = new Vue({ el: '#app', components: { 'like-component': likeComponent }, data: { newItem: '', todos: [], total: 0 }, watch: { todos: { handler: function () { localStorage.setItem('todos',JSON.stringify(this.todos)); }, deep: true } }, mounted: function () { this.todos = JSON.parse(localStorage.getItem('todos')) || [] }, methods: { addItem: function () { var item = { title: this.newItem, isDone: false }; this.todos.push(item); this.newItem = ''; }, deleteItem: function (index) { if (confirm(('agre you sure?'))) { this.todos.splice(index, 1); } }, purge: function () { if(!confirm('delete finished?')){ return; } this.todos = this.remaining; }, incrementtotal: function () { this.total++; } }, computed: { remaining: function () { return this.todos.filter(function(todo){ return !todo.isDone }); } } }); });
index.html.erb
<div class="container"> <div id="app"> <p>Total Likes: {{ total }}</p> <like-component message="Like" @increment="incrementtotal"></like-component> <like-component message="Awesome" @increment="incrementtotal"></like-component> <like-component message="Great" @increment="incrementtotal"></like-component> <like-component @increment="incrementtotal"></like-component> <h1> <button @click="purge">Purge</button> My Todo <span class="info">({{ remaining.length }}/{{ todos.length }})</span> </h1> <ul> <li v-for="(todo, index) in todos"> <input type="checkbox" v-model="todo.isDone"> <span v-bind:class="{done: todo.isDone}"> {{ todo.title }} </span> <span @click="deleteItem(index)" class="command">[x]</span> </li> <li v-show="!todos.length">Nothing to do, yay!</li> </ul> <form @submit.prevent="addItem"> <input type="text" v-model="newItem"> <input type="submit" value="Add"> </form> </div> </div>
rails enum の日本語表示の作業メモ
結果的に、ほぼ、これ通りにやるとできた。
最初、この辺りをみてて、同じようやってたはずなのに日本語化され図、いろいろとハマる。
いろいろ調べてみた結果、理由はおそらく、localeの言語設定変更、config/application.rb
にconfig.i18n.default_locale = :ja
を追加してなかったからだと思われる。追加したらちゃんと日本語化された。
設定反映後、pryでいろいろ確認してみた作業ログ
[32] pry(main)> i = Item.find(2) Item Load (0.8ms) SELECT "items".* FROM "items" WHERE "items"."id" = $1 LIMIT $2 [["id", 2], ["LIMIT", 1]] => #<Item:0x000055a71e328ed8 id: 2, name: "シンボル", category_id: 11, user_id: 2, price: 3500, description: "引越しするので譲ります", status: "published", created_at: Mon, 13 Aug 2018 15:30:58 UTC +00:00, updated_at: Tue, 14 Aug 2018 01:40:55 UTC +00:00> [33] pry(main)> i.status_i18n => "公開" [36] pry(main)> i.status => "published" [38] pry(main)> Item.statuses => {"draft"=>0, "published"=>1, "done"=>2} [39] pry(main)> Item.statuses.keys => ["draft", "published", "done"]
正規表現お勉強メモ
正規表現お勉強メモ
このシリーズすごくわかりやすかった。振り返る場所メモ。
初心者歓迎!手と目で覚える正規表現入門・その2「微妙な違いを許容しつつ置換しよう」 https://t.co/NBOg1ZeoCB pic.twitter.com/38179JyB5p
— 島袋恵 (@20092014) August 6, 2018
このシリーズわかりやすかくて、途中パズル解いてるっぽくって楽しかったー
— 島袋恵 (@20092014) August 7, 2018
初心者歓迎!手と目で覚える正規表現入門・その3「空白文字を自由自在に操ろう」 https://t.co/B9qFRXigYR pic.twitter.com/zAYywfWfzl
laravel-mixがやっていることを理解する(理解するというか、railsのフロント環境をlaravel-mixで構築してみて、 よくわからないところを整理する)
以下のサボの記事を参考に構築する。(気になったところをメモしていく)
RailsでLaravel Mix(webpack)を使って15分でES6を書きはじめる
webpack.mix.js は何者?
→resources/assets/js/app.jsをコンパイルして、public/js配下に出力してくれるようにしてくれてるやつっぽい。アセットをどのようにコンパイルするか定義してる。
let mix = require('laravel-mix');
mix.setPublicPath('public')
.js('resources/assets/js/app.js', 'public/js')
.sass('resources/assets/sass/app.scss', 'public/css');
if (mix.inProduction()) {
mix.version();
}
参考情報
Laravel mixは、jsやsassなどのアセットを簡単にいい感じにコンパイルしてくれるビルドツールで、コンパイル対象のファイルを増やしたい時とかは、webpack.mix.jsに書く。
public/mix-manifest.json何者?
→yarn run devコマンドを実行して(package.jsonに定義されてるコマンド npm run dev が実行されて)、アセットファイルがコンパイルされると、public下に作成されてるやつ。このファイルの中身をみると、resource配下のjs/app/jsをコンパイルして、public配下のjs/app.jsを作成したよって意味っぽい(cssも同じ)
$ cat public/mix-manifest.json
{
"/js/app.js": "/js/app.js?id=2357e5caf066e7a52ea8",
"/css/app.css": "/css/app.css?id=52caa47f003ce624f239"
}
- yarn run dev バージョニングされない
- yarn run prod バージョニングされる とかある。
app/helpers/laravel_mix_helper.rbは、何やってるんだろ?
$ cat app/helpers/laravel_mix_helper.rb
module LaravelMixHelper
class LaravelMixError < StandardError; end
MANIFEST_FILE = 'public/mix-manifest.json'
def mix(path)
unless File.exists?(MANIFEST_FILE)
raise LaravelMixError.new('The Mix manifest does not exist. Run `yarn run dev`.')
end
manifest = JSON.parse(File.read(MANIFEST_FILE))
asset_path(manifest[path])
end
end
このmixメソッドが呼び出される場所は、例えば、以下の$ cat app/views/layouts/application.html.erbとか。laravel_mix_helperは、MANIFEST_FILEがあるかどうかチェックして、なかったらアセットファイルをコンパイルするよう(yarn run dev)、例外が発生するようになってて、MANIFEST_FILEが存在したら、そのファイルを元にコンパイルした後のアセットファイルのパスを返してるっぽい。
$ cat app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
<head>
<title>RailsLaravelMix</title>
<%= csrf_meta_tags %>
<link rel="stylesheet" href="<%= mix('/css/app.css') %>">
<script src="<%= mix('/js/app.js') %>"></script>
</head>
<body>
<%= yield %>
</body>
</html>
- app.jsデフォルトのままだとコンポーネント表示されなかった。なぜ?
$ cat resources/assets/js/app.js require('./bootstrap'); window.Vue = require('vue'); Vue.component('example-component', require('./components/ExampleComponent.vue')); const app = new Vue({ el: '#app' });
以下の感じに書き換えたら、表示された
$ cat resources/assets/js/app.js
require('./bootstrap');
window.Vue = require('vue');
Vue.component('example-component', require('./components/ExampleComponent.vue'));
document.addEventListener("DOMContentLoaded", function() {
const app = new Vue({
el: '#app'
});
});
次は、この環境を使って、vuejsを書いてみる。
参考
- webpack.mix.js って何?追記
Laravel mix事始め