からあげ日記

Webエンジニア的なこととか。

サーバのメモリ使用率が高い・増加し続けている時の対処法

サーバのメモリ使用率が高い時に、調査したこととその対処法です。

該当のサーバの用途 : kusanagi + WordPress + MySQL ( Conoha VPS 4GB )

調査

メモリの使用率確認

# dstat -m
------memory-usage-----
 used  buff  cach  free
2823M    0   776M  192M
2823M    0   776M  192M
2823M    0   776M  192M

4GB 中 2.8GB 使用。

# free -m
              total        used        free      shared  buff/cache   available
Mem:           3790         816         184         233        2789        2412
Swap:          3967           4        3963

ページキャッシュとバッファキャッシュが大部分。

ページキャッシュ ファイルシステムに対するキャッシュで、ファイル単位でアクセスする際に使用
バッファキャッシュ ディスクブロックに対するキャッシュで、ブロックデバイスに直接アクセスする際に使用

メモリの用途を確認

# slabtop

 Active / Total Objects (% used)    : 10520156 / 10645459 (98.8%)
 Active / Total Slabs (% used)      : 499661 / 499661 (100.0%)
 Active / Total Caches (% used)     : 67 / 95 (70.5%)
 Active / Total Size (% used)       : 1990202.24K / 2019348.50K (98.6%)
 Minimum / Average / Maximum Object : 0.01K / 0.19K / 8.00K

  OBJS ACTIVE  USE OBJ SIZE  SLABS OBJ/SLAB CACHE SIZE NAME
10153920 10153487  99%    0.19K 483520       21   1934080K dentry
184392 103697  56%    0.10K   4728   39     18912K buffer_head
106092 100896  95%    0.19K   5052   21     20208K kmalloc-192

メモリの使用の大部分が dentry_cache

dentry cache ディレクトリやファイル名と inode とを結びつけに使われるキャッシュ。
ディスクからのディレクトリエントリの読み取りをキャッシュする

存在しないディレクトリ情報( inode を持たない dentry )量を確認

# sar -v
Linux 3.10.0-514.6.1.el7.x86_64 (150-95-155-161)   06/29/2018   _x86_64_    (4 CPU)

12:00:01 AM dentunusd   file-nr  inode-nr    pty-nr
12:10:01 AM  10053432      1472     28047         0
12:20:01 AM  10052647      1472     27096         0
12:30:01 AM  10052899      1504     27339         0
12:40:01 AM  10053122      1504     27090         0
12:50:01 AM  10053338      1504     27276         0
dentunusd キャッシュされてしまっているが、存在しないディレクトリ情報( negative dentry )
file-nr システムで使用しているファイルハンドルの数
inode-nr システムで使用しているinodeハンドルの数
pty-nr システムで使用している疑似端末の数

対処法

  1. ファイルシステムのメモリバッファをディスクと同期させる
  2. dentry キャッシュを削除

1. ファイルシステムのメモリバッファをディスクと同期させる

メモリ内のオブジェクトのうち、変更後ディスクに書き込まれていないファイル(Dirtyオブジェクト)を確認

# grep 'Dirty' /proc/meminfo
Dirty:                40 kB

ファイルシステムのメモリバッファをディスクと同期させる

# sync

# grep 'Dirty' /proc/meminfo
Dirty:                 0 kB

2. dentry キャッシュを削除

# echo 3 > /proc/sys/vm/drop_caches
1 ページキャッシュの解放
2 slab オブジェクトの解放
3 ページキャッシュと slab オブジェクトの解放
4 ログ( KERN_INFO )への出力の ON / OFF を切り替える

結果

# free -m
              total        used        free      shared  buff/cache   available
Mem:           3790         808        2615         233         366        2543
Swap:          3967           5        3962
# dstat -m
------memory-usage-----
 used  buff  cach  free
2766M    0   745M  280M
2766M    0   745M  280M
2435M    0   270M 1087M
2362M    0   270M 1160M
1365M    0   270M 2157M
1362M    0   270M 2159M
 869M    0   270M 2653M
 868M    0   270M 2653M

🎉

( buff / cach の値が少ないので、メモリを増やしたほうが良さそう)

間違い等あればご指摘いただけると嬉しいです。

参考

減り続けるメモリ残量! 果たしてその原因は!? (1/3):Linuxトラブルシューティング探偵団 番外編(1) - @IT

qiita.com

s-tajima.hateblo.jp

okisanjp.hatenablog.jp

IntelliJ IDEA ( JetBrains Toolbox )のオープンソースライセンスを取得する

f:id:Karage_Ageta:20180514231410p:plain

取得しました 🎉

概要

IntelliJ IDEA & その他 JetBrains 社のツールには、オープンソースプロジェクトの開発用の Open Source License があります。

www.jetbrains.com

今回、自分の開発しているプロジェクトで無事取得が出来たので、その手順を書いておきます。

ちなみに、自分が取得したのは、 JetBrains Toolbox Subscription ( JetBrains All Products Pack ) という JetBrains 社の全てのツールが使えるライセンスでした。

オープンソースライセンス

オープンソースライセンスを申請するプロジェクトは、以下の条件を満たしている必要が有ります。

  • プロジェクトのリーダー、またはメインのコミッターであること
  • オープンソースの定義を満たしたプロジェクトであること
  • プロジェクトが資金援助を受けていない/特定の団体や企業、政府等のスポンサーがいないこと
  • 開発期間が3ヶ月以上であること
  • アクティブに開発がされていること
  • 定期的にリリースされていること

今回自分が申請したのは以下のプロジェクトです。

github.com

Android 用の画像選択( picker )のライブラリです。

リリース回数が少ないので申請が通るか不安でしたが、結論から言うと無事取得できました!

良かった!!🎉

申請手順

申込みは以下のページから行います。

www.jetbrains.com

Regular open source projects の項目の Apply をクリック。

入力内容はこんな感じ。

f:id:Karage_Ageta:20180612214107p:plain

項目 説明
Do we know you? 初申請の場合は No / 2回目以降は Yes
Project name プロジェクト名
Primary language(s) 主な使用言語
License type ライセンスの種類( Apache 2.0 , MIT 等)
Project age プロジェクトの開発期間
No. of developers 開発者数(必要なライセンス数)
City 市町村区
Country / region
Short description プロジェクトについての簡単な説明
Per-user licenses JetBrains のライセンスの種類
( All Products : JetBrains 社の全てのツールが使えるライセンス)
Team tools チームでの開発に必要なツールがあればチェックを入れる
Project website プロジェクトの Web サイト
(例 : https://github.com/KarageAgeta/android-image-picker
Repository URL リポジトリの URL
(例 : https://github.com/KarageAgeta/android-image-picker
License URL ライセンスの URL
(例 : https://github.com/KarageAgeta/android-image-picker/blob/master/LICENSE
Latest release URL 最新のリリースの URL
(例 : https://github.com/KarageAgeta/android-image-picker/releases
Name 名前( 名 姓 )
Email address メールアドレス
Project role プロジェクト上の役割(例 : project lead , team member)
Your role in project コミットログなどの、プロジェクトでの役割がわかる URL
(例 : https://github.com/KarageAgeta/android-image-picker/commits?author=KarageAgeta

最後に、 JetBrains のアカウントの規約に同意する場合はチェックを入れて [ Apply for free licenses ] をクリック。

申請したのが 2018/4/28 18:39 、ライセンスが届いたのが 2018/4/28 21:25 と、わずか3時間で届きました! 🙌

GitHubリポジトリを指定して申請する場合にやっておくと良さそうなのは、

  • README やプロジェクトの Web サイト等のプロジェクトの説明は英語で書く
  • Github の場合は LICENSE ファイルを設置する

辺りです。

ライセンスは README に明記しておくだけでも OK のようですが、 LICENSE ファイルを設置しておくといい感じに表示してくれるのでオススメです✨

f:id:Karage_Ageta:20180514234853p:plain

f:id:Karage_Ageta:20180514234916p:plain


これでオープンソースの開発が捗っちゃいますね!

1年後の再申請に向けて、またバリバリ開発していきたいと思います! (๑˃̵ᴗ˂̵)و✧

ちなみに、

Licenses can be used for non-commercial OS development only. Please consider purchasing separate licenses to work on commercial projects.

とあるように、こちらのライセンスはオープンソースの開発のみ使用可能で、仕事や営利目的の開発には使えないのでお気をつけ下さい。

Android Studio / Gradle でキャッシュ周りがおかしくなった際の対処

Android Studio や Gradle でキャッシュ周りがおかしくなったときの対処法。

たまに忘れるのでメモ。

クリーンビルド

DI 周りを変更したとき等

Build -> Clean Project

ローカルビルドキャッシュの削除

$ ./gradlew clean cleanBuildCache
$ ./gradlew --stop

Invalidate Cache

文法上特に問題ないにもかかわらず、 Android Studio でエラー(赤い破線)が出るとき等

File-> Invalidate Caches / Restart -> Invalidate and Restart

f:id:Karage_Ageta:20180227163840p:plain

Python3 のスクリプトを Systemd でデーモン化

Python3 のスクリプトを Systemd でデーモン化( Systemd にスクリプトを登録)する方法とAnsible のサンプルです。

環境は Ubuntu 16.04 (64bit) です。

環境

2017/12/12 時点。

Ubuntu

# cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=16.04
DISTRIB_CODENAME=xenial
DISTRIB_DESCRIPTION="Ubuntu 16.04.3 LTS"

# arch
x86_64

Systemd

# systemctl --version
systemd 229
+PAM +AUDIT +SELINUX +IMA +APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ -LZ4 +SECCOMP +BLKID +ELFUTILS +KMOD -IDN

Python

# cd <project_root>
# ./venv/bin/python3.6 --version
Python 3.6.2

Systemd にスクリプトを登録

手順

/etc/systemd/system/<app_name>.service にサービス設定ファイルを追加。

[Unit]
Description=My Task Scheduling Script

[Service]
Type=simple
KillMode=control-group
ExecStart=<project_root>/venv/bin/python3 <project_root>/run.py
Restart=on-failure
User=<user>
Group=<group>

[Install]
WantedBy=multi-user.target

※ グローバルではなく <project_root>/venv/bin/ 以下の python3 を使用

venv を使用してライブラリをインストールしているため、 venv 上の python3 を使用します。

Type サービスの起動完了を判定するタイミング
  • simple
    • フォアグラウンドで実行を継続。コマンド実行後即起動完了判定
KillMode グループ内にプロセスが残っている場合の処理
  • control-group
    • グループ内の全プロセスを停止
Environment 環境変数
ExecStart サービス起動コマンド
ExecStop サービス停止コマンド
Restart サービスプロセス停止時の再起動条件
  • on-failure
    • プロセスがzero exit code 以外で停止した場合
User サービス実行ユーザ
Group サービス実行ユーザのグループ

その他のオプションについては以下を参照。

https://www.freedesktop.org/software/systemd/man/systemd.service.html

ansible

sudoers でコマンドの実行許可の設定

root 以外の特定のユーザで実行したい場合は、 sudoers の設定も行う。

手順

/etc/sudoers.d/ などに追記する。

Cmnd_Alias MY_APP = /bin/systemctl start <app_name>.service , /bin/systemctl stop <my_app>.service , /bin/systemctl status <app_name>.service

<user>       ALL = (root) NOPASSWD:/bin/su, MY_APP
Cmnd_Alias コマンドの一覧に名前をつける

実行例

$ sudo /bin/systemctl status myappd.service


^[[0;1;32m●^[[0m <app_name>.service -My App
   Loaded: loaded (/etc/systemd/system/<app_name>.service; enabled; vend
or preset: enabled)
   Active: ^[[0;1;32mactive (running)^[[0m since Wed 2017-12-12 13:13:0
2 JST; 28s ago
  Process: 10403 ExecStop=<project_root>/venv/bin/python3
lask shutdown_scheduler (code=exited, status=0/SUCCESS)
 Main PID: 10412 (python3)
   CGroup: /system.slice/<app_name>.service
           └─10412 <project_root>/venv/bin/python3 <project_root>/run.py

Dec 12 13:13:02 <server> systemd[1]: Started My App.

ansible

参考

qiita.com

よろしくない設定や間違っている部分があればご指摘いただければ幸いです。

Fabric の sudo() でパスワードの入力をせずに処理を実行

Fabric でコマンドを実行する際にパスワードを聞かれてしまい、処理が失敗する場合。 shell=False オプションを追加する。

エラー内容

[<remote_server>] sudo: /bin/systemctl restart myapp.service
[<remote_server>] out: sudo password:

[<remote_server>] out: Sorry, user my_user is not allowed to execute '/bin/bash -l -c /bin/systemctl restart myapp.service' as root on <remote_server>.
[<remote_server>] out:


Fatal error: sudo() received nonzero return code 1 while executing!

Requested: /bin/systemctl restart myapp.service
Executed: sudo -S -p 'sudo password:'  /bin/bash -l -c "/bin/systemctl restart myapp.service"

Aborting.

対処法

shell=False オプションを追加する。

$ sudo('systemctl restart myapp.service', shell=False)

環境

2017/12/12 現在。

$ fab --version
Fabric3 1.12.post1
Paramiko 2.0.2

$ python3 --version
Python 3.6.2

参考

stackoverflow.com

Operations — Fabric documentation

len() で全角記号の長さが 2 になる / Unicode と variation selector

先日、こんなことがおきました。

どう考えてもおかしい気がする。

Twitter でつぶやいている ▶︎ は、Webサイト上の文章の処理中に出力された文字列をコピペしたものだったので、この文字自体がおかしいのではないかと思い調べてみることにしました。

環境

$ ./venv/bin/python3.6 --version
Python 3.6.2

調べてみた

  • text_copyed_symbol = '▶︎' : コピペした記号(ツイート内でつぶやいた記号)
  • text_triangle = '▶' : GoogleIMEで「さんかく」で変換して出て来る記号(右向黒三角)
./venv/bin/python3.6
Python 3.6.2 (default, Jul 17 2017, 16:44:45)

>>> text_copyed_symbol = '▶︎'
>>> len(text_copyed_symbol)
2
>>> text_triangle = '▶'
>>> len(text_triangle)
1

なんかおかしい。

>>> import unicodedata
>>> text_copyed_symbol.encode('unicode-escape')
b'\\u25b6\\ufe0e'
>>> text_triangle.encode('unicode-escape')
b'\\u25b6'
>>>
>>> b'\\u25b6\\ufe0e'.decode('unicode-escape')
'▶︎'
>>> b'\\u25b6'.decode('unicode-escape')
'▶'

\\ufe0e 誰やお前。

バイト文字に変換してみる。

>>> bytes(text_copyed_symbol, 'utf-8')
b'\xe2\x96\xb6\xef\xb8\x8e'
>>>
>>> b'\xe2\x96\xb6'.decode('utf-8','strict')
'▶'
>>> b'\xef\xb8\x8e'.decode('utf-8','strict')
'︎'

どうやら \xef\xb8\x8e は VARIATION SELECTOR のようです。

Unicode/UTF-8-character table - starting from code position FE00

U+FE0E ︎ \xef\xb8\x8e VARIATION SELECTOR-15

variation selector をつけることで絵文字と非絵文字を区別しており、また、絵文字にスタイルを付与しているようです。

d.hatena.ne.jp

qiita.com

そして、 \xef\xb8\x8e 自体は幅がなく、前の文字( \xe2\x96\xb6 )に結合してひとつの形になるようです。

つまりこの2文字カウントの謎の右向黒三角は、本来は右向き三角の絵文字( f:id:Karage_Ageta:20171207134217j:plain:h15 )だった、ということですね!

対処法

1. variation selector に対応しているパッケージを使う

grapheme は variation selector を考慮して文字数をカウントしてくれるようです。 github.com

2. variation selector を切り落とす(非推奨)

本当は variation selector 込で 1 文字として扱うのが一番ですが、切り落として無理やり 1 文字にするパターンです。

>>> import re
>>> r = re.compile(u'[\uFE0E\uFE0F]', re.UNICODE)
>>> r.sub(r'', text_copyed_symbol)
'▶'
>>>
>>> len(r.sub(r'', text_copyed_symbol))
1
>>> bytes(r.sub(r'', text_copyed_symbol), 'utf-8')
b'\xe2\x96\xb6'
>>> r.sub(r'', text_copyed_symbol).encode('unicode-escape')
b'\\u25b6'

参考

c4se.hatenablog.com

medium.com

「Ionic 2+ ミートアップ東京 #1 」に登壇しました

紹介しようと思いつつ忘れていたのですが、 2017/08/06 に行われた「Ionic 2+ ミートアップ東京 #1 」に登壇させていただきました。

「Ionic + Cordova アプリを自動デプロイ」というタイトルで、 CircleCI を使用して Ionic で作られたアプリを自動デプロイ・リリースする内容です。

資料

イベント概要

ionic-jp.connpass.com

どなたかのお役に立てば幸いです。