星になれたなら

つみあげログです

「Software Design 2023年2月号 今さら聞けないログの基本」によせて

連作のページ一覧

  • 一章 ログの基礎とログ出力のしくみ TBU
    • Linux のログ管理のしくみについてです
  • 二章 Web サーバログの読み方・調べ方
    • Apache / nginx のログに関してです
    • LTSV / Combined Log Format は AWS Athena の SerDe でバトって以来知ってるので今回は省略します
  • 三章 ロギング設計の基本 TBU
    • アプリケーションのログの設計についてです

背景

ぼくはログを読むことも書くことも自己流でやっています。 そんな中で、Linux のログに関するしくみ、アプリケーションのログの設計の体系知が欲しいなと感じていました。

「第一章」「第三章」を選んだ理由

まず、Linux のログについて。 今日の Containerized な世界観では syslog を扱うよりも、 fluentd などで stdout / stderr を吸い出すことのほうがずっと多いでしょう。 とはいえ、Linux Desktop やオンプレ環境では依然 syslog を扱うことになる以上不要な知識ではないですし、Linux という巨大なエコシステムを支え続けているログの仕組みを知ることはどんなログの設計においても役立つでしょう。 そこで、Linux のログは外せないトピックかと考えています。

また、アプリケーションのログの設計について。 ログを書く方法は世の中に数あれど、そこに書くべき情報は何か、どういう形式であれば後々利用しやすいかなどを考慮した適切な設計ができるでしょうか。 こうした悩みはロギングライブラリの肩に載ってさえ完全に解決する問題ではありません。 そこで、ログ設計に関しても外せないトピックだと考えています。

この連作でやること・やらないこと

  • Do's
    • がんばったこと、感じたことの記録
  • Don'ts
    • 引き写し
      • リファレンスや目録のようなものは期待しないでください
    • 技術解説
      • RFC やその他書籍をあたってください

なので、「おー、読んでるね」と格闘の様子を楽しんでいただき、 プログラミングの勉強って楽しいよ、ということが伝えられたらと思います。

底本

「初めてのPerl」2章 スカラーデータ を読む

2章 スカラーデータ

この章でわかること

読んでいく

オーディオコメンタリー方式で、言いたいこと、補足があるぶぶんだけ書いていきます。

  • スカラー Scalar
  • 数値
    • Perl での数値の扱い方(精度、サイズ)は Perl ビルド時の環境に依存する
      • C のライブラリを使っているらしい
      • どのように扱い方が選択される?
    • 整数、小数や、その底によらず、内部的には倍精度浮動小数点(double)
      • 常に丸め誤差がありうる
        • 値がいくつかを判定するときは微小値で挟み込んだほうがいいのだろうか?
          • ε << 1 のとき n-ε < x < n+ε ならば x = n のような
    • リテラル
      • 整数リテラル
        • アンダースコアで区切ることが可能
        • 2進整数リテラル 0b11111111 = 255
        • 8進整数リテラル 0377 = 255
        • 16進整数リテラル 0xFF = 255
        • ただし、文字列を整数にキャストする際は、明示的に指定しない限り10進整数扱い
      • 小数リテラル
        • e記法が可能
          • 16進のときは意味的に衝突してしまうため、 p で表記
    • 数値演算子
      • 四則演算に加えて %** がある
  • 文字列
    • (文字列って配列じゃないんですね、参照なのかな、値なのかな)
    • どんなバイナリも突っ込めるので、画像なんかも一旦文字列として格納するらしい
    • Unicodeリテラルを扱いたい場合は utf8 プラグマを使う
    • リテラル
      • Single-quoted string literal
        • シングルクォートとバクスラのみエスケープが効く
        • 改行できる
      • Double-quoted string literal
        • バクスラでたいていのエスケープシーケンスや、hexadecimal octal を使ったコードポイントの指定ができる
          • \x{2668} => :hotsprings: (Unicode Codepoint)
          • \x7f => 削除文字 (ASCII Code)
        • 変数展開 variable interplation ができる
      • 文字列演算子
        • . … 結合
        • x … 右オペランド回文字列を繰り返す。繰り返し回数は端数切捨て
        • 数値演算子を文字列に対して適用すると数値にパースしようとするので、演算子が分けられている
      • パース
        • hex('0xBEEF') / oct('0377') で 文字列 を n 進数でパースできる
        • prefix なしでも n 進数と認識される
          • なぜか oct は10進以外のあらゆる n 進数をパースする
        • 数値リテラルを渡すと文字列にキャストされてからパースされる
          • hex(10) = 16
  • スカラー変数
    • sigil … $ @ % のこと
      • 対象の変数の扱い方を決定する記号
    • ひとつの値(Scalar Value)を格納するもの
  • if control structure
    • いわゆる if 文のこと
    • curly brace が必須
  • 行入力演算子
    • <STDIN>
  • chomp
    • 引数に指定された文字列の末尾に改行文字があればそれを削除する
  • 未定義値
    • 未定義の変数にアクセスすると undef が得られる
    • 状況に応じて数値の 0 、文字列の '' に解釈される
      • どちらも falsy
    • 未定義の変数に演算を行うことで、暗黙的に宣言することができる
    • undef だけを分岐したいときは defined を使う
    • 変数に代入するとその場でメモリが解放される
  • 警告
    • warnings pragma
      • warnings を出すようになる
        • 12fred34 のような文字列を数値として扱おうとしたときなど
    • diagnostics pragma
      • warnings に加え、詳細な説明を出すようになる
      • stack trace も出る
      • プロセスの起動が若干遅くなる

補足事項です。

  • pragma
  • スコープ
    • レキシカルスコープでの変数宣言 my
      • lexical … 修辞的な
        • 書いた場所ベースでスコープが変化する、という程度の意味
    • パッケージレベルでグローバルな変数の宣言 our
      • local パッケージ変数を一時的に上書きする
        • mylocal の違い?
          • local では処理がスコープの外に出るまで、一時的に変数を読み替える(変数自体は同じもので、値だけが異なる)らしい
            • サブルーチンA 内で、 local な変数を宣言してサブルーチン Bを呼び出したときに、B 内でもA内で定義された値が使われる、というレキシカルではない挙動をする
          • https://perldoc.jp/docs/perl/strict.pod
    • グローバル
      • 修飾子なしでの変数宣言
    • サブルーチンのスコープ
      • サブルーチンはスコープの影響を受けない
        • 定義された時点でシンボルテーブルに載るため
        • スコープを持たせる場合はレキシカル変数に無名サブルーチンを格納すればよい
          • 処理がスコープ外に出ると、無名サブルーチンの リファレンスが 解放される
          • 無名サブルーチン自体は、無名なままシンボルテーブルに載る

生まれた疑問点

ここでは特になかったです。

おわりに

スカラーデータが紹介されました。 これが何かを本質的に知るには、スカラーではないデータは何か、を知る必要がありそうです。 次章以降に期待しましょう。

また、数値と文字列とで利用する演算子が異なるのは、プログラミング言語では珍しい気がします。 これでバグを埋め込んでしまわないように気をつけないとですね。

「初めてのPerl」1章 Perl 入門 を読む

1章 Perl 入門

この章でわかること

  • この本は誰が読むべきか
  • この本を読み終えた人が次にやるといい教材はなにか
  • Perl の特徴はなにか
  • Perl で Hello, World できる

読んでいく

オーディオコメンタリー方式で、言いたいこと、補足があるぶぶんだけ書いていきます。

  • Perl とは Perl 5 のこと
    • Perl 5 と 6 はベースは同じですがそれぞれ独自路線を進んでいます
    • とくに Perl 6 は Raku と呼ばれています
    • Raku の機能が Port されることもあるようです
  • 想定読者
    • 自分で使うシンプルなプログラムを書くのに十分な Perl 5 の基礎を学びたい人向け
      • リファレンスではない
        • perldoc や metacpan などを見ていくことになるでしょう
    • 少なくともプログラミングについて多少なりとも理解している
      • ターミナルの使い方
      • ファイルの編集
      • プログラムの実行方法
      • 変数
      • サブルーチン
      • ……
    • 演習問題がついている
      • 手を動かしながら学べます、良問とは言えないものもありますが
  • 次に読むべき本
  • Perl は簡潔な構文を備える
    • デフォルト値、ショートカット、糖衣構文など
    • 学習量は必要になるものの、短い記述で多くのことができるようになっています。

Perl プログラムは、不慣れな人には、回線ノイズのように見えることがあります。しかし、経験を積んだ Perl プログラマには、壮大な交響曲の楽譜に見えるのです。

p.6

だんだんこわくなってきたぞ。

#!/usr/bin/env perl

@lines = `perldoc -u -f atan2`;
foreach(@lines) {
    s/\w<([^>]+)>/\U$1/g; # 処理対象の値(この場合 @lines から切り出された各行)が省略されている
    print;                # 処理対象の値(この場合 ↑ の処理結果)が省略されている
}

本で紹介されている実例はこれです。 こうした暗黙の値を利用するケースですが、サブルーチンの返り値を暗黙的に書く、とかがあります。

交響曲に見えるかは謎ですが、慣れたらサクっと書けそうな点は好感が持てます。

  • Perl のサポートポリシー
  • CPAN
    • Comprehensive Perl Archive Network
    • Perl のソース、サンプル、ドキュメント、モジュールが手に入る
    • さまざまなミラーサイトがある
      • 通信経路の短縮や冗長性の観点で、地理的に近いミラーを使ってみたほうがいい……んでしょうか?
        • WIDE や JAIST など日本のミラーもあるようです
    • Perl モジュールを検索するときは metacpan が便利
  • Perl ファイルの拡張子
    • Perl の側から拡張子をつけることを要請していない
      • つけないほうがよい、とも言っています
        • なので、executable なファイルが Perl のファイルだった、ということがありますね
        • shebang を書けるので shell によしなにしてもらったり、あるいは好きなコマンドに渡して実行できます
    • 典型的なのは .pl .t あたり
  • 特定の Perl バージョンからしかない機能を使うとき
    • say (Perl v5.10 or higher)を使いたい場合
      • use v5.10; or use 5.010;
        • feature プラグマの Implicit Loading のことのようです
          • 特定の Perl バージョンから使える機能すべてを有効化する構文
          • use feature を使えば一部の機能だけを有効化することもできる
          • 古い Perl インタプリタで実行しようとするとエラーを送出してくれる
        • バージョンの表記方法
          • 歴史的経緯がある部分のように思います、特に Semantic Versioning の世界観に慣れているとビビりますね
          • v を使うもの
          • 使わないもの(その場合マイナーバージョンは3桁の数字)がある

生まれた疑問点

ここでは特になかったです。

おわりに

引き写し的にゆっくり勉強してみたわけですが、 これは効率が悪いように見えて、細部の疑問が浮き彫りになっていいですね。

たとえば use feature qw/state/; は書いたことがあったのですが、あれらと use v5.10; が関係するのは知りませんでした。

それでも、これは教科書をもう一度編纂して出版するような営みです。

願わくは、こうした大仰な手を取らずとも、細部の疑問に対して反応できたらよいのですけれど。

「愛するということ」はじめに を読む

「はじめに」

この章でわかること

  • この本の立場はなにか?

読んでいく

いわく、愛は誰もが簡単に浸れる感情ではないそうです。ではどういうものか。

この本は読者にこう訴える――人を愛そうとしても、自分の人格全体を発達させ、それが生産的な方向に向かうように全力で努力しない限り、けっしてうまくいかない。特定の個人への愛から満足を得るためには、隣人を愛せなくてはならないし、真の謙虚さ、勇気、信念、規律がなくてはならない。これらの特質がほとんど見られない社会では、愛する能力を身につけることは容易ではない。

p.3

この部分では、この本の立場を明らかにしています。

  • 愛する能力に必要なこと
    • 人格全体を発達させること
      • e.g. 隣人を愛すること、謙虚さ、勇気、信念、規律
    • それらが生産的な方向に向かうようにすること
  • 愛する能力の獲得は困難
    • 人格全体の発達それ自体
    • 社会の特質が人格の発達を阻害する場合

思想書はすらすら読めないため、細部に焦点がいきやすく、同時に大筋を見失いがちです。 大筋を見失うと迷子になってしまうのできちんと覚えておくことにします。

しかし、その仕事が困難だからと言って、それを口実に、その仕事の困難さや、その仕事を達成するのに何が必要かを知ろうとする努力を放棄してはいけない。

p.3

生まれた疑問点

これらの疑問はのちに解決されるはずです。

  • 愛する能力とは何か?
    • 人格全体がなぜ愛する能力に関与するのか?
    • 生産的であることはなぜ愛する能力に関与するのか?
  • 人格の発達を阻害する社会とは?
    • (3章で説明されます)

おわりに

とりあえず、この本を読むことによって、愛を知るだけでなく、人格の発達の重要性や、社会が人格の発達に与える影響の考察を見ることができそうですね。おとくそう。

この連作はこんな感じで読み進めていきます。

よろしければ今後もお付き合いくださいませ。

nginx / ELB の 414 URI Too Long の対処

nginx や AWS の ELB を使っていると、 414 URI Too Long というエラーに遭遇することがあります。 このエラーの対処方法や切り分け方を以下に記します。

414 URI Too Long

このステータスコードは何なのか

414 というステータスコードは何を意味しているのでしょうか。

標準化団体のひとつである IETFRFC に以下のような記述があります。

The 414 (URI Too Long) status code indicates that the server is refusing to service the request because the request-target (Section 5.3 of [RFC7230]) is longer than the server is willing to interpret.

RFC 7231 - Hypertext Transfer Protocol (HTTP/1.1): Semantics and Content

request-target が、Web サーバーでは扱えないくらい長いことを示すためのステータスコードだ、ということです。

(RFC ではこのあと、このエラーが送出される典型例がぱらぱらと書いてありますが、読み飛ばして問題ありません。)

HTTP Request

まず、基本的な知識を押さえておきましょう。

HTTP は Hypertext Transfer Protocol と言われる通り、プロトコルの一種です。

このプロトコルで Request はどのように定義されているのでしょうか。

GET /where?q=now HTTP/1.1 # ... Request Target / Request Line
Host: www.example.org     # ... Request Headers
Authorization: Bearer xxx

hoge                      # ... Request Body

典型例はこの通りです。

HTTP では、TCP 1 でのコネクションを確立したのち、このようなテキストを送信します 2

一行目を含む、Request Body の開始を意味する空行までの行を Request Header と呼びます。 うち、一行目だけは特別に RFC では request-target 、俗に Request Line と呼んでいます。

ミドルウェア、インフラにおける実態

nginx

nginx においては Request Header の解釈時にバッファがあふれたときにエラーが送出されます。

(ref. https://github.com/nginx/nginx/blob/bfc5b35827903a3c543b58e4562db8b62021c164/src/http/ngx_http_request.c#L1187-L1205)

どのようなバッファでしょうか。

nginx は Request Header を読む際に二種類のバッファを用います。 Client Header BufferLarge Client Header Buffer です。

Nginx HTTP Server (邦題: マスタリング nginx) 3 を読んでみましょう。

client_header_buffer_size

This directive allows you to define the size of the buffer that Nginx allocates to request headers. Usually, 1k is enough. However, in some cases, the headers contain large chunks of cookie data or the request URI is lengthy. If that is the case, then Nginx allocates one or more larger buffers (the size of larger buffers is defined by the large_client_header_buffers directive).

client_header_buffer_size - Nginx HTTP Server - Fourth Edition [Book]

いわく Client Header Buffer というのは、Request Header を読むときのバッファです。 ソースコードを読むとわかるのですが、nginx は送られてきたテキストを一行ずつこのバッファにまるまる格納しようとします。 このバッファよりも Request Header の一行が大きかった場合、 Large Client Header Buffer に格納を試み、 それでも格納できなかった場合はエラーを返す、という処理になっています。

なお、Request Line を読んだときにバッファがあふれた場合は 414 が、 Request Line 以外の Request Header を読んだときにバッファがあふれた場合は 400 が返ります。

ref. http://nginx.org/en/docs/http/ngx_http_core_module.html#large_client_header_buffers

ELB

ALB と NLB とで扱いが異なります。

ALB に関しては Request Line 、それ以外の Request Header それぞれ、 Request Header 全体に対して最大バッファサイズが決まっています。 Request Header 全体に対して上限があるのが特徴で、 URI だけでなく他のヘッダ(巨大になりやすいものでいうと Cookie とか)まで含めて、バッファに収まるか気にする必要があります。

ref. https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-limits.html#HTTP_headers

このクォータは固定値で、調整ができません。

また、少なくとも Request Line が長すぎた場合は 414 が返却されます。 (ほかのヘッダが長すぎた場合に何が返るかは未検証です)

NLB に関しては記述がありません。 これは NLB が L4 の LB であり、HTTPが L7 のプロトコルであるため、上位レイヤーで何をやっているかに関心がないためでしょう。

ref. Quotas for your Network Load Balancers - Elastic Load Balancing

この記事でも NLB に関してはスコープ外とします。

対処方法

全体的な方針

Request Header の長すぎる行、特に 414 発生時は Request Line を短くできないか検討してください。

nginx の場合

large_client_header_buffers のバッファサイズに大きな値を指定し、 Large Client Header Buffer のサイズを大きくしてください 4

なお、 Client Header Buffer のサイズを大きくしてもバッファがあふれなくなりますが、 バッファサイズが大きすぎると Request Header が小さくても余分にメモリアロケートをすることになり、非効率的です。 小さなバッファで済むような処理は小さなバッファで済ませたほうがパフォーマンスの面では優れるので、 414 ないし 400 が送出されたときに Client Header Buffer のサイズを変更しないほうがよいでしょう。

ELB の場合

クォータが固定値なので、Request Header の長すぎる行を短くしてください。

まとめ

  • nginx / ELB には Request Header を解釈するバッファが存在する
    • バッファがあふれたときは、
      • Request Line の解釈であれば 414 が返却される
      • ↑以外の Request Header の解釈時であれば 400 が返却される(nginx / ALB で未検証)
  • 414 が送出された時は、
    • Request Line を短いものにできないか検討する
    • nginx を使っている場合は Large Client Header Buffer を大きくしてもよい

おわりに

蛇口のひねりかたに終始せず、蛇口の向こう側がどうなっているか知ることができた、それはとてもよかったのかなと思います。

今回は nginx に二種類のバッファがあることを突き止めました。 小さくて効率の良いバッファを使いながら、どのように大きな値を処理するか、という観点ではおもしろい実装なのかなと思います。 Cは読むの慣れてないので、完全に理解するまでに時間かかりそうですが……。

エンジニアリングは常々、現実の複雑性とその抽象化に向き合う営みなので、抽象化されているものから複雑性が顔を出したり、複雑性を抽象化したり、蛇口の向こう側を知ることが力になるのかな、と思っています。ドメイン知識、実装テクニック、ものの捉え方、といった形で。

参考文献


  1. HTTP/3 (HTTP over QUIC) では UDP を使います
  2. テキストを送るのは HTTP/1.1 のような素朴なプロトコルのみです。このとき、 telnet:80 に対してテキストを打っても HTTP としては正常なリクエストになります。HTTP over SSL/TSL(HTTPS)、HTTP/2、HTTP/3 ではより効率的・安全なデータの送受信を行うために、送受信する値や暗号化有無が異なります。
  3. nginx の公式ドキュメントを読んでもよいのですが、マスタリング nginx の方が体系知がない状態でもやさしい表現がなされているように感じます。
  4. バッファの数は任意です。大きなバッファを同時に多数要求するようなワークロードでは多めに用意しておくとうまく処理できるでしょう。

「初めてのPerl 第7版」によせて

連作のページ一覧は こちら

背景

UNIX ユーザーひいてはサーバー管理者の道具箱として、かつて非常に多くのシェアを獲得していた Perl ですが、唯一無二と言ってよい文法の自由度や大規模なユーザーコミュニティなどを擁し、現代で学習するのはおもしろくかつ十分通用しうる枯れた技術の代表格といえましょう。

また、自分の周囲には歴戦の Perl Mongers がたくさんいるので、これ以上の学習の機会はありません。

自分は Perl 初学者ではないのですが、体系的な理解を目的とし、入門書からはじめてみます。

「初めてのPerl」を選んだ理由

  • Perl といえばリャマ本というウワサを聞いたから
  • 新卒研修でこれを読むといいよ、という文書を探していたから

この連作でやること・やらないこと

  • Do's
    • がんばったこと、感じたことの記録
  • Don'ts
    • 引き写し
      • リファレンスや目録のようなものは期待しないでください
    • 技術解説
      • perldoc や Perl Mongers をあたってください

なので、「おー、読んでるね」と格闘の様子を楽しんでいただき、 プログラミングの勉強って楽しいよ、ということが伝えられたらと思います。

演習の解答

github.com

ここに演習問題の解答をまとめておきます。

底本

Randal L. Schwartz, et al., (2018), 初めてのPerl, オライリー・ジャパン

「愛するということ」によせて

連作のページ一覧は こちら

背景

ぼくには大切で大好きな推しがいます。

日ごろ元気をくれる推しに対して、「活動してよかった」と思ってもらえるようなことをしたいと常々考えるのですが、 誰かに何かを与えるということに関してとんと自信がなく、与えるとは何か、大事にするとは何かを問う毎日です。 それがわからずしてどうして推し活ができましょうか。

さて、ぼくは文学理論ひいては西洋思想を修めております。

ということで、今回は西洋思想であるところの、 Erich Fromm の「愛するということ」を紐解きまして、 与えることや人を大事にすることとは何かを学び、もって推し活に資することとしましょう。

どうしてブログにするのか

思想書を読むひとはそう多くないようですが、面白いよ、というのがまずひとつ。

それから、Twitter の紙幅では思想の展開に限界があり、Twitter というプラットフォーム(少なくともぼくのフォロワーの利用形態)でそういう文書を望んでいる人がいないというのがひとつです。

実際にやってみましょう。

急にアクセル踏むじゃん、風邪ひくわ

「愛するということ」を選んだ理由

  • 作者の立場として「愛は技術である」と断定していること
    • 技術ならがんばれば習得できますよね!
  • 比較的近年の著作であること
    • 時代背景・思想潮流が現代の感覚と近く、読みやすいことが多いです
  • 思想で引用されるのがフロイトスピノザ、その他数名であること
    • 引用件数が少なく、その引用先も比較的読解しやすい思想なので読みやすいと思いました

この連作でやること・やらないこと

  • Do's
    • がんばったこと、感じたことの記録
  • Don'ts
    • 引き写し
      • リファレンスや目録のようなものは期待しないでください
    • 思想解説
      • 哲学者をあたってください

なので、「おー、読んでるね」と格闘の様子を楽しんでいただき、 思想本って楽しいよ、ということが伝えられたらと思います。

底本

Erich Fromm, (2020), 愛するということ, 紀伊国屋書店