【メモ】他人が書いたソースコードを読むときのアレコレ

はじめに

業務中にソースコードを読んでいると、以下の問題が発生する。

  • 一つの機能を追いすぎる
  • そもそも自分が何を目的に読んでいたのか途中で分からなくなる/忘れる
  • オブジェクト間のデータの受け渡しの流れが分からなくなる

これらの問題をどうにか解消したいと思い、参考になりそう記事を探した。

後で自分が読み返すようにメモとして残しておく。

 

リンク集

qiita.com

www.itmedia.co.jp

medium.com

 

せっかくなので、自分がプライベートで使用頻度が高いGoのソースコードの読み方も調べた。

devblog.thebase.in

 

まとめ

とりあえずメモを取るところから始めようかな。。。

 

おまけ

実際に自分が業務でソースコードを読むにあたって、苦労したこともメモとして残しておく。

 

ドキュメントが無い or メンテナンスが止まっている

あるあるだと思います。

使用しているフレームワーク(自家製)、ライブラリ(自家製)のドキュメントが無かったりメンテナンスが止まっている。

原因不明のバグを踏んだ時は、ひたすらデバッグモードで動作を追いかけるしかなくなる。

 

(社内ツールとかの)ソースコードをプロジェクト・パッケージ単位で残しておいてくれない

複数のフォルダに分けて1ファイルずつネットワークドライブに保管していたりする。なんで?

 

ソースコードのコピーが大量に作られている

↓みたいなのも見かける。ちなみに最新の日付が最新とは限らない。

tool_A.sh

tool_A_20220819.sh

tool_A_20220820.sh

 

【メモ】asdf 経由でインストールした Go のパスを Visual Studio Code が読み込んでくれない現象

原因を調べていくうちに、以下の記事が見つかった。

blog.framinal.life

 

www.web-dev-qa-db-ja.com

 

bash 関連の諸々の設定をVisual Studio Code が読み込んでいないのが原因らしい。

自分の場合、Visual Studio Code に GOROOT の設定について怒られたていた。この問題を settings.json に GOROOT の設定を書くことで解決した。

>|json|

{
  ...
  "go.goroot": "/home/hujimori/.asdf/installs/golang/1.17.6/go",
  "go.gopath": "/home/hujimori/go"
}

||<

 

本当だったら、リンク先のように設定する方がいいのだろうか。とりあえず、問題は解決したので良しとする。

 

チーム「DREAM TEAM TRIANGLE」で ISUCON12 予選に参加しました

はじめに

チーム「DREAM TEAM TRIANGLE」で ISUCON 12 予選に参加しました(通算3回)。

まずは、このような素敵な大会を開催していただいた運営様に心より感謝申し上げます。

 

今年は例年より個人的な勉強に加えて一か月半ほど前からチーム内勉強会(週末に6~8時間/回  程度)を開いて準備を行ってきました。

気合を入れて予選に挑みましたが、本番ではうまくいかないことも多く、予選敗退と辛酸をなめる結果に終わってしまいました。

ですが、得られた学びも多く、それらを次に生かすためにも今回の参加記録を残したいと思います。

チームメンバー・役割

基本的は以下の役割で作業を進めました。

<hujimori(自分)>

・マニュアル理解

・アプリケーション改修

<4423>

・チーム創設以来、じっくりコトコト煮込み続けた秘伝のタレの作成者

・deploy 環境構築

<kakuden>

・DB周りのお世話

使用したツール・言語

・Slack → スロークエリ の解析結果、top の実行結果などを通知する先 

・New Relic  → ログ解析

・Pyroscope → アプリケーションのプロファイリング

・Discord → 連絡手段

・Go → 選択した言語

Visual Studio Code → コーディング、confファイルを弄る用

今回、私たちが使用したツールの中で注目すべきは Pyroscope です。

pprof と同じようにプロファイリングができます。 そして、UI がイケています。

ISUCONの競技でインターネットを使った時 みんなpprofでプロファイリングしている時に
自分だけこれみよがしにPyroscopeにつないでCPU使用率とかを周りに見せてたこと しかも「このページって何?」って聞かれたときに「(CPU使用率が)ヤバイやつら(関数)の集会場みたいなもん」とか答えたこと さらにPyroscopeへの行き方を教えるためにヤフーでPyroscopeって検索させて でてきたリンクをクリックしてPyroscopeのトップページが表示された瞬間に そいつの耳元でWelcome to Underground」ってささやいたこと

詳細は下記を見てください。

pyroscope.io

 

最終スコア

最終スコアは 9417 でした。

順位は上から数えて 103 位でした。予選敗退とは言え、参加チーム数 600 超えの大会で 103 位という順位はまぁまぁ良いのでないかと思っています。

スコアの推移(17時点)

やったこと

10:00~11:00 準備・deploy 環境構築

<hujimori(自分)>

 問題の理解を進める。

→ 事前の勉強会で全く触らなかった SQLite に登場にビビる。

きっと、一護だって驚く

 

<4423>

deploy 環境の構築を進める。

 

<kakuden>

MySQL のバージョン、テーブルの構成を確認する。

 

11:00~12:00 準備最終段階

<hujimori(自分)>

自PCにインストールしていた Go のバージョンが古いせいでビルドエラーになることに気づく。

→ 大慌てで Go のバージョンを上げる(心臓が止まりかけた)。

 

<4423>

New Relic と Pyroscope を設定する。

→ NewRelic でログが出力されない問題が発生。

 

<kakuden>

スロウクエリにインデックスを張る。

 

12:00~15:00 本格的にチューニングを始める

<hujimori(自分)>

昼食をとる。

→ メンバー間で作業状況の確認をおこなう。

GET /api/player/competition/:competition_id/ranking が重かったので、API 内で大会のデータを毎回取得しているを部分をキャッシュしてみる。

→ キャッシュした結果、ベンチマークの整合性チェックが失敗する。

→ 終了した大会のデータもレスポンスしてしまったことが原因と分かる。

→ 解決方法が思いつかなかったので改善は断念。

 

<4423>

NewRelic でログの出力は断念。

→ tenantDB の connection pool を実装する。

public.pem を起動時に読み込むように修正する。

→ スコアが上がりだす。

 

<kakuden>

visit_history に index を張る作業を進める。

→ スコアには影響は出ず。

 

15:00~17;30

<hujimori(自分)>

POST /api/organizer/competition/:competition_id/score の for 文の中で INSERT クエリを呼び出している部分を見つける。

ソースコードを読むと、for 文の外にINSERTを切り出すだけで直ぐにBULK INSERT にできそうだと分かる。

→ BULK INSERT にする。

→ スコアが少し上がる。

 

<4423>

GET /api/player/player/:player_idをキャッシュを試みるが断念。

GET /api/player/competition/:competition_id/ranking をキャッシュする。その他いろいろな部分でキャッシュを試す。

→ 放置していた isu3 を使えるようにする。

→ 秘伝のタレ(設定ファイル)を反映する。

 

<kakuden>

isu3 を DB サーバー専用にする。

 

17;30~18;00

<hujimori(自分)>

悪あがきでマックスコネクションを弄ってみる。

→ スコア上がらず。むしろ下がる。

→ 燃え尽きる。

 

<4423>

モニタリング/デバッグ用設定を削除する。

→ スコアが上がる。

 

<kakuden>

燃え尽きる。

個人的に良かった点・反省点

良かった点

・INSERT クエリを BULK INSERT にできたこと(去年はそれすらもできなかった)。

・勉強会で事前に練習していたこと(ロードバランシング、アプリケーションサーバーとDB サーバーの分離)が実施できたこと。

・Pyroscope が見やすかった。来年も使う。

反省点

・Go のバージョンを事前に上げ忘れていたこと。

→ 準備不足。プログラミング言語に限らず競技で使うミドルウエアもバージョンは事前に確認しておくこと。

 

・マニュアルの理解が足りていない状態で、闇雲に作業をやりはじめたこと。

→ ISCUON 中にやるのはコスパが悪いのかもしれないが、アプリケーションの構成図やER図を書いてチーム内で共有しても良かったかもしれない。

 

・New Relic の操作に迷うことが多々あった。

→ 習熟度が足りない。

 

・競技時間が経過するにつれて、パフォーマンスの確認を怠りつつあった。

→ 作業に集中すると、気に掛けるなくなってしまう。。。

まとめ

私個人としてはアプリケーションの仕様を理解する能力が足りていないなと感じました。

事前学習では、N+1 の解消やキャッシュのコーディングなど、主にプログラミング面の勉強を重点的に行いました。そのせいか、予選前日までは「今回は結構やれちゃうんじゃない?」と内心調子に乗っていました。

しかし、いざ本番で問題を目の前にすると、どこから手を付けて良いか分からず途方に暮れていました。その結果、「良く分からんけど、なんとなく遅そうだからチューニングしてみる」と手当たり次第に作業を進めてしまい、スコアも大して上げることができませんでした。

ISUCON を戦う上でコーディングはもちろん、各種ミドルウェアの使い方、ログを分析するスキルは重要だと思っています。それらのスキルを活かすにはアプリケーションの仕様を理解してチューニングの方針を決めていくことが大切であると痛感しました。

 

今回の経験を糧にして、来年も頑張りたいと思います。

 

 

 

【メモ】【勉強】nginxでロードバランス先を出力する

nginxでロードバランスを行った際、
デフォルトの設定ではアクセスログにロードバランス先が出力されない。

ロードバランス先の出力方法を調べてみると、以下の記事が参考になったのでメモとして残しておく。
yapud.hatenablog.com

修正内容は以下の通りになります。
ポイントは、nginx.confでは複数のログフォーマットをそれぞれ別名で定義できること。

下記の場合だと、nginx宛のアクセスログのフォーマットを「main 」、
ロードバランス先のアクセスログのフォーマットを「upstreamlog」という名称で定義しています。

※まだ検証途中なので、nginxとロードバランス先のサーバーは同じインスタンスで動かしています。

worker_processes 1;

events {
        worker_connections 1024;
}

http {
        include mime.types;
        default_type application/octet-stream;

        log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" '
        access_log /var/log/nginx/access.log main;
        
        # 追記したログフォーマット
        log_format upstreamlog '[$time_local] $remote_addr $host $upstream_addr $request';
        access_log /var/log/nginx/upstream.log upstreamlog;

        upstream backends {
                keepalive 32;
                server 127.0.0.1:8080;

        }

        server {
                listen 80;
                server_name www.example.com;

                location / {
                        proxy_http_version 1.1;
                        proxy_set_header Connection "";
                        proxy_set_header Host $http_host;

                        proxy_pass http://backends;
                }
        }
}

以上。

【メモ】【勉強】EC2にnginxをインストール

下記コマンドでnginxをインストールする。

$ amazon-linux-extras | grep "nginx" 
38 nginx1 available [ =stable ] 

$ sudo amazon-linux-extras install nginx1
Installing nginx Loaded plugins: extras_suggestions, langpacks, priorities, update-motd Cleaning repos: amzn2-core amzn2extra-docker amzn2extra-kernel-5.10 amzn2extra-nginx1 0 metadata files removed
略


インストール後、下記コマンドでnginxを起動。

$ sudo systemctl start nginx

下記コマンドでEC2起動時に自動的にnginxを起動するように設定。

$ sudo systemctl start nginx

下記コマンドでStatusを確認。

$ systemctl status nginx
 ● nginx.service - The nginx HTTP and reverse proxy server Loaded
略

EC2のパブリックIPにブラウザからアクセスして確認。

f:id:huji_mori:20211228225027p:plain
ブラウザでnginxの起動を確認

【メモ】WslRegisterDistribution failed with error: 0x800701bc

WSLインストール時に発生したエラーについてメモ。

新しく組んだデスクトップPCにWSLをインストールしようとしたら、以下のようなエラーが発生した。

stalling, this may take a few minutes...
WslRegisterDistribution failed with error: 0x800701bc
Error: 0x800701bc WSL 2 ???????????? ??????????????????????? https://aka.ms/wsl2kernel ?????????

Press any key to continue...

調べてみると、Linux カーネル更新プログラム パッケージをダウンロードする必要がある模様。
docs.microsoft.com

指示に従い、Linuxカーネル更新プログラムパッケージをダウンロード&インストール。
その後、無事インストールが完了した。

Installing, this may take a few minutes...
Please create a default UNIX user account. The username does not need to match your Windows username.
For more information visit: https://aka.ms/wslusers
Enter new UNIX username: hujimori
New password:
Retype new password:
passwd: password updated successfully
Installation successful!
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

Welcome to Ubuntu 20.04.3 LTS (GNU/Linux 5.10.16.3-microsoft-standard-WSL2 x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Tue Dec 28 21:11:44 JST 2021

  System load:  0.07               Processes:             8
  Usage of /:   0.5% of 250.98GB   Users logged in:       0
  Memory usage: 0%                 IPv4 address for eth0: 172.20.128.7
  Swap usage:   0%

1 update can be applied immediately.
To see these additional updates run: apt list --upgradable


The list of available updates is more than a week old.
To check for new updates run: sudo apt update


This message is shown once a day. To disable it please create the
/home/hujimori/.hushlogin file.

go1.16で「no required module provides package~」が出たときの対処方法

go1.16でコードを書いてビルドすると以下のメッセージが出た

no required module provides package

go1.16からgo.modやgo.sumが自動でビルド時に更新されないので、以下のコマンドを対象のファイルがある場所で実行すれば解消される。

$ go mod tidy