【アーキテクチャ】クライアントから Oracle Databaseへの接続

# Oracle Net Services
Oracleをネットワーク環境で使用するために必要なコンポーネント群をまとめた総称

- Oracle Net：クライアント／サーバ間のネットワーク通信を実現するソフトウェア
- Oracle Net Listener（リスナー）：リオート接続を受け付ける常駐型のサーバプロセス
- Neto Configuration ASsistant：リスナーの構成と、Oracle Net Servicesの基本的な構成を行う GUIツール
- Net Manager：Oracle Net Services全般の設定を行うGUIツール

## 設定ファイル
|ファイル名|配置先|説明|
|:---|:---|:---|
|listener.ora|・データベースサーバ|リスナーの構成情報を記述する設定ファイル|
|tnsnames.ora|・クライアントマシン<br>・データベースサーバ|リスナーとOracleに関する接続情報（ネットサービス名）を記述する設定ファイル|
|sqlnet.ora|・クライアントマシン<br>・データベースサーバ|Oracle Netに関する各種パラメータの設定ファイル|

## 設定ファイルの読み込み順（Linux）
1. $HOME（ホームディレクトリ）：ユーザレベルの設定ファイル
2. TNS_ADMIN：環境変数指定
3. /etc：システムレベルの設定ファイル
4. $ORACLE_HOME/network/admin：デフォルトの設定ファイル

# インスタンスへの接続方法
## ローカル接続
インスタンスが稼働するデータベースサーバ上のクライアントアプリケーションから、リスナーを介さずにインスタンスにアクセスする場合のみ使用できる接続方法。

- ORACLE_SID環境変数に接続先のインスタンス名を設定してOracle独自のノード内通信方法を使用
- Oracle Net Servicesの構成は不要
- 使用する場面
    - データベースの起動／停止などの管理作業
    - スタンドアロン環境
    - 単一データベースのバッチ処理

<img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141308/8898f9a7-6507-7c4c-98a2-0e7c89668eb8.png">
1. サーバにログイン
2. セッション確立（ローカル接続）

## リモート接続
データベースサーバ以外のクライアントマシンのクライアントアプリケーションから、ネットワーク（TCP/IP）を経由し、リスナーを介してインスタンスにアクセスする場合に使用する接続方法。

- Oracle Netとネットワークを介して通信をする
- Oracle Net Servicesを構成する必要がある
- データベースサーバでリスナーの起動が必須

<img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141308/60827abd-f576-0a9c-3470-291fb1a0160d.png">
1. 接続要求
2. サーバ・プロセス生成
3. セッション確立（リモート接続）

# リスナー
クライアントアプリケーションからネットワークを経由して送信されたインスタンスへの接続要求を受け付けるプロセス。接続を受け付けたリスナーは、接続元情報をサーバプロセスに受け渡し、以後の処理をサーバプロセスに引き継ぐ。
接続を引き継いだ時点でサーバプロセスとクライアントアプリケーションでセッションが確立される。セッションの確立後は、リスナーはそのセッションの処理に関与しない。

11gまでは、PMONプロセスがリスナーへの情報更新を行なっていたが、12cからはLREGプロセスがリスナーへの情報更新を行う。ログの service_update間隔を見るとASMは1分強、インスタンスは10分くらい

<img width="400" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141308/7136c223-1f8d-a784-1adf-a67e592532a8.png">

送信される情報

- インスタンス名
- データベース・サービス名
- サービス・ハンドラ（ディスパッチャ、専用サーバプロセス）のタイプとアドレス

## リスナーの構成情報（listener.ora）
- リスナーのリスニング用プロトコルアドレス
    - TCP
        - ホスト名もしくはIPアドレス
        - TCPポート番号
    - SDP
- リスナーが接続を中継するインスタンスの情報（省略可能）
    - グローバルデータベース名
    - ORACLE_SID

## 接続記述子
クライアントマシンから Oracle Netを使ってリモート接続をするときのリスナープロトコルアドレスと接続先インスタンスの情報から構成されるのが接続記述子。

- 接続記述子
    - リスナーのプロトコルアドレス
    - 接続先インスタンスの情報

```:例）接続記述子
(DESCRIPTION=
  (ADDRESS=(PROTOCOL=tcp)(HOST=dbserver)PORT=1521))
  (CONNECT_DATA=(SERVICE_NAME=orcl)))
```

<img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141308/0fb87d89-465b-0796-440c-62c12ea8c06f.png">
0. リスニング：リスニング用プロトコル
1. 接続要求：リスナーのプロトコルアドレスに接続要求
2. サーバプロセス生成：接続先のインスタンスを決定
3. セッション確立：インスタンスと接続

## ローカル・ネーミング・メソッド
ネット・サービス名（接続識別子）をtnsnames.oraに追加し、ネット・サービス名から接続記述子を取得する。

```:例）接続識別子（tnsnames.ora）
ORCL=　　　　<<<-- 上記接続記述子の別名（ショートカット）
(DESCRIPTION=
  (ADDRESS=(PROTOCOL=tcp)(HOST=dbserver)PORT=1521))
  (CONNECT_DATA=(SERVICE_NAME=orcl)))
```

# サーバプロセス
インスタンスに接続されたクライアント・プロセスの要求を処理するために、サーバプロセスが作成される。
クライアント・プロセスは常に別のサーバプロセスを介してデータベースと通信する。

- アプリケーションを介して発行されたSQL文の解析し、実行（問い合わせ計画の作成／実行含む）
- PL/SQLコードの実行
- データファイルからデータベース・バッファ・キャッシュにデータ・ブロックを読取
- アプリケーションが情報を処理できるような方法で結果を戻す

<img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141308/53b321d6-a0cb-4b72-852e-a25dbd357eb6.png">
0. OSに新しいプロセスを割り当ててもらう（サーバプロセスのこと）
1. OS上のメモリ割り当て、Oracle用に初期化
2. SGAとやりとりするための情報取得、登録
3. パラメータ読み込み、初期化SQLの実行

これらのことをするため接続を確立する処理は重く、時間がかかるその後、クライアントから依頼されたSQLを実行するため都度接続のSQL文は処理時間がかかる。

サーバプロセス生成時のCPU使用状況は、vmstatのSYSTEM部分に表示される。

## コネクションプール
サーバプロセスを1つのアプリケーションが占有するのではなく、みんなで仲良く空いているサーバプロセスを使う方法。データベース接続オブジェクトのキャッシュ。

<img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141308/223183dd-6118-2241-363b-85002d370bad.png">

1. コネクション生成
3. 獲得
4. 返却
1. コネクション切断

- 接続プールを使うメリット
    - 新しい接続オブジェクトが作成される回数を減らす
    - 接続オブジェクトの再利用を促す
    - 接続取得プロセスを短縮する
    - 接続オブジェクトを主導で管理するために必要な労力を削減する
    - 失効した接続を最小限にする。
    - 接続の維持に消費されるリソース量を制御する。
- 接続プールのデメリット
    - アイドル状態のコネクションは、メモリリソースを無駄に消費する

### UCP（Universal Connection Pool）
アプリケーションは、UCP for JDBCプール対応のデータソースを使用して、UCP JDBC接続プール・インスタンスから接続を取得する。

実際の本番環境に導入していましたが、感想としては優秀！素晴らしく優秀に感じました。
メンテナンスで１ノードずつダウンさせる時なんて、アプリケーションに影響なく即接続可能ノードに移動してくれる。

<img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141308/f66e97d9-7572-f8f7-8dc6-a55b6b72a7fe.png">
1. アプリケーションは、接続ハンドルをプールから流用してデータベースで処理を実行
2. 処理が完了すると、接続はクローズされ、接続ハンドルはプールに返されて再利用できるようになる

### DRCP（データベース常駐接続プーリング）
一般的なWebアプリケーション使用のシナリオで、専用サーバの接続プールを提供する。
Webアプリケーションは、データベースへの接続を取得し、その接続を短時間使用した後、接続を解放する。DRCPを使用すると、データベースは同時接続数を数万まで増やすことができる。

本番導入前に検証環境で気づくことができたバグが、シャットダウンコマンドを実行しても落ちなくなるというもの。とりあえず個別パッチを適用して回避したけど、他にもいろいろある様子。

<img width="400" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141308/1e4a2033-9dfe-7f93-a75e-78a929167041.png">

1. データベース・アクセスをリクエストする
2. 接続ブローカがプールから、サーバ・プロセスを選択してクライアントに渡す
3. クライアントは、リクエストが処理されるまで、サーバ・プロセスに直接接続する
4. サーバでの処理が終了すると、サーバ・プロセスはプールに戻され、クライアントからの接続はブローカにリストアされる

※ データベース常駐接続プールから接続を取得したクライアントは、接続ブローカ（バックグランド・プロセス）に接続する<br>接続ブローカはプール機能を実装して、プールされたサーバをクライアント・プロセスからのインバウンド接続間で多重化する

- メリット
    - 中間層プロセス内のスレッド間で接続を共有する、中間接続プールを補完する
    - 複数の中間層プロセスんいわたってデータベース接続を共有できるようにする。これらの中間プロセスは、中間層ホストが同一の場合と異なる場合がある。
    - 多数のクライアント接続のサポートに必要な、主要データベース・リソースを大幅に削減できる。
    - 中間層接続プーリングを実行できないPHPやApachサーバなど、マルチ・プロセスのシングルスレッド・アプリケーション・サーバを含むアーキテクチャでプーリング実行できるようになる。

# 専用サーバ接続と共有サーバ接続の違い
## 専用サーバ接続
デフォルトの接続方法で、1つのセッションごとに、1つのサーバプロセスが起動する。
ユーザが活発にデータベース・リクエストをしていない場合でも、専用サーバ・プロセスはそのまま残る。

<img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141308/77708ea7-1f8e-ff73-6b61-d8e8051207f3.png">

1. 接続要求
2. プロセス生成
3. セッション確立
    4. 3-A) 要求／応答
    5. 3-B) 要求／応答

- クライアント・プロセスと専用サーバ・プロセスが同じコンピュータで実行される場合、プログラム・インタフェースは、ホスト・オペレーティング・システムのプロセス間通信メカニズムを使用してジョブを実行する
- クライアント・プロセスと専用サーバ・プロセスを別々のコンピュータで実行する場合は、プログラム・インターフェイスがプログラム間の通信メカニズム（ネットワーク・ソフトウェアやOracle Net Serviceなど）を提供する

## 共有サーバ接続
DBサーバ側で実施するコネクションプーリングの形態。ディスパッチャが共有サーバとの通信を中継し、SQL単位で共有サーバへ処理を振り分けます。既存のアプリケーションを変更がいらない。

<img width="500" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/141308/87c0417c-ce0e-8405-1778-33c127e157c2.png">

1. 接続要求
2. ディスパッチャによりSQL単位で共有サーバへ処理振り分け

コネクションプール管理モジュール＝ディスパッチャ
ディスパッチャは、接続形態が専用サーバ構成とは異なり複雑になる。同一のセッションでも異なる共有サーバをまたがって処理が実施されるため、SQLトレースなどを取得して分析を行うなどの作業も困難。現在ではアプリケーション側のコネクションプーリングがあるため、ほとんど使用されていない。まれに、大量のアイドル接続が存在するときや、物理接続の生成／切断が頻繁に行われるコネクションプーリングを使用せざるを得ない時などに併用する場合がある。