前置き
RACやOracle Restart構成でサービスを追加(srvctl)することはあれど、
シングルインスタンスの構成でサービスを追加する機会というのはなかなかありませぬ。
コンテナDBではPDBへの接続にサービスを利用しているようなのですが、
とある案件でPDBにたくさんサービスを付けたい!みたいな話になりまして。
しかもシングルインスタンス構成で。
最初は無邪気に初期化パラメータのservice_names
パラメータに複数のサービス名を登録してみたのですが、、、
本題
ということで、マニュアルなどなどをぐるぐる巡回して無事に追加することができました。
その時のことを備忘ということでまとめておきたいと思います。
サービスの作成
PDBにサービスを作成する時は、PDBに接続したうえで作成する必要があります。
SYSDBA権限を持つユーザでやりましょう。
DBMS_SERVICEパッケージには、特定のセキュリティ要件があります。
権限
このパッケージを使用するクライアントは、ALTER SYSTEM実行権限、およびV$SESSION表読込み権限を持っている必要があります。スキーマ
このパッケージは、SYSスキーマの下に作成する必要があります。ロール
このパッケージのEXECUTE権限は、DBAロールにのみ付与されます。
以下のプロシージャでサービスを作成します(複数可)
最低限、以下の2つで作成は可能です。欲張りさんはDBMS_SERVICEのマニュアル参照ください。
パラメータ | 説明 |
---|---|
service_name | サービス名を指定。 データディクショナリ用。64byteまで。 |
network_name | リスナーが認識する名前。 tnsnames.ora の SERVICE_NAME などでも使用する。 |
BEGIN
DBMS_SERVICE.CREATE_SERVICE(
service_name => 'new_service',
network_name => 'new_service');
END;
/
上記のプロシージャを複数回実行することで、1つのPDBに対して複数のサービスを紐付けることができます。ただ、それだけでは新しいサービスは使えないので、以下のコマンドでサービスを開始する必要があります。
BEGIN
DBMS_SERVICE.START_SERVICE(
service_name => 'new_service');
END;
/
これで新しいサービスが利用できるようになります。
SQL> select NAME, NETWORK_NAME, PDB from v$services order by 1;
NAME NETWORK_NAME PDB
---------------------------------------- ------------------------------ ----------
new_service new_service PDB
pdb pdb PDB
最後におまじないをかけておくと、少し早く使えるようになります。
alter system register;
$ lsnrctl status
...(略)...
サービス"new_service.local"には、1件のインスタンスがあります。
インスタンス"cdb"、状態READYには、このサービスに対する1件のハンドラがあります...
DBにドメイン設定(db_domainパラメータ)がある場合は、サービス名もドメイン付きのFQDNで指定する必要があります。ドメインなしで接続した場合は「ORA-12514: TNS: リスナーは接続奇術師でリクエストされたサービスを現在認識していません」が表示され接続できません。
$ sqlplus system@localhost.local:1521/new_service.local
...(略)...
Oracle Database 19c Enterprise Edition Release 19.0.0.0.0 - Production
Version 19.20.0.0.0
に接続されました。
SQL> show con_name
CON_NAME
------------------------------
PDB
以上でサービスの登録と開始の手順はおしまいです。
削除、変更なども同じプロシージャでできるのですが、詳細はDBMS_SERVICEプロシージャのマニュアル参照ください。
サービス系の情報表示
以下あたりを使うことでサービスの状態が分かります。
リスナーとかも見ておきたいですね。
ディクショナリ表
列名まで同じですが、v\$servicesとall_servicesで登録されている情報が異なります。
細かい動作までは検証できていませんが、v$services には開始しているサービスが表示されており、all_servicesにはDBMS_SERVICE.CREATE_SERVICE
で登録したサービス、alter system set service_names
で登録したサービスなどが登録されている様子。
他にも登録される条件(例えば、srvctl add service
で登録したサービス等)はあると思います。
例えば、先ほどの DBMS_SERVICE.CREATE_SERVICEのみを実行し、START_SERVICEを実行していない場合は以下のような表示になります(開始していないのでリスナーも認識しません)
select NAME, NETWORK_NAME, PDB from v$services order by 1;
NAME NETWORK_NAME PDB
---------------------------------------- ------------------------------ ----------
SYS$BACKGROUND CDB$ROOT
SYS$USERS CDB$ROOT
cdb.local cdb.local CDB$ROOT
cdbXDB cdbXDB CDB$ROOT
pdb pdb PDB
NAME NETWORK_NAME PDB
---------------------------------------- ------------------------------ ----------
pdb pdb PDB
※開始されているサービスであれば、CDBで実行することですべてのPDBのサービスを確認できますね。
all_services表の場合はCDB, PDBそれぞれ、自分のサービスしか認識していない。
select NAME, NETWORK_NAME, PDB from all_services order by 1;
NAME NETWORK_NAME PDB
---------------------------------------- ------------------------------ ----------
SYS$BACKGROUND CDB$ROOT
SYS$USERS CDB$ROOT
cdb.local cdb.local CDB$ROOT
cdbXDB cdbXDB CDB$ROOT
NAME NETWORK_NAME PDB
---------------------------------------- ------------------------------ ----------
PDB PDB PDB
new_service new_service PDB
初期化パラメータ
初期化パラメータ SERVICE_NAMES は19cから非推奨パラメータとなっています。
また、PDB個別には設定できないパラメータです。つまり、CDBに接続するためのサービスしか作成することができないため、(CDBに接続するのはたいていが管理者や保守員だろうから)個人的には使わない方針がよいかと思います。
なお、service_names を変更するたびに、ディクショナリ表に履歴という名のゴミが蓄積されていきます。何気にこの理由も重要です(メンテが大変)
select NAME, VALUE from v$parameter
where NAME = 'service_names';
NAME VALUE
---------------------------------------- ----------------------------------------
service_names cdb.local
最終的にはリスナー経由で接続することになるので、リスナー登録されているかは重要。
19c からOSの環境変数 ORACLE_PDB_SID を設定することで Beq 接続がPDBでもできるようになりましたが、今回の趣旨からは逸れてしまうので割愛してます。
リスナーステータス
$ lsnrctl status LISTENER
...(略)...
サービスのサマリー...
サービス"06cb96ed80151311e065322c6b579ae4.local"には、1件のインスタンスがあります。
インスタンス"cdb"、状態READYには、このサービスに対する1件のハンドラがあります...
サービス"06cc0df247892328e065322c6b579ae4.local"には、1件のインスタンスがあります。
インスタンス"cdb"、状態READYには、このサービスに対する1件のハンドラがあります...
サービス"cdb.local"には、1件のインスタンスがあります。
インスタンス"cdb"、状態READYには、このサービスに対する1件のハンドラがあります...
サービス"cdbXDB.local"には、1件のインスタンスがあります。
インスタンス"cdb"、状態READYには、このサービスに対する1件のハンドラがあります...
サービス"pdb.local"には、1件のインスタンスがあります。
インスタンス"cdb"、状態READYには、このサービスに対する1件のハンドラがあります...
コマンドは正常に終了しました。
「登録されてないな?」と思っ時に使いがちな魔法の言葉
alter system register;