libcurlが使用するNSSにdentryが肥大化するバグがあった


- ある日、壁紙みたいに表示させてるモニタリングおいて、がっつりメモリリークしてるパターンに気づく。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/58788/93d9b318-de97-c5d6-31da-b4277d60aebc.png)

- とりあえず、アプリケーションエンジニアに状況を共有(サーバサイドも並行して調査)し、あるリリースからスタックし始めてるのでメモリリークしちゃってる箇所がないか確認してもらったけど、それっぽいところが見つからないという回答。


---

- 気になる子が居た
	- こいつ、スタックし続けているぞ...

```/proc/meminfo
(snip)
Slab:            1955484 kB
(snip)
```

```bash
# slabtop -o
(snip)
  OBJS ACTIVE  USE OBJ SIZE  SLABS OBJ/SLAB CACHE SIZE NAME
9575244 9575244 100%    0.19K 455964       21   1823856K dentry
(snip)
```

- クリアして様子見したけど、その後、同じ曲線を描きながらスタックし続けている。dentryはスタックするものだけど、こう短期間に値が増えるとかちょっと考えにくい

  ```bash
# sync && echo 2 >> /proc/sys/vm/drop_caches
  ```


- [dentryキャッシュが肥大化する事例](https://bugzilla.redhat.com/show_bug.cgi?id=1044666)にたどり着く

  ```
Cause: The NSS did not check whether the NSS_SDB_USE_CACHE environment variable was set to trye before calling the sdb_measureAccess internal function. 
Consequence: When using curl or libcurl, which depennds on nss, to make a HTTPS requests there were many "access" system calls to paths/directories/files that do not exist, and this bloated the dentry_cache.
Fix: NSS now avoids calls to sdb_measureAccess in lib/softoken/sdb.c s_open if NSS_SDB_USE_CACHE is "yes"
Result: The system calls to non-existent paths have gone down and curl HTTPS requests not longer cause bloats in in the directory entry cache.
  ```

- libcurlが使用するNSSにdentryが肥大化するバグがあるとのこと
  - NSSを3.16.0以降のバージョンにupdateして環境変数`NSS_SDB_USE_CACHE`に"YES"を記述すれば肥大化する問題は解決しそう...!

- アプリケーションエンジニアに再度ヒアリングすると、curlを使用した機能を新たにデプロイしたとのことで、原因の90%はこれだと推測。いざ計測。

- NSSのversion確認
  - versionは問題なさそう

  ```
$ yum list installed nss-softokn* *curl*
Loaded plugins: priorities, update-motd, upgrade-helper
15 packages excluded due to repository priority protections
Installed Packages
curl.x86_64                                                                                         7.40.0-3.52.amzn1                                                                         installed
libcurl.x86_64                                                                                      7.40.0-3.52.amzn1                                                                         installed
libcurl-devel.x86_64                                                                                7.40.0-3.52.amzn1                                                                         @amzn-updates/latest
nss-softokn.x86_64                                                                                  3.16.2.3-13.37.amzn1                                                                      @amzn-main/latest
nss-softokn-devel.x86_64                                                                            3.16.2.3-13.37.amzn1                                                                      @amzn-main/latest
nss-softokn-freebl.x86_64                                                                           3.16.2.3-13.37.amzn1                                                                      @amzn-main/latest
nss-softokn-freebl-devel.x86_64                                                                     3.16.2.3-13.37.amzn1                                                                      @amzn-main/latest
python27-pycurl.x86_64                                                                              7.19.0-17.12.amzn1                                                                        installed
  ```

- 環境変数`NSS_SDB_USE_CACHE`に`yes`記述
  - この辺はitamaeでプロビジョニングするけど、設定とかは割愛
     - 既存セッションもこの変数を使えるようにするにはサーバ再起動が手っ取り早い

  ```/etc/profile
(snip)
#Dentry Cache Prevention of hypertrophy
export NSS_SDB_USE_CACHE=YES
(snip)
  ```
  ```bash
$ env | grep NSS
NSS_SDB_USE_CACHE=YES
  ```

- 結果
  - curlを実行してもdentryはスタックせず、その後のメモリ使用量も上昇し続けることはなくなりました。
![スクリーンショット 2017-12-18 18.31.45.png](https://qiita-image-store.s3.amazonaws.com/0/58788/c43ef82b-778a-cc13-0c30-4a019dc1c68b.png "スクリーンショット 2017-12-18 18.31.45.png")