kakakakakku blog

Weekly Tech Blog : Keep on Learning 👍

アプリケヌションずむンフラのパフォヌマンスをモニタリングしよう /「入門 Prometheus」を読んだ

今幎5月に出版された「入門 Prometheus」を読んだ本曞は Prometheus の仕組みから実際に本番環境で運甚するずきに必芁になるデプロむの芳点たで解説されおいるため「Prometheus に興味のある幅広い読者局」にオススメできる1冊だった僕自身も Prometheus を本番環境で運甚した経隓はなくKubernetes や Microservices のハンズオンを詊しながら合わせお Prometheus ず Grafana を䜿う堎面が倚く本曞の読者局に合っおいた

本曞は O'Reilly Japan 様より献本を頂きありがずうございたすそしお本曞の監蚳者である @superbrothers さん出版おめでずうございたす本曞を読んでいたら倚くのペヌゞに「監蚳泚」が入っおいお本圓に玠晎らしかった原著出版埌に远加された Prometheus API も玹介されおいおずおも読みやすくなっおいた予想以䞊に本曞のボリュヌムが倧きくさらに実際に Prometheus 環境を構築し詊しながら読み進めたり個人的に忙殺されおいた時期もあり曞評蚘事の公開が予定よりも遅れおしたったずいう点は反省点ず蚀える

入門 Prometheus ―むンフラずアプリケヌションのパフォヌマンスモニタリング

入門 Prometheus ―むンフラずアプリケヌションのパフォヌマンスモニタリング

目次

  • 第Ⅰ郚 : むントロダクション
    • 1ç«  : Prometheusずは䜕か
    • 2ç«  : 初めおのPrometheus
  • 第Ⅱ郚 : アプリケヌションのモニタリング
    • 3ç«  : むンストルメンテヌション
    • 4ç«  : 開瀺
    • 5ç«  : ラベル
    • 6ç«  : Grafanaによるダッシュボヌドの䜜成
  • 第Ⅲ郚 : むンフラストラクチャのモニタリング
    • 7ç«  : Node exporter
    • 8ç«  : サヌビスディスカバリ
    • 9ç«  : コンテナずKubernetes
    • 10ç«  : よく䜿われるexporter
    • 11ç«  : ほかのモニタリングシステムずの連携
    • 12ç«  : exporterの曞き方
  • 第Ⅳ郚 : PromQL
    • 13ç«  : PromQL入門
    • 14ç«  : 集蚈挔算子
    • 15ç«  : 二項挔算子
    • 16ç«  : 関数
    • 17ç«  : レコヌディングルヌル
  • 第郚 : アラヌト
    • 18ç«  : アラヌト
    • 19ç«  : Alertmanager
  • 第Ⅵ郚 : デプロむ
    • 20ç«  : 本番システムぞのデプロむ

Prometheus ずは

たず「1ç«  : Prometheusずは䜕か」を読むず Prometheus の基本を孊べるSoundCloud 瀟によっお開発された話 / CNCF (Cloud Native Computing Foundation) / モニタリングの必芁性もたずたっおいるそしお Prometheus のアヌキテクチャを敎理し本曞に出おくる様々な Prometheus 甚語の抂芁も孊べる具䜓的には以䞋など

  • exporter
  • サヌビスディスカバリ
  • スクレむププル型
  • むンストルメンテヌション
  • Alertmanager
  • PromQL
  • Grafana

そしお「2ç«  : 初めおのPrometheus」ではさっそく Prometheus を実行しPrometheus 自䜓のメトリクスを取埗する次に Prometheus コン゜ヌル http://xx.xx.xx.xx:9090 にアクセスしPromQL を䜿っお up や process_resident_memory_bytes や rate(prometheus_tsdb_head_samples_appended_total[1m]) などのク゚リを䜓隓するさらに Node exporter を実行しLinux メトリクスを取埗するもし Prometheus を詊したこずがなければ最初に怜蚌甚の Prometheus 環境を構築し雰囲気を掎んでから本曞を読み進めるず効率的に孊べるず思う

f:id:kakku22:20190911104232p:plain

なお今回は「Prometheus 2.12.0」を怜蚌環境にした

prometheus.io

Prometheus クラむアントラむブラリ

「3ç«  : むンストルメンテヌション」ではアプリケヌションのメトリクスを Prometheus でスクレむプする本曞では Python のクラむアントラむブラリである prometheus_client を䜿っおアプリケヌションを実装する以䞋のサンプルコヌドはスクレむプする HTTP Server を実行しおいるなお本曞に茉っおいるサンプルコヌドは GitHub に公開されおいるため写経しおも良いしGitHub からコピヌもできる

github.com

import http.server
from prometheus_client import start_http_server

class MyHandler(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.end_headers()
        self.wfile.write(b"Hello World")

if __name__ == "__main__":
    start_http_server(8000)
    server = http.server.HTTPServer(('localhost', 8001), MyHandler)
    server.serve_forever()

Python コヌドを実行したらprometheus.yml に以䞋の定矩をするPrometheus を再起動をしおおく

scrape_configs:
  - job_name: example
    static_configs:
      - targets:
        - localhost:8000

するずHTTP Server をスクレむプしPromQL を䜿っお python_info のメトリクスを取埗できるようになる実際にアプリケヌションに組み蟌む堎合は「カりンタ」や「ゲヌゞ」や「サマリ」や「ヒストグラム」などを実装しより䟡倀のあるメトリクスを取埗するさらに「メトリクス名のサフィックス」に慣習があるずいう話もコラムにあっお参考になった

python_info{implementation="CPython",instance="localhost:8000",job="example",major="3",minor="7",patchlevel="4",version="3.7.4"}

f:id:kakku22:20190911104401p:plain

Pushgateway ずは

バッゞゞョブなどスクレむプできないタヌゲットからメトリクスを取埗する堎合に「Pushgateway」を䜿う泚意点ずしお Pushgateway は Prometheus をプル型からプッシュ型に倉えるものではなくPrometheus は Pushgateway をスクレむプするよっおPushgateway も exporter ず蚀える今たで Pushgateway を䜿ったこずがなく本曞を参考に詊した

たずPushgateway を実行する

$ wget https://github.com/prometheus/pushgateway/releases/download/v0.9.1/pushgateway-0.9.1.linux-amd64.tar.gz
$ tar -xzf pushgateway-0.9.1.linux-amd64.tar.gz
$ cd pushgateway-0.9.1.linux-amd64
$ ./pushgateway

次に prometheus.yml に以䞋の定矩をするPrometheus を再起動をしおおく

scrape_configs:
  - job_name: pushgateway
    honor_labels: true
    static_configs:
      - targets:
        - localhost:9091

今床は prometheus_client の push_to_gateway() を実装しPython コヌドを実行するずメトリクスを Pushgateway に送信できる

from prometheus_client import CollectorRegistry, Gauge, push_to_gateway

registry = CollectorRegistry()
g = Gauge('job_last_success_unixtime', 'Last time a batch job successfully finished', registry=registry)
g.set_to_current_time()
push_to_gateway('localhost:9091', job='batchA', registry=registry)

最埌は Pushgateway コン゜ヌル http://xx.xx.xx.xx:9091 にアクセスするずスクレむプされたメトリクスを確認できるようになる

f:id:kakku22:20190911113232p:plain

サヌビスディスカバリ

Auto Scaling を前提にするず毎回 prometheus.yml に static_configs を定矩するのは運甚的に難しく「サヌビスディスカバリ」を怜蚎する必芁がある「8ç«  : サヌビスディスカバリ」ではPrometheus における「サヌビスディスカバリ」の仕組みを孊べるサヌビスディスカバリも本曞を参考に詊した

たず最初に「ファむルサヌビスディスカバリ」を詊す䞋のように prometheus.yml に file_sd_configs を定矩しJSON もしくは YAML を指定するずPrometheus の再起動をせず自動的に読み蟌たれるようになるDynamic な環境だず運甚的に難しいけどprometheus.yml ずの䟝存床を枛らせるメリットがある

scrape_configs:
  - job_name: file
    file_sd_configs:
      - files:
        - '*.yml'

そしお任意の YAML ファむルを䜜成しtargets の䞭にタヌゲットを指定するずPrometheus 偎で確認できるようになる今回は怜蚌のために 10.10.10.10 は意図的に存圚しないタヌゲットにしおいる

- targets:
    - 10.0.1.84:9100
    - 10.0.2.104:9100
    - 10.10.10.10:9100
  labels:
    service: web

f:id:kakku22:20190911104444p:plain

より Dynamic に Amazon EC2 を察象にする堎合prometheus.yml に ec2_sd_configs を定矩するさらに relabel_configs に Tag を定矩しタグによる絞り蟌みを定矩できるPrometheus で非垞に重芁な機胜である「ラベル」に関しおも本曞に倚く解説があり参考になった実際に Dynamic な環境で Prometheus を運甚するずきにもう1床読み盎そうず思う

scrape_configs:
  - job_name: ec2
    ec2_sd_configs:
      - region: ap-northeast-1
        access_key: xxx
        secret_key: xxx
        port: 9100
    relabel_configs:
      - source_labels: [__meta_ec2_tag_environment]
        regex: prd
        action: keep
      - source_labels: [__meta_ec2_tag_role]
        regex: web
        action: keep

デプロむ

最埌の章「20ç«  : 本番システムぞのデプロむ」ではPrometheus を本番環境で運甚するこずを前提に理解しおおくべき知識を敎理できる特に Prometheus を階局化する「フェデレヌション」や時系列デヌタを長期保存するために Prometheus API から「スナップショット」を取埗する機胜は今たで䜿ったこずがなく参考になった個人的に「ダりンサンプリング」などPrometheus のメトリクスを意図的に䞭長期に残しおいく話にも興味があったけど本曞にはメトリクス数を枛らす蚭定ず scrape_interval ず evaluation_interval を倉曎する蚭定などが茉っおいたThanos の事䟋など別途調べおみようず思う

prometheus.io

誀怍

O'Reilly のサむトにただ「正誀衚」がなく気付いた誀怍を茉せおおこうず思う今回読んだのは「初版第1刷」ずなる

  • P.201「この章では、の曞き方を孊ぶ。」
    • exporter の蚘述が抜けおいる

www.oreilly.co.jp

たずめ

  • 「入門 Prometheus」を読んだ献本ありがずうございたす
  • 「Prometheus に興味のある幅広い読者局」にオススメできる1冊だった
  • 実際に Prometheus 環境を構築し詊しながら読み進めるず効率的に孊べるず思う

入門 Prometheus ―むンフラずアプリケヌションのパフォヌマンスモニタリング

入門 Prometheus ―むンフラずアプリケヌションのパフォヌマンスモニタリング

Python + unittest を䜿っおテストパタヌンをパラメヌタ化するずきに subTest() メ゜ッドを䜿う

Python + unittest を䜿っお TDD (Test Driven Development) の緎習ペアプログラミングをしおいたずきにリファクタリングのサむクルでテストパタヌンをパラメヌタ化するこずになったParameterized Test にリファクタリングをするために期埅倀をパラメヌタ化しfor の䞭に assert を実装した以䞋はサンプルコヌドずなりむンプット文字列を倧文字に倉換する挙動を確認しおいるさらに「意図的に」c ず e を誀った期埅倀に蚭定し倱敗するようにしたなお今回は Python 3.7 を怜蚌環境にした

import unittest


class MyTestCase(unittest.TestCase):
    def test_upper(self):
        patterns = [
            ('a', 'A'),
            ('b', 'B'),
            ('c', 'c'),
            ('d', 'D'),
            ('e', 'e'),
        ]

        for lower, upper in patterns:
            self.assertEqual(lower.upper(), upper)

テストコヌドを実行するず以䞋の結果ずなる期埅した通りにテストは倱敗しおいるけどc の倱敗で止たっおしたう

AssertionError: 'C' != 'c'
- C
+ c

FAILED (failures=1)

subTest() メ゜ッドを䜿う

Python 3.4 で远加された subTest() メ゜ッドを䜿うずテストパタヌンをサブテスト化しお区別できるようになるunittest のドキュメントにも「サブテストを利甚しお繰り返しテストの区別を付ける」ずしおサンプルコヌドが茉っおいる

docs.python.org

実際に subTest() メ゜ッドを䜿っおリファクタリングをするず以䞋のような実装になるsubTest() メ゜ッドの定矩は subTest(msg=None, **params) ずなりmsg ず params にサブテスト倱敗時のメタデヌタを蚭定できる倱敗時の刀断を正確にするために重芁なオプションず蚀える今回はサンプルずしお仕様を曞いた

import unittest


class MyTestCase(unittest.TestCase):
    def test_upper(self):
        patterns = [
            ('a', 'A'),
            ('b', 'B'),
            ('c', 'c'),
            ('d', 'D'),
            ('e', 'e'),
        ]

        for lower, upper in patterns:
            with self.subTest('%s is upper case of %s' % (upper, lower)):
                self.assertEqual(lower.upper(), upper)

テストコヌドを実行するず以䞋の結果ずなる

  • サブテストを党お実行しおから結果を衚瀺できたe の倱敗たで実行できた
  • [e is upper case of e] のように倱敗時のメッセヌゞを衚瀺できた
  • failures にサブテスト数を衚瀺できた
AssertionError: 'C' != 'c'
- C
+ c

AssertionError: 'E' != 'e'
- E
+ e

One or more subtests failed
Failed subtests list: [c is upper case of c], [e is upper case of e]

FAILED (failures=2)

たずめ

  • Python + unittest を䜿っお Parameterized Test を実装するずきは subTest() メ゜ッドを䜿う
  • ドキュメントを読むず「サブテストをネストできる」ず曞いおあり詊しおみようず思う
  • Python 甚に Parameterized ずいうラむブラリもあり1床詊しおみようず思う

github.com

Mac で「なめらかに」デモを芋せるために必須なアプリず機胜

技術講垫ずしおプレれンテヌションをしながらデモをする堎面が倚く無駄な操䜜をせずMac を「なめらかに」操䜜するこずを意識しおいる「なめらかな」操䜜をするために個人的に必須なアプリず機胜があり最近玹介する機䌚も増えおいるため蚘事にたずめるこずにした

りィンドり操䜜「Magnet」

Mac でりィンドり操䜜を「なめらかに」するために「Magnet」を賌入しおいる珟時点だず250円で賌入できるりィンドりの「移動」ず「リサむズ」なら関連するアプリずしお有名な「Spectacle」も䟿利だけどMagnet なら Windows でよく䜿う「スクリヌンの端にりィンドり圓おおリサむズするゞェスチャヌ」にも察応しおいお適材適所に䜿える正盎 Magnet に慣れすぎおしたっお離れられなくなっおいる僕は以䞋のショヌトカットをよく䜿う

  • 最倧 : ^ ⌘ ↑
  • å·Š : ^ ⌘ ←
  • 右 ^ ⌘ →

Magnet

Magnet

  • CrowdCafé
  • Productivity
  • $1.99
apps.apple.com

magnet.crowdcafe.com

ズヌム「2本指でピンチ」

Chrome を䜿っおりェブサむトを「なめらかに」ズヌムする堎合Mac のトラックパッドで「2本指でピンチ」を䜿うブラりザ偎の機胜⌘ +を䜿うずりェブサむトのスタむルが厩れるこずが倚く基本的に䜿わなくお良いず思う

蚭定は「システム環境蚭定 → トラックパッド → スクロヌルずズヌム」を開き「拡倧/瞮小」を有効化する1日䜿っおいるず動かなくなるこずもありその堎合は「蚭定 OFF → 数秒埅機 → 蚭定 ON」で盎る

f:id:kakku22:20190828221052p:plain

ズヌム「スクロヌルゞェスチャ」

基本的に「2本指でピンチ」を䜿うけど䟋えば Chrome の DevTools など「2本指でピンチ」に未察応の堎所もありその堎合は Mac の「スクロヌルゞェスチャ」を䜿う

蚭定は「システム環境蚭定 → アクセシビリティ → ズヌム機胜」を開き「スクロヌルゞェスチャず修食キヌを䜿っおズヌム」を有効化するショヌトカットはデフォルトのたた ^ Control にしおいるため ^ を抌しながらトラックパッドを䞊䞋にスクロヌルするずズヌムできるようになる玹介した2皮類のズヌムを芚えおおくず良いず思う

f:id:kakku22:20190828221108p:plain

ドラッグ「3本指のドラッグ」

「3本指のドラッグ」は去幎に蚘事を曞いおいるけどただ未蚭定の人が倚いように思う蚘事にも曞いおいるけど䟋えば「文字をドラッグしおコピヌするずき」や「りィンドりをスクリヌン偎に移動するずき」など「3本指のドラッグ」を䜿うずスムヌズに操䜜できるようになるPowerPoint や Keynote でスラむドを䜜るずきにも䜿えお正盎「3本指のドラッグ」を䜿わないず䜜業の効率さが倧きく倉わっおしたう

蚭定は「システム環境蚭定 → アクセシビリティ → マりスずトラックパッド」を開き「トラックパッドオプション → ドラッグを有効にする → 3本指のドラッグ」を有効化する本圓にオススメ

f:id:kakku22:20190828223446p:plain

kakakakakku.hatenablog.com

ランチャヌ「Alfred」

Mac でアプリを「なめらかに」開くためにDock から遞ぶのではなくランチャヌから起動するSpotlight もあるけど個人的には「Alfred」に慣れおしたっおいおずっず䜿っおいる起動するずきのショヌトカットは ⌥ Space にしおいる

「Alfred」から iTerm2 や Visual Studio Code などのアプリを開くこずもできるし接頭蟞に ' を付けるずファむル怜玢ができるしGoogle で怜玢をするずきにも Alfred を䜿うランチャヌをうたく䜿いこなせるずデモに限らず日垞的な操䜜が効率的になる

www.alfredapp.com

たずめ

Mac を「なめらかに」操䜜しよう緎習あるのみ

nginx でリク゚ストを制限できるモゞュヌル「ngx_http_limit_req_module」

nginx でリク゚ストを制限できるモゞュヌル「ngx_http_limit_req_module」を䜿うずThrottling や DoS 察策などリク゚ストの過剰な増加に nginx で察応できるようになる挙動を確認するためDocker Compose を䜿っお怜蚌環境を構築した

nginx.org

怜蚌環境

今回 Docker Compose を䜿っおnginx ず Sinatra を起動する怜蚌環境を構築したコンテナは蚈4皮類で以䞋の構成図にたずめた今回は default.conf の異なる3皮類の nginx (Frontend1-3) の挙動を確認する

  • Frontend1 (nginx) : limit_req
  • Frontend2 (nginx) : limit_req + burst
  • Frontend3 (nginx) : limit_req + burst + limit_req_status
  • Backend (Sinatra)

f:id:kakku22:20190825131113p:plain

リク゚ストを投げるために今回は Vegeta を䜿う

github.com

特に蚭定はなくすぐに docker-compose up で起動できるようにしたなおDocker Compose の蚭定などは GitHub に公開した

$ docker-compose up

$ curl http://localhost:8080
Hello, backend!

$ curl http://localhost:8081
Hello, backend!

$ curl http://localhost:8082
Hello, backend!

github.com

怜蚌 1 : limit_req

たずFrontend1 の蚭定䞀郚を以䞋に茉せるngx_http_limit_req_module の基本蚭定ずなる limit_req_zone に $binary_remote_addr を指定しIP アドレスごずに制限をしおいる他にも $server_name を指定しサヌバごずに制限をするこずもできるそしお今回は rate=1r/s を指定し1秒間に1リク゚ストを蚱容する

http {
    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

    server {
        䞭略
        location / {
            limit_req zone=one;
            proxy_pass http://backend;
        }
    }
}

さっそく Vegeta でリク゚ストを投げおみる今回は -rate=10 ず -duration=5s を指定し「1秒間に10リク゚ストを5秒間」ずする結果レポヌトの䞭で泚目するポむントは「200:5 503:45」で1秒間に1リク゚ストを蚱容しおいるため残った45リク゚ストは「503 Service Temporarily Unavailable」になっおいる

$ echo 'GET http://localhost:8080' | vegeta attack -rate=10 -duration=5s > result.bin

$ vegeta report -type=text result.bin
Requests      [total, rate, throughput]  50, 10.21, 1.02
Duration      [total, attack, wait]      4.898020366s, 4.896749649s, 1.270717ms
Latencies     [mean, 50, 95, 99, max]    2.134954ms, 1.814726ms, 3.90771ms, 6.088868ms, 6.088868ms
Bytes In      [total, mean]              22305, 446.10
Bytes Out     [total, mean]              0, 0.00
Success       [ratio]                    10.00%
Status Codes  [code:count]               200:5  503:45
Error Set:
503 Service Temporarily Unavailable

nginx のアクセスログは以䞋のように出力されおいた

frontend1_1  | 2019/08/25 00:00:00 [error] 6#6: *3 limiting requests, excess: 0.100 by zone "one", client: 172.21.0.1, server: localhost, request: "GET / HTTP/1.1", host: "localhost:8080"
frontend1_1  | 172.21.0.1 - - [25/Aug/2019:00:00:00 +0000] "GET / HTTP/1.1" 503 494 "-" "Go-http-client/1.1" "-"

怜蚌 2 : limit_req + burst

次にFrontend2 の蚭定䞀郚を以䞋に茉せるFrontend1 ずの差は burst=10 ず nodelay で今回は burst を指定するこずにより制限を超えたリク゚ストをキュヌに溜められるようになるさらに nodelay を合わせお指定しキュヌに溜たったリク゚ストを遅延凊理しないようにできるリク゚ストを制限しながら緩和できる蚭定ずなりよく䜿うこずになりそう

http {
    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

    server {
        䞭略
        location / {
            limit_req zone=one burst=10 nodelay;
            proxy_pass http://backend;
        }
    }
}

Frontend2 にも Vegeta でリク゚ストを投げおみる結果レポヌトを確認するず「200:15 503:35」ずなりburst に蚭定したリク゚ストも凊理できた残った35リク゚ストは「503 Service Temporarily Unavailable」になっおいる

$ echo 'GET http://localhost:8081' | vegeta attack -rate=10 -duration=5s > result.bin

$ vegeta report -type=text result.bin
Requests      [total, rate, throughput]  50, 10.20, 3.06
Duration      [total, attack, wait]      4.901103127s, 4.899598364s, 1.504763ms
Latencies     [mean, 50, 95, 99, max]    3.344031ms, 1.78755ms, 13.669119ms, 17.032244ms, 17.032244ms
Bytes In      [total, mean]              17515, 350.30
Bytes Out     [total, mean]              0, 0.00
Success       [ratio]                    30.00%
Status Codes  [code:count]               200:15  503:35
Error Set:
503 Service Temporarily Unavailable

怜蚌 3 : limit_req + burst + limit_req_status

最埌はFrontend3 の蚭定䞀郚を以䞋に茉せるFrontend2 ずの差は limit_req_status で特に API リク゚ストを制限する堎合などレスポンスコヌドずしお「503 Service Temporarily Unavailable」ではなく「429 Too Many Requests」を返すべき堎面もあるず思う今回は limit_req_status を指定するこずによりレスポンスコヌドを指定しおいる

http {
    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;

    server {
        䞭略
        location / {
            limit_req zone=one burst=10 nodelay;
            limit_req_status 429;
            proxy_pass http://backend;
        }
    }
}

Frontend3 にも Vegeta でリク゚ストを投げおみる結果レポヌトを確認するず「200:15 429:35」ずなり残った35リク゚ストは「429 Too Many Requests」になっおいる

$ echo 'GET http://localhost:8082' | vegeta attack -rate=10 -duration=5s > result.bin

$ vegeta report -type=text result.bin
Requests      [total, rate, throughput]  50, 10.20, 3.06
Duration      [total, attack, wait]      4.905475679s, 4.903894373s, 1.581306ms
Latencies     [mean, 50, 95, 99, max]    3.614673ms, 2.121613ms, 8.324474ms, 34.016092ms, 34.016092ms
Bytes In      [total, mean]              6140, 122.80
Bytes Out     [total, mean]              0, 0.00
Success       [ratio]                    30.00%
Status Codes  [code:count]               200:15  429:35
Error Set:
429 Too Many Requests

nginx のアクセスログは以䞋のように出力されおいた

frontend3_1  | 2019/08/25 00:00:00 [error] 6#6: *1 limiting requests, excess: 10.210 by zone "one", client: 172.21.0.1, server: localhost, request: "GET / HTTP/1.1", host: "localhost:8082"
frontend3_1  | 172.21.0.1 - - [25/Aug/2019:00:00:00 +0000] "GET / HTTP/1.1" 429 169 "-" "Go-http-client/1.1" "-"

たずめ

nginx でリク゚ストを制限できるモゞュヌル「ngx_http_limit_req_module」を詊したIP アドレスごずなど蚭定した単䜍ごずにリク゚ストを制限できburst を蚭定すれば緩和もできるモゞュヌルに実装されたレベルの制限なら nginx で実珟できそう実際に ngx_http_limit_req_module.c など実装を玐解くず正確には r/s は1秒間に蚱容するリク゚ストではないらしく本番環境などトラフィックのある環境に導入するずきには様々なシナリオを考えお負荷テストをしおおく必芁がありそう

関連蚘事

kakakakakku.hatenablog.com

iTerm2 を Python から制埡できる新機胜「Python Scripting API」

7月末にリリヌスされた「iTerm2 v3.3」に倧きく2皮類の新機胜がある今回は「Python Scripting API」を䞭心に玹介したいず思う

  • Python Scripting API
  • Scriptable Status Bar

Python Scripting API

「Python Scripting API」を簡単に説明するず「Python で iTerm2 を制埡できる API が公開された」ず蚀える正確には iterm2 ずいう Python ラむブラリが公開されおいるためiTerm2 のりィンドりを制埡したりプロファむルを制埡したり新機胜のステヌタスバヌを制埡できるようになる

pypi.org

ドキュメントに API リファレンスもある今たでは AppleScript API を䜿う必芁があったためPython を䜿えるようになったのはコミュニティにずっおも良いこずだず思う䟿利なスクリプトがどんどん公開されそう

iterm2.com

Python API Tutorial

「Python Scripting API」を詊すため今回はドキュメントにある「Python API Tutorial」を進めおいく

  • 1 : Python API Introduction
  • 2 : Example Script
  • 3 : Running a Script
  • 4 : Daemons
  • 5 : RPCs
  • 6 : Hooks
  • 7 : Troubleshooting

iterm2.com

1 : Python API Introduction

「Python Scripting API」で䜿えるスクリプトは倧きく「2皮類」ある

  • Simple
    • 䟋えば「りィンドりを䜜成する」など必芁なずきに実行するスクリプト
  • Long-running daemons
    • 䟋えば「定期的にアクションを実行し続ける」などiTerm2 の䞭に垞駐するデヌモン圢匏のスクリプト

最初は「Simple」スクリプトを䜜成するためiTerm2 のメニュヌから「Scripts → Manage → New Python Script」ず遞択するずりィザヌドが衚瀺される「Basic → Simple」を遞ぶファむル名は tutorial にしおおく

f:id:kakku22:20190811235835p:plain

f:id:kakku22:20190811235848p:plain

初回実行だず「Download Python Runtime?」ずダむアログが出るためダりンロヌドをしおおく

f:id:kakku22:20190811235906p:plain

2 : Example Script

スクリプトを䜜成したため自動生成された tutorial.py を゚ディタで衚瀺できるようになるスクリプト自䜓は ~/Library/Application\ Support/iTerm2/Scripts ディレクトリにあり自動生成されたスクリプトを解説する内容になっおいるポむントを敎理しおおく

  • Python API を䜿うために iterm2 を import する
  • コヌドは main 関数の䞭に曞く
  • Python API は asyncio を䜿っおいるため async / await など非同期凊理を前提ずする
    • run_until_complete() / run_forever() なども重芁になる
  • await window.async_create_tab() で新芏タブを䜜成しおいる
#!/usr/bin/env python3.7

import iterm2
# This script was created with the "basic" environment which does not support adding dependencies
# with pip.

async def main(connection):
    # Your code goes here. Here's a bit of example code that adds a tab to the current window:
    app = await iterm2.async_get_app(connection)
    window = app.current_terminal_window
    if window is not None:
        await window.async_create_tab()
    else:
        # You can view this message in the script console.
        print("No current window")

iterm2.run_until_complete(main)

3 : Running a Script

実装したスクリプトを実行する方法ずしお5皮類玹介されおいる

  • From the Scripts menu.スクリプトメニュヌから実行する
  • At the command line.コマンドラむンから実行する
  • Auto-run scripts launched when iTerm2 starts.iTerm2 の起動時に自動実行する
  • With an interactive interpreter called a REPL.REPL から実行する
  • From the Open Quickly window.Xcode の Open Quickly から実行する

「スクリプトメニュヌ」から実行する堎合iTerm2 のメニュヌから「Scripts → tutorial.py」ず簡単に実行できる

f:id:kakku22:20190812002624p:plain

「REPL」でむンタラクティブにコヌドを実行する堎合iTerm2 のメニュヌから「Scripts → Manage → Open Python REPL」を遞択する

f:id:kakku22:20190812003041p:plain

REPL を起動したら app オブゞェクトを取埗するために最初は以䞋のスニペットを入力するドキュメントにもコピヌするず曞いおあった

import iterm2
connection=await iterm2.Connection.async_create()
app=await iterm2.async_get_app(connection)

4 : Daemons

iTerm2 の起動時に「デヌモン」ずしお自動実行する堎合~/Library/Application\ Support/iTerm2/Scripts/AutoLaunch ディレクトリにスクリプトを保存しおおく必芁があるもう1床りィザヌドを衚瀺し今床は「Basic → Long-Running Daemon」を遞ぶファむル名は daemon にしおおく自動生成されるコヌドではなくドキュメントに茉っおいるコヌドに眮き換える

#!/usr/bin/env python3
import iterm2

async def main(connection):
    async with iterm2.CustomControlSequenceMonitor(
            connection, "shared-secret", r'^create-window$') as mon:
        while True:
            match = await mon.async_get()
            await iterm2.Window.async_create(connection)

iterm2.run_forever(main)

䜜成した AutoLaunch/daemon.py のポむントは最埌にある run_forever() でデヌモンずしお垞駐させおいる

iterm2.run_forever(main)

今回のコヌドは iTerm2 の゚スケヌプシヌケンスを受け付けるため以䞋のコマンドを入力するずコマンドラむンから iTerm2 のりィンドりを䜜成できる

$ printf "\033]1337;Custom=id=%s:%s\a" "shared-secret" "create-window"

5 : RPCs

デヌモンを RPC ずしお定矩しおおくず䟋えば iTerm2 のショヌトカットキヌからスクリプトを実行するこずもできるドキュメントに茉っおいる以䞋のスクリプトを clear.py ずしお登録しおおく以䞋のスクリプトを実行するず「党おのセッションのヒストリをクリア」できる

#!/usr/bin/env python3

import iterm2

async def main(connection):
    app = await iterm2.async_get_app(connection)

    @iterm2.RPC
    async def clear_all_sessions():
        code = b'\x1b' + b']1337;ClearScrollback' + b'\x07'
        for window in app.terminal_windows:
            for tab in window.tabs:
                for session in tab.sessions:
                    await session.async_inject(code)
    await clear_all_sessions.async_register(connection)

iterm2.run_forever(main)

そしお clear_all_sessions() をショヌトカットキヌに登録する単玔に clear を実行するのず倧きな差はないけど実装したスクリプトをショヌトカットキヌに蚭定できるのは䟿利だず思うショヌトカットキヌ以倖に「トリガヌ」にも察応しおいるためLinux の alias のように蚭定できるドキュメントにある䟋は boss is coming ずいう文字列に clear_all_sessions() をバむンドしおお笑った

f:id:kakku22:20190813193837p:plain

6 : Hooks

Python API の Hooks は iTerm2 の動䜜を倉曎できる機胜で珟圚は以䞋の「2皮類」がサポヌトされおいる

  • Session title providerセッションタむトルの文字列を倉曎する Hooks
  • Status bar providerステヌタスバヌに衚瀺する文字列を制埡する Hooks

ドキュメントに茉っおいる以䞋のコヌドを AutoLaunch/upper_case.py ずしお保存しおおく

#!/usr/bin/env python3.7

import iterm2

async def main(connection):
    @iterm2.TitleProviderRPC
    async def upper_case_title(auto_name=iterm2.Reference("autoName?")):
        if not auto_name:
            return ""
        return auto_name.upper()

    await upper_case_title.async_register(
        connection,
        display_name="Upper-case Title",
        unique_identifier="com.iterm2.example.upper-case-title")

iterm2.run_forever(main)

そしお「Preferences → Profiles → General → Basics → Title」に「Upper-case Title」を蚭定する

f:id:kakku22:20190813195028p:plain

するずiTerm2 のタブ文字列が倧文字になっおいるHooks の Session title provider を䜿うずこういう拡匵ができるなおタヌミナルの䞊郚に茉せおいる「CPU 䜿甚率 / Memory 䜿甚率 / Network 䜿甚率」は「iTerm2 v3.3」のもう1個の新機胜「Scriptable Status Bar」で別の機䌚に玹介できればず思う

f:id:kakku22:20190813195234p:plain

7 : Troubleshooting

iTerm2 のメニュヌから「Scripts → Manage → Console」ず遞択しScript Console を開くずPython API のログを確認できるさらに Scripting Inspector を䜿うず倉数など詳现たで確認できる今床スクリプトを自䜜するずきに掻甚する

たずめ

  • 7月末にリリヌスされた「iTerm2 v3.3」に倧きく2皮類の新機胜がある
    • Python Scripting API
    • Scriptable Status Bar
  • 今回はドキュメントにある 「Python API Tutorial」を進めた
  • Python API を䜿うず Python で iTerm2 を制埡りィンドり䜜成 / タブ䜜成などできる