CubicLouve

Spring_MTの技術ブログ

nginxのconfの内容をdumpする

nginxのconfですが、includeとか大量にしていると、うっかり上書きされててハマったことないですか?

自分は最近ドハマりして、イラッとして、confをdumpできるようにならなかと調べてみました。

で、最新のnginxのソースcloneして読んでたらもうあるじゃんと思ったのですが、 自分のマシンに入ってたnginx(1.6.2)にないので、調べてみたら20150/05/15に入った変更だったのですね。。。

github.com

で、1.9.3を手元でコンパイルして試してみました。

nginxのコマンドオプションに-Tが追加されて、これを使うと、confファイルが吐出されるようになります。

# /foo/bar/nginx-1.9.3/objs/nginx -h
nginx version: nginx/1.9.3
Usage: nginx [-?hvVtTq] [-s signal] [-c filename] [-p prefix] [-g directives]

Options:
  -?,-h         : this help
  -v            : show version and exit
  -V            : show version and configure options then exit
  -t            : test configuration and exit
  -T            : test configuration, dump it and exit
  -q            : suppress non-error messages during configuration testing
  -s signal     : send signal to a master process: stop, quit, reopen, reload
  -p prefix     : set prefix path (default: /usr/local/nginx/)
  -c filename   : set configuration file (default: conf/nginx.conf)
  -g directives : set global directives out of configuration file

dumpされる内容はこんな感じ。

# configuration file /nginx.conf:
include ../hoge.conf;
worker_processes 8;

events {
    accept_mutex off;
    worker_connections 8192;
    use epoll;
}

http {
    server_names_hash_bucket_size 64;
    upstream hoge {
        server 127.0.0.1:3000;
    }

    server {
        include ../hoge1.conf;
        listen 80;
        client_max_body_size 500M;
        location / {
            proxy_pass http://hoge;
        }
        keepalive_timeout 5;
        keepalive_requests 5;
    }
}

# configuration file ../hoge.conf:
pid                   /var/run/nginx.pid;
user                  nginx;
worker_rlimit_nofile  65535;

# configuration file ../hoge1.conf:
include           ../mime.types;
default_type               application/octet-stream;

gzip                       on;


# configuration file ../mime.types:

types {
    text/html                             html htm shtml;
    text/css                              css;
    text/xml                              xml;
    image/gif                             gif;
    image/jpeg                            jpeg jpg;
    application/x-javascript              js;
    application/atom+xml                  atom;
    application/rss+xml                   rss;
}

とりあえずconfファイルを出すだけなのか。。。

ネストされている、confも全部だしてくれます。

includeされたファイルを反映させて、最終的に適用される値が出てくるわけではないので、もう一工夫いるなあ。

workerの枯渇状況が分かるrack-server_statusというgemを書いています

unicornのwokerのbusy数とidle数の比率がわからなくて、うっかりworkerが枯渇して大変なことになったので、workerの状況を返すエンドポイントを追加するrackミドルウェアを書いています。

github.com

ぶっちゃけkazeburoさんのPlack-Middleware-ServerStatus-Liteのruby版です。

github.com

この中で使っているkazuhoさん製のParallel-Scoreboardも移植しました。(まだREADMEがない。。。)

github.com

元は下記です。

github.com

Kazuho@Cybozu Labs: Parallel::Scoreboard でワーカープロセスをモニタリングする方法

使い方

config.ruに下記の用に書く。

# In config.ru
use Rack::ServerStatus, scoreboard_path: './tmp'

それでrackサーバーを立ち上げるて、/server-statusというエンドポイント叩くと、workerの状態を返してくれます。(jsonでも返すように指定できます。)

% curl http://server:port/server-status
Uptime: 1432227723 (12 seconds)
BusyWorkers: 1
IdleWorkers: 3
--
pid status remote_addr host method uri protocol ss
55091 _  -    0
55092 _  -    1
55093 A 127.0.0.1 localhost:3000 GET /server-status HTTP/1.1 0
55094 _  -    0

# JSON format
% curl http://server:port/server-status?json
{"Uptime":1432388968,"BusyWorkers":1,"IdleWorkers":3,"stats":[{"remote_addr":null,"host":"-","method":null,"uri":null,"protocol":null,"pid":87240,"status":"_","ss":2},{"remote_addr":"127.0.0.1","host":"localhost:3000","method":"GET","uri":"/server-status?json","protocol":"HTTP/1.1","pid":87241,"status":"A","ss":0},{"remote_addr":null,"host":"-","method":null,"uri":null,"protocol":null,"pid":87242,"status":"_","ss":3},{"remote_addr":null,"host":"-","method":null,"uri":null,"protocol":null,"pid":87243,"status":"_","ss":3}]}

まだ、本番環境に投入していないですが、もうそろそろ投入予定です。

投入してみて、運用実績ができたらまた報告します。

2015/06/30 本番に投入して様子見中

サーバーの状態やMySQLの状態の指標のまとめ

指標に関していつもググってばっかりいたので、まとめてみました。

ツッコミ大歓迎。

CPU usage

name detail
User ユーザ空間(アプリケーション)でCPUが使われた時間の割合
Nice 優先度を変更された(nice値が変更された)プロセスにより、ユーザ空間でCPUが使われた時間の割合
System カーネル空間でCPUが使われた時間の割合
Idle CPUが何も処理をせずに待機していたCPUの時間の割合(ディスクI/O待ち以外)
Wait(iowait) CPUがディスクI/O、またはネットワークI/Oの結果を待っていた時間の割合(I/O処理中で、その終了を待機している時間)
Intr 割り込み
SoftIRQ ソフト割り込み
Steal 仮想サーバがCPUを使って待たされていた時間の割合

http://blog.suusuke.info/2011/10/24/365/

hiboma/Linuxカーネル解読室-3-1.md at master · hiboma/hiboma · GitHub

yakst.com

O'Reilly Japan - 詳解 システム・パフォーマンス6.3.6 6.6.3 も合わせて参照

Memory Usage

name detail
used 使用している物理メモリ量
buffer ファイルなどのメタデータをキャッシュしている物理メモリ量
cached ページキャッシュに使用されているメモリ量
avail real 利用可能な物理メモリの量
total real 総物理メモリの量
used swap Swap領域で使用している量

cached も buffers も空きメモリの一部 状況に応じてflushされる

Nginx

name detail
Reading nginxはリクエストヘッダーを読み込んでいる数
Writing nginxはリクエストボディーを読み込んでいる、リクエストを処理中、またはクライアントへ返信している数。upstreamから結果を受け取ってクライアントに返し中なのか、upstreamからの回答待ちであるかが区別されてないっぽいのが困る。
Waiting リクエスト処理を待っているクライアントのコネクション数 (idle client connections waiting for a request.) keep-aliveの接続数

http://wiki.nginx.org/HttpStubStatusModule#stub_status

MySQL

変数の参照はここ

MySQL :: MySQL 5.6 リファレンスマニュアル :: 5.1.6 サーバーステータス変数

MySQL Threads

name detail
Cached キャッシュされているスレッド数(スレッドは使いまわされる)
Connected 現在の接続数
Running スリープ状態になっていないスレッドの数

Threads_created 接続を処理するために生成されたスレッド数(この値が増えまくるなら、cached が足りていない)

Threads_cached + Threads_connected が thread_cache_sizeの値より小さければ想定内。

MySQLのスレッドとか接続数とか - @bayashi Wiki

MySQL Processlist

name detail
State Closing Tables 変更されたテーブルデータをディスクにフラッシュし、使用されたテーブルを閉じているスレッド数
State Copying To Tmp Tables モリー内の一時テーブルにコピーしているスレッド数
State End ALTER TABLE、CREATE VIEW、DELETE、INSERT、SELECT、または UPDATE ステートメントの最後、ただしクリーンアップの前に発生しまる状態のスレッド数
State Freeing Items コマンドの実行を完了したスレッド数、通常、この状態のあとは cleaning up になります
State Init ALTER TABLE、DELETE、INSERT、SELECT、または UPDATE ステートメントの初期化の前に発生する状態のスレッド数
State Locked 別のクエリーによってロックされているスレッド数
State Login クライアントが正常に認証されるまでの初期状態のスレッド数
State Reading From Net ネットワークからパケットを読み込んでるスレッド数
State Sending Data SELECT ステートメントのために行を作成し、また、クライアントにデータを送っているスレッド数
State Sorting Result
State Statistics クエリー実行計画を開発する統計を計算しているスレッド数
State Updating 更新する行を探していて、それらを更新しているスレッド数
State Writing To Net ネットワークにパケットを書き込んでいるスレッド数
State None Stateのないスレッド数 例えば SLEEP中のスレッド
State Other

http://mysql.stu.edu.tw/doc/refman/5.1-olh/ja/general-thread-states.html

MyISM Indexes

name detail
Key Read Requests
Key Reads
Key Writes Requests
Key Writes

MySQL Handlers

クエリの I/O 動作

name detail
Handler Write INSERTの回数
Handler Update UPDATEの回数
Handler Delete DELETEの回数
Handler Read First テーブルやインデックスの全件検索(インデックスフルスキャン)の際にまず最初に先頭レコードの取得するが、その回数。フルスキャンが多いとこの回数が増える。(要チューニング)
Handler Read Key インデックスに基づく読み込み回数。これが多い場合は適切にインデックスが貼られている。
Handler Read Next インデックスに基づいて行を特定した後、後続の行を読んだ回数。範囲指定のインデックススキャンの場合に増えます。
Handler Read Prev インデックスに基づいて行を特定した後、その前の行を読んだ回数。範囲指定のインデックススキャンの場合に増えます。
Handler Read Rnd 固定位置に基づくレコード読んだの回数(handler::rnd_pos()が呼ばれた回数)。固定位置に基づくレコードの読み込みとは、Random Readのこと。結果のソートを必要とするクエリを多く実行すると、この値が大きくなる。(要チューニング)
Handler Read Rnd Next データファイルでの次のレコードを読み取った回数。 テーブルスキャンが多く実行されると、この値が大きくなる。(要チューニング)

www.percona.com

MySQL Select Types

name detail
Select Full Join インデックスのないカラムで JOINした回数
Select Full Range Join 範囲指定の効果はあるがインデックスは使わず JOINした回数
Select Range WHERE などの指定によって範囲が限定された探索を行った回数
Select Range Check インデクッスなしのJOIN数
Select Scan テーブル(またはインデックスでも)の先頭行から全件検索(スキャン)をした回数

JOINに関してはEXPLAINしてtypeがeq_refになるようにする。

MySQL Sorts

name detail
Sort Rows ソートしたレコード数
Sort Range 範囲検索ソートの回数
Sort Merge Passes ソートで必要としたマージパスの回数
Sort Scan テーブルスキャンでソートした回数

MySQL Temporary Objects

name detail
Created Tmp Tables 作成した一時テーブルの数
Created Tmp Disk Tables ディスク上に作成した一時テーブルの数
Created Tmp Files 作成した一時ファイルの数

sort_buffer_sizeを超える大きなORDER BYなどで作成される。

漢(オトコ)のコンピュータ道: Using filesort

MySQL Transaction Handle

name detail
Handler Commit コミットの要求数
Handler Rollback ロールバックの要求数
Handler Savepoint セーブポイントの要求数
Handler Savepoint Rollback セーブポイントロールバックの要求数

Cache hit rate

name detail
key cache
query cache
table lock immediate
thread cache
tmp table on memory

Dirty page rate

buffer pool の page のうち disk に flush されてない page の比率

ここが増加していると、diskへの書込みが追いついていない

https://dev.mysql.com/doc/refman/5.6/ja/glossary.html#glos_dirty_page

Buffer Pool Activity

name detail
Page Created 作成されたページの数
Page Read 読み込まれたページの数
Page Written 書き込まれたページの数

Checkpoint Age

Current Lock Wait

トランザクションのロック開放待ち時間の合計秒数

InnoDB I/O

InnoDB I/O Pending

Lock Structures

開放まちLock structの数

InnoDB Log

name detail
Innodb Log Buffer Size ログバッファのサイズ
Log Byte Written ログに書き込まれたデータ量
Log Byte Flushed ロクから書き出されたデータ量
Unflushed Log ログから書き出されていないデータ量

Row Lock Time

行ロック獲得のための所用総時間(msec)

Row Lock Waits

行ロック獲得待機回数

InnoDB Tables In Use

name detail
InnnoDB Tables In Use 実行中のトランザクションが利用しているテーブル数の合計数
InnnoDB Locked Tables 実行中のトランザクションがロックしているテーブル数の合計数

InnoDB Transactions

name detail
InnnoDB Transactions 生成されたトランザクション
History List undo領域にある未破棄のトランザクション

参照

mpstat

CPUごとの使用状況 -P ALLですべてのコアの情報を表示する

vmstat

unix domain socketのstatus

cat /proc/net/unixの中身

項目 説明
Num カーネルのテーブルスロット ffff8800798ec0c0
RefCount ソケットを使用しているユーザー数 00000002
Protocol いまのところいつも 0
Flags ソケット の状態を保持しているカーネル内部のフラグ
Type always '1' とかいてあるが2もある。。。 0001
St ソケットの内部状態 01 02 03 https://github.com/torvalds/linux/blob/master/include/uapi/linux/net.h#L47
Inode
Path (もしあれば) ソケットのパス名

sinatraで設定したパス一覧を取得する

メモ

こんな感じでスクリプトを書いた。

require 'rack'
require 'sinatra'

class Sinatra::Base
  private
  class << self
    attr_reader :original_routes
    # なぜかsuperが呼べない...
    def route(verb, path, options = {}, &block)
      @original_routes ||= {}
      (@original_routes[verb] ||= []) << path
      host_name(options.delete(:host)) if options.key?(:host)
      enable :empty_path_info if path == "" and empty_path_info.nil?
      signature = compile!(verb, path, block, options)
      (@routes[verb] ||= []) << signature
      invoke_hook(:route_added, verb, path, block)
      signature
    end
  end
end

def run(*args)
  args.first.instance_variable_get(:@mapping).each do |mapping|
    # 二番目の要素がmappingのbase path
    base_path = mapping[1]
    # 三番目の要素がcontroller class
    mapping[3].original_routes.each do |method, paths|
      paths.each { |path| puts "#{method}\t#{base_path}#{path}" }
    end
  end
end

Sinatra::Base.set :running_server, true
load './config.ru'

railsで特定のモデルに対してbelongs_toで参照先を設定しているモデルを取り出す

まあ、いろいろ調べる必要がありまして。。。

ざっくりとこんな感じでとれた。

# production環境では要らないが、development環境では必要かと
Dir.glob(File.expand_path('./app/models/*.rb', Rails.root)).each do |f|
  require f
end

# 定数を全部取得
constants = Object.constants.map do |name|
  Object.const_get(name)
end

# 定数一覧からモデルを絞り込む
all_models = constants.select do |c|
  c.class == Class && c < ActiveRecord::Base && !c.abstract_class?
end
                                                                                                                          
target = {}
all_models.each do |model|
  model.reflect_on_all_associations(:belongs_to).each do |association|
    if association.name == :hoge || %w(Hoge).include?(association.options[:class_name])
      target[association.active_record.name] = { model: association.active_record, foreign_key: association.foreign_key }
    end
  end
end
target

これで対象モデルが取得できたのであとはよしなに使う。 例えば、一つも参照がされていないデータを取ってくるとか。

target_ids = Hoge.pluck(:id)

target.each do |name, modle|
  used_ids = model[:model].where(model[:foreign_key] => target_ids).pluck(:"#{model[:foreign_key]}")
  target_ids -= used_ids
end
target_ids

とか

rubyで局所的にパッチを当てる方法を模索中

下記のようなコードで、Cクラスの中だけで何とかAクラスに対するパッチを当てたい。

class A
  def self.foo
    p 'foo'
  end
  def bar
    p 'bar'
  end
end

module ExtendFoo
  refine A.singleton_class do
    def foo
      p 'extend foo'
    end
  end
  refine A do
    def bar
      p 'extend bar'
    end
  end
end

class B
  def initialize
    A.foo
    A.new.bar
  end
end

class C
  using ExtendFoo
  def initialize
    B.new
  end
end

C.new

これを実行すると、

"foo"
"bar"

になるのだが、

"extend foo"
"extend bar"

にする方法がないものか。。。