2024/03/03(日)Windows 11でパスフレーズ付きの公開鍵認証SFTPをマウントする
投稿日:
古のSFTPマウントツールが軒並み死んでいるためRcloneを使う。WindowsからLinux上に構築したストレージに繋ぐときに便利。
前提条件
- 接続先のSSH環境がある
- 接続先のSSH環境の公開鍵認証に利用する秘密鍵にパスフレーズが付いている
確認環境
| Env | Ver |
|---|---|
| OS | Windows 11 Home 25H2(26200.8039) |
| Rclone | 1.73.3 |
手順
1. 基本環境のインストール
- Rcloneをインストールする
choco install rclone - WinFspもインストールする。これがないとマウントできない
2. マウント設定の作成
- 次のコマンドで設定ウィザードを起動する
rclone config 設定はこんな感じ
# 新しい設定ファイルの作成 No remotes found, make a new one? n) New remote s) Set configuration password q) Quit config n/s/q>n # 接続名を設定する Enter name for new remote. name> hoge # 接続先のストレージ種別をSSHで設定する Option Storage. Type of storage to configure. Choose a number from below, or type in your own value. 1 / 1Fichier \ (fichier) 2 / Akamai NetStorage \ (netstorage) 3 / Alias for an existing remote \ (alias) 4 / Amazon S3 Compliant Storage Providers including AWS, Alibaba, ArvanCloud, BizflyCloud, Ceph, ChinaMobile, Cloudflare, Cubbit, DigitalOcean, Dreamhost, Exaba, FileLu, FlashBlade, GCS, Hetzner, HuaweiOBS, IBMCOS, IDrive, Intercolo, IONOS, Leviia, Liara, Linode, LyveCloud, Magalu, Mega, Minio, Netease, Outscale, OVHcloud, Petabox, Qiniu, Rabata, RackCorp, Rclone, Scaleway, SeaweedFS, Selectel, Servercore, SpectraLogic, StackPath, Storj, Synology, TencentCOS, Wasabi, Zata, Other \ (s3) 5 / Backblaze B2 \ (b2) 6 / Better checksums for other remotes \ (hasher) 7 / Box \ (box) 8 / Cache a remote \ (cache) 9 / Citrix Sharefile \ (sharefile) 10 / Cloudinary \ (cloudinary) 11 / Combine several remotes into one \ (combine) 12 / Compress a remote \ (compress) 13 / DOI datasets \ (doi) 14 / Drime \ (drime) 15 / Dropbox \ (dropbox) 16 / Encrypt/Decrypt a remote \ (crypt) 17 / Enterprise File Fabric \ (filefabric) 18 / FTP \ (ftp) 19 / FileLu Cloud Storage \ (filelu) 20 / Filen \ (filen) 21 / Files.com \ (filescom) 22 / Gofile \ (gofile) 23 / Google Cloud Storage (this is not Google Drive) \ (google cloud storage) 24 / Google Drive \ (drive) 25 / Google Photos \ (google photos) 26 / HTTP \ (http) 27 / Hadoop distributed file system \ (hdfs) 28 / HiDrive \ (hidrive) 29 / ImageKit.io \ (imagekit) 30 / In memory object storage system. \ (memory) 31 / Internet Archive \ (internetarchive) 32 / Internxt Drive \ (internxt) 33 / Jottacloud \ (jottacloud) 34 / Koofr, Digi Storage and other Koofr-compatible storage providers \ (koofr) 35 / Linkbox \ (linkbox) 36 / Local Disk \ (local) 37 / Mail.ru Cloud \ (mailru) 38 / Mega \ (mega) 39 / Microsoft Azure Blob Storage \ (azureblob) 40 / Microsoft Azure Files \ (azurefiles) 41 / Microsoft OneDrive \ (onedrive) 42 / OpenDrive \ (opendrive) 43 / OpenStack Swift (Rackspace Cloud Files, Blomp Cloud Storage, Memset Memstore, OVH) \ (swift) 44 / Oracle Cloud Infrastructure Object Storage \ (oracleobjectstorage) 45 / Pcloud \ (pcloud) 46 / PikPak \ (pikpak) 47 / Pixeldrain Filesystem \ (pixeldrain) 48 / Proton Drive \ (protondrive) 49 / Put.io \ (putio) 50 / QingCloud Object Storage \ (qingstor) 51 / Quatrix by Maytech \ (quatrix) 52 / Read archives \ (archive) 53 / SMB / CIFS \ (smb) 54 / SSH/SFTP \ (sftp) 55 / Shade FS \ (shade) 56 / Sia Decentralized Cloud \ (sia) 57 / Storj Decentralized Cloud Storage \ (storj) 58 / Sugarsync \ (sugarsync) 59 / Transparently chunk/split large files \ (chunker) 60 / Uloz.to \ (ulozto) 61 / Union merges the contents of several upstream fs \ (union) 62 / WebDAV \ (webdav) 63 / Yandex Disk \ (yandex) 64 / Zoho \ (zoho) 65 / iCloud Drive \ (iclouddrive) 66 / premiumize.me \ (premiumizeme) 67 / seafile \ (seafile) Storage> 54 # 接続先のホストを設定 Option host. SSH host to connect to. E.g. "example.com". Enter a value. host> ssh.example.com # 接続先のユーザー名を設定 Option user. SSH username. Enter a value of type string. Press Enter for the default (MYPC\myuser). user> hoge # 接続先のポートを指定、デフォルトならエンターで飛ばせると思う Option port. SSH port number. Enter a signed integer. Press Enter for the default (22). port> 12345 # 鍵認証なのでエンターで飛ばす Option pass. SSH password, leave blank to use ssh-agent. Choose an alternative below. Press Enter for the default (n). y) Yes, type in my own password g) Generate random password n) No, leave this optional password blank (default) y/g/n> # エンターで飛ばす Option key_pem. Raw PEM-encoded private key. Note that this should be on a single line with line endings replaced with '\n', eg key_pem = -----BEGIN RSA PRIVATE KEY-----\nMaMbaIXtE\n0gAMbMbaSsd\nMbaass\n-----END RSA PRIVATE KEY----- This will generate the single line correctly: awk '{printf "%s\\n", $0}' < ~/.ssh/id_rsa If specified, it will override the key_file parameter. Enter a value. Press Enter to leave empty. key_pem> # 秘密鍵のパスを指定 Option key_file. Path to PEM-encoded private key file. Leave blank or set key-use-agent to use ssh-agent. Leading `~` will be expanded in the file name as will environment variables such as `${RCLONE_CONFIG_DIR}`. Enter a value. Press Enter to leave empty. key_file> C:\path\to\hoge.sec # 秘密鍵のパスフレーズを入れる Option key_file_pass. The passphrase to decrypt the PEM-encoded private key file. Only PEM encrypted key files (old OpenSSH format) are supported. Encrypted keys in the new OpenSSH format can't be used. Choose an alternative below. Press Enter for the default (n). y) Yes, type in my own password g) Generate random password n) No, leave this optional password blank (default) y/g/n> y Enter the password: password: Confirm the password: password: # エンターで飛ばす Option pubkey. SSH public certificate for public certificate based authentication. Set this if you have a signed certificate you want to use for authentication. If specified will override pubkey_file. Enter a value. Press Enter to leave empty. pubkey> # エンターで飛ばす Option pubkey_file. Optional path to public key file. Set this if you have a signed certificate you want to use for authentication. Leading `~` will be expanded in the file name as will environment variables such as `${RCLONE_CONFIG_DIR}`. Enter a value. Press Enter to leave empty. pubkey_file> # エンターで飛ばす Option key_use_agent. When set forces the usage of the ssh-agent. When key-file is also set, the ".pub" file of the specified key-file is read and only the associated key is requested from the ssh-agent. This allows to avoid `Too many authentication failures for *username*` errors when the ssh-agent contains many keys. Enter a boolean value (true or false). Press Enter for the default (false). key_use_agent> # エンターで飛ばす Option use_insecure_cipher. Enable the use of insecure ciphers and key exchange methods. This enables the use of the following insecure ciphers and key exchange methods: - aes128-cbc - aes192-cbc - aes256-cbc - 3des-cbc - diffie-hellman-group-exchange-sha256 - diffie-hellman-group-exchange-sha1 Those algorithms are insecure and may allow plaintext data to be recovered by an attacker. This must be false if you use either ciphers or key_exchange advanced options. Choose a number from below, or type in your own boolean value (true or false). Press Enter for the default (false). 1 / Use default Cipher list. \ (false) 2 / Enables the use of the aes128-cbc cipher and diffie-hellman-group-exchange-sha256, diffie-hellman-group-exchange-sha1 key exchange. \ (true) use_insecure_cipher> # エンターで飛ばす Option disable_hashcheck. Disable the execution of SSH commands to determine if remote file hashing is available. Leave blank or set to false to enable hashing (recommended), set to true to disable hashing. Enter a boolean value (true or false). Press Enter for the default (false). disable_hashcheck> # エンターで飛ばす Option ssh. Path and arguments to external ssh binary. Normally rclone will use its internal ssh library to connect to the SFTP server. However it does not implement all possible ssh options so it may be desirable to use an external ssh binary. Rclone ignores all the internal config if you use this option and expects you to configure the ssh binary with the user/host/port and any other options you need. **Important** The ssh command must log in without asking for a password so needs to be configured with keys or certificates. Rclone will run the command supplied either with the additional arguments "-s sftp" to access the SFTP subsystem or with commands such as "md5sum /path/to/file" appended to read checksums. Any arguments with spaces in should be surrounded by "double quotes". An example setting might be: ssh -o ServerAliveInterval=20 user@example.com Note that when using an external ssh binary rclone makes a new ssh connection for every hash it calculates. Enter a value of type SpaceSepList. Press Enter to leave empty. ssh> # エンターで飛ばす Edit advanced config? y) Yes n) No (default) y/n> # 設定内容に問題ないことを確認してエンターで飛ばす # 設定を直す場合はeを選ぶと、ここまでの設定内容から修正したい箇所だけ編集できて便利 Configuration complete. Options: - type: sftp - host: ssh.example.com - user: hoge - port: 12345 - key_file: C:\path\to\hoge.sec - key_file_pass: *** ENCRYPTED *** Keep this "hoge" remote? y) Yes this is OK (default) e) Edit this remote d) Delete this remote y/e/d> # 設定の登録結果が出てくるので、特になければqで終わる Current remotes: Name Type ==== ==== hoge sftp e) Edit existing remote n) New remote d) Delete remote r) Rename remote c) Copy remote s) Set configuration password q) Quit config e/n/d/r/c/s/q> q- 設定が完了したら、以下のコマンドでマウントできる
# 例:rclone mount hoge: Z: --network-mode # マウントパスを指定する場合はhoge:/path/toのようにすればよいと思うが試してない rclone mount <config name>:<mount path> <drive letter>: --network-mode
設定ファイルの在り処と中身
一回作った設定ファイルは持ち運べるし、手組もできるのでフォーマットが分かっていれば一々設定ウィザードを起動する必要はない。
- 設定ファイルの在り処
%USERPROFILE%\AppData\Roaming\rclone\rclone.conf
中身のフォーマットはiniファイルで接続先がWindowsのSSHだと
shell_typeがcmd、UbuntuのSSHだとunixとなっていた[hoge] type = sftp host = ssh1.example.com user = foo port = 12121 key_file = C:\path\to\hoge.sec key_file_pass = XXXXXXXXXXXXXX shell_type = cmd [piyo] type = sftp host = ssh2.example.com user = bar port = 12122 key_file = C:\path\to\piyo.sec key_file_pass = YYYYYYYYYYYYYY shell_type = unix
トラブルシューティング
マウント時のターミナルウィンドウが邪魔
公式の解説によると、Windowsではバックグラウンドで動かすことができない
Use the --daemon flag to force background mode. On Windows you can run mount in foreground only, the flag is ignored.
どうしてもバックグラウンドで動かしたい場合はVDeskを使って適当な仮想デスクトップで起動するか、タスクトレイ系のユーティリティを使ってタスクトレイに突っ込んだりすると良さそうだ。
私は必要なときに都度起動し、仮想デスクトップを作って、そこに避難させとけば良いかな程度で今のところ考えている。この手のはネットワークが不安定な場所で動かすと色々面倒だし、使う頻度も低いので、今はそれで良いかなという感じ。
参考
2024/02/22(木)JavaScriptでtry-catchとif文でエラー処理にかかる時間を調べた
投稿日:
Node.jsとGoogle Chrome, Microsoft Edgeを用いて、try-catchとif文でエラー処理にかかる時間がどのくらい違うのかを調べた。
計測手法
次の4パターンを100万回実行した結果を記載している。
- Result型としてエラーオブジェクトをreturnし、if文で判定する方式
- Result型としてエラーインスタンスをreturnし、if文で判定する方式
- エラーオブジェクトをthrowし、try-catchで判定する方式
- エラーインスタンスをthrowし、try-catchで判定する方式
確認に使用したコード:https://gist.github.com/Lycolia/304bc9e825e821c2d582f3ef9f700817
計測結果
CPUによって処理速度がかなり変動するが、いずれの環境でも処理速度の速さは以下の通り。
- Result型としてエラーオブジェクトをreturnし、if文で判定する方式
- エラーオブジェクトをthrowし、try-catchで判定する方式
- Result型としてエラーインスタンスをreturnし、if文で判定する方式
- エラーインスタンスをthrowし、try-catchで判定する方式
計測に使用したCPU
| CPU | コア | スレッド | クロック | L2キャッシュ | L3キャッシュ |
|---|---|---|---|---|---|
| Intel Core i7 13700 | 16 | 24 | 5.20GHz | 24.00MB | 30.00MB |
| Intel Core i7 1265U | 10 | 12 | 4.80GHz | 6.50MB | 12.00MB |
| AMD Ryzen 5 5600G | 6 | 12 | 3.90GHz | 3.00MB | 16.00MB |
Intel Core i7 13700端末
16C24T, 5.20GHz, L2 24.00MB, L3 30.00MB。ミドルタワーPC。
Node.js v16.20.2
処理環境
| Env | Ver |
|---|---|
| CPU | Intel Core i7 13700 |
| OS | Ubuntu 20.04.6 LTS (WSL2) |
処理結果
| 処理方式 | 処理時間(ms) |
|---|---|
| Result型としてエラーオブジェクトをreturnし、if文で判定する方式 | 802 |
| Result型としてエラーインスタンスをreturnし、if文で判定する方式 | 5,942 |
| エラーオブジェクトをthrowし、try-catchで判定する方式 | 1,847 |
| エラーインスタンスをthrowし、try-catchで判定する方式 | 6,527 |
Node.js v18.19.1
処理環境
| Env | Ver |
|---|---|
| CPU | Intel Core i7 13700 |
| OS | Ubuntu 20.04.6 LTS (WSL2) |
処理結果
| 処理方式 | 処理時間(ms) |
|---|---|
| Result型としてエラーオブジェクトをreturnし、if文で判定する方式 | 887 |
| Result型としてエラーインスタンスをreturnし、if文で判定する方式 | 5,826 |
| エラーオブジェクトをthrowし、try-catchで判定する方式 | 2,006 |
| エラーインスタンスをthrowし、try-catchで判定する方式 | 6,464 |
Node.js v20.11.1
処理環境
| Env | Ver |
|---|---|
| CPU | Intel Core i7 13700 |
| OS | Ubuntu 20.04.6 LTS (WSL2) |
処理結果
| 処理方式 | 処理時間(ms) |
|---|---|
| Result型としてエラーオブジェクトをreturnし、if文で判定する方式 | 720 |
| Result型としてエラーインスタンスをreturnし、if文で判定する方式 | 5,375 |
| エラーオブジェクトをthrowし、try-catchで判定する方式 | 1,690 |
| エラーインスタンスをthrowし、try-catchで判定する方式 | 5,978 |
Microsoft Edge 121.0.2277.128
処理環境
| Env | Ver |
|---|---|
| CPU | Intel Core i7 13700 |
| OS | Windows 11 Pro 22H2(22621.3155) |
処理結果
| 処理方式 | 処理時間(ms) |
|---|---|
| Result型としてエラーオブジェクトをreturnし、if文で判定する方式 | 4,246 |
| Result型としてエラーインスタンスをreturnし、if文で判定する方式 | 12,329 |
| エラーオブジェクトをthrowし、try-catchで判定する方式 | 11,985 |
| エラーインスタンスをthrowし、try-catchで判定する方式 | 14,105 |
Google Chrome 122.0.6261.58
処理環境
| Env | Ver |
|---|---|
| CPU | Intel Core i7 13700 |
| OS | Windows 11 Pro 22H2(22621.3155) |
処理結果
| 処理方式 | 処理時間(ms) |
|---|---|
| Result型としてエラーオブジェクトをreturnし、if文で判定する方式 | 3,507 |
| Result型としてエラーインスタンスをreturnし、if文で判定する方式 | 10,793 |
| エラーオブジェクトをthrowし、try-catchで判定する方式 | 10,482 |
| エラーインスタンスをthrowし、try-catchで判定する方式 | 12,452 |
Intel Core i7 1265U端末
10C12T, 4.80GHz, L2 6.50MB, L3 12.00MB。ノートPC。
Node.js v16.20.2
処理環境
| Env | Ver |
|---|---|
| CPU | Intel Core i7 1265U |
| OS | Ubuntu 20.04.6 LTS (WSL2) |
処理結果
| 処理方式 | 処理時間(ms) |
|---|---|
| Result型としてエラーオブジェクトをreturnし、if文で判定する方式 | 972 |
| Result型としてエラーインスタンスをreturnし、if文で判定する方式 | 11,416 |
| エラーオブジェクトをthrowし、try-catchで判定する方式 | 2,288 |
| エラーインスタンスをthrowし、try-catchで判定する方式 | 13,993 |
Node.js v18.19.1
処理環境
| Env | Ver |
|---|---|
| CPU | Intel Core i7 1265U |
| OS | Ubuntu 20.04.6 LTS (WSL2) |
処理結果
| 処理方式 | 処理時間(ms) |
|---|---|
| Result型としてエラーオブジェクトをreturnし、if文で判定する方式 | 1,102 |
| Result型としてエラーインスタンスをreturnし、if文で判定する方式 | 11,333 |
| エラーオブジェクトをthrowし、try-catchで判定する方式 | 2,441 |
| エラーインスタンスをthrowし、try-catchで判定する方式 | 12,827 |
Node.js v20.11.1
処理環境
| Env | Ver |
|---|---|
| CPU | Intel Core i7 1265U |
| OS | Ubuntu 20.04.6 LTS (WSL2) |
処理結果
| 処理方式 | 処理時間(ms) |
|---|---|
| Result型としてエラーオブジェクトをreturnし、if文で判定する方式 | 888 |
| Result型としてエラーインスタンスをreturnし、if文で判定する方式 | 10,881 |
| エラーオブジェクトをthrowし、try-catchで判定する方式 | 2,269 |
| エラーインスタンスをthrowし、try-catchで判定する方式 | 12,254 |
Microsoft Edge 121.0.2277.128
処理環境
| Env | Ver |
|---|---|
| CPU | Intel Core i7 1265U |
| OS | Windows 11 Pro 22H2(22621.3155) |
処理結果
| 処理方式 | 処理時間(ms) |
|---|---|
| Result型としてエラーオブジェクトをreturnし、if文で判定する方式 | 7,526 |
| Result型としてエラーインスタンスをreturnし、if文で判定する方式 | 34,761 |
| エラーオブジェクトをthrowし、try-catchで判定する方式 | 39,005 |
| エラーインスタンスをthrowし、try-catchで判定する方式 | 65,752 |
Google Chrome 122.0.6261.58
処理環境
| Env | Ver |
|---|---|
| CPU | Intel Core i7 1265U |
| OS | Windows 11 Pro 22H2(22621.3155) |
処理結果
| 処理方式 | 処理時間(ms) |
|---|---|
| Result型としてエラーオブジェクトをreturnし、if文で判定する方式 | 6,303 |
| Result型としてエラーインスタンスをreturnし、if文で判定する方式 | 16,460 |
| エラーオブジェクトをthrowし、try-catchで判定する方式 | 17,979 |
| エラーインスタンスをthrowし、try-catchで判定する方式 | 23,378 |
AMD Ryzen 5 5600G端末
6C12T, 3.90GHz, L2 3.00MB, L3 16.00MB。ミニタワーPC。
この端末はOSがUbuntuであるため、これまでのWindows環境との単純比較はできない。
Node.js v16.20.2
処理環境
| Env | Ver |
|---|---|
| CPU | AMD Ryzen 5 5600G |
| OS | Ubuntu 22.04.3 LTS |
処理結果
| 処理方式 | 処理時間(ms) |
|---|---|
| Result型としてエラーオブジェクトをreturnし、if文で判定する方式 | 1,786 |
| Result型としてエラーインスタンスをreturnし、if文で判定する方式 | 11,242 |
| エラーオブジェクトをthrowし、try-catchで判定する方式 | 3,880 |
| エラーインスタンスをthrowし、try-catchで判定する方式 | 12,716 |
Node.js v18.19.1
処理環境
| Env | Ver |
|---|---|
| CPU | AMD Ryzen 5 5600G |
| OS | Ubuntu 22.04.3 LTS |
処理結果
| 処理方式 | 処理時間(ms) |
|---|---|
| Result型としてエラーオブジェクトをreturnし、if文で判定する方式 | 1,933 |
| Result型としてエラーインスタンスをreturnし、if文で判定する方式 | 11,094 |
| エラーオブジェクトをthrowし、try-catchで判定する方式 | 3,839 |
| エラーインスタンスをthrowし、try-catchで判定する方式 | 12,767 |
Node.js v20.11.1
処理環境
| Env | Ver |
|---|---|
| CPU | AMD Ryzen 5 5600G |
| OS | Ubuntu 22.04.3 LTS |
処理結果
| 処理方式 | 処理時間(ms) |
|---|---|
| Result型としてエラーオブジェクトをreturnし、if文で判定する方式 | 1,714 |
| Result型としてエラーインスタンスをreturnし、if文で判定する方式 | 10,741 |
| エラーオブジェクトをthrowし、try-catchで判定する方式 | 3,444 |
| エラーインスタンスをthrowし、try-catchで判定する方式 | 11,978 |
Microsoft Edge 121.0.2277.128
処理環境
| Env | Ver |
|---|---|
| CPU | AMD Ryzen 5 5600G |
| OS | Ubuntu 22.04.3 LTS |
処理結果
| 処理方式 | 処理時間(ms) |
|---|---|
| Result型としてエラーオブジェクトをreturnし、if文で判定する方式 | 4,348 |
| Result型としてエラーインスタンスをreturnし、if文で判定する方式 | 21,584 |
| エラーオブジェクトをthrowし、try-catchで判定する方式 | 15,543 |
| エラーインスタンスをthrowし、try-catchで判定する方式 | 23,119 |
Google Chrome 122.0.6261.57
これだけバージョンが合わなかった。
処理環境
| Env | Ver |
|---|---|
| CPU | AMD Ryzen 5 5600G |
| OS | Ubuntu 22.04.3 LTS |
処理結果
| 処理方式 | 処理時間(ms) |
|---|---|
| Result型としてエラーオブジェクトをreturnし、if文で判定する方式 | 4,842 |
| Result型としてエラーインスタンスをreturnし、if文で判定する方式 | 16,607 |
| エラーオブジェクトをthrowし、try-catchで判定する方式 | 15,051 |
| エラーインスタンスをthrowし、try-catchで判定する方式 | 18,095 |
全体サマリ表
凡例
- Result型としてエラーオブジェクトをreturnし、if文で判定する方式
- Result型としてエラーインスタンスをreturnし、if文で判定する方式
- エラーオブジェクトをthrowし、try-catchで判定する方式
- エラーインスタンスをthrowし、try-catchで判定する方式
CPUによってかなり差が出ているが、Intel CPUの13700と1265Uを比較した場合、例外を作らない1, 3のケースでは処理に大きな差がないが、例外を作る2, 4のケースでは有意な差が認められるので、モバイル向けとデスクトップ向けでCPUの処理効率に差があることがわかる。
AMD CPUと比較した場合、Node.js環境で例外を作らないケースではIntel CPUに大きく引けを取るが、ブラウザ上でのそれではパフォーマンスは高い。また例外を作るケースでもNode.js・ブラウザ共にIntel CPUと比較した場合のパフォーマンスが比較的よいという、面白い結果になっている。但しOSが違うことの影響もあるため、単純比較はできないが…。
あとがき
ひとまずtry-catchを使うと遅くなるということが確かめられたので良かったし、環境によって劇的遅くなるケースがあるというのは思わない収穫だった。
これを試そうと思った切欠はtry-catchが乱用されているコードを見てパフォーマンス劣化に繋がっているのではないかという疑問を抱いたからだ。try-catchでパフォーマンスの劣化が起きることは知識としても経験としても知っていたのだが、ちゃんとレポートしたことがなかったので今回まとめてみた。
try-catchの利用によりパフォーマンスの劣化が起きるというのは、古い時代にあった開発のお作法を知っている人であれば、それなりに常識だとは思うが、最近は知られていないか、知られていても意識していないことが少なくないと思われるので、今回記事にしてみた感じだ。
100万回の実行なので細かい話になるとは思うがパフォーマンスチューニングは細かいことの積み重ねでもあるので、むやみやたらに例外を使わないことは重要だと思う。そもそも例外は制御しづらいので、可能な限りif文で処理を書くことが望ましいだろう。
処理が遅延する原因としては二つあると考えていて、一つは例外生成時に顕著であることからスタックトレースの生成を初めとしたエラーオブジェクトの生成に時間がかかっているのと、もう一つはcatchでも遅延が出ることから、コールスタックから最寄りのcatchを辿るのに時間を取られていると思われる。今回の検証では特に出してないが、以前確認した時の記憶が確かであれば、catchに入らない限り、tryだけで顕著に処理が遅延することはなかったと思う。
あと、どうでもいいことだがconsole.log()で結果を出したときにEdgeだけObjectのKeyの順序が他と違ったので転記しているときに微妙に不便だった。何回やっても同じだったので恐らくEdgeだけキーをソートするアルゴリズムが違うのだと思う。まぁObjectとかHashとかMapとかDictionaryみたいなやつは順序が保証されないので別にいいっちゃいいんだけど、まさか実装によってソート方式が違うというのは思いもしなかった。
EdgeとChromeで処理結果が優位に違うのも、恐らくこれが原因なのだろう。分からないが多分JSのエンジンの実装が違う気がする。
それとLinuxのEdgeにはマウスジェスチャー機能がないという悲しいことも分かった。
参考
2024/02/17(土)CMSをadiaryに変えてよかったこと
投稿日:
以前WordPressで構築していたサイトが頻繁に落ちていることについて記事にしたが、adiaryに変えてからどうなったかというと、恐らく落ちなくなったと思う。
何故そう思ったかだが、今までGoogleにインデックスさせるときは毎回Search Consoleから手動登録していたが、そんなことをしなくても勝手にインデックスしてくれるようになったからだ。BingにもIndexNowを使わずとも勝手にインデックスされている。いや、BingのクローラーについてはIndexNowの有無による差を検証したことがないので有意に改善しているかは正直不明だが…w
少なくともこれでインデックスされやすくなり、以前よりアクセスしやすくなることだろう。読み込み時間が0.3秒変わるだけでブラウザバックが減るとかいう話も昔どっかで読んだ気がするし、0.3秒どころか6秒くらい改善してそうなので、効果はかなり期待できると考えている。
Markdownのレンダリングについても作者に要望を出しまくったので大分改善した。とはいえ、まだ問題点は残るので、そこはMarkdown parserを自作する事で上手いことやっていきたいと思う。結果としてadiaryへの乗り換えは大成功だったといえる。
adiaryは非常に素晴らしいCMSだと思うので、WordPressを使っていて重さに悩む人や、CDNなどの費用を節減したい人は検討されてもいいのではないだろうか?WordPressのように素晴らしいテーマや有益なプラグインは存在しないが、なければ作ればいいので、そういう気概のある人には非常にお勧めできると思う。
また本体やプラグイン、テーマが勝手にアップデートされることがないので「何もしてないのに壊れた」が起きないのもいいところだ。当然、その分の保守能力はサイト管理者に求められるが、本来ホームページ運営というのはそういうものである。一定のリテラシーがないとできないのは当然のことだ。少なくとも昔のインターネットでは常識だった筈だ。
何よりこのCMSは日本製だ、日本人なら日本製に拘ってみるというのもありだろう。
改善の余地は山ほどあると思うので、最近開発から遠ざかっていた人にも大変お勧めできる。adiaryはOSSなので、コントリビュートするのもよし、フォークするのもよしだ。逆にシンプルで複雑さがないので、これで必要十分というケースもあるだろう。
この機会に昔懐かしいPerlに触ってみるというのも一つの経験になるだろう。かつてCGIを書いていた人も、使っていただけの人も、どっちでもない人も、Perlという言語の魅力に触れてみたり、新しく発見してみる一つの機会になると思う。Perlの言語仕様はもしかしたら余り良くはないかもしれないが、夢中になって書いていれば、そんな言語でも新しい発見があったりして、きっと楽しいと思う。
いろんな意味で自分のホームページを作るという意味では非常に良いCMSだと思うので、私はそこが好きだ。
余談だが記事ID「0268」以降がadiaryの記事で、それ以前がWordPressの記事となる。厳密にいうとWordPressの記事の中には、はてなダイアリーやQiitaで書いた記事も入っているのだが、区別する術がないのでWordPressの記事ということで一緒くたにしている。特にない限りCMSの乗り換えはもうしないと思うので、この法則がずれることは恐らくないだろう。
因みに私がフォークしているバージョンでは暫定的にクリップボードの画像を直接アップロードできるように改造している。実験的な機能であるため動作保証などは一切しないが、もし画像が貼り付けられずに不便を感じる人がいたら使ってみてほしい。
2024/02/02(金)adiaryのHTMLを書き換える
skel
- 書き替えたいコードの所在をgrepする
skel/の中に該当する行を見つけるskel.local/に該当ファイルをコピーする- 該当行を編集
- ブログの管理>ブログを再構築する
plugin
skel書き換えでうまくいかない場合
- 書き替えたいコードの所在をgrepする
plugin/配下のmodule.htmlに該当する行を見つける- 該当行を編集
- プラグイン設定>リセット>再インストール
参考
- adiary開発マニュアル
- 大まかな全体の考えを知るのに役立つが細かい情報はなく、リファレンスとしては微妙
2024/02/01(木)WordPress運用の限界
前々からGoogle Search Consoleがエラーでクロールできないと言っていたのだが、最近サイトがダウンしている瞬間に出くわすことが増え、やっと意味が分かった。負荷によってMySQLに繋がらない状態になっているのだ(ブーストすると解除されたので、恐らく何かしら制限かかけられているのだろう)
かつてMovaleTypeからBlognに移った時はテキストDBだったので軽くなり、BlognPlusに移った時にDBがMySQLになったのでサイトが重くなったのは記憶に深いし、WordPressにしてさらに重くなったのも記憶にある。うちはさくらのレンタルサーバーで共用なのでDBが重いのだと思う。
私が遭遇するのは深夜帯が多いが、このサイトはIT企業の業務時間中にアクセスが増える傾向があるので、そういったケースでも落ちている可能性がある(ログを見ていなないので推測だが)
更に昨日WordPressのテーマをアップデートしてからYet Another Related Posts Plugin (YARPP)のカスタムテーマが意味不明なエラーを吐き、動かなくなった。
エラーの内容は以下の通りだが、意味不明である。同じ行で同じ名前の関数が再定義されているとか言われている。
Fatal error: Cannot redeclare get_post_data() (previously declared in /wp-content/themes/sango-theme-child/yarpp-template-thumbnail.php:3) in /wp-content/themes/sango-theme-child/yarpp-template-thumbnail.php on line 3
というわけで、WordPressに見切りをつけるかどうか迷っていた矢先だったので、もうWordPressを捨てようと思った。早々にMarkdown parserを書いてadiaryに乗り換えるか、或いは表示が崩れている今でも乗り換えたほうがいい気がしてきたくらいだ。
週末を目途にadiaryへの移行作業を行おうと思う。幸いなことにWordPressからadiaryにリダイレクトするための.htaccessは2024/01/23の記事分までは作ってあるので、ちょっと足せば使える。
markedをadiaryのMarkdown parserに噛まして何とかするのも試したのだが、さつき構文がHTML化されてadiaryのパーサーが上手く食べてくれず、頑張って再パースする必要がありそうなので諦めた。そもそもMarkedのパーサーも地味にバグっていたり、注釈の出力が結構不便だったり不満はあるので、自分でパーサーを書くのは全然ありだと思った。或いはEditor.mdをadiaryにねじ込んで、どうにかしてさつき構文のパーサーを組み込めれば、それも一つだと思う。(が、こいつはクライアントサイドでHTMLを捏ねるのでadiaryの仕組みと相性が悪い)
何よりパーサーを書こうとしただけでブログ記事はポコポコ湧くし、Perlは面白いしで、いろいろ発見があり、退屈な日常が無駄に忙しくなったので、これは是非ともやっていきたいし、やろうという感じで、一旦WordPressを捨てadiaryに移ろうと思う。しばらく色んな記事で表示が崩れるだろうが、現状でもサイト自体にアクセスできないことがあると考えれば大差のない話だと思うし、どうでもよくなった。
むしろ能動的にサイトをいじれるほうがいいし、ある日突然謎のアップデートでサイトが壊れるとか、そういうのは要らないので、平穏なadiaryに移れれば精神的にも安定できるかもしれない。正直WordPress 5でGutenbergが実装されたときとか、軽く絶望したわけで…。Classic Editorがなかったらやっていけないレベル。
というわけで、十数年ぶりの真っ当なサイト制作、再開していきますか~
