✖
Chrome の brotli 圧縮アルゴリズム対応がデフォルトで有効に
https://chromium.googlesource.com/chromium/src.git/+/52b672b2462d6a3751a13187a1003e6fffdfbfbd
手元で確認した限りだと、バージョン 51.0.2704.63 (64-bit) で accept-encoding:gzip, deflate, sdch, br が送信されるようになっていました。
フラグとしてはバージョン49で実装されていたみたいですが、51 (2016-05-25)でようやくデフォルトでも有効になりました。リリースノートには書いてませんが、「log」をたどると上記コミットで有効になったことがわかります。
他のブラウザだと Firefox は 44 (2016-01-26)から有効になっています。
なお、Chrome でも Firefox でも brotli 対応は HTTPS 限定です。
感想
「Chrome が新圧縮アルゴリズム対応!」みたいなニュースが流れてからだいぶ経っています。しばらくは Firefox だけ有効な状態だったので「まだかまだか」とちょくちょくチェックしていたのですが、ついにデフォルト有効になりました。これによって劇的にパフォーマンスが改善するわけではないと思いますが、accept-encoding に新しいのが加わるとわくわくします。
なおこのサイトは全体的に brotli 対応にしてあるので、開発者ツールとかで眺めてニヤニヤしています。
関連エントリー
- Firefox の開発者ツールのほうが HTTP2 でサーバプッシュされたコンテンツがわかりやすい Firefox だと上記のようにリクエストが消滅してタイミングも全てない表示になるみたいです。 Chrome の Network タブだとプッシュしてもキャッシュからひいてくる時間を表示しているのか区...
- 最近の Raspberry Pi はデフォルトで ssh が無効 Raspbian 2016-11-25 のリリースから ssh がデフォルトで無効になっていて port 22: Connection refused となる。 起動してからキーボードで有効化してもい...
- Mac で VoiceOver が起動しているかどうかを判定する方法 / または Google Chrome を強制的にアクセシビリティ有効にする方法 自分のアプリケーション (AXApplication ) の AXEnhancedUserInterface (bool) を調べて、1 が入っていたら VoiceOver が起動している。 Goog...
- Chrome の WebAudio でステレオ入力ができない場合 input channel 数はちゃんと2なのに同じデータが入っている モノラルになるとかじゃなく、ステレオ入力すると、デフォルトではモノラル結合されて、同じデータが2チャンネルにコピーされて流れてく...
- h2o で特定のファイルがオンザフライ圧縮されないとき h2o は compress: ON にすると、レスポンスに accept-encoding に応じたオンザフライな圧縮が有効になります。ただしデフォルト状態ではcontent-type が text...
h2o で特定のファイルがオンザフライ圧縮されないとき
h2o は compress: ON にすると、レスポンスに accept-encoding に応じたオンザフライな圧縮が有効になります。ただしデフォルト状態ではcontent-type が text/ から始まる場合と +xml で終わる場合に限られているようです。
この条件に一致しない application/json などに対しても圧縮をかけたい場合、file.mime.settypes で設定すれば良いようです。すなわち
file.mime.settypes:
"application/json":
extensions: [".json"]
is_compressible: yes
priority: normal このようにすれば application/json でも自動的に圧縮してくれます。
これは file. で始まるディレクティブですが、バックエンドサーバから送るレスポンスに対しても(リバースプロキシとしても)これで圧縮がかかるようになります。
関連エントリー
- h2o の status/json を mackerel に送る mackerel にメトリクスとして送る mackerel-plugin-h2o みたいなのは今のところないっぽい? ので、status/json からとれる内容をポストするプラグインを書いた。 ht...
- h2o を systemd 管理下にした 徐々に daemontools 依存を外していってるが、とりあえず h2o を systemd に管理にすることにした。どうも daemontools だと annotate-backtrace-sy...
- h2o の duration stats h2o の status ディレクティブのJSON出力を眺めていたら、duration-25 とか connect-time-50 とか 不思議なプロパティがいくつか含まれることに気がついた。しかしど...
- h2o の casper を一時的に無効にする h2o の casper (cache-aware server-push) を有効にしていると、force reload したときでも push されなくなってしまって、だんだん混乱してきます。YA...
- Google Fit の REST API で体重を自動入力する (画像は過去に入力したデータを全て Google Fit へ入力しなおした様子) Fit API 全体の概念 単純にグローバルな「体重」に対して値を追加するみたいになっているわけではない。 各アプリケ...
✖
SQLite で「PRIMARY KEY」を《真のプライマリキー》とするには
http://www.sqlite.org/withoutrowid.html WITHOUT ROWID 最適化について
SQLite は常に暗黙的な rowid カラムを持っていることになっている。これはカラムとして明示することもできるし、interger primary key として定義されたフィールドは暗黙的な rowid の代わりにすることができる。SQLite ではこの rowid が基本のプライマリキーになっている。
適当な数値をプライマリキーにしたい場合はこれで全く問題ないが、複合キーだったり文字列をプライマリキーにしたい場合、その表面上のプライマリキーとは別に rowid カラムができる。このケースでは表面上のプライマリキーを使って SELECT しようとすると、表面上のプライマリキーのインデックスを探したうえで、さらに rowid のインデックスを探すことになる。つまり、このケースのプライマリキーとは単に UNIQUE なインデックスでしかない。
そこそこ最近(3.8.2・2013年)からは WITHOUT ROWID をテーブル定義時に指定することで、暗黙的な rowid 生成を抑制して、プライマリキー指定した定義を「真のプライマリキー」とすることができる。
これによって
- インデックスを辿る回数が減るのでパフォーマンスがあがる
- 表面上のプライマリキー→rowid のインデックスがなくなるのでDBサイズが減る
- インデックスが減るので挿入時の負荷が減る
と良いことがある。一方デメリットで気になるのは
- 古い SQLite (3.8.2 より前) で該当DBを読もうとすると malformed database schema で怒られて読めない
- sqlite3_last_insert_rowid() が使えない
- インクリメンタルblob I/Oが使えない (大きなカラムを少しずつ読める低レベルな仕組み)
関連エントリー
- SQLite の WITHOUT ROWID の効果測定 SQLite で「PRIMARY KEY」を《真のプライマリキー》とするには | tech - 氾濫原 の続きです。 以下のような簡単なベンチマークスクリプトを使って差を測ってみました。 Linux ...
- 関連画像を表示 libpuzzle の Perl binding である Image::Libpuzzle を使って関連画像を実装してみた。pHash や avgHash も試してみたけど、どれが良いかというとなんと...
- ブログのキャッシュバックエンドの変更 今までは Cache::FileCache によるファイルシステムキャッシュにしていたけど、いくつか問題があって SQLite にかえた ファイルシステムキャッシュで困っていたこと なんか遅い キャッ...
- Ruby Sequel で生 SQL をメインに使う Sequel はドキュメント見ると SQL そのまま書くやりかたもとクエリビルダを介すやりかたも許されていると感じるので (別に他のライブラリでも可能だろうが)、導入負荷が低くてよさそうです。結構機能...
- Lightroom のカタログを SQLite で読んで統計を出したりする .lrcat っていったい何なのか カタログファイルの実体である lrcat は SQLite の DB ファイルそのもの。sqlite3 foo.lrcat すると中身を見ることもできる。 部分的に...
TF-IDFとコサイン類似度による類似エントリー機能の実装
TF-IDFによる類似エントリー機能の実装をしてみました。ほぼSQLiteですませるような構成です。
やっていることの概要
- エントリーのHTMLを適当なワード単位に分割
- タグ削除とか記号削除とかしつつ、簡単な形態素解析で分割
- エントリごとのワード出現回数をSQLiteに全て入れる (テーブル構造的には転置インデックスとして機能)
- エントリ・ワードごとにTF-IDF の計算
- エントリごとにTF-IDFのベクトルとして正規化
- エントリごとに共通語が一定数を超えるエントリ複数に対しコサイン類似度でスコアを計算
ワード分割
MeCab を使った形態素解析などでもいいのですが、お手軽にやりたかったので以下のようにしています。
my $text = ...;
$text =~ s{<style[^<]*?</style>}{}g;
$text =~ s{<script[^<]*?</script>}{}g;
$text =~ s{<[^>]+?>}{}g;
$text =~ s{[^\w]+}{ }g;
my $words = reduce {
$a->{$b}++;
$a;
} +{},
map {
s/^\s|\s$//g;
$_;
}
map {
if (/[^a-z0-9]/i) {
Text::TinySegmenter->segment($_);
} else {
$_;
}
} split /\s/, $text; 不必要なHTML要素及びタグを削除し、記号類を全てスペースに置換したうえでスペースで分割し、日本語が含まれていそうな部分だけ TinySegmenter による簡易形態素解析をしています。
自分しか書かない日記の類似をとるので、表記揺れが殆どないことを前提に、アルファベットだけで構成される部分に関してはそのまま特徴語としたいためです。また、プログラムについて書くことが多いので日本語部分は比較的重要度が低いという見立てがあります。
転置インデックス
転置インデックスはあるワードがどのエントリに含まれるかを記録したデータ構造です。エントリー中の文章を適切な粒度で分割して、ワードからエントリーをひけるインデックスをつくります。
転置インデックスだけでも、あるワードが含まれるエントリーのリストを得るのは簡単になるので、例えば「共通ワードが多いエントリ同士は類似している」というスコアリングを採用するなら、転置インデックスのみで実現できます。
DBとしてSQLiteを使っているので、簡単な定義の単一テーブルだけを作ってなんとかしています。
CREATE TABLE tfidf (
`id` INTEGER PRIMARY KEY,
`term` TEXT NOT NULL,
`entry_id` INTEGER NOT NULL,
`term_count` INTEGER NOT NULL DEFAULT 0, -- エントリ内でのターム出現回数
`tfidf` FLOAT NOT NULL DEFAULT 0, -- 正規化前の TF-IDF
`tfidf_n` FLOAT NOT NULL DEFAULT 0 -- ベクトル正規化した TF-IDF
);
CREATE UNIQUE INDEX index_tf_term ON tfidf (`term`, `entry_id`);
CREATE INDEX index_tf_entry_id ON tfidf (`entry_id`); 見ての通りですがターム(ワード)とエントリIDでユニークなテーブルです。
エントリ内のHTMLを適当な粒度で分割したのち、このテーブルに入れています。この段階では term, entry_id, term_count だけ埋めます。
INSERT INTO tfidf (`term`, `entry_id`, `term_count`) VALUES (?, ?, ?); TF-IDF
TF-IDFは特徴語抽出のアルゴリズムです。文書中のワード出現頻度 (Term Frequency) と、全文書中のワード出現頻度の逆数( Inverse Document Frequency) から、ある文書のあるワードがどれぐらいその文書を特徴付けているかをスコアリングできます。
転置インデックスから「共通ワードが多いエントリ同士は類似している」というスコアリングを使ってエントリを抽出すると、ワード数の多いエントリ同士は類似していなくても類似しているとスコアリングされてしまいます。
TF-IDF を使って各ワードに重み付けをすれば「特徴語の傾向が似ている文書は類似してる」というスコアリングにすることができます。
まずは後述する正規化を考えずにテーブルの tfidf カラムを埋めます。
-- SQRT や LOG を使いたいので
SELECT load_extension('/path/to/libsqlitefunctions.so');
-- エントリ数をカウントしておきます
-- SQLite には変数がないので一時テーブルにいれます
CREATE TEMPORARY TABLE entry_total AS
SELECT CAST(COUNT(DISTINCT entry_id) AS REAL) AS value FROM tfidf;
-- ワード(ターム)が出てくるエントリ数を数えておきます
-- term と entry_id でユニークなテーブルなのでこれでエントリ数になります
CREATE TEMPORARY TABLE term_counts AS
SELECT term, CAST(COUNT(*) AS REAL) AS cnt FROM tfidf GROUP BY term;
CREATE INDEX temp.term_counts_term ON term_counts (term);
-- エントリごとの合計ワード数を数えておきます
CREATE TEMPORARY TABLE entry_term_counts AS
SELECT entry_id, LOG(CAST(SUM(term_count) AS REAL)) AS cnt FROM tfidf GROUP BY entry_id;
CREATE INDEX temp.entry_term_counts_entry_id ON entry_term_counts (entry_id);
-- TF-IDF を計算して埋めます
-- ここまでで作った一時テーブルからひいて計算しています。
UPDATE tfidf SET tfidf = IFNULL(
-- tf (normalized with Harman method)
(
LOG(CAST(term_count AS REAL) + 1) -- term_count in an entry
/
(SELECT cnt FROM entry_term_counts WHERE entry_term_counts.entry_id = tfidf.entry_id) -- total term count in an entry
)
*
-- idf (normalized with Sparck Jones method)
(1 + LOG(
(SELECT value FROM entry_total) -- total
/
(SELECT cnt FROM term_counts WHERE term_counts.term = tfidf.term) -- term entry count
))
, 0.0) 一時テーブルを使いまくっています。何度も同じ TF-IDF 計算をするなら効率化のため保存しておけそうなテーブルもありますが、更新処理が複雑になるためTF-IDF更新時に作っては消しています。修正が頻発するような開発初期段階では特に一時テーブルは設計変更などに強くて便利です。
TF-IDF のベクトル正規化
TF-IDF を計算して、エントリごとにエントリ中の単語数次数を持つ特徴ベクトルを作ったことになります。このあとコサイン類似度をとるわけですが、その際にはベクトルの大きさが不要なのでこれを正規化します。
ベクトル正規化はあるベクトルを方向(角度)をそのままに長さを1にするとこを言っています。コサイン類似ではエントリごとの角度だけを比較したいので、あらかじめ文書ごとのベクトルを正規化することで計算を簡単にできます。
-- エントリごとのTF-IDFのベクトルの大きさを求めておきます
CREATE TEMPORARY TABLE tfidf_size AS
SELECT entry_id, SQRT(SUM(tfidf * tfidf)) AS size FROM tfidf
GROUP BY entry_id;
CREATE INDEX temp.tfidf_size_entry_id ON tfidf_size (entry_id);
-- 計算済みの TF-IDF をベクトルの大きさで割って正規化します
UPDATE tfidf SET tfidf_n = IFNULL(tfidf / (SELECT size FROM tfidf_size WHERE entry_id = tfidf.entry_id), 0.0) コサイン類似
コサイン類似はベクトル長さを無視しての角度の差を求めるためのアルゴリズムです。2つのベクトルの角度の差のコサインを求めます。例えば、2つのベクトルの角度差が0(一致している)場合、 = 1、90度(直交・相関関係なし) なら 、180度(負の相関)なら と、なります。
前もってベクトル正規化をしているのでかけ算と足し算だけで計算できます。
ただ計算が簡単とはいえ、候補エントリ数*関係するワード(ターム)の数だけレコードをひいてくる必要があるので結構大変になってしまいます。
ここの効率化方法があまり思いつかず以下にようにしています
- エントリの特徴語を50語取得する(TF-IDF順にソートして大きいほうから50件)
- 特徴語を含むエントリを共通語が多い順に100エントリ取得する (コサイン類似前に足切り)
- それぞれのエントリ同士でコサイン類似度を計算してスコアを算定してソートする
特徴語の共通語が多い順で足切りをしているので、長いエントリほどここでは有利となってしまいます。また、極端に短いエントリに関しては100エントリ以上が同一数の共通語を持つ状態になる場合があり、このケースではスコアをつける前に「類似」と判定すべきエントリが確率的に足切りされてしまうので正確ではありません。
TF-IDF の大きい順に50件だけを採用しているので、正確なコサイン類似度ではありません (ベクトル正規化のときに使った次数と違う) が、無視しています。
うまくいった場合はスコアリングで上位に類似エントリが集まるようになります。
-- 類似していそうなエントリを共通語ベースでまず100エントリほど出します
CREATE TEMPORARY TABLE similar_candidate AS
SELECT entry_id, COUNT(*) as cnt FROM tfidf
WHERE
entry_id > ? AND
term IN (
SELECT term FROM tfidf WHERE entry_id = ?
ORDER BY tfidf DESC
LIMIT 50
)
GROUP BY entry_id
HAVING cnt > 3
ORDER BY cnt DESC
LIMIT 100
-- 該当する100件に対してスコアを計算してソートします
SELECT
entry_id AS eid,
SUM(a.tfidf_n * b.tfidf_n) AS score
FROM (
(SELECT term, tfidf_n FROM tfidf WHERE entry_id = ? ORDER BY tfidf DESC LIMIT 50) as a
INNER JOIN
(SELECT entry_id, term, tfidf_n FROM tfidf WHERE entry_id IN (SELECT entry_id FROM similar_candidate)) as b
ON
a.term = b.term
)
WHERE eid != ?
GROUP BY entry_id
ORDER BY score DESC
LIMIT 10 これによって求められた類似エントリは別途テーブルに保存しておいて、表示時にはこのテーブルのみをひいてくる構成にしました。
関連エントリー
- SQLite の WITHOUT ROWID の効果測定 SQLite で「PRIMARY KEY」を《真のプライマリキー》とするには | tech - 氾濫原 の続きです。 以下のような簡単なベンチマークスクリプトを使って差を測ってみました。 Linux ...
- Lightroom のカタログを SQLite で読んで統計を出したりする .lrcat っていったい何なのか カタログファイルの実体である lrcat は SQLite の DB ファイルそのもの。sqlite3 foo.lrcat すると中身を見ることもできる。 部分的に...
- 関連画像を表示 libpuzzle の Perl binding である Image::Libpuzzle を使って関連画像を実装してみた。pHash や avgHash も試してみたけど、どれが良いかというとなんと...
- ブログのキャッシュバックエンドの変更 今までは Cache::FileCache によるファイルシステムキャッシュにしていたけど、いくつか問題があって SQLite にかえた ファイルシステムキャッシュで困っていたこと なんか遅い キャッ...
- SQLite で LOG や SQRT を使うには SQLite にはかなり基本的な算術演算関数しかない。追加で何かしらやるためには拡張 (Run-Time Loadable Extension) を使う必要がある。 LOG や SQRT などはオフィ...
今期見てるアニメ
結構みてる気がする
- ふらいんぐうぃっち
- 田中くんはいつもけだるげ
- くまみこ
- 学戦都市アスタリスク 2nd SEASON
- 甲鉄城のカバネリ
- Re:ゼロから始める異世界生活
- 坂本ですが?
- ネトゲの嫁は女の子じゃないと思った?
- あんハピ♪
- クロムクロ
- マクロスΔ
- ジョジョの奇妙な冒険 ダイヤモンドは砕けない
- ばくおん!!
関連エントリー
- アニメ 全部感想を書いていくのも大変なので、放映からn日以内に見ている、みたいな感じで書いたらどうか 今期のアニメだと リアルタイム なし 放映当日〜翌日 (ほぼ常に未試聴マークがないぐらい) Re:ゼロから...
- ポケモン Go 僕はポケモンシリーズを一切プレイしたことがなくて、子供のときはコロコロか何かについてきたポケモンのモンスター一覧を眺めて「進化先が複数あるポケモンとかいるんか! すげーな!」とか思っていただけだった。...
- 勇者ヨシヒコの本放送に追いついた 勇者ヨシヒコと魔王の城【テレビ東京オンデマンド】 cho45 福田雄一 ★ 5.0 / 5.0 cho45 勇者ヨシヒコと悪霊の鍵【テレビ東京オンデマンド】 cho45 福田雄一 ★ 5.0 / 5....
- 無限にアニメみてる しばらくコンテンツ消費する気力もわかず見てない作品が多かったので一気にみた ぼっち・ざ・ろっく! 12話 きらら系だけど「この子が可愛い」みたいなのがない 1ミリも悪い人出てこないのに世界が悪意に満ち...
- ✖ 元気が全く、全然出てこなくて、どうしようもない。1回大きい負荷がかかって以来全方面にすっかり心が折れてるのがずっと続いてる。 コーディングは、別に、個人的に書きたいコードとかは比較的普通に書けるしまぁ...
Hello darkness, my dear friend / ART-SCHOOL
久しぶりに CD を買った。原点回帰っぽい構成みたいだけど、どうなんだろうな〜
ところで久しぶりにリッピングしようと思ったら CD ドライブがついているPCが起動せず、面倒なのでドライブを買った……
ASUS外付けDVDドライブ 軽量薄型/M-DISC/バスパワー/Win&Mac/USB2.0(USB3.0搭載PCでも利用可能)/書込みソフト付属/ブラック SDRW-08D2S-U LITE cho45
前までは EAC でリッピングしていた記憶があるけど、今回は iTunes でリッピングした。CDDB がまだ生きてて簡単だった。
関連エントリー
- SIGMA 35mm F1.4 DG HSM | Art を買った SIGMA 単焦点広角レンズ Art 35mm F1.4 DG HSM キヤノン用 フルサイズ対応 340544 cho45 シグマ(Sigma) ★ 5.0 / 5.0 cho45 かなり久しぶりに...
- 『Act2 或いは Act3』BURGER NUDS Act 2 或いは Act 3 cho45 BURGER NUDS ★ 5.0 / 5.0 cho45 解散して14年も経っていて自分の感じかたも曲作りも変わっているのは当然のはずなのに、なぜだか14...
- 900円でソフトウェアラジオ入門 ゾックス パソコンでワンセグテレビを楽しめるUSB接続ワンセグチューナー ブラック DS-DT305BK cho45 オウルテック ★ 5.0 / 5.0 cho45 ワンセグチューナーでソフトウェア...
- LTSpice でヘッドフォンアンプを解析する2 LTSpice でヘッドフォンアンプを解析する | tech - 氾濫原 の続き NJM4556A は 70mA と余裕があるオペアンプだが、こんなに電流とれるオペアンプはそれほどないので、もう少し普...
- 逆作用ピンセットは便利 電子工作などのときに、一時的に部品を挟んでおきたいときとかの道具として何を使っているかといえば標題にある通り逆作用ピンセットというもので、これはすなわちノーマリークローズなピンセットである。力を加えて...
Quick Charge 2.0 対応の充電器
自宅にいくつか Anker の充電器はあるが、Quick Charge 付きのものはなかった。そして、充電器いくつかあるとはいえ、旅行にいこうとすると足りなくて不便だった。
ということで上記のものを買った。ポート数多くなって便利。
Zenfone2 は Quick Charge 2.0 対応なので (特にそうとは書いてないが 9V 充電可能)、繋ぐと以下のように「急速充電中」とともに、発熱に関しての警告がマーキーで表示される。
ただ、Quick Charge 対応ポートは1つだけなので、急速充電したいときは気をつける必要がある。USBケーブルをQuick Charge ポートだけ色が違うものにした。
関連エントリー
- Quick Charge 2.0 の仕様 Quick Charge 2.0 とは 現行でも採用事例がある USB コネクタでの急速充電の仕様。USB は規格上 5V なので、急速充電のために電力高めようとすると電流が多くなってしまいコネクタや...
- 12V 出力のモバイルバッテリー Quick Charge 2.0 で 12V 出力できるバッテリーがいつのまにか Anker からも出ていた。 Anker cho45 ★ 5.0 / 5.0 cho45 https://jp.ank...
- 急速充電用の USB ACアダプタでいいのがない。 手元にあったACアダプタが突然死したため、代わりのを探しているけど、いいのが本当にない。不思議 アダプタ内で D+ D- ショート(急速充電) 1ポートで2A出せること という条件だけなのだけれど、び...
- Quick Charge 2.0 電源から 12V とる 続きをかきました 500 Can't connect to lowreal.net:443 (certificate verify failed) 仕様はちょっと前に調べて、先日対応バッテリーがきたの...
- Quick Charge 2.0 バッテリーから12Vをとる(追試) とりあえずとれるところまではやっていたが、ちゃんと負荷をかけていなかったのでかけたメモ cho45 ★ 5.0 / 5.0 cho45 例によってこのバッテリーで、結論からいうとスペック通り(12V ...
syrup16g の再始動後のライブ映像集
関連エントリー
- 生還 - syrup16g 『生還』 live at NHKホール 2013/05/08 [Blu-ray] cho45 五十嵐隆 ★ 5.0 / 5.0 cho45 非常に良かった。とりあえず中畑氏が最後のほう笑いながらたいこ...
- 最近のプレイリスト ミナソコ / BURGER NUDS カナリア / BURGER NUDS エコー / BURGER NUDS 鋼鉄の朝 / BURGER NUDS ANALYZE / BURGER NUDS MAR...
- YAPC::Asia で「ウェブエンジニアのローレベルプログラミング」という発表をしました ちょっと時間に対して話したいことが多すぎて、各分野での掘り下げが足りなかったとは思いますが、一通り下のほうまで盛りこみました。 電子工学について:自分は学校で電子工学を体系的に学んだことはありません。...
- アンテナアナライザの回路 - ブリッジの三つの電位差を測るタイプ http://www.rigexpert.com/index?s=articles&f=aas ブリッジの50Ω/50Ωで分圧したほうの電位 、負荷側の電位 、ブリッジ間の電位差 を測っているタイプで...
- ESP-WROOM-02 OTA firmware update / platformio Over The Air で (すなわち Wifi 経由で)、ファームウェア書きかえをするやつ。 コード https://github.com/esp8266/Arduino/blob/master/...
SQLite で LOG や SQRT を使うには
SQLite にはかなり基本的な算術演算関数しかない。追加で何かしらやるためには拡張 (Run-Time Loadable Extension) を使う必要がある。
LOG や SQRT などはオフィシャルの Contributed Files のextension-functions.c をコンパイルして使う。 http://www.sqlite.org/contrib
Ubuntu でのコンパイル。当然ながら SQLite のヘッダファイルなどが必要なので入れておく。
sudo apt-get install libsqlite3-dev
そのうえで以下のようにコンパイルする。apt-get で入れてる場合 -I などは指定しなくてもデフォルトで良さそう。必要なら pkg-config sqlite3 とかして引数を得る。
gcc -fPIC -shared extension-functions.c -o libsqlitefunctions.so -lm
extension-functions.c の冒頭にもコンパイル方法が書いてある。ただし、今はそれだと上手くいかなくて、-lmは最後につけないとダメ。罠があって、リンクに失敗しても load_extension するまで気付かない。
使うときは以下のように load_extension() を使う
select load_extension("/path/to/libsqlitefunctions.so"); Perl の DBD::SQLite で使うには
Perl から DBD::SQLite 経由で使う場合、
$dbh->do('SELECT load_extension("/path/to/libsqlitefunctions.so")'); とする。が、実はこれだけだと動かず、以下のように謎のエラーが出る。
DBD::SQLite::db do failed: SQL logic error or missing database not authorized
ドキュメントにも書いてあるが、sqlite_enable_load_extension を前もって呼ぶ必要がある。
$dbh->sqlite_enable_load_extension(1);
# または
$dbh->func(1, "enable_load_extension"); 備考
拡張の開発方法については Run-Time Loadable Extensions を見る。
関連エントリー
- SQLite の WITHOUT ROWID の効果測定 SQLite で「PRIMARY KEY」を《真のプライマリキー》とするには | tech - 氾濫原 の続きです。 以下のような簡単なベンチマークスクリプトを使って差を測ってみました。 Linux ...
- TF-IDFとコサイン類似度による類似エントリー機能の実装 TF-IDFによる類似エントリー機能の実装をしてみました。ほぼSQLiteですませるような構成です。 やっていることの概要 エントリーのHTMLを適当なワード単位に分割 タグ削除とか記号削除とかしつつ...
- Lightroom のカタログを SQLite で読んで統計を出したりする .lrcat っていったい何なのか カタログファイルの実体である lrcat は SQLite の DB ファイルそのもの。sqlite3 foo.lrcat すると中身を見ることもできる。 部分的に...
- Swift で Mac の ScriptingBridge を無理矢理つかう ちょいちょい「環境設定」→「セキュリティとプライバシー」→「アクセシビリティ」を開かせたいケースがあるが、openURL とかで Security.prefPane を開くだけだと「どこやねん」となり...
- Ubuntu 16.4 LTS クリーンインストールして引越 カスタムOSインストールガイド - Ubuntu 16.04 – さくらのサポート情報 を見ながらインストールまでやる。 旧サーバと同じホスト名にしてDNSをふりかえたいが、DNS やホスト名まわりは...
豆乳飲むと大豆イソフラボンの安全な一日摂取目安量の上限値は案外超えやすい
食品安全委員会の QA によると、
大豆イソフラボンの安全な一日摂取目安量の上限値70〜75mg/日(大豆イソフラボンアグリコン換算値)
と書いてある。150mg ぐらい摂取すると健康被害の影響があるかもしれないので、その半分を上限にしているらしい。ちょっと調べてみると、これが案外厳しい基準に思えたので記録しておく。
豆乳の大豆イソフラボン含有量
大豆イソフラボンアグリコン換算は以下のようになっている。食品表示にある「イソフラボン」はイソフラボン配糖体のことなので、換算して考える必要がある。
(例)大豆イソフラボン配糖体10mg×0.625 =大豆イソフラボンアグリコンとして 6.25mg
ここで、一番メジャーな紀文の調整豆乳について見てみると、「イソフラボン 43mg/200ml」となっている。0.625 をかけて、26.875mg/200ml (大豆イソフラボンアグリコン換算値)
また、FAQ中の表に豆乳の含有量について記載がある。
(大豆イソフラボンアグリコンとしてmg/100g)
〜 省略 〜食品名(検体数):豆乳(3検体)
含有量: 7.6〜59.4
平均含有量: 24.8
紀文の調整豆乳はだいたい平均的な値の倍(訂正)
もし毎食コップ一杯の豆乳を飲むと、それだけで75mg/日を超える。もちろん他の大豆製品 (特に味噌や納豆) にも含まれるので豆乳単体でどうとはいえない。
なお、大豆イソフラボンアグリコンの一日摂取目安量の上限値、70~75 ㎎/日は、この量を毎日欠かさず長期間摂取する場合の平均値としての上限値であること、また、大豆食品からの摂取量がこの上限値を超えることにより、直ちに、健康被害に結びつくというものではないことを強調しておく。
と書いてある通りなので、豆乳めっちゃ好きすぎる!!!とか、豆乳で必要タンパク質全部とるぞ!!みたいな意気込みがなければ、平均的には大丈夫なのかな。
主観による温度感
大人は毎日1日コップ一杯ぐらいは他に大豆食品をとっていても問題なさそう。妊婦や子供に対してはもっと気をつけるべきのようで、だぶん牛乳代わりに毎日飲む/飲ませるみたいな習慣はやめたほうが良さそう、というのが僕からみた温度感です。
キッコーマン飲料 調製豆乳 200ml×18本 cho45
関連エントリー
- HTML5 の svg 要素 を canvas に描く方法 こうする async function loadAsImage(svg) { return new Promise((resolve, reject) => { const svgXml = new ...
- 角度の平均・分散 角度は周期があるのでよくよく考えると平均や分散を出すのがむずかしい。いろいろやりかたがあるみたいだけど「単位ベクトル合算法」で計算してみる。 #!/usr/bin/env python import ...
- 電解コンデンサは常温放置でも劣化する http://www.rubycon.co.jp/products/alumi/technote3.html#3-7 https://www.nichicon.co.jp/lib/aluminum.p...
- タカチ電機工業のサイトの検索結果を値段でソート ケースのタカチの製品検索 ( https://www.takachi-el.co.jp/search/detail ) で結果をソートする方法がないので、JS でやる。 JS コンソールで以下を実行す...
- YONGNUO YN600Air 5500K モデルを買ってみた YONGNUO YN600Air LED ビデオライト 5500K SMD LED搭載 超薄 カメラ ビデオカメラ用 補助照明 撮影用 Canon Nikon Olympus Pentax Panas...
逆作用ピンセットは便利
電子工作などのときに、一時的に部品を挟んでおきたいときとかの道具として何を使っているかといえば標題にある通り逆作用ピンセットというもので、これはすなわちノーマリークローズなピンセットである。力を加えていないときはピンセット自体のバネで閉じており、挟んでおいておくことができる。
便利な特徴がいくつかある
- ピンセット形状なので、基板の中央付近の部品など、少し遠い位置を一時的におさえたりできる
- ほどよいバネ圧
この手の逆作用ピンセット(反作用ピンセットや逆作動ピンセットなど、用語が揺れてる)は100均でも売ってることがある。自分が使っているのも100均でたまたま買ったものだけど、ものすごく活用している。
余談:ヒートクリップ
だいぶ前に便利かと思ってヒートクリップというのを買ったことがあるが、結局ほとんど使っていない。
ヒートクリップはリード付き半導体のはんだ付け時に熱から守るために使うというのが本来の用途だが、そもそもそんなに熱に弱い半導体って今時使うことがない。
そして汎用のクリップの用途で考えるとこの商品はバネ圧が強すぎて使いにくい。ので、この手の用途でも逆作用ピンセットのほうが圧倒的に使いやすい。
関連エントリー
- 半導体の基礎 N型、P型 半導体って「導体と絶縁体の中間」って説明されるけど、実感としてよくわからなかった。自分の中では導体か絶縁体しかなくて、半導体は特別なイメージがあった。 しかし、調べてみると、まさに「導体と絶縁体の中間...
- ラジオペンチはバネがないほうが良い 新しくラジオペンチ(やニッパー)を買ったときに違和感があって、なんでだろうなあと考えていたところ、バネの有無ということがわかった。 なんとなくバネがあったほうが自動的に開いて便利な気がするけど、これが...
- 電子部品の整理 抵抗器とかコンデンサとかをうまく整理する方法を考えてる。とにかく種類が多いし、そこそこ体積があったりするので面倒くさい。 値わけして袋詰めするまではいいとして、袋がばらばらにあっても、ソートされていな...
- curl で大きなファイルを resume しながらファイルダウンロード 細い回線で Chrome のダウンローダだとうまくレジュームできないことが多々あって厳しい。キャンセルするとダウンロード途中のファイルが消えたりするし (余計なお世話だ)、大きなファイルはダウンロード...
- 非導体系材料用に Touch Probe を作った 東急ハンズで真鍮の円柱を買ってきてそなりに磨いて、表面にM3で穴をあけてタップを切ってネジをさしこんだ。ネジ部分を Probe のワニグチクリップでつかんで使う。 ノギス(マイクロメーターを持ってない...
時計の電池を変えた
腕時計は普段しないのだが、某国家試験をうけるときに時計が必要だったのでこれを買っていた。最近はしばらく妻が使っていたが、電池切れで動かなくなってしまった。妻用には別の時計を買ったが、動かない時計だけ放置しておくのもなんなので電池を変えることにした。
元々入っていたのは SR626SW だが、100均で売ってたのが SR621SW だけだったため、こちらで代用した。この2つは厚みが違う。よって入らないことも予想されたが、100円なので試してみることに。結果的にはうまくいった。ただし、やはりすこしゆるい。
元が1000円の時計を時計屋で電池交換してもらうのもかなりアレなので、自分でやった。
この時計の場合特に特殊な工具はいらず、小さめのドライバーがあれば裏蓋をはずせる。裏蓋さえはずせば電池が見えるのでとりかえるだけだった。
余談:ボタン電池・コイン電池の型番
Wikipedia のIEC_60086の項にも書いてあるけど、型番によって化学構造(電圧や電流などの決定要因)と寸法がわかるようになっている。
SR626SW は
- S 酸化銀 (1.55V)
- R 円形
- 626 6mm 2.6mm を表わすが、実際の直径は6.8mm
- SW これは電流量を表わしている ref SR626SWとSR626Wなどの[SW]と[W]の違い
関連エントリー
- シチズン Q&Qのバンドを交換した cho45 ★ 5.0 / 5.0 cho45 1000円の時計。3年前に買って、去年に電池を交換したけど、バンドがかなりヘタって、もうダメという感じだったので交換した。 [ランドン] 【バネ棒+工具...
- CASIO WVA-200 腕時計つけることが全くなくなったので、電池切れのまましまってあったけど、久しぶりに電池交換して動かしてみることにした。 WAVE CEPTOR WVA-200 (説明書番号 2370) いつ発売された...
- 腕時計 [シチズン Q&Q] 腕時計 フォルコン V722-850 ブラック cho45 CITIZEN ★ 5.0 / 5.0 cho45 試験とか用に時計が必要だったので安いのを買った。これ1000円ぐら...
- 時計(セイコー SBPX157)を買った いろいろ検討したけど、文字盤が一番気に入ったのでこれを買ってしまった。 3つ折れバックル 蓄光 [セイコーウオッチ] 腕時計 セイコー セレクション Sシリーズ メンズ ソーラー フルアラビア SBP...
- 激安パタパタクロックの改造 パタパタ時計 (flip clock) ebay で 1300円ぐらいで買った。デザイン上不可解な点があるが一応そこそこ動いてくれる。パーツが多い製品になりがちなのでこれ以上安いものはないみたい。 ち...
体調不良(続)
体調不良 - 氾濫原 のあと、月曜日の昼ぐらいから気持ち悪くなった。20時ぐらいにマスク(電車が臭いので)して帰宅開始したがなんとか(というか奇跡的に)吐き気を抑えて帰宅できた。夕食は食べずに寝たが、22時ぐらいに結局トイレで吐いて、多少はすっきりした。ただ下痢なのと発熱で夢見が悪くあまり寝れず。昼食から10時間ぐらい経っていたけど、胃の中に滞留物がまだ残っていた。
子供も夕方あたりに吐いたらしくて家の中がだいぶひどかった。
火曜日は会社休んで病院。結局ウィルス性胃腸炎らしいが、待ってる以外に特に治療法もないみたいで、ビオフェルミンと吐き気止めと抗生物質が処方された。午前中は何も食べず、昼ぐらいにおかゆを食べた。火曜日中は特に良くならず。
火曜の昼あたりから今度は妻が発症した。 (定期検診で病院にいってたがついでに点滴をうけてきたらしい)。一方子供は火曜夕方ぐらいには元気になった。
水曜朝もまだ気持ち悪くて結局会社を休んだ。昼ぐらいまでに一度症状が軽くなったが、うどんを食べてしばらく経ったらまた気持ち悪く。
胃腸炎といえば一ヶ月前にも患っておりとにかく体調不良の頻度と強度が高い。なんとかしてほしい。
関連エントリー
- 断続的に体調不良 先週火曜日は体調不良で休んだが、子供も熱を出してひきとることになったので、結局完全には休めなかった。 鼻炎と喉がすこし痛いぐらいなので耳鼻科にいって薬をもらっているけど治らない。というか鼻炎と喉はとも...
- 最近の体調不良 先週は1日おきぐらいにちょいちょい調子が悪くて1日は休んだ。よくなったかと思ったら、月曜日の昼ぐらいから劇的に調子が悪くなり38.3℃ぐらいまで熱があがる。熱があがっている間って、あまりにもだるくて身...
- ✖ 2週間前と同じように体調不良になった。普通に帰宅して体温を計ると38度弱だった。とにかくだるいので夕食を食べてすぐに寝た。 朝は平熱にとりあえず戻った。
- 体調不良 火曜日の午後ぐらいからちょっとダルくて、とはいえすぐさま早退するほどでもない (というか早退を告げて帰宅開始するほうがストレス高い) ので普通に帰ってから熱を計ったら 37.4 ぐらい。あんまり食欲も...
- 体調不良 金曜日の夕方ぐらいから全身倦怠感と頭痛がはじまり、微熱(37度台)に。熱は土曜日中ぐらいで下がったが頭痛は治らず、今(月曜日)でもまだ痛い。
モバイルHFトランシーバKX2。KX3 と比較
KX2
http://qrznow.com/new-elecraft-kx2-announced-this-thursday-at-the-dayton-hamvention-2016/
アメリカの Elecraft から KX2 という無線機が出たらしいです。KX3 よりも小さい! バンドはCW/DATA/SSB 80m〜10m と、KX3 からは 50MHz と AM/FM がオミットされています。出力も KX3 が最大15Wに対しKX2 は 10Wのようです。KX3 のオプションにあったルーフィングフィルタはKX2ではなし。I/Q 出力もなし。
肝心の重さは 13oz (369g) と、KX3 よりもさらに半分ぐらいの軽さのようです。
本体 $749。ATU が $179.95、Li-ion のバッテリーパックが $59.95。モバイルの HF トランシーバとしては競合するものがもともと殆どないんですが、KX2 は完全に競合するものがなく、コストパフォーマンスは良さそうです。とはいえ I/Q 出力がないのがちょっと時流からするとキツい感じがします。回路図みながら辿ればとれそうな気はしますが。
関連エントリー
- Elecraft KX3 Bottom Keyer Paddle Pin assign "KXPD3 Keyer Paddle" は普通の KEY 端子とは別に、下部で4ピンで出ているのを使っている。マニュアルにも回路図にもピン配置が書いていないので調べた。(KXPD3 は持ってない) ...
- KX3 + Aukey Quick Charge 12V Out そういえば単体でどれぐらい出力を出せるか試していなかったのでやってみた。 KX3 は 7MHz 帯 5W で送信すると 1.6A〜1.7A ぐらい流れる。この状態で10秒ぐらい経過するとバッテリーが落...
- 192kHz サンプリングのUSBオーディオデバイス バンドスコープ を作ったのはいいが、41.1kHz サンプリングだし、0Hz付近にUSB オーディオデバイス由来の強力なノイズが入ってるのがイケてないので、良さげな192kHz サンプリングのUSBオ...
- 無線機まわりのグラウンドループの排除 KX3 は、自宅に置いてる間は ACC1 (シリアル接続) と RX I/Q を Mac に接続しており、普通に繋ぐとグラウンドループが発生する。(KX3 -> ACC1 -> Mac -> RX /...
- KX3 用のマウンタ KX3 は 8.8cm x 18.8cm x 4.1cm と、スマフォとして考えると大きすぎるし、タブレットとして考えると厚さが多すぎるという大きさなので、市販の殆どのマウントアームは直接使用できない...
体調不良
金曜日の夕方ぐらいから全身倦怠感と頭痛がはじまり、微熱(37度台)に。熱は土曜日中ぐらいで下がったが頭痛は治らず、今(月曜日)でもまだ痛い。
関連エントリー
- 風邪 土曜日午後から頭痛がひどくなり寝た。翌日日曜日も頭痛がひどく、体温を計ると37度台後半でずっと寝てた。月曜日もまだ微熱で頭痛で会社休んで寝てた。
- ✖ 昨日は帰宅後微熱(というほどでもないぐらい)。身体はそこまでだるくないが頭痛がひどい。
- 断続的に体調不良 先週火曜日は体調不良で休んだが、子供も熱を出してひきとることになったので、結局完全には休めなかった。 鼻炎と喉がすこし痛いぐらいなので耳鼻科にいって薬をもらっているけど治らない。というか鼻炎と喉はとも...
- ✖ オフィスにいるとだんだん体調が悪くなる。15時ぐらいからだんだんひどくなってくる。熱があるかはわからないが(たぶんない)、全身倦怠感がひどい。
- 体調不良 火曜日の午後ぐらいからちょっとダルくて、とはいえすぐさま早退するほどでもない (というか早退を告げて帰宅開始するほうがストレス高い) ので普通に帰ってから熱を計ったら 37.4 ぐらい。あんまり食欲も...
Google Search Console のページのダウンロード時間
sitemap.xml を送信した翌日ぐらいに Googlebot からの連続したアクセスがくるようになる。Googlebot は HTTP/1.1 で Keep-Alive が有効なため、普段にパラパラくるアクセスよりも、このときのように連続してアクセスされる場合、多くの場合でコネクション時間がなくなるために高速にレスポンスを返せる。
連続したアクセスの場合、2分ぐらい Keep-Alive している。
これは結果として Search Console の「クロールの統計情報」に表示されている「ページのダウンロード時間 」のグラフにも反映されているような感じで、sitemap.xml を追加した次の日あたりで平均ダウンロード時間がかなり少なく表示される。
関連エントリー
- ✖ Google Keep が使用に耐えないぐらい重かったり、挙動不審だったりする。 ブラウザ版で WebGL 停止の警告がでたりする ブラウザ版で入力するときに入力が遅い ブラウザ版でテキストをペースト...
- Applebot アクセスログを見ていたら Applebot なるものからのアクセスがあった。 https://support.apple.com/ja-jp/HT204683 ほんとに Apple のウェブクローラら...
- Android SDK の各プラットフォームのビルドツールの一部を使いたいとき sdkmanager をダウンロードする Android Studio のダウンロードページから「コマンドラインツールのみ」を選んでダウンロードしてくる。Android Studio が必要なら別に全...
- Mac で VoiceOver が起動しているかどうかを判定する方法 / または Google Chrome を強制的にアクセシビリティ有効にする方法 自分のアプリケーション (AXApplication ) の AXEnhancedUserInterface (bool) を調べて、1 が入っていたら VoiceOver が起動している。 Goog...
- curl で大きなファイルを resume しながらファイルダウンロード 細い回線で Chrome のダウンローダだとうまくレジュームできないことが多々あって厳しい。キャンセルするとダウンロード途中のファイルが消えたりするし (余計なお世話だ)、大きなファイルはダウンロード...
Server::Starter を node.js のサーバ起動に使う
Server::Starter は hot deploy 用の汎用スーパーデーモンで、Perl で書かれています。h2o の起動にも使われているのでみなさんおなじみでしょう!
Server::Starter がやってることは、Server::Starter 側で listen したソケットの fd を環境変数につっこんで子プロセスを起動というものです。子プロセス側では渡ってきた環境変数を読んで、fd について accept すれば良いことになります。
これを node.js でやるには以下のようにすれば良いようです。
//#!/usr/bin/env node
"use strict";
const http = require('http');
const server_starter_port = process.env['SERVER_STARTER_PORT'];
if (!server_starter_port) {
console.log('SERVER_STARTER_PORT is not set');
process.exit(1);
}
const fds = server_starter_port.split(/;/).map( (i) => i.split(/=/) );
const server = http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
});
process.on('SIGTERM', () => {
console.log('server exiting');
server.close();
});
for (let fd of fds) {
console.log('listen', fd);
server.listen({ fd: +fd[1] });
} 起動はたとえば以下のように
start_server --port=5001 -- node server.js
http.Server の listen() のドキュメントには fd を渡せるバージョンが書いてありませんが、net.Server の listen() がサポートしているので、同様に渡せるようです。
これだけで node.js のプロセスの hot deploy が簡単にできます。
余談:cluster
node.js には cluster というのがあります。これは node.js を複数プロセスで動かすための仕組みなんですが、これの woker プロセス側の listen() は master プロセスと ipc してうまいことやるみたいな感じのようです。
関連エントリー
- h2o で listen するポートを増やしたときは master プロセスの再起動が必要 start_server が listen してないポートは以下のようなエラーになる。 cp socket:(null):80 is not being bound to the server h2o...
- node.js で Perl における Test::TCP または Ruby における Glint Perl には Test::TCP というのがあって、テスト中、空いてるポートで何かしらのサーバーを起動して使うということができます。Ruby においては Glint というライブラリがあって、同じこ...
- ブログシステムの HTML 生成を効率化 そろそろやることなくなったので minify などをやることにしました。 ただ、ブログシステムの出力の最後ほうでページごとに全体を minify すると、全体としてどうしても処理に時間がかかってしまい...
- golang で websocket websocket.JSON を使った場合 JSON をやりとりする場合専用の方法がある (JSON-RPC ライクな実装を書いてみた場合) package main import ( "fmt" "...
- HTTPS 開発環境 そろそろ HTTPS でしか使えない新機能なんかを使いたくなるので、すこしずつノウハウを溜めようという気持ちはあります。 localhost 自己証明書 ググって出てくるコマンドだと対話的インターフェ...
複数の psgi を1つのサーバでサービスするときにメモリをケチる
このサーバはVPS 1台で動いていて、メモリは1GBしかありません。常時メモリ上限まで使いきっており、スワップファイルもそこそこあります。そういうわけで、できるだけメモリ消費をケチりたいのです。
稼働率の低い複数のサービスを1つのプロセスにまとめる
このサーバ上で動いているサービスがいくつかあるのですが、実際のところどれも殆どアクセスはありません。一番アクセスされていてこの日記システムぐらいです。
それらのサービスをそれぞれ別プロセスで起動させておくと、たいへん無駄なので、できるだけプロセス自体を同居させています。
psgi の vhost 化
Plack::Builder が提供している mount() を使うと、vhost を実現できます。
builder {
mount 'http://lowreal.net' => do {
my $guard = cwd_guard("lowreal.net/");
Plack::Util::load_psgi("script/app.psgi")
};
mount 'http://env.lowreal.net' => do {
my $guard = cwd_guard("env.lowreal.net/");
Plack::Util::load_psgi("script/app.psgi")
};
}; このようにすると、Host ヘッダに応じて、ディスパッチするアプリケーションを変えることができます。
これを利用して、複数の psgi アプリケーションを1つの psgi アプリケーションにまとめて起動しています。
ただし、起動時 (load_psgi時) にだけ cwd を設定しているため、cwd 依存のコードがあるとうまく動きません。
単にプロセス数も減らせますが、それぞれのアプリケーションで共通で使うモジュールがかなり多いので、それらを fork 前にロードして共有しておくことで、プライベートメモリ使用量を削減しようという意図もあります。
メモリリークや Copy on Write が発生したプロセスを捨てる
上記のまとめた psgi アプリケーションを start_server と plackup 経由で起動しています。
start_server 用には以下のような環境変数を設定しています
export KILL_OLD_DELAY=15
export ENABLE_AUTO_RESTART=1
export AUTO_RESTART_INTERVAL=3600
exec setuidgid cho45 \
$PERL/bin/start_server --path=/tmp/backend.sock --port=5001 -- $PERL/bin/plackup -p 5001 -s Starlet\
--max-workers=5 \
--max-reqs-per-child=500 \
-a backend.psgi ENABLE_AUTO_RESTART によって、時間経過で自動的にプロセス全体を再起動しています。再起動間隔は AUTO_RESTART_INTERVAL に決まり、この場合1時間ごとになっています。
KILL_OLD_DELAY には新プロセスが起動して、リクエストが受けつけられるようになるまでにかかる時間を余裕をもって指定します。これを指定しないと、プロセス再起動がかかるたびに、モジュールなどのロードが終わるまでの数秒アクセス不能時間ができるので、特に ENABLE_AUTO_RESTART する場合は必須そうです。
これで、もしメモリリークしていても1時間以内に綺麗になることが保証されるとともに、fork した worker プロセスが働いて Copy on Write が起こってプライベートメモリ量が増えたとしても、1時間以内に fork しなおしになるため、共有メモリ量が一定より高い状態を保つことができます。
余談:プライベートメモリ使用量を観測する
Linux のプロセスが Copy on Write で共有しているメモリのサイズを調べる - naoyaのはてなダイアリー にある shared_memory_size.pl が便利でした。共有メモリの割合を表示してくれるのでわかりやすいです。
Starlet のプロセス名をわかりやすくしたかったのも、このスクリプト実行時に指定しやすくするためでした。
こんな感じで使っています。
shared-memory-size.pl `pgrep -f /srv/www/backend.psgi` PID RSS SHARED 29583 55460 47792 (86%) 29584 55760 44688 (80%) 29585 65224 41396 (63%) 29586 56280 44704 (79%) 29587 55352 44660 (80%) 29588 58908 46748 (79%)
起動してすこし経ったあとの状態です。起動直後は90%以上ですが、プロセスが動くごとに少しずつ共有割合が減っていきます。自分の環境で、観測したうちだと60%ぐらいまで下がるようです。
ps -c で見るメモリ使用量には共有分が考慮されていないので、実際の物理メモリ使用量よりもかなり大きく出ます。仮に1プロセスあたり70MBぐらいメモリを消費していても、うち40MBぐらいが共有であることを考えると、worker プロセス1つあたり30MB、5プロセスで150MB程度の物理メモリ消費量になります。
関連エントリー
- Starlet でプロセス名をわかりやすくしたい ps とかで表示されるプロセス名をわかりやすくしたいという話です。 Starman だと $0 に適当な値を入れてくれて、master なのか worker なのかとか、どの psgi が動いているか...
- 日記システムPerlからgolangに書き換え この日記システムを golang で書きなおした。元日から4日ぐらいかけた。なんかおかしかったら教えてください。 前々から日記システムをgolangにしたいなという気持ちを抱きつつxatena-goを...
- Ruby でスコープをはずれたときに自動で何かをする Guard オブジェクト Perl だと Guard オブジェクトとかいうハックがあって、スコープを出るタイミングで必ず呼ばれるファイナライザを使って、あるスコープでだけ有効な処理を書けたりします。 ...
- Server::Starter を node.js のサーバ起動に使う Server::Starter は hot deploy 用の汎用スーパーデーモンで、Perl で書かれています。h2o の起動にも使われているのでみなさんおなじみでしょう! Server::Star...
- node.js で Perl における Test::TCP または Ruby における Glint Perl には Test::TCP というのがあって、テスト中、空いてるポートで何かしらのサーバーを起動して使うということができます。Ruby においては Glint というライブラリがあって、同じこ...
Applebot
アクセスログを見ていたら Applebot なるものからのアクセスがあった。
https://support.apple.com/ja-jp/HT204683
ほんとに Apple のウェブクローラらしい。ただ
robots の制御指示で Applebot には言及していなくても Googlebot について指定されている場合、Apple のロボットは Googlebot に対する指示に従います。
と書いてあって、それはどうなんだ、という感じがする。
関連エントリー
- Google Search Console のページのダウンロード時間 sitemap.xml を送信した翌日ぐらいに Googlebot からの連続したアクセスがくるようになる。Googlebot は HTTP/1.1 で Keep-Alive が有効なため、普段にパラ...
- Manifest for a web application https://w3c.github.io/manifest/ https://developers.google.com/web/updates/2014/11/Support-for-instal...
- macOS の EOS Utility 「カメラとUSB接続できませんでした」 どうあがいても接続できなくて困った。 どうやらなんか Google Chrome が USB デバイスをかたっぱしからオープンする挙動をしているようで、busy 状態になっているようだった。libus...
- スクリーンキャスト用のキーストローク表示アプリ 前にMacRuby でスクリーンキャスト用のキーストローク表示スクリプトを書いたんですが、それを Swift で書きなおして機能を追加したりしてアプリにしました。 https://github.com...
- Mac で VoiceOver が起動しているかどうかを判定する方法 / または Google Chrome を強制的にアクセシビリティ有効にする方法 自分のアプリケーション (AXApplication ) の AXEnhancedUserInterface (bool) を調べて、1 が入っていたら VoiceOver が起動している。 Goog...
crawler/1.0 という User-Agent
UAからしてなんか怪しいが、210.160.8.236 からくる BOT で、DNSを逆引きすると target.microad.jp. らしい。マイクロアドを使ってるつもりはないんだけど、Adsense 貼るとくるのかな?
まともなクローラのつもりなら、UA をもうちょっとわかりやすくしといてほしいですね。まともな会社なら自社クローラのUAと目的ぐらい書いとくべきだと思います。
関連エントリー
- さくらのVPSのウェブサーバでIPv6の接続をうける 最初からアドレスついてたので意外とやることない。 ifconfig すると既に v6 のアドレスがついている。Scope:Global になっているやつがグローバルIPアドレス (正確にはグローバルユ...
- Ubuntu 16.4 LTS クリーンインストールして引越 カスタムOSインストールガイド - Ubuntu 16.04 – さくらのサポート情報 を見ながらインストールまでやる。 旧サーバと同じホスト名にしてDNSをふりかえたいが、DNS やホスト名まわりは...
- サーバー移行 さくらのVPSにMongo Rescueのリストアができなかった (未解決) | tech - 氾濫原 の続きで、結局クリーンインストールした。さっき DNS を切り替えたので様子見。一応 DNS の...
- Adsense の新しい広告ユニット 最近になって「関連コンテンツ」と「ページ単位の広告」というのが beta になって登場した。サイト最適化と同時にこれらも有効にしてみたりしていた。 関連コンテンツ 広告ユニットではあるが、サイト内の関...
- HTTPS 開発環境 そろそろ HTTPS でしか使えない新機能なんかを使いたくなるので、すこしずつノウハウを溜めようという気持ちはあります。 localhost 自己証明書 ググって出てくるコマンドだと対話的インターフェ...






![再発患者 [Blu-ray] - syrup16g](https://m.media-amazon.com/images/I/41kwBbi7K5L._SL500_.jpg)



![[シチズン Q&Q] 腕時計 フォルコン V722-850 ブラック - CITIZEN](https://m.media-amazon.com/images/I/41OvjM8ihNL._SL500_.jpg)