awkでデータの絞り込み
やりたかったこと
- 本番RDSから割と大きめのデータをエクスポート
- 負荷がかからないローカルDBでそのデータをこねくる
- 割とデータ量が多いのである程度はawkなどを駆使してデータを絞る
実践
[必要なデータを本番DBからexport]
mysql -u hoge_user -P 9000 -h 127.0.0.1 -D hoge_db -pxxxxx N --batch -e "SELECT * FROM hoges PARTITION (p201704);" > hoges.tsv
[uniqu_data作成]
sudo cat hoges.tsv | cut -f1-16 | tr " " _ | gawk '{volume[sprintf("%s_%s", $3,$4)]=$6};END{for (key in volume) {print sprintf("%s_%s", key, volume[key])}}' > uniqu_log.tsv
[bulk insert用のimport file作成]
cat uniqu_log.text | gawk 'BEGIN{ FS="_"; OFS="," } {print (NR) == 1 ? sprintf("insert into user_summary values(\"%s\", %s, %s)", $1, $2, $3 ) : sprintf(",(\"%s\", %s, %s)", $1, $2, $3 ) } END{print ";"}' > insert.sql
[LocalDBにimport]
mysql -u hoge_user -phoge -D hoge < insert.sql
[error]
ERROR 2006 (HY000) at line 1: MySQL server has gone away
[予想原因]
クライアントからサーバに送ることができるパケットの最大数が小さい
[対策]
max_allowed_packet を増やす
でもできなかった......
他にもタイムアウト系伸ばしたけど、無理
なのでbulkを分割して対応することに
cat uniqu_log.text | gawk 'BEGIN{ FS="_"; OFS="," } {print (NR%100) == 1 ? (NR) == 1 ? sprintf("insert into user_summary values(\"%s\", %s, %s)", $1, $2, $3 ) : sprintf(";insert into user_summary values(\"%s\", %s, %s)", $1, $2, $3 ) : sprintf(",(\"%s\", %s, %s)", $1, $2, $3 ) } END{print ";"}' > insert.sql
[再度import]
mysql -u hoge_user -phoge -D hoge < insert.sql
実践
取得したいデータをもう少しはっきり定義していたら手前のシェルでもう少しデータ加工できそう。
今更ながGitHubのカンバン機能「Project」を使って見る
GitHub Projects
http://dev.classmethod.jp/tool/git/github-projects/
目的
プロジェクトで、ClientとServer間のコミュニケーションの効率化/作業の見える化をしたかった
概要
ディレクターとデザイナーとのコミュニケーションは別ツールを使用。 Projectは基本プロジェクトのエンジニア間での連携で使用するつもりです。
GitHub Projectは大きく分け3つの概念があります。
- Project
- Card
- Note
Projectについて
Projectは名前のとおりです。発足したプロジェクト名を記載してください Projectの単位ですが2通りあります。
- organization単位(Organizationプランのみ)
- repository単位
どちらでもいいと思いますが、 organization単位で作成しておくと、一目でどういうプロジェクトが 動いているのかを確認できるので私はこちらをお勧めします。
Cardについて
CardはProjectに1対多で紐づく概念です。 役割や概念の違いで分けるといいと思います。
Noteについて
NoteはCardに1対多で紐づく概念です。 役割や概念に関係するTopicsを記載するものと考えていいと思います。
またNoteはRepositoryのIssueの情報と紐づけることができます。
ルールExample
こういうツール系はある程度ルールを決めておくと運用しやすいですね
Projectのルール
- 命名規則
- {事業部名}_{サービス名}_{Version}
- もちろん英語
Cardのルール
Noteのルール
- 命名規則
- [画面機能構成名][新規 or 修正 or 要望]-{簡潔なタイトル}
- 着手中のものはIssueと紐付けて自分をassigneesとして登録
- 要望のものはIssueと紐付けて要望に対応してほしい人をassigneesとして登録
- CloseしたIssueのNoteはその機能がリリースされてからCardから削除する
Issueの運用ルール
- 基本的に直接Issueは登録しない(NoteをIssueに紐づける)
- タイトルはNoteの命名規則に従う(自然と統一されるはず)
- ボールを持っている人がassignees
- labelはNoteのルールの[新規 or 修正 or 要望]に従う
- 新規 ラベルなし
- 修正 bugs
- 要望 help_wanted
Commitルール
- CommitのタイトルはIssueのタイトル名#nでコミット(Issueのタイトルコピペ)
- 詳細を記載するっ場合は改行して記載
良いなと感じているところ
プロジェクトを開くと開発で必要な情報がどこにあるのか一目でわかるかも? 誰が今何をやっているのかわかるので、自分のタスクの優先順位づけがしやすくなる?
足りないと感じているところ
期日を設定しにくい(他のツールと組み合わせたりして改善?) まだ運用の準備段階なので何とも言えないですが、
運用し始めてからも改善していけたらと思います。
気軽にRDSの負荷分散
RDSの負荷分散にnginxのstream機能を使った話。
やりたいイメージ
前提
- RDSのマスターとレプリカで負荷分散させたい
- ELBでやろうとしたけどEC2にしか対応していない
- HAproxy MySQLproxyちゃんと構築する時間がない
nginx再ビルド
TCP Load Balancing with NGINX Plus R6 and NGINX 1.9.0
http://nginx.org/download/nginx-1.11.9.tar.gz
./configure --with-stream
make
make install
設定ファイル
nginx.conf
helthcheckの設定とかtimeout設定したい場合は、
色々オプションあるので適当に。
以下最低限
stream { error_log /var/log/nginx/mysql_proxy.log; upstream mysql { zone backends 64k; server rds-master:3306 fail_timeout=30s; server rds-rep:3306 fail_timeout=30s; } server { listen 3360; proxy_pass mysql; proxy_timeout 10s; proxy_connect_timeout 1s; } }
確認
- 接続できればOK
mysql -h 127.0.0.1 --port 3360 --protocol tcp -u hoge --pass
- ちゃんと分散されてるかはMasterとReplicaにそれぞれ接続しコネクション数を確認
SELECT * FROM information_schema.PROCESSLIST;
- あとはwightの調整とか分散具合に合わせて調整すればOK
- writeの場合はmasterに書き込みにいくようApplicatino側を修正。
- 書き込めたらOK
fluentdによるlogの集約とS3への保存
業務でログ収集をやることになったのでその時のメモ
やりたいイメージ
- A B C Dのnginxのログはltsv形式
- A B C DのログをEに集約
- Eに集約したログを大dailyでzipしてs3に保存
各サーバーのHDのスペックは以下
A B C D - 8G
E - 100G
まずは各サーバーの設定とtd-agentのインストール
[公式ドキュメント]
http://docs.fluentd.org/v0.12/articles/quickstart
[インストール前に]
/etc/security/limits.conf
root soft nofile 65536 root hard nofile 65536 * soft nofile 65536 * hard nofile 65536
/etc/sysctl.conf
net.ipv4.tcp_tw_recycle = 1 net.ipv4.tcp_tw_reuse = 1 net.ipv4.ip_local_port_range = 10240 65535
[インストール]
curl -L https://toolbelt.treasuredata.com/sh/install-redhat-td-agent2.sh | sh
[設定]
コレクター A B C D
<source> @type tail tag nginx.log path /usr/local/nginx/logs/access.log pos_file /var/log/td-agent/access.log.pos format ltsv time_key time </source> <match nginx.log> type forward buffer_path /var/log/td-agent/buffer/access.*.buffer buffer_chunk_limit 8M buffer_queue_limit 256 queued_chunk_flush_interval 20s try_flush_interval 1 flush_interval 60s retry_wait 30s retry_limit 5 num_threads 2 <server> name nginx_log host xx.xxx.xxx.xxx port 24224 </server> </match>
集約サーバー E
<source> type forward port 24224 bind 0.0.0.0 </source> <match nginx.log> type copy #<store> # type file # format ltsv # path /var/log/fluentd/nginx_log # buffer_chunk_limit 30g # time_slice_format %Y%m%d # time_slice_wait 1m # compress gzip # flush_at_shutdown true #</store> <store> @type s3 path log/nginx/%Y/%m/%d/ #S3の保存ディレクトリ format ltsv #logの形式 aws_key_id XXXXXXXXXXXXXXX aws_sec_key XXXXXXXXXXXXXXX s3_bucket hoge_bucket s3_region hoge_region acl public-read buffer_path /var/log/fluentd/access.*.log time_slice_format %d buffer_type file time_slice_wait 10m buffer_chunk_limit 30g #デイリーのログの容量に合わせて変更 </store> </match>
※ログのローテトでハマりました。buffer_chunk_limitが肝
参考
@Spring_MT buffer_size_limit ではなくて buffer_chunk_limit でしたorz しかし v0.10.27 の buf_file だとデフォルトで 8MB なので、何か違う気がする…。
— Sadayuki Furuhashi (@frsyuki) 2012年11月27日
[監視用スクリプト]*cronで動かす
参考
- td-agentのプロセスが死んだ場合再起動&slackへの通知
#!/bin/sh #slack通知 function post_to_slack () { SLACK_MESSAGE="*$1*" SLACK_URL=hoge case "$2" in RECOVER) SLACK_ICON=':slack:' ;; DOWN) SLACK_ICON=':warning:' ;; *) SLACK_ICON=':slack:' ;; esac curl -X POST --data "payload={\"text\": \"<!channel> \n ${SLACK_ICON} ${SLACK_MESSAGE}\"}" ${SLACK_URL} } function restart_td_agent () { sudo /etc/init.d/td-agent restart } function stop_td_agent () { sudo /etc/init.d/td-agent stop } #test用 #stop_td_agent SERVER_NAME="manga-OauthChargeUser-api-prod_0" # process数が2以下ならalert&t再起動 PROCESS_COUNT=`ps w -C ruby -C td-agent --no-heading | grep td-agent | wc -l` if [ ${PROCESS_COUNT} != 2 ] ; then DATE=`date` STATUS="DOWN" MESSAGE="[${SERVER_NAME}][td-agent] \`\`\`プロセスがダウンしました\`\`\`" post_to_slack "${MESSAGE}" "${STATUS}" restart_td_agent NOT_RECOVER=true while $NOT_RECOVER do PROCESS_COUNT=`ps w -C ruby -C td-agent --no-heading | grep td-agent | wc -l` if [ ${PROCESS_COUNT} == 2 ] ; then STATUS="RECOVER" MESSAGE="[${SERVER_NAME}][td-agent] \`\`\`プロセスが復帰しました\`\`\`" NOT_RECOVER=false post_to_slack "${MESSAGE}" "${STATUS}" fi done fi exit 0
nginxの設定ファイルのメモ
openresty-1.11.2.2 Linux version 4.4.30-32.54.amzn1.x86_64
APIで高速化するために設定ファイルをごにょごにょ。 一旦こんな感じになった。 もっとこうしたらいいとか、 ここどうなってるのとかあればツッコミが欲しい。
他にもカーネルパラメーターとかちょっといじった。
どんなことしたか、別の機会に書こう!
nginx.conf
user nginx; worker_processes auto; worker_rlimit_nofile 65536; pid /var/run/nginx.pid; events { worker_connections 65536; #worker_connections 1024; multi_accept on; #accept_mutex off; use epoll; } http { include mime.types; server_tokens off; client_header_timeout 3m; client_body_timeout 3m; send_timeout 3m; sendfile on; sendfile_max_chunk 512k; tcp_nopush on; tcp_nodelay on; access_log off; error_log off; open_file_cache max=1000 inactive=20s; open_file_cache_valid 30s; open_file_cache_min_uses 5; open_file_cache_errors off; keepalive_requests 1000; keepalive_timeout 120; proxy_headers_hash_max_size 1024; proxy_headers_hash_bucket_size 256; log_format main_ext '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for" ' '"$host" sn="$server_name" ' 'rt=$request_time ' 'ua="$upstream_addr" us="$upstream_status" ' 'ut="$upstream_response_time" ul="$upstream_response_length" ' 'cs=$upstream_cache_status' ; include /usr/local/openresty/nginx/conf/site-enable/*.conf; }
site-enable/hoge.conf
upstream hoge { server unix:/var/run/circus/hoge.sock; keepalive 1000; } server { listen 80 default_server; server_name hoge.com; gzip on; gzip_http_version 1.0; gzip_comp_level 6; gzip_types application/json; gzip_vary on; gzip_proxied any; gzip_buffers 16 8k; access_log logs/hoge.access.log main_ext buffer=32k; error_log logs/hoge.error.log warn; # health check location = /hoge { access_log off; empty_gif; break; } location / { proxy_pass http://hoge; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Forwarded-Host $host; proxy_set_header Connection ""; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $remote_addr; proxy_set_header X-Forwarded-Host $host; } }
vagrant cloud
virtualbox vagrant chef で仮想環境作りたい
vvirtualbox4.3.12
vagrant1.3.5
インストール済み
Ubuntu 14.04
http://www.ubuntulinux.jp/News/ubuntu1404
作成後、設定→ストレージから
CD/DVDドライブにダウンロードしてきたubuntu14.04のisoファイルセット
設定→システムから起動順序変更
ubuntuのインストル設定手順に従いインストール。
ネットワークはNATにした。
ブリッジにしようと思ったがPPPoeでの設定になるので、IP固定できない。
【ssh】
ポートワードの設定にsshを追加。
ターミナルからssh接続できるようにする。
ubuntuにsshデーモンインストール
sudo apt-get install ssh
【VirtualboxGuestAdditionインストール】
Cのコンパイルに必要なライブラリー
sudo apt-get install build-essential
VirtualboxGuestAddition インストールに必要らしい
sudo apt-get install module-assistant
sudo m-a prepare
sudo mount /dev/cdrom /mnt
cd /mnt
sudo ./VboxLinunxAdditions.sh
参考
http://d.hatena.ne.jp/kumamidori/20130512/p1
【ssh公開鍵認証】
ssh、公開鍵で認証できるようにする。
公開鍵作成済み。
ゲストOS側に.sshディレクトリ作成。
sudo mkdir .ssh
vagrantユーザーで認証するから
sudo chown vagrant:vagrant .ssh
.sshフォルダの権限700じゃないとssh接続できない
sudo chmod 700 .ssh
公開キーを転送(2222でゲストOSの22に転送する設定にしてある)
scp -P 2222 ~/.ssh/id_rsa.pub vagrant@localhost:~/.ssh/authorized_keys
・VMを元にボックスファイル作成
vagrant package --base ubuntu64(ホスト名)
・boxファイルから仮想環境(ubuntu14.04VagrantBox)作成
vagrant box add ubuntu14.04VagrantBox package.box
・仮想環境初期化
vagrant init ubuntu14.04VagrantBox
・仮想環境起動
vagrant up
※ssh公開鍵認証なのでVagrantfileに秘密キーの場所設定してあげる
Vagrant::Config.run do |config| config.vm.box = "ubuntu14.04VagrantBox" config.ssh.private_key_path = "~/.ssh/id_rsa" end
config.ssh.private_key_path = "~/.ssh/id_rsa"
~/.ssh/id_rsa → 公開鍵の場所
vagrant up うまく行けば一旦終わり。
もちょっとカスタマイズしよ。
redisインストール
ただのメモ
現状の安定板のgipファイル
wget http://download.redis.io/releases/redis-2.8.9.tar.gz
解凍
tar xvzf redis-2.8.9.tar.gz
できたフォルダに入って
make
make test
make install
tcl8.5以上必要って怒られたから
yum install tclでインストールした。
【Rails】WEBrickについて
RackでWebサーバーたてた。
よくわからないから、コードを追っていたら前からわからなかったWEBrickについてなんかわかったような。
めも
まずはコード張っとく。
require 'webrick' require 'erb' document_root = '/var/www/html/rails/rubyApp/app/' server = WEBrick::HTTPServer.new({ :DocumentRoot => document_root, :BindAddress => '0.0.0.0', :Port => 10080 }) server.mount_proc("/") { |req, res| path = File.join(document_root,*req.path.split("/")) path += ".utf-8" if /\.html\.[a-z][a-z]$/ =~ path File.open(path){|file| res.body = (ERB.new(File.read(path)).result(binding)) } # 拡張子とContent-Typeの対応表 content_types = { ".html" => "text/html", ".txt" => "text/plain", ".jpg" => "image/jpeg", ".jpeg" => "image/jpeg", ".gif" => "image/gif", ".png" => "image/png", ".mp3" => "audio/mpeg", ".mid" => "audio/midi", ".css" => "text/css", ".xhtml" => "application/xhtml+html", ".svg" => "image/svg+xml" } # filenameの拡張子を見てContent-Typeを設定 content_type = content_types[File.extname(path)] #Content-Typeが見つからなかったらtext/htmlを設定 if content_type==nil content_type = "text/html" end res["Content-Type"] = content_type } ['INT', 'TERM'].each {|signal| Signal.trap(signal){ server.shutdown } } server.start <|| まず werbrickとerb(テンプレートエンジン読み込む) >|ruby| require 'webrick' require 'erb'
WEBrick::HTTPServer.newしてあげる。
/.rbenv/versions/2.1.0/lib/ruby/2.1.0/webrick.rb
のinitialize method で初期化される。
document_root = '/var/www/html/rails/rubyApp/app/' server = WEBrick::HTTPServer.new({ :DocumentRoot => document_root, :BindAddress => '0.0.0.0', :Port => 10080 })
webrickのinitialize method確認
/.rbenv/versions/2.1.0/lib/ruby/2.1.0/webrick.rb
def initialize(config={}, default=Config::HTTP) super(config, default) @http_version = HTTPVersion::convert(@config[:HTTPVersion]) @mount_tab = MountTable.new if @config[:DocumentRoot] mount("/", HTTPServlet::FileHandler, @config[:DocumentRoot], @config[:DocumentRootOptions]) end unless @config[:AccessLog] @config[:AccessLog] = [ [ $stderr, AccessLog::COMMON_LOG_FORMAT ], [ $stderr, AccessLog::REFERER_LOG_FORMAT ] ] end @virtual_hosts = Array.new end
いっぱいnewしてる。
ここで書くときりがないので、
super(config, default)
コレより前に
require 'webrick/server'
書いてあるのと
class HTTPServer < ::WEBrick::GenericServer <|| ::WEBrick::GenericServer継承してるから 中身確認 .rbenv/versions/2.1.0/lib/ruby/2.1.0/webrick/server.rb >|ruby| def initialize(config={}, default=Config::General) @config = default.dup.update(config) @status = :Stop @config[:Logger] ||= Log::new @logger = @config[:Logger] @tokens = SizedQueue.new(@config[:MaxClients]) @config[:MaxClients].times{ @tokens.push(nil) } webrickv = WEBrick::VERSION rubyv = "#{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]" @logger.info("WEBrick #{webrickv}") @logger.info("ruby #{rubyv}") @listeners = [] unless @config[:DoNotListen] if @config[:Listen] warn(":Listen option is deprecated; use GenericServer#listen") end listen(@config[:BindAddress], @config[:Port]) if @config[:Port] == 0 @config[:Port] = @listeners[0].addr[1] end end end
またいろいろ書いてる。。。
まぁログの設定とかか。
listen methodだけみとこ。多分ソケット作ってる。
def listen(address, port) @listeners += Utils::create_listeners(address, port, @logger) end
また違うファイルから読んでるー。。
一応確認
.rbenv/versions/2.1.0/lib/ruby/2.1.0/webrick/utils.rb
>|ruby|
##
# Creates TCP server sockets bound to +address+:+port+ and returns them.
#
# It will create IPV4 and IPV6 sockets on all interfaces.
def create_listeners(address, port, logger=nil)
unless port
raise ArgumentError, "must specify port"
end
sockets = Socket.tcp_server_sockets(address, port)
sockets = sockets.map {|s|
s.autoclose = false
TCPServer.for_fd(s.fileno)
}
return sockets
end
|