最も"攻撃力"が高い負荷試験ツールは...?
この記事は決して DoS 攻撃を推奨・肯定するものではありません。DoS 攻撃は攻撃対象へ金銭的・物損的被害が発生する可能性がある非常に危険な行為です。本記事に起因するいかなるトラブル・損失・損害に対しても、著者は責任を負いません。
こんにちは k-jun です。先日 GitHub の海を泳いでいると以下のようなリポジトリを発見しました。
https://github.com/ajax-lives/NoRussian
Volunteer DoS tool via HTML + JS. Made to be user friendly and simple to use - as to maximize the amount of people able to help. Running the HTML locally on your device will run a DoS attack on Russian and Belarussian websites (gov, mil, banks, propaganda sites), through complete volunteering.
HTML と JavaScript を利用して、特定のサイトへボランティア DoS 攻撃を行うためのツールのようです。
中身のコードを見てみると、リストアップした URL へ JavaScript より大量のリクエストを発行。アクセスするだけで誰でも Dos 攻撃に参加できる、まさに Volunteer DoS tool というわけです。
さてここで、ある疑問が自分の中に湧いてきました。JMeter などに代表される負荷試験ツールならもっと効率的に負荷を与えられるのではと。Volunteer DoS Tool はブラウザから大量のリクエストを発行しているが、負荷試験ツールならより少ないコンピューターリソースで高い負荷を生み出せるのではと。ということで、休日の時間を利用してこれを調べて実験してみることにしました。
目的
今回の目的は、同じコンピューターリソースを利用して、対象に最も高い負荷を与え続けられる負荷試験ツールの特定 です。考えの発端は Volunteer DoS Tool ですが、要するに単純で大量のリクエストを送信し続ける場合、最も効率の良い負荷試験ツールは何かというお話です 笑。
手法
星の数ほどある負荷試験ツールですが、今回は以下の7種類のものを調査の対象としました。選定基準はそれなりに有名であること、簡単に試せることの2つです。これだけ言語がバラバラで7種類もあればそれなりの結果が得られるでしょう。僕の時間も無限ではないのです...。
name | url | language | stars |
---|---|---|---|
wrk | https://github.com/wg/wrk | C | 31.5k |
hey | https://github.com/rakyll/hey | Go | 13k |
ab | https://github.com/CloudFundoo/ApacheBench-ab | C | 89 |
siege | https://github.com/JoeDog/siege | C | 4.9k |
vegeta | https://github.com/chidakiyo/vegeta | Go | 19.2k |
locust | https://github.com/locustio/locust | Python | 18.4k |
gatling | https://github.com/gatling/gatling | Scala | 5.5k |
次に、負荷をかける環境を AWS 上に構築していきます。構築と言ってもターゲットとランチャーだけのシンプルなものです。
ランチャー上では上記7種の負荷試験ツールのインストールを、ターゲットでは負荷を受ける役割の NGINX を起動させておきます。なお、VPC は ap-northeast-1 、Subnet は ap-northeast-1a に作成しました。その他インスタンスタイプ、OS などは以下のとおりです。
name | OS | instance type |
---|---|---|
target | Ubuntu v18.04 | c5.large |
launcher | Ubuntu v18.04 | c5.large |
また socket: too many open files
を回避するため、ランチャーとターゲットのファイルディスクリプタは予め最大値まで上げておきます。ターゲット上の NGINX にも同様に反映しておきます。
# in target & launcher $ sudo tail -n 4 /etc/security/limits.conf * soft nproc 780246 * hard nproc 780246 * soft nofile 780246 * hard nofile 780246 # in target $ sudo cat /etc/nginx/nginx.conf | grep worker worker_processes 16; worker_rlimit_nofile 780246; worker_connections 780246;
最後に実験手順です。ランチャーとターゲットへ ssh でログインし、以下の手順で実験を行いました。(RAM に関しては特段目立った変化が見られたなかったので省略しました。)
- ランチャー & ターゲット: vmstat を実行。
- ランチャー: 調査対象の負荷試験ツールを30秒間実行。
- ランチャー: 負荷試験ツールから出力された RPS を記録。
- ランチャー & ターゲット: vmstat から出力された CPU と RAM の変化量を記録。
負荷試験ツールは 実行時間は30秒、RPS は最大となるように設定を弄っています。例として wrk を例に取った実際のコマンドを以下に示します。
# ubuntu@target $ vmstat 1 -nt | awk '{printf("%s,%s,%s\n", $19,$15,$4)}' # ubuntu@launcher $ vmstat 1 -nt | awk '{printf("%s,%s,%s\n", $19,$15,$4)}' $ ./wrk/wrk -d 30 -t 4 -c 100 http://10.1.101.10
結果
name | rps 1回目 | rps 2回目 | rps 3回目 | command |
---|---|---|---|---|
wrk | 77491.89 | 78012.51 | 76856 | ./wrk/wrk -d 30 -t 4 -c 100 http://10.1.101.10 |
hey | 45224.8694 | 45779.8114 | 46258.3372 | ./hey -z 30s http://10.1.101.10 |
ab | 39328.21 | 39147.51 | 38708.19 | ab -n 1000000 -c 100 http://10.1.101.10/ |
siege | 32088.11 | 31622.09 | 31692.97 | siege -t 30S http://10.1.101.10 |
vegeta | 14999.48 | 15000.44 | 14999.59 | echo "GET http://10.1.101.10" | vegeta attack -rate 15000 -duration 30s | vegeta report |
locust | 3287 | 3306 | 3313 | python3 -m locust --master (※詳細は別途参照) |
gatling | 833.333 | 833.333 | 833.333 | bin/gatling.sh (※詳細は別途参照) |
※ locustfile.py
from locust import HttpUser, task class HelloWorldUser(HttpUser): @task def hello_world(self): self.client.get("/")
※ BasicSimulation.java
package computerdatabase; import static io.gatling.javaapi.core.CoreDsl.*; import static io.gatling.javaapi.http.HttpDsl.*; import io.gatling.javaapi.core.*; import io.gatling.javaapi.http.*; import java.time.Duration; public class BasicSimulation extends Simulation { HttpProtocolBuilder httpProtocol = http .baseUrl("http://10.1.101.10") .acceptHeader("text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8") .doNotTrackHeader("1") .acceptLanguageHeader("en-US,en;q=0.5") .acceptEncodingHeader("gzip, deflate") .userAgentHeader( "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:16.0) Gecko/20100101 Firefox/16.0"); ScenarioBuilder scn = scenario("simplest") .exec(http("request_1").get("/") .check(status().is(200))); { setUp(scn.injectOpen(stressPeakUsers(10000).during(30)).protocols(httpProtocol)); } }
wrk
hey
ab
siege
vegeta
locust
gatling
考察
wrk
最も目を引くのは wrk の 78,012 RPS ですね。他を寄せ付けないほど圧倒的な RPS であり、ターゲット側の CPU をほとんど 0% まで使い切らせています。ランチャー側の CPU が 60% 程度で安定しているところを見るに、まだ余力がありそうです。ターゲット側のスペックをより積めばより高い PRS を出すでしょう。
hey, siege
hey, siege はそれぞれ 46,000 RPS, 32,000 RPS と高い数値を記録しています。ランチャー側の CPU を使い切っていることから wrk よりリソースの使用効率が悪いものの、負荷試験ツールとしては十分な RPS を出せています。特に hey はインストール・設定共に簡単であり、良い負荷試験ツールと感じました。
ab
ab は 39,000 RPS とかなり高い値を出しているにも関わらず、ランチャー・ターゲット共に CPU に余裕が見られます。この余剰リソースを使い切るため試行錯誤してみましたが、今回の実験ではこれ以上の PRS を実現することは無理でした...。実験終盤に CPU 使用量が回復しているのは、秒数ではなく 1,000,000 リクエストを打ち切った後に終了するという設定で ab を実行しているためです。
vegeta
vegeta は 14999.59, 15000.44, 14999.59 と全ての PRS がほとんど同じ値になっています。コマンドを見てもらえばわかりますが、vegeta -rate 15000
で RPS を予め指定しているため、このような均一的な結果になっています。どうやら実行時に address の食い合いが起きるらしく、15,000 以上の RPS を指定すると以下のエラーが頻繁に見られました。
Get "http://10.1.101.10": dial tcp 0.0.0.0:0->10.1.101.10:80: bind: address already in use
名前と GitHub の画像は面白いですが、同じ Go 言語の hey と比べてみると微妙かなぁというのが正直な印象です。
locust, gatling
locust, gatling の2種類は他と比較して RPS がかなり低い値に抑えられています。この2つは他と異なり言語によるシナリオが記述可能であり、locust は GUI。gatling は JVM と負荷試験の箇所以外でのリソース消費要因も備えています。
コネクションに関しても懸念が残ります。locust, gatling はそれぞれユーザーという設定項目により並列度を指定します。このため、他ツールとはことなり、リクエストごとにコネクションを都度都度切っているのかも...? という予想をしています。
総じてこれら2つは単純なリクエストを送信する以上の複雑な機構を備えた高級な負荷試験ツールであり、純粋に今回の目的には適していなかったのかもしれません。
結論
今回の実験の結果 同じコンピューターリソースを利用して、対象に最も高い負荷を与え続けられる負荷試験ツール は wrk ということになりました。wrk 側の CPU を余らしつつ NGINX 側の CPU を使い切っており、最も負荷を与えるという点ではまず確実に wrk が結論になるでしょう。要するに手っ取り早く大量の負荷を掛けたいときには wrk を脳死でぶっ放せばよさそうということです 笑。
おまけとしてですが、gatling や hey などのツールに触れられたこと。siege・wrk の設定を一通り眺めて知らなかったオプションを発見・利用出来たこと。実験・比較・調査し自分の中に自分なりの回答を持つということが出来たので良い経験となりました。今後もこのようなことをどんどんやっていければと思います。それでは今回はこの辺で!
Golang 製の CUI ツールを作成する! gocui を試してみた。
こんにちは k-jun です。今回は Golang にて TUI を構築するツール gocui を試してみます。
https://github.com/jroimartin/gocui
go"cui" と銘打っていますが、TUI じゃないんですかね、これ。Console User Interface と Terminal User Interface だったら後者のほうが正しそうな。
Setup
$ go get github.com/jroimartin/gocui
Run
一旦 README に記載もある以下のコードを実行してみます。
package main import ( "fmt" "log" "github.com/jroimartin/gocui" ) func main() { g, err := gocui.NewGui(gocui.OutputNormal) if err != nil { log.Panicln(err) } defer g.Close() g.SetManagerFunc(layout) if err := g.SetKeybinding("", gocui.KeyCtrlC, gocui.ModNone, quit); err != nil { log.Panicln(err) } if err := g.MainLoop(); err != nil && err != gocui.ErrQuit { log.Panicln(err) } } func layout(g *gocui.Gui) error { maxX, maxY := g.Size() if v, err := g.SetView("hello", maxX/2-7, maxY/2, maxX/2+7, maxY/2+2); err != nil { if err != gocui.ErrUnknownView { return err } fmt.Fprintln(v, "Hello world!") } return nil } func quit(g *gocui.Gui, v *gocui.View) error { return gocui.ErrQuit }
何やら window らしきものが生成されていそうですね。
よさそうなので、他に何ができるのかを Document を参考に見てみます。
https://pkg.go.dev/github.com/jroimartin/gocui#section-readme
更新する例も作ってみました。
package main import ( "fmt" "log" "math/rand" "strconv" "time" "github.com/jroimartin/gocui" ) func main() { ... g.Update(func(g *gocui.Gui) error { time.Sleep(1000 * 3 * time.Millisecond) v, err := g.View("hello") if err != nil { // handle error } v.Clear() fmt.Fprintln(v, "Writing from different goroutines") return nil }) ... }
Update 関数により View をリセットすることで新しい View が render され、見えるようになるようです。layout 関数にて、for で rendering を繰り返す形にもしてみましたが、どうやら layout 関数が return して初めて rendering が開始されるようです。
layout 関数はあくまでも position を決定するのみで、更新の際には別途 Update 関数が必要ということですね。他にも mouse イベントが取得できるようなのでこれも試してみます。
package main import ( "fmt" "log" "math/rand" "time" "github.com/jroimartin/gocui" ) func main() { g, err := gocui.NewGui(gocui.OutputNormal) if err != nil { log.Panicln(err) } defer g.Close() g.SetManagerFunc(layout) g.Mouse = true if err = g.SetKeybinding("", gocui.MouseLeft, gocui.ModNone, quit); err != nil { log.Panicln(err) } ... }
左クリックで 終了する機能をつけてみました。筆者は iTerm2 から基本的にコーディングをしていますが、iTerm2 からは クリックイベントを受け取れず.... しかし、Mac デフォルトの Terminal アプリからは クリックイベントが取得できることが確認できました!!!
これを使用することでなかなかおもしろいことができそうです。それでは今回はこのへんで。
ライブラリのバージョンを一覧表示する syft で遊んでみた。
こんにちは k-jun です。今回は 自動で Software Bill of Materials (SBOM) を出力してくれるツール syft を試して見ます。
https://github.com/anchore/syft
自動で package を探索し、関連するライブラリなどを一覧で出力してくれるようです。再現環境を用意する際にもバージョンを簡単に合わせることができて便利そうです。
Setup
$ brew tap anchore/syft $ brew install syft
Run
内容すらも忘れた適当な TODO アプリに対して syft を適用してみます。
$ syft todo-app ✔ Loaded image ✔ Parsed image ✔ Cataloged packages [91 packages] NAME VERSION TYPE adduser 3.118 deb apt 1.8.2.1 deb base-files 10.3+deb10u4 deb base-passwd 3.5.46 deb bash 5.0-4 deb bsdutils 1:2.33.1-0.1 deb coreutils 8.30-3 deb dash 0.5.10.2-5 deb debconf 1.5.71 deb debian-archive-keyring 2019.1 deb debianutils 4.8.6.1 deb diffutils 1:3.7-3 deb dpkg 1.19.7 deb e2fsprogs 1.44.5-1+deb10u3 deb fdisk 2.33.1-0.1 deb findutils 4.6.0+git+20190209-2 deb gcc-8-base 8.3.0-6 deb gpgv 2.2.12-1+deb10u1 deb grep 3.3-1 deb gzip 1.9-3 deb hostname 3.21 deb init-system-helpers 1.56+nmu1 deb iproute2 4.20.0-2 deb iputils-ping 3:20180629-2+deb10u1 deb libacl1 2.2.53-4 deb libapt-pkg5.0 1.8.2.1 deb libattr1 1:2.4.48-4 deb libaudit-common 1:2.8.4-3 deb libaudit1 1:2.8.4-3 deb libblkid1 2.33.1-0.1 deb libbz2-1.0 1.0.6-9.2~deb10u1 deb libc-bin 2.28-10 deb libc6 2.28-10 deb libcap-ng0 0.7.9-2 deb libcap2 1:2.25-2 deb libcap2-bin 1:2.25-2 deb libcom-err2 1.44.5-1+deb10u3 deb libdb5.3 5.3.28+dfsg1-0.5 deb libdebconfclient0 0.249 deb libelf1 0.176-1.1 deb libext2fs2 1.44.5-1+deb10u3 deb libfdisk1 2.33.1-0.1 deb libffi6 3.2.1-9 deb libgcc1 1:8.3.0-6 deb libgcrypt20 1.8.4-5 deb libgmp10 2:6.1.2+dfsg-4 deb libgnutls30 3.6.7-4+deb10u4 deb libgpg-error0 1.35-1 deb libhogweed4 3.4.1-1 deb libidn2-0 2.0.5-1+deb10u1 deb liblz4-1 1.8.3-1 deb liblzma5 5.2.4-1 deb libmnl0 1.0.4-2 deb libmount1 2.33.1-0.1 deb libncursesw6 6.1+20181013-2+deb10u2 deb libnettle6 3.4.1-1 deb libp11-kit0 0.23.15-2 deb libpam-modules 1.3.1-5 deb libpam-modules-bin 1.3.1-5 deb libpam-runtime 1.3.1-5 deb libpam0g 1.3.1-5 deb libpcre3 2:8.39-12 deb libseccomp2 2.3.3-4 deb libselinux1 2.8-1+b1 deb libsemanage-common 2.8-2 deb libsemanage1 2.8-2 deb libsepol1 2.8-1 deb libsmartcols1 2.33.1-0.1 deb libss2 1.44.5-1+deb10u3 deb libstdc++6 8.3.0-6 deb libsystemd0 241-7~deb10u4 deb libtasn1-6 4.13-3 deb libtinfo6 6.1+20181013-2+deb10u2 deb libudev1 241-7~deb10u4 deb libunistring2 0.9.10-1 deb libuuid1 2.33.1-0.1 deb libxtables12 1.8.2-4 deb libzstd1 1.3.8+dfsg-3 deb login 1:4.5-1.1 deb mawk 1.3.3-17+b3 deb mount 2.33.1-0.1 deb ncurses-base 6.1+20181013-2+deb10u2 deb ncurses-bin 6.1+20181013-2+deb10u2 deb passwd 1:4.5-1.1 deb perl-base 5.28.1-6 deb sed 4.7-1 deb sysvinit-utils 2.93-8 deb tar 1.30+dfsg-6 deb tzdata 2020a-0+deb10u1 deb util-linux 2.33.1-0.1 deb zlib1g 1:1.2.11.dfsg-1 deb
こんな感じで出力されるんですね。結構良さそう。json フォーマットなど他のフォーマットにも対応している様子。
$ syft todo-app -o json | head ✔ Loaded image ✔ Parsed image ✔ Cataloged packages [91 packages] { "artifacts": [ { "id": "c78f941fc6ded0fe", "name": "adduser", "version": "3.118", "type": "deb", "foundBy": "dpkgdb-cataloger", "locations": [ {
行えることはシンプルですが、使い所もありそうで結構面白そうですね。それでは今回はこのへんで。
Ingress によるサービス公開! nginx-ingress-controller を試してみる。
こんにちは k-jun です。今回は nginx-ingress-controller を試してみます。
https://github.com/kubernetes/ingress-nginx
そもそも ingress とはなんぞやという話ですが、k8s における 外部からのアクセスを内部の適切な Pod へ ルーティングする LB のようなものです。
https://kubernetes.io/docs/concepts/services-networking/ingress/
Ingress exposes HTTP and HTTPS routes from outside the cluster to services within the cluster. Traffic routing is controlled by rules defined on the Ingress resource.
ここらへんの リソースは自分が前触った際には クラウドサービスの LB をプラグイン連携して使用するみたいになっていた気がしますが、いつの間にか nginx を使用できるようになっていたみたいですね。
Setup
ここ を参考にセットアップを進めていきます。
アプリケーションをデプロイしていきます。使用するイメージはサンプルアプリケーションのもの。
$ kubectl create deployment web --image=gcr.io/google-samples/hello-app:1.0 deployment.apps/web created $ kubectl expose deployment web --type=NodePort --port=8080 service/web exposed $ kubectl get service web NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE web NodePort 10.97.252.61 <none> 8080:31074/TCP 35s
Run
ということで、本題の Ingress を作っていきます。
$ kubectl apply -f https://k8s.io/examples/service/networking/example-ingress.yaml
中身で叩いている yaml はこんな感じ。
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: example-ingress annotations: nginx.ingress.kubernetes.io/rewrite-target: /$1 spec: rules: - host: hello-world.info http: paths: - path: / pathType: Prefix backend: service: name: web port: number: 8080
ingress が起動している様子もコマンドから確認できます。
$ kubectl get ingress NAME CLASS HOSTS ADDRESS PORTS AGE example-ingress <none> hello-world.info 35.190.25.54 80 8m58s
External IP でアクセスしてみるとこんな感じ。
$ curl -I http://35.190.25.54 -H 'Host: hello-world.info' HTTP/1.1 200 OK date: Sat, 04 Dec 2021 13:35:51 GMT content-length: 60 content-type: text/plain; charset=utf-8 x-envoy-upstream-service-time: 0 server: istio-envoy x-envoy-decorator-operation: web.default.svc.cluster.local:8080/* Via: 1.1 google $ curl -I http://35.190.25.54 -H 'Host: hello-world.dummy' HTTP/1.1 404 Not Found Date: Sat, 04 Dec 2021 13:37:48 GMT Content-Length: 74 Content-Type: text/plain; charset=utf-8 Via: 1.1 google
HostName の制限もしっかりと生きている様子。外部 IP が簡単に付与できて感激です。数年前はここまで簡単にできなかった記憶。
$ kubectl create deployment web2 --image=gcr.io/google-samples/hello-app:2.0
deployment.apps/web2 created
path ごとの振り分けを試すべく、2つ目のサンプルアプリケーションを作成。
$ kubectl expose deployment web2 --port=8080 --type=NodePort $ kubectl expose deployment web2 --port=8080 --type=NodePort
$ curl -s https://kubernetes.io/examples/service/networking/example-ingress.yaml > ./ingress.yaml $ vim ./ingress.yaml $ cat ./ingress.yaml $ cat ./ingress.yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: example-ingress annotations: nginx.ingress.kubernetes.io/rewrite-target: /$1 spec: rules: - host: hello-world.info http: paths: - path: / pathType: Prefix backend: service: name: web port: number: 8080 - path: /v2 pathType: Prefix backend: service: name: web2 port: number: 8080
$ curl http://35.190.25.54/v2 -H 'Host: hello-world.info' Hello, world! Version: 2.0.0 Hostname: web2-5d47994f45-nj67t
いい感じに、version 2 の方にアクセスが飛んでいますね。 ということで、nginx-ingress-controller を使用することで、いい感じにサービスを外部に公開できることがわかりました。 それでは今回はこのへんで。
ブラウザからターミナル! XTerm を試してみる。
こんにちは k-jun です。今回はブラウザでターミナルが再現できるライブラリ XTerm を試してみます。
https://github.com/xtermjs/xterm.js
以前カロリーメイトのドリンク版の広告サイトが似たようなことをやっていた気がします。これ や。
久しぶりに遊んでみたら、前からあったのか面白い機能を見つけましたw。宗教戦争はごめんとw。
caloriemateliquid $ vim DON’T FIGHT ANY MORE! This is a neutral zone. caloriemateliquid $ emacs DON’T FIGHT ANY MORE! This is a neutral zone.
Setup
$ mkdir xterm $ cd xterm $ npm install xterm
# xterm/index.html <!doctype html> <html> <head> <link rel="stylesheet" href="node_modules/xterm/css/xterm.css" /> <script src="node_modules/xterm/lib/xterm.js"></script> </head> <body> <div id="terminal"></div> <script> var term = new Terminal(); term.open(document.getElementById('terminal')); term.write('Hello from \x1B[1;3;31mxterm.js\x1B[0m $ ') </script> </body> </html>
Run
作成した index.html にブラウザからアクセスしてみます。
なんか違う...。何も入力できないし...。本当にただターミナルっぽいものが出現しただけじゃん...。 調べてみると input と output は自分で設定する必要があるんだとか。えぇ...
Xterm.js is not bash. Xterm.js can be connected to processes like bash and let you interact with them (provide input, receive output).
なんのためのライブラリ...。まあ、Terminal に接続するとかではなく完全に Terminal が画面に現れただけでしたし。 それでは今回はこのへんで。
分散メッセージングシステム!? NSQ を試してみる。
こんにちは k-jun です。今回はリアルタイムな分散メッセージングシステム NSQ を試してみます。
star 数から見るにかなり有名なプロダクトのようですね。各種クラウドサービスの キューイングサービスももとにしている技術は同じだったりするんでしょうか...?
Setup
$ brew install nsq
Run
ここ に従っていきます。
以下 3つのコマンドをそれぞれ 別ターミナルで起動します。
$ nsqlookupd $ nsqd --lookupd-tcp-address=127.0.0.1:4160 $ nsqadmin --lookupd-http-address=127.0.0.1:4161
1つ目は名前解決、2つめは NSQ 本体となる daemon, 3つ目は GUI とかでしょうか。
ということでここに 何かを放り込んでみます。
$ curl -d 'hello world 1' 'http://127.0.0.1:4151/pub?topic=test' OK
何やら Topic が追加されましたね。SNS とかの Topic もここから来ているんでしょうか。
手順にしたがって、nsq_to_file というコマンドを実行してみます。一緒にさらなるメッセージも追加。
$ curl -d 'hello world 2' 'http://127.0.0.1:4151/pub?topic=test' OK ~/source-code/remix/my-remix-app master* $ curl -d 'hello world 3' 'http://127.0.0.1:4151/pub?topic=test' OK $ nsq_to_file --topic=test --output-dir=/tmp --lookupd-http-address=127.0.0.1:4161 2021/11/27 16:44:10 INF 1 [test/nsq_to_file] querying nsqlookupd http://127.0.0.1:4161/lookup?topic=test 2021/11/27 16:44:10 INF 1 [test/nsq_to_file] (MacBook-Pro.local:4150) connecting to nsqd [nsq_to_file] 2021/11/27 16:44:10.864197 INFO: [test/nsq_to_file] opening /tmp/test.MacBook-Pro.2021-11-27_16.log [nsq_to_file] 2021/11/27 16:44:10.864381 INFO: [test/nsq_to_file] syncing 1 records to disk [nsq_to_file] 2021/11/27 16:44:40.614075 INFO: [test/nsq_to_file] syncing 2 records to disk
管理画面を見てみて、キューがなくなっていることに気づきました。
つまり、nsq_to_file というのはおそらく Topic を listen してファイルに吐き出しているものでは。と /tmp ディレクトリを見に行くと入ってた。
$ tail -f /tmp/test.MacBook-Pro.2021-11-27_16.log hello world 1 hello world 2 hello world 3
なるほどこうやってメッセージをやり取りできるのか。
ドキュメントをよく見てみると、使用していた daemon の説明も載っています。
- nsqd: https://nsq.io/components/nsqd.html
- nsqlookupd: https://nsq.io/components/nsqlookupd.html
- nsqadmin: https://nsq.io/components/nsqadmin.html
- nsq_to_file: https://nsq.io/components/utilities.html
https://nsq.io/components/utilities.html を見てみると、他にもいろいろと便利そうなコマンドがあるんですね。
ということで分散メッセージングライブラリの NSQ を見てみました。今回はこのへんで。
次世代のフロントフレームワーク! Remix を試してみる。
こんにちは k-jun です。今回は React Router の作成者が、作ったフレームワーク Remix を試してみます。
https://github.com/remix-run/remix
README によると work in progress ということですが、面白そうなので触ってみてしまいます。
Setup
create-remix で一撃でした。
$ npx create-remix@latest Need to install the following packages: create-remix@latest Ok to proceed? (y) y R E M I X 💿 Welcome to Remix! Let's get you set up with a new project. ? Where would you like to create your app? ./my-remix-app ? Where do you want to deploy? Choose Remix if you're unsure, it's easy to change deployment targets. Remix App Server ? TypeScript or JavaScript? TypeScript ? Do you want me to run `npm install`? Yes
Run
では早速起動してみます。
$ npm run dev > dev > remix dev Watching Remix app in development mode... 💿 Built in 373ms Remix App Server started at http://localhost:3000 GET / 200 - - 43.888 ms
おおお、ひとまず立ち上がることは立ち上がりましたね。
中身を見てみましたが、一番近いのは React ですね。拡張子は tsx ですし。
こちら に従って続きを作っていきます。
app/root.tsx の内容を以下のように書き換えます。
import { LiveReload, Outlet } from "remix"; export default function App() { return ( <html lang="en"> <head> <meta charSet="utf-8" /> <title>Remix: So great, it's funny!</title> </head> <body> <Outlet /> {process.env.NODE_ENV === "development" ? ( <LiveReload /> ) : null} </body> </html> ); }
そして、app/routes/index.tsx を以下のように追加すると、いい感じに。
export default function IndexRoute() { return <div>Hello Index Route</div>; }
変更して気づきましたが、Remix 反映がめちゃくちゃ早いですね。変わったことにすら気づかない Flutter レベルで早いです...。
どうもこの
import { Outlet } from "remix"; export default function JokesRoute() { return ( <div> <h1>J🤪KES</h1> <main> <Outlet /> </main> </div> ); }
export default function NewJokeRoute() { return ( <div> <p>Add your own hilarious joke</p> <form method="post"> <div> <label> Name: <input type="text" name="name" /> </label> </div> <div> <label> Content: <textarea name="content" /> </label> </div> <div> <button type="submit" className="button"> Add </button> </div> </form> </div> ); }
こんな感じになる。
絵文字の箇所は app/routes/jokes.tsx から来ているがそれ以外は app/routes/jokes/new.tsx ってことですね。 ワイルドカードを含むルーティングには app/routes/jokes/$jokeId.tsx のように指定するようです。
ということで軽く触るだけしてみましたが、なかなかおもしろそうです。本格的には展開されていないので真の力はこれからですが。 それでは今回はこのへんで。