publickeyを使ったsshの設定

1.鍵を用意する

$ ssh-keygen -t rsa

2.公開鍵をインスタンス上の ~/.ssh/authorized_keys に追記する

$ cat ~/.ssh/ssh_test.pub | ssh ([USER]@)[HOSTNAME] "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys"

3.秘密鍵を使ってsshする

$ ssh -i ~/.ssh/ssh_test ([USER]@)[HOSTNAME]

4.~/.ssh/config を設定する

Host ssh-test
         HostName [HOSTNAME]
         User [USER]
         IdentityFile /path/to/home/.ssh/ssh_test
$ ssh ssh-test

Refs

Solrについて

Solrとは

Solr is the popular, blazing-fast, open source enterprise search platform built on Apache Lucene™.

Apache Solr -

こちらの記事が要点を抑えていてわかりやすいです。

qiita.com

形態素解析

文章を単語ごとに分解する方法。

例:「東京特許許可局」 →「東京」「特許」「許可局」

意味のわからないトークンが作られない一方、例えば「京特」で調べた時に引っかからないという事が起こる。

N-gram

文章をN文字で機械的に分解する方法。

例:「東京特許許可局」N=2 →「東京」「京特」「特許」「許許」「許可」「可局」

検索する文字に対して漏れなく結果を返せる反面、それが全く関連のないノイズとなりえる。

転置インデックス

データソースとトークンの間のM:N関係。

動かしてみる

こちらの記事を参考にdockerで動かしてみます。

$ docker pull solr
$ docker run -d --name=solr -p8983:8983 solr

NOTE: docker run をすると8983ポートでsolrが起動します。もし以下のTutorialのようにSolrCloudを試したい場合は違うポートを繋いでおき、コンテナ内で別プロセスを立ち上げるのが楽です。またその後任意のコマンドを実行する際にはポートを指定する必要があるので注意。

疑問

  • Schemaの書き方
  • 検索の適合度
  • 地理検索機能の実例

Refs

読書リスト2017

kentakudo.hatenablog.com

あっと言う間すらないほど早い一年でした。2017年版です。

  1. チームが機能するとはどういうことか
  2. Webを支える技術
  3. 大規模開発サービス技術入門
  4. Webサービスの作り方
  5. まつもとゆきひろ 言語の仕組み
  6. ゼロから作るDeep Learning
  7. Server-Side Swift
  8. きつねさんでもわかるLLVM
  9. 開眼!JavaScript
  10. JavaScript本格入門
  11. Reactビギナーズガイド
  12. ふつうのLINUX
  13. 新しいLinuxの教科書
  14. プロになるためのWeb技術入門
  15. できるPRO Apache Webサーバー
  16. Real world http
  17. 計算理論の基礎
  18. オペレーションシステムの仕組み
  19. JavaScriptデザインパターン
  20. 最短経路の本
  21. アルゴリズムサイエンス 出口からの超入門
  22. たった2日でわかるLinux
  23. PHPはどのように動くのか
  24. プログラミングコンテストチャレンジブック
  25. アルゴリズムクイックリファレンス
  26. 達人に学ぶSQL徹底指南書
  27. 達人に学ぶDB設計徹底指南書
  28. The Go Programming Language
  29. SQLパズル
  30. プログラマのためのSQL
  31. SQLアンチパターン

計31冊(減ってるやん。。。)


前半は相変わらず乱読を続けていましたが、秋頃から一つのテーマを掘り下げるスタイルにしました。 こちらの方がいろんな知識を線で捉えられるため体系的に学びやすいと感じているのでとりあえず続けてみようと思います。

春から夏にかけてJavaScriptに興味が湧いたため手をつけていたのですが、仕事で使わないだけでなくプライベートで何かを作る、ということもしなかったため中途半端な知識になってしまったのが残念です。反省。

今は「トレンドを追うよりもコンピュータサイエンスに近いところを学んで足腰を鍛えることを優先した方が後々効率が良いのではないか」という気がしているので、以前よりもだいぶ慎重に読む本を選んでいます。

昨年「2017年学びたいこと」として

をあげていました。達成度は30%以下です。反省。

来年は

あたりを中心に読みたいなと思っています。

また、最近こちらのエントリを読んで感心しました。

qiita.com

「より効率的な読書法」も同時に求めていきたいと思います。

Varnishについて

今週FastlyのStockholm(BMA)で障害が発生1し、私たちのサイトも影響を受けました。その際出てきた「varnish」というミドルウェアについて調べたときのメモです。

Varnishとは

github.com

Varnish Cache is a web application accelerator also known as a caching HTTP reverse proxy.

Introduction to Varnish

  • HTTPレベルでキャッシュを行うHTTPアクセラレータ。
  • カーネルの機能を最大限利用することで高速化を図っている。
  • ディスクへのデータ書き込みをデフォルトでは一切しないので、プロセス終了時に全てのキャッシュが消える。
  • 設定はVCL(Varnish Configuration Language)というDSLで記述する。動的に変更可能。
  • ログもデフォルトではファイルに書き込まれない。
  • Fastlyの中心技術2。各リージョンにVarnishキャッシュサーバを置いていると雑に考えても間違いではなさそう。
  • SSLが使えないのでnginxを前に置く構成が多いらしい。

動かしてみる

varnishをnginxの手前に置いて、nginxのindex.htmlをvarnish経由で返してみる。

参考記事: Getting Started with Varnish Cache

環境

1. コンテナの起動 3

$ docker run --privileged -d -p80:80 --name=varnish centos /sbin/init

2. nginxのインストール&起動 4

$ sudo vi /etc/yum.repos.d/nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/mainline/centos/7/$basearch/
gpgcheck=0
enabled=1
$ yum install -y nginx
$ systemctl start nginx

3. Varnish Cashのインストール

$ yum install -y epel-release
$ yum install -y varnish

4. nginxのポートを8080に変更

etc/nginx/conf.d/default.conf

server {
    listen       8080;

    ...
}

リロード

$ systemctl reload nginx

5. varnishのポートを80に変更

etc/varnish/varnish.params

VARNISH_LISTEN_PORT=80

起動

$ systemctl start varnish

6. アクセスしてみる

$ curl -I http://localhost
HTTP/1.1 200 OK
Server: nginx/1.13.6
Date: Sun, 19 Nov 2017 10:46:05 GMT
Content-Type: text/html
Content-Length: 612
Last-Modified: Tue, 10 Oct 2017 15:59:40 GMT
ETag: "59dcee6c-264"
X-Varnish: 22 20
Age: 3
Via: 1.1 varnish-v4
Connection: keep-alive

2回目アクセス以降X-Varnishの値が2つ返っていればキャッシュされている5

また、nginxのアクセスログに2回目以降のアクセスログが残らないことも確認できた。(キャッシュ間隔のデフォルトは5分。)

疑問

  • (リバースプロキシとしている)nginxでも同じことができるのではないか。
    • わざわざnginxの後ろにVarnishを置く理由。

参考

JSON-RPCについて

JSON-RPCについて調べた際のメモです。

特徴

JSON-RPC is a stateless, light-weight remote procedure call (RPC) protocol.

JSON-RPC 2.0 Specification

  • データのエンコードJSONを利用したRPC(Remote Procedure Call)1プロトコルの一種。
  • レスポンスを期待しない「通知」、複数の呼び出しを一度に行う「Batch」が可能。
  • リクエスト、レスポンスのjsonに含めるべきフィールドが決められており(プロトコルなので)、それを満たしさえすればよい。
  • HTTPメソッドは全てPOSTとするのが通例。

リクエス

以下、例は主にJSON-RPC 2.0 Specificationから拝借いたしました。

  • jsonrpc [string]: JSON-RPCのバージョン(現在2.0)
  • method [string]: 呼び出したいメソッド名
  • params [array|object]: メソッドの引数(単純に列挙する場合はarray、ラベルを使う場合はobject)
  • id [string|int]: リクエストを識別するID、レスポンスに同じ値が含まれる、よってBatch(後述)で送ってもどのリクエストに対するレスポンスかを識別できる
{
  "jsonrpc": "2.0",
  "method": "subtract",
  "params": [42, 23],
  "id": 1
}

ラベル付き

{
  "jsonrpc": "2.0",
  "method": "subtract",
  "params": {
    "subtrahend": 23,
    "minuend": 42
  },
  "id": 3
}

レスポンス

成功時:

  • jsonrpc [string]: JSON-RPCのバージョン
  • result [object]: 成功時のデータ、特にフォーマットの指定はない
  • id [string|int]: リクエストID

失敗時:

  • jsonrpc [string]: JSON-RPCのバージョン
  • error [object]: 失敗時のデータ、フォーマットは以下の通り
  • id [string|int]: リクエストID

errorのフォーマット

  • code [int]: エラーコード、あらかじめ定義されている → error object
  • message [string]: エラーメッセージ
  • data [any]: 追加情報用のフィールド、型の指定もなく、省略も可能

成功時:

{
  "jsonrpc": "2.0",
  "result": 19,
  "id": 1
}

失敗時:

{
  "jsonrpc": "2.0",
  "error": {
    "code": -32601,
    "message": "Method not found"
  },
  "id": "1"
}

通知

リクエスト時にIDフィールドを省略すると、レスポンスを期待しないと解釈され、何も返ってこない。これを「通知」と呼んでいる。

{
  "jsonrpc": "2.0",
  "method": "update",
  "params": [1,2,3,4,5]
}

Batch

トップレベルを配列にし、リクエストを複数一気に送ることができる。

リクエスト:

[
  {"jsonrpc": "2.0", "method": "sum", "params": [1,2,4], "id": "1"},
  {"jsonrpc": "2.0", "method": "notify_hello", "params": [7]},
  {"jsonrpc": "2.0", "method": "subtract", "params": [42,23], "id": "2"},
  {"foo": "boo"},
  {"jsonrpc": "2.0", "method": "foo.get", "params": {"name": "myself"}, "id": "5"},
  {"jsonrpc": "2.0", "method": "get_data", "id": "9"} 
]

レスポンス:

[
  {"jsonrpc": "2.0", "result": 7, "id": "1"},
  {"jsonrpc": "2.0", "result": 19, "id": "2"},
  {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null},
  {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}, "id": "5"},
  {"jsonrpc": "2.0", "result": ["hello", 5], "id": "9"}
]

GoでJSON-RPCを扱う代表的なパッケージは以下の3つ

【思ったより手間取っているので追記予定】

疑問

  • JSON-RPCを使う理由
    • URL設計が鍵になるRestAPIとメソッド設計が鍵になるJSON-RPCだと大分性格が違うと感じたが、どのケースはRestAPI向きでどのケースはJSON-RPC向きなのか
  • 一般的なidの割り振り方

参考


  1. RPCの例 wiki

ISUCONカンニングペーパー

【10/23追記】 f:id:KK462:20171024034517p:plain

残念ながら本選に出場することはできませんでした。

インデックス貼ったりN+1を直したりはできたのでせめて最後にスコアを残したかったと後悔しています。

とはいえ8時間があっという間に感じるくらい楽しかったです。 夜中の2時のサイクリングも最高にエキサイティングでした。

準備不足につきます。 来年こそは本選出場できるように頑張ります。


サーバーの状態確認コマンド群

pstree
ps auxwf
top
htop
dstat -ta
glances

ユーザーの追加

adduser username
usermod -aG sudo username

git

git init
git add .
git commit -m "first commit"

ファイルの転送

remote → local

# file
scp your_username@remotehost.edu:foobar.txt /some/local/directory
# directory
scp -r your_username@remotehost.edu:/some/remote/directory/foo bar

local → remote

# file
scp foobar.txt your_username@remotehost.edu:/some/remote/directory
# directory
scp -r foo your_username@remotehost.edu:/some/remote/directory

ディレクトリのときは

local$ tar -czvf local.tar directory/
local$ scp local.tar user@remote:/directory
ssh user@remote
remote$ tar -xzvf local.tar

がよい。

言語の切り替え

systemdに登録されたサービスは /etc/systemd/system/ 以下。

sudo -s
systemctl stop XXX
systemctl start YYY
journalctl -f

netdata の設定

bash <(curl -Ss https://my-netdata.io/kickstart-static64.sh)

して <host>:19999 にアクセス。

alp の設定

1.Releases · tkuchiki/alp · GitHub で最新版を確認する

2.インストール

wget https://github.com/tkuchiki/alp/releases/download/v0.3.1/alp_linux_amd64.zip
unzip alp_linux_amd64.zip
sudo install ./alp /usr/local/bin

3.access.log の設定 /etc/nginx/nginx.conf を以下のように修正

...

http {
    log_format ltsv "time:$time_local"
                "\thost:$remote_addr"
                "\tforwardedfor:$http_x_forwarded_for"
                "\treq:$request"
                "\tstatus:$status"
                "\tmethod:$request_method"
                "\turi:$request_uri"
                "\tsize:$body_bytes_sent"
                "\treferer:$http_referer"
                "\tua:$http_user_agent"
                "\treqtime:$request_time"
                "\tcache:$upstream_http_x_cache"
                "\truntime:$upstream_http_x_runtime"
                "\tapptime:$upstream_response_time"
                "\tvhost:$host";
    access_log /var/log/nginx/access.log ltsv;
}

...

4.再起動

rm /var/log/nginx/access.log && systemctl reload nginx

5.実行

alp --sum -r -f /var/log/nginx/access.log --aggregates='/keyword/.*'

slow query

1.my.conf の設定

以下を追記

[mysqld]
...
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 0

2.mysql、アプリの再起動

systemctl restart mysql
systemctl restart XXX

3.percona-toolkit のインストール (Debian8: jessie)

wget https://www.percona.com/downloads/percona-toolkit/3.0.3/binary/debian/jessie/x86_64/percona-toolkit_3.0.3-1.jessie_amd64.deb
apt install libdbd-mysql-perl libdbi-perl libio-socket-ssl-perl libnet-ssleay-perl libterm-readkey-perl
dpkg -i percona-toolkit_3.0.3-1.jessie_amd64.deb

4.解析

pt-query-digest --limit 10 /var/log/mysql/slow.log

再起動用のスクリプト

#!/bin/sh
set -e

now=`date +%Y%m%d-%H%M%S`
mv /var/log/nginx/access.log /var/log/nginx/access.log.$now
systemctl reload nginx

mv /var/log/mysql/slow.log /var/log/mysql/slow.log.$now
mysqladmin -uisucon -pisucon flush-logs

systemctl restart XXX

journalctl -f

静的データのnginxでの配信

location / {} の前に、

location ^/(img|css|js|favicon.ico) {
    root /path/to/static/files;
}

my.cnf

innodb_buffer_pool_size = 1G
innodb_flush_log_at_trx_commit = 0
innodb_flush_method=O_DIRECT

nginx.conf

とりあえず、

# Worker connections
events {
    worker_connections XXX;
    use epoll;
    multi_accept on;
}

http {
    ...

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;
    etag off;

    ...
}

worker_connections = ulimit -n

あとは How to Configure nginx for Optimized Performance

autostart (with sysetmd)

check

systemctl is-enabled <SERVICE_NAME>

enable

systemctl enable <SERVICE_NAME>

参照


雑記

  • systemctl restartsystemctl reload の違い

reload: Unitに対して設定ファイルの再読み込みを促す。(対象のUnitがreload動作に対応している必要がある)

restart: 起動中のUnitを停止後、起動(stop -> start)する。対象のUnitが停止中である場合、起動操作のみ実施する。

「Systemd」を理解する ーシステム管理編ー | ギークを目指して

【メモ】Redisについて

Redisについての雑多なメモです。

特徴

Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache and message broker.

Redis

  • Key-Valueストレージで、NoSQLに分類される
  • そういう文脈上キャッシュというよりはデータストレージ
  • 最大の特徴は構造を持つデータ(リストやオブジェクト)をそのまま保存できること
  • パフォーマンスはmemcachedremarkably similarらしい
  • データは定期的にディスクに保存されるためサーバが落ちてもデータが残るし、再起動時にはロードされる
  • データのサイズに制限はないが、全体サイズがメモリ容量に収まる必要がある、あるいは削除の設定をする必要がある

導入

// ダウンロード
$ wget http://download.redis.io/redis-stable.tar.gz
$ tar xzf redis-stable.tar.gz
$ cd redis-stable
// ビルド
$ make

// 起動
$ src/redis-server

PHPでの利用方法

PHPでRedisを利用する際は、以下の2つがメジャー。

どちらのクライアントも基本的にRedisのコマンド名と同じメソッドが定義されているので利用法に大きな差異はないが導入方法が異なる。また、phpredisはextensionなのでpredisよりも高速で動作することが予想される。

predis

ライブラリなのでcomposer経由でインストール。

{
    "require": {
        "predis/predis": "^1.1.1"
    }
}

アプリケーション側からは以下のように利用する。

<?php
require __DIR__ . '/../vendor/autoload.php';

use Predis\Client as PredisClient;

try {
  $redis = new PredisClient();
} catch (Exception $e) {
  die($e->getMessage());
}

// 値の設定
$redis->set('message', 'Hello world');
// 値の取得
$value = $redis->get('message');

print($value); // Hello world

phpredis

こちらはextensionとなっているので、

ダウンロード & ビルド → php.iniにモジュールの登録

の手順を踏む必要がある。

  • ダウンロード & ビルド
$ git clone git://github.com/nicolasff/phpredis.git
$ cd phpredis
$ phpize // エクステンションを追加する際に,phpを最初からコンパイルし直す必要なく,追加するためのコマンド(*)
$ ./configure
$ make && make install

(*) Redisの使い方

  • モジュールの登録

ビルドされたredis.soというファイルをphpのextensionが入っているディレクトリにコピーし、php.iniに登録する。

$ cp modules/redis.so {php-config–extension-dir}
$ sudo echo “extension=redis.so”  > /etc/php5/conf.d/redis.ini

アプリケーション側からは以下のように利用する。

<?php
$redis = new Redis(); // extensionとして登録しているからロードせず使える
$redis->connect('127.0.0.1',6379);

$redis->set('dog', 'bow-bow');
$res = $redis->get('dog');
echo $res . PHP_EOL;

$redis->close();

気になる点

  • 導入するタイミングはいつなのか
  • 結局memcachedとどっちがいいのか
    • データ構造が保存できるとはいえmemcachedシリアライズの方法、共通の実装が揃えば使い勝手は一緒な気がする。

参考