サイトアクセスをどう伸ばしていくか?
Kindleセール情報サイトを作ったが、まあ作っただけではどんなサイトでもアクセスは増えない。
nginxによるアクセス制御に関して調べてみた
業務でアクセス制御する必要があったので、どのような解決策があるかを調べてみた。
要件
nginx
- brew install nginx
- sudo nginx
- http://localhost:8080/にアクセスするとデフォルトページが表示された。
mkdir /usr/local/var/www/test
cp /usr/local/var/www/index.html /usr/local/var/www/test
http {
limit_req_zone $uri zone=one:10m rate=2r/s;
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/access.log main;
sendfile on;
keepalive_timeout 65;
server {
limit_req zone=one burst=5;
listen 8080;
server_name localhost;
location / {
root html;
index index.html index.htm;
}
設定完了したので、nginx再起動。
sudo nginx -s reload
そしてアクセスログを見守りつつ、/ と /testにpararel 4, request数12で飛ばす。
ab -n 12 -c 4 http://127.0.0.1:8080/index.html & ab -n 12 -c 4 http://127.0.0.1:8080/test/index.htmlするとアクセスログは以下のように同じ秒間にはuriごとに2リクエストしかさばいてないので、nginxの方でよしなに遅延させて処理してくれた模様。
[01/May/2017:00:31:23 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"秒間をこえたリクエストを遅延して処理するかどうかはburstが決めているのでそれをいじってエラーにしてみる。
[01/May/2017:00:31:23 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:23 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:24 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:24 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:24 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:24 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:25 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:25 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:25 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:25 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" [01/May/2017:00:31:26 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:26 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:26 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:26 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:27 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:27 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:27 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:27 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:28 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:28 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:28 +0900] "GET /index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
[01/May/2017:00:31:28 +0900] "GET /test/index.html HTTP/1.0" 200 612 "-" "ApacheBench/2.3" "-"
十分これで目的を達成できそうな気がするな。
react-router を使った遷移の話
キンドルセール情報のサイトでreact-routerを使ってホーム画面と検索画面の遷移を作成したのでメモ。
root 'main#index' # ホーム画面
get '/books', to: 'main#index' # 検索結果画面
import React from 'react';
import ReactDOM from 'react-dom';
import darkBaseTheme from 'material-ui/styles/baseThemes/darkBaseTheme';
import lightBaseTheme from 'material-ui/styles/baseThemes/lightBaseTheme';
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
import getMuiTheme from 'material-ui/styles/getMuiTheme';
import Sales from './components/sales.jsx';
import Books from './components/books.jsx';
import injectTapEventPlugin from 'react-tap-event-plugin';
import { IndexRoute, Link, Router, Route, browserHistory } from 'react-router';
export default class Main extends React.Component {
constructor(props) {
super(props);
injectTapEventPlugin();
}
render() {
return (
<MuiThemeProvider muiTheme={getMuiTheme(lightBaseTheme)}>
<div>
<Header query={this.props.location.query}/>
{ this.props.children }
<Footer />
</div>
</MuiThemeProvider>
);
}
}
ReactDOM.render((
<Router history={browserHistory} >
<Route path="/" component={Main}>
<IndexRoute component={Sales} />
<Route path="/books" component={Books} />
</Route>
</Router>
), document.getElementById('app'),
);
EC2の外部接続許可について
セルフプロジェクトとして頑張っている、Kindleセール情報おすすめサイトの開発環境、バッチサーバをAWSに移行したのだが、外部からの接続ではまったのでメモ。
通常サーバを立ち上げたあと、セキュリティの設定iptablesなどいじいじしてポートを開けたりしなければならないのだがEC2ではその必要がなさそうだ。
EC2でサーバを立ち上げた後、開発環境なので
bundle exec rails s -b 0.0.0.0 -p 3000
で開発環境サーバを立ち上げ、外部から接続してみたが繋がらないのでIptables -L で調べてみると何も設定されたない。。。
なんじゃこりゃ?と思ってAWSコンソールを調べてみると、なんのことはない、Security Groupを設定する必要があった。
以下画像のように開けたいポートをSecurity GroupのInboundに追加する必要あり。
Ubuntuスクレイピングサーバの構築
なんかしらの価値ある情報サービスを提供するばあい、
- 自分でコンテンツを作成する
- コンテンツを集めて加工する
- ユーザがコンテンツを提供するフラットフォームを提供
のどれかの手段を取る必要があるが、今回作成したキンドルセール情報の検索サイトは「2」なので、スクレイピングして情報を集めることにした。
結構この手段を使うひとはいると思うので、構築手順を書いておく。
スクレイピングサーバ構築手順
node.js install
sudo apt-get install nodejsruby install
apt install rbenv ruby-buildruby project deploy
git clone https://github.com/sstephenson/rbenv.git ~/.rbenv
git clone https://github.com/sstephenson/ruby-build.git ~/.rbenv/plugins/ruby-build
sudo apt-get install -y autoconf bison build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm3 libgdbm-dev ruby-dev libmysqlclient-dev
mkdir -p "$(rbenv root)/plugins"
git clone https://github.com/rkh/rbenv-update.git "$(rbenv root)/plugins/rbenv-update"
rbenv install 2.3.1
git clone xxxxxxxブラウザ動作環境を整える
sudo apt install ruby-bundler
bundle install
chromium install
sudo apt-get install chromium-browserchrome-driver install
sudo apt-get install xvfb
wget https://chromedriver.storage.googleapis.com/2.26/chromedriver_linux64.zip~/.bash.rcに追加
unzip chromedriver_linux64.zip
cp chromedriver ~/.rbenv/versions/2.3.1/bin
# rbenv
export PATH="$HOME/.rbenv/bin:$PATH"
eval "$(rbenv init -)"
nohup Xvfb :99 -ac -screen 0 1024x768x8 &
export DISPLAY=":99"
のちにAnsibleで書いて自動化する気持だけは強くもっている。
キンスメの技術スタックの話
シンガポールから帰還後、時間があったのでKindleのセール情報を収集して、検索できるサイトを作成している。
このサイトでどんな技術を使っているか紹介する。自分でサイトを作成するとき興味があるもの、つかってみたいものが遠慮なく使えるのがいいなぁと
とはいいつつ興味があるものを選択しながら、開発スピードが出るものを選ぶのが結構難しい。
サーバ
- ruby 2.3.1
- ruby on rails 5.0.1
- MySQL 5.7
- Ubuntu 14.04
- nginx
- unicorn
バッチ
- jbuilder (jsonよう)
- vacuum (Amazon Associate API のラッパーかなり助かった)
- nokogiri
- whenever
- selenium-webdriver
- paranoia
- unicorn
フロント
- node.js
- npm
- react
- material-ui
- awesome-font
- babel
- webpack (設定がかなり面倒だった。。。)
Rubyの継承, include, prepend, extendの違い
Rubyの継承の仕方
通常の継承の例
includeの例
prependの例
extendの例
myModuleMethod' for #<MyClass:0x0000000d374c88></div><div style="background-color: black; color: whitesmoke; font-family: Ricty; line-height: normal;">from (pry):13:in
<main>'じゃあinclude と pretend は一体何が違うのかというと、メソッドを呼び出していく順番に違いが出てくるらしい。
Includeの例 クラスの親階層にはいる。
2.1.5 :001 > module MyModule
2.1.5 :002?> def my_class
2.1.5 :003?> p "my_class in my module"
2.1.5 :004?> end
2.1.5 :005?> end
=> :my_class
2.1.5 :006 > class MyClass
2.1.5 :007?> include MyModule
2.1.5 :008?> def my_class
2.1.5 :009?> p "my class"
2.1.5 :010?> end
2.1.5 :011?> end
=> :my_class
2.1.5 :012 > class SubMyClass < MyClass; end
=> nil
2.1.5 :013 > SubMyClass.ancestors
=> [SubMyClass, MyClass, MyModule, Object, Kernel, BasicObject]
2.1.5 :019 > sub_my_class = SubMyClass.newPretendの例 クラスの子階層の子になる。
=> #<SubMyClass:0x000000024ecff8>
2.1.5 :020 > sub_my_class.my_class
"my class"
=> "my class"
2.1.5 :001 > module MyModule
2.1.5 :002?> def my_class
2.1.5 :003?> p "my_class in my module"
2.1.5 :004?> end
2.1.5 :005?> end
=> :my_class
2.1.5 :006 > class MyClass
2.1.5 :007?> prepend MyModule
2.1.5 :008?> def my_class
2.1.5 :009?> p "my class"
2.1.5 :010?> end
2.1.5 :011?> end
=> :my_class
2.1.5 :012 > class SubMyClass < MyClass; end
=> nil
2.1.5 :013 > SubMyClass.ancestors
=> [SubMyClass, MyModule, MyClass, Object, Kernel, BasicObject]
2.1.5 :016 > sub_my_class = SubMyClass.new
=> #<SubMyClass:0x000000011fabc0>
2.1.5 :017 > sub_my_class.my_class
"my_class in my module"
=> "my_class in my module"
SubMyClassから呼び出した時に、PretendだとMyModuleが先にメソッドがあるかどうか走査され、IncludeだとMyClassが先に走査される。