BaseDBのメモリ領域を変更したい

Oracle Databaseのデフォルトで決定されている
メモリのSGA/PGA領域のサイズを変更します。

# デフォルト値の確認
Autonomous Database (ADB)とBase Database (BaseDB)の比較をするための準備として、
それぞれのメモリ領域を一致させることが必要になりました。
変更後の値はそれぞれのDBで設定されている値を確認して決定します。

作成直後のBaseDBとADBのSGA/PGAの領域を確認します。

**BaseDBのデフォルト値**
```
SQL> SHOW PARAMETER pga_aggregate_target;
SQL> SHOW PARAMETER sga_target;
SQL> SHOW PARAMETER sga_max_size;

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
pga_aggregate_target                 big integer 3712M
sga_target                           big integer 14848M
sga_max_size                         big integer 14848M
```

**ADBのデフォルト値**
```
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
pga_aggregate_target                 big integer 6000M
sga_target                           big integer 16000M
sga_max_size                         big integer 595200M
```
今回はBaseDBのSGA/PGAをADBのSGA/PGAに変更して、
それぞれのSGA/PGAを一致させます。

# BaseDBのメモリサイズを変更する
spfileかpfileを書き換えれば、変更できるはず・・と思い
こんな流れで変更しようと思いました。

**spfile or pfileを書き換える → DB再起動**

イメージは想像できたものの、実際に実行するコマンドとかはあまり浮かばなかったので
実行したコマンドをメモに残します。

## spfile or pfile
そもそもspfileとpfileが何なのかを、これを機に復習しておきます。
どちらもパラメータファイルで、インスタンスやDBの構成情報が書かれているものです。
パラメータファイルは、停止状態→nomountへ移行するタイミングで読み込まれます。

:::note
**spfile**
・バイナリ形式のため、altersystem文での変更
・scopeを指定することによって、変更の適用範囲を設定する
　　memory　＝ 起動中のインスタンスにのみ適用、再起動後は以前の値が使用
　　spfile 　　＝ spfileに変更を書き込み、次回再起動時に適用
　　both 　   　＝ [デフォルト]起動中インスタンスに適用、次回再起動時も有効
:::

:::note
**pfile**
・テキスト形式のため、エディタで変更可能
・エディタで変更した内容を反映させるためには、再起動が必要
・altersystem文での変更も可能だが、一時的な変更で停止すると失われる
:::

いま使用しているファイルがどちらなのかを判断します。
```
SQL> SHOW PARAMETER spfile;

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
spfile                               string      +DATA/xx_236_IAD/PARAMETE
                                                 RFILE/spfile.xx.xx
```

spfileパラメータが設定されているので、spfileを使用していることがわかりました。
この使っているspfileパラメータを変更すれば、すぐにメモリサイズが変更できそうです

## spfileの変更
BaseDBの`sga_target 14848M`をADBの`16000M`に変更します。
```
SQL> alter system set sga_target = 16000M SCOPE=BOTH;
alter system set sga_target = 16000M SCOPE=BOTH
*
ERROR at line 1:
ORA-02097: parameter cannot be modified because specified value is invalid
ORA-00823: Specified value of sga_target greater than sga_max_size
Help: https://docs.oracle.com/error-help/db/ora-02097/
```
設定したい`16000M`は`sga_max_size`を超えているから設定できない
というエラーが発生しました。
```
SQL> SHOW PARAMETER sga_max_size

NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
sga_max_size                         big integer 14848M
```
たしかに`16000M`は`sga_max_size`超えちゃっているので、`sga_max_size`から変更します。



## pfileの作成
spfileはエディタで編集できないので、
編集できるpfileを作成してpfileから設定を変更することを試みます。
SQLを実行してpfileを作成します。
```
SQL> CREATE PFILE FROM SPFILE;
```
作成されていることを確認できました。(コマンド内★のファイル)
```
[oracle@test dbs]$ ls -l
total 24
-rw-rw---- 1 oracle asmdba   1544 Jan 23 05:00 hc_test.dat
-rw-r--r-- 1 oracle asmdba   2279 Jan 23 06:20 inittest.ora★
-rw-r----- 1 oracle oinstall 3079 May 14  2015 init.ora
-rw-r----- 1 oracle asmdba     24 Jan 23 04:52 lkTEST
-rw-r----- 1 oracle asmdba     24 Jan 23 04:52 lkTEST_236_IAD
-rw-r----- 1 oracle oinstall 2048 Jan 23 04:53 orapwtest
```
エディタを使用して必要箇所を変更して、DBを再起動します。

```
SQL> STARTUP PFILE='$ORACLE_HOME/dbs/inittest.ora';
ORA-27106: system pages not available to allocate memory
Additional information: 6506
Additional information: 1
```
エラーになりDBを実行できませんでした。
エラーの対処方法がわからなかったのでchatGPTに聞いてみると、
以下のように教えてくれました。
>`ORA-27106: system pages not available to allocate memory` エラーは、データベースがシステムメモリの割り当てを要求した際に、OSが要求を満たせない場合に発生します。
**HugePagesが設定されていない、または不足している**
OracleはSGAにHugePagesを利用することを推奨していますが、設定が不十分だとこのエラーが発生します。

:::note warn
他にも
`ORA-00093: Parameter pga_aggregate_limit outside valid range 12000M to 100000G.`
が発生しました。
`*.pga_aggregate_limit=12000m`
のように変更して対応しました。
:::


## HugePageの設定
そもそもHugePageが何かを簡単に確認しておきます。

::: note
**HugePage**
メモリを小さく分割した2MB程度の仮想メモリ（ページ）ではなく、
拡張された大規模なページ（=HugePage）を使用できる機能
:::

実際に使われる時メモリはページという2MB程度の大きさに分割され、
それぞれのプロセスはページをつなぎ合わせてメモリ空間を確保しています。
プロセスが使用しているページはアドレス変換テーブルに書かれるものの、
メモリ確保や解放のたびにいちいち書き直す必要があります。
HugePageは使用できる分割されたメモリである1ページが大きく、
アドレス変換テーブルを使用しないため、キャッシュの性能に大きく影響します。
[参考] [リソース設定(メモリ) NTTテクノクロス](https://www.ntt-tx.co.jp/column/dpdk_blog/20190122/#:~:text=HugePage%E3%81%A8%E3%81%AF%E5%8D%98%E8%AA%9E%E3%81%AE,2MB%E3%82%841GB%E3%81%8C%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%E3%80%82)

上記HugePageの説明とエラーメッセージを見比べると、おそらく
SGAにはHugePageが必要で、現在確保しているHugePageの領域以上の値を`sga_max_size`に設定してしまっていることでエラーになっているのでは？と理解することができました。

現在の設定を確認します。
```
[oracle@test dbs]$ grep Huge /proc/meminfo
AnonHugePages:         0 kB
ShmemHugePages:        0 kB
FileHugePages:         0 kB
HugePages_Total:    7796
HugePages_Free:     7796
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
Hugetlb:        15966208 kB
```
>`HugePages_Total`が Oracleが使用するSGAサイズに対応している必要があります。たとえば、`SGA_MAX_SIZE`が8GBの場合、`HugePages_Total`は 8GB ÷ 2MB（1ページサイズ） = **4096ページ** 必要です。

現在の`HugePages_Total`から逆算すると、設定できる`SGA_MAX_SIZE`の最大値は**15.22GB**
ということがわかります。
今回は16GBに設定したいので、**8192ページ**必要になります。

ここからはroot権限で実行していきます。
`/etc/sysctl.conf`を編集して、HugePageを設定します。
`vm.nr_hugepages`を先ほど計算した**8192**に変更します。
（★の部分）
```
fs.file-max = 6815744
kernel.sem = 250 32000 100 128
kernel.shmmni = 4096
kernel.shmall = 1073741824
kernel.shmmax = 4398046511104
kernel.panic_on_oops = 1
net.core.rmem_default = 262144
net.core.wmem_default = 262144
net.ipv4.conf.all.rp_filter = 2
net.ipv4.conf.default.rp_filter = 2
fs.aio-max-nr = 1048576
net.ipv4.ip_local_port_range = 9000 65535
kernel.panic = 10
fs.suid_dumpable = 1
kernel.core_pattern = core.%e.%p
net.ipv4.conf.all.arp_announce = 2
net.ipv4.conf.all.arp_ignore = 1
net.ipv4.conf.all.arp_filter = 1
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.ipv4.tcp_rmem = 4096 87380 134217728
net.ipv4.tcp_wmem = 4096 65536 134217728
net.core.netdev_max_backlog = 300000
net.ipv4.tcp_moderate_rcvbuf = 1
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
fs.aio-max-nr = 3145728
vm.min_free_kbytes = 524288
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
kernel.pid_max = 99999
kernel.unknown_nmi_panic = 1
vm.nr_hugepages = 8192★
```
変更を反映させて、実行前にサーバの総メモリサイズを確認しておきます。
```
[root@test etc]# sysctl -p
fs.file-max = 6815744
（略）
vm.nr_hugepages = 8192

[root@test etc]# grep Huge /proc/meminfo
AnonHugePages:         0 kB
ShmemHugePages:        0 kB
FileHugePages:         0 kB
HugePages_Total:    8192★
HugePages_Free:     8192
HugePages_Rsvd:        0
HugePages_Surp:        0
Hugepagesize:       2048 kB
Hugetlb:        16777216 kB

[root@test etc]# free -h
              total        used        free      shared  buff/cache   available
Mem:           31Gi        19Gi       1.8Gi       1.3Gi       9.5Gi       8.0Gi
Swap:           9Gi       2.0Mi         9Gi
```
HugePageの設定変更を確認できました。
メモリサイズも問題なさそうです！

## DB起動
HugePageを変更によって先ほどのエラーは解消されて、DBを起動できるはずです。
作成したpfileを指定して起動させます。
```
SQL> startup pfile='$ORACLE_HOME/dbs/inittest.ora';
ORACLE instance started.

Total System Global Area 1.6753E+10 bytes
Fixed Size                  5441368 bytes
Variable Size            2181038080 bytes
Database Buffers         1.4428E+10 bytes
Redo Buffers              138514432 bytes
Database mounted.
Database opened.
```
作成したpfileを使って、起動できました。
変更した値が正しく反映されているのか確認します。
```
SQL> SHOW PARAMETER pga_aggregate_target;
SQL> SHOW PARAMETER sga_target;
SQL> SHOW PARAMETER sga_max_size;
NAME                                 TYPE        VALUE
------------------------------------ ----------- ------------------------------
pga_aggregate_target                 big integer 6000M
sga_target                           big integer 16000M
sga_max_size                         big integer 16000M
```
設定した通りの値になりました！！
`sga_max_size`はHugePageで指定した値になっていることも確認できます。

# まとめ
エラーによってウロウロしてしまいましたが、
メモリサイズを変更するために実施した内容は以下です。

::: note
・spfileからpfile作成
・pfile変更
・HugePage設定変更
:::