検索

クリアフィルター
記事
Toshihiko Minamoto · 2023年9月5日

整合性チェック: 高速化と低速化

Caché と InterSystems IRIS データベースの[整合性](https://docs.intersystems.com/irislatest/csp/docbookj/DocBook.UI.Page.cls?KEY=GCDI_integrity)は、システム障害から完全に保護されてはいますが、物理ストレージデバイスが保管しているデータは、デバイスの障害によって破損してしまいます。  そのため、多くのサイトでは、データベースの整合性チェックを定期的に実行するように選択しており、特に特定のバックアップが災害時に信頼できるかどうかを検証するためにバックアップが行われています。  システム管理者がストレージの破損を伴う災害に対応するために、整合性チェックも緊急に必要となる場合もあります。  整合性チェックはチェックされているグローバルの各ブロック(すでにバッファーにない場合)を、グローバル構造で指示された順序で読み取る必要があります。 これには膨大な時間がかかりますが、**整合性チェックは、ストレージサブシステムが維持できる限り高速に読み取ることができます**。  一部の状況においては、できる限り迅速に結果を取得するために、そのように実行することが望ましい場合がありますが、  他の状況においては、ストレージサブシステムの帯域幅の過剰な消費を避けるために、整合性チェックをより保守的に行う必要があります。  ## 攻撃への対応計画 以下の概要は、ほとんどの状況に対応します。  この記事の残りの部分では、以下に示すいずれの攻撃にも対応するため、または他の対応方針を導き出すために必要な情報を詳しく説明しています。  1. Linux を使用しており、整合性チェックが低速化している場合は、非同期 I/O を有効にする作業について以下の情報をご覧ください。  2. 隔離された環境で実行しているか緊急に結果が必要であるため、整合性チェックをできるだけ素早く完了する必要がある場合は、マルチプロセス整合性チェックを使って、複数のグローバルまたはデータベースを並行してチェックします。  実行中の同時読み取り数の制限は、プロセス数 x 各プロセスが実行する同時非同期読み取りの数(デフォルトでは 8、または非同期 I/O が無効になっている Linux を使用している場合は 1)です。  平均はこの半分である場合があることを考慮し、ストレージサブシステムの能力と比較します。  たとえば、ストレージが 20 個のドライブにストライプ化されており、プロセスごとにデフォルトで 8 つの同時読み取りが行われる場合、ストレージサブシステムの全能力を得るには 5 つ以上のプロセスが必要になる可能性があります(5*8/2=20)。 3. 整合性チェックの速度をプロダクションに対するインパクトに合わせて調整する場合、まず、マルチプロセス整合性チェックのプロセス数を調整してから、必要に応じて SetAsyncReadBuffers を調整します。  長期的なソリューション(および誤検出の排除)については、以下の「整合性チェックの分離」をご覧ください。 4. すでに単一のプロセスに限定されており(1 つの非常に大きなグローバル制約またはその他の外部制約がある場合)、整合性チェックの速度の増減を調整する必要がある場合は、以下の SetAsyncReadBuffers 調整パラメーターをご覧ください。 ## マルチプロセス整合性チェック 整合性チェックをより素早く完了させる(より高い速度でシステムリソースを使用する)ための一般的なソリューションは、複数の並列プロセスで作業を分割することです。  整合性チェックの一部のユーザーインターフェースと API は分割するようになっていますが、単一のプロセスを使用するものもあります。  プロセスへの割り当てはグローバルごとに行われるため、1 つのグローバルのチェックは必ず 1 つのプロセスによって行われます(Caché 2018.1 より前のバージョンでは、グローバルではなくデータベースによって作業が分割されていました)。 マルチプロセス整合性チェックの主要 API は、**CheckList^Integrity** です(詳細は[ドキュメント](https://docs.intersystems.com/irislatest/csp/docbookj/Doc.View.cls?KEY=GCDI_integrity#GCDI_integrity_verify_utility)を参照)。 一時グローバルに結果を収集して、Display^Integrity によって表示されます。 以下は、5 つのプロセスを使って 3 つのデータベースをチェックしている例です。 ここでデータベースリストのパラメーターを省略すると、すべてのデータベースがチェックされます。 set dblist=$listbuild(“/data/db1/”,”/data/db2/”,”/data/db3/”) set sc=$$CheckList^Integrity(,dblist,,,5) do Display^Integrity() kill ^IRIS.TempIntegrityOutput(+$job) /* 注意: 結果を表示するだけであれば、上記の ‘sc’ を評価する必要はありませんが...    $system.Status.IsOK(sc) - 正常に実行され、エラーは見つからなかった    $system.Status.GetErrorCodes(sc)=$$$ERRORCODE($$$IntegrityCheckErrors) // 267                            - 正常に実行されたが、エラーが見つかった。    その他の値 - 問題により、一部が実行できなかった。‘sc’ に複数のエラーコードがある可能性あり。うち 1 つは $$$IntegrityCheckErrors の可能性がある。 */ このように CheckList^Integrity を使用するのが、私たちが求めている制御レベルを達成する最も簡単な方法です。  管理ポータルのインターフェースと整合性チェックタスク(組み込み、ただしスケジュールなし)は複数のプロセスを使用しますが、目的に適う十分な制御が提供されていない場合があります。* 他の整合性チェックインターフェース、特にターミナルユーザーインターフェースの ^INTEGRIT または ^Integrity、および Silent^Integrity は、単一のプロセスで整合性チェックを実行します。 したがって、これらのインターフェイスは、可能な限り早くチェックを完了することはできず、使用するリソースも少なくなります。  ただし、目に見える結果を得られるというメリットがあります。ファイルにログされるか、グローバルごとにチェックされる過程で十分に定義された順番でターミナルに出力されます。  ## 非同期 I/O 整合性チェックプロセスは、グローバルの各ポインターブロックを一度に 1 つずつ、それが指すデータブロックのコンテンツに対して検証しながら行われます。  データブロックは非同期 I/O で読み取られ、ストレージサブシステムが処理できる多数の読み取りリクエストを処理し続け、それぞれの読み取りが完了するたびに検証が実行されます。  Linux のみ: 非同期 I/O は、ダイレクト I/O と組み合わせた場合にのみ効果がありますが、ダイレクト I/O は InterSystems IRIS 2020.3 までデフォルトで有効になっていません。  これは、Linux 上で整合性チェックに時間がかかりすぎるという多くのケースの原因です。  幸いにも、Cache 2018.1 と IRIS 2019.1 以降では、.cpf ファイルの [config] セクションで **wduseasyncio=1** を設定して再起動することで有効にできます。  このパラメーターは、ビジー状態のシステムにおいて I/O スケーラビリティを得るために一般的に推奨されており、Caché 2015.2 以降の Linux 以外のプラットフォームでデフォルトとなっています。  これを有効にする前に、データベースキャッシュ(グローバルバッファー)用に十分なメモリが構成されていることを確認してください。ダイレクト I/O を使用すると、データベースは Linux では(冗長して)キャッシュされなくなるためです。  有効でない場合、整合性チェックによって行われる読み取りは同期的に行われるため、ストレージで効率よく使用できません。  すべてのプラットフォーム: 整合性チェックプロセスが一度に実行する読み取りの数は、デフォルトで 8 に設定されています。  1 回の整合性チェックプロセスがディスクから読み取る速度を変更する必要がある場合は、このパラメーターを調整できます。単一のプロセスをより素早く完了する場合は増やし、ストレージ帯域幅の使用を抑える場合は減らします。  以下の点に注意してください。 * このパラメーターは整合性チェックプロセスごとに適用されます。  複数のプロセスが使用される場合、プロセスの数とこの実行中の読み取りの数を乗算します。同時整合性チェックプロセスの数の変更にははるかに大きな影響があるため、最初に行われるのが通例です。  各プロセスは、特に計算時間によって制限されるため、このパラメーターの値の増加のメリットには制限があります。 * これは、ストレージサブシステムの同時読み取りの処理能力にのみ適用されます。 データベースが単一のローカルドライブに格納されている場合には、値を高くしても何のメリットもありませんが、数十個のドライブでストライプされているストレージアレイであれば、同時に数十個の読み取りを処理できます。 %SYS ネームスペースからこのパラメーターを調整するには、**do SetAsyncReadBuffers^Integrity(**value**)** を使用します。 現在の値を確認するには、**write $$GetAsyncReadBuffers^Integrity()** を使用します。 変更は、次のグローバルがチェックされるときに適用されます。  現時点では設定はシステムの再起動によって永続されませんが、SYSTEM^%ZSTART に追加することが可能です。 ディスク上でブロックが連続している(またはほぼ連続している)場合に、各読み取りの最大サイズを制御する同様のパラメーターがあります。  このパラメーターはそれほど必要ではありませんが、ストレージレーテンシの高いサブシステムまたはブロックサイズのより大きなデータベースの場合は、微調整を行うとメリットが得られる可能性があります。  値は 64KB 単位であるため、値 1 は 64KB、4 は 256KB、のようになります。0(デフォルト)にすると、システムによって選択され、現時点では 1(64KB)が選択されるようになっています。  このパラメーターの ^Integrity 関数は、上述の関数と同様に **SetAsyncReadBufferSize** と **GetAsyncReadBufferSize** です。 ## 整合性チェックの分離 多くのサイトでは、直接プロダクションシステムで定期的な整合性チェックを実行しています。 もちろん最も単純な構成ではありますが、理想的ではありません。  ストレージ帯域幅に対する整合性チェックの影響についての懸念だけでなく、同時データベース更新アクティビティによって、(チェックアルゴリズムには対策が組み込まれてはいるものの)誤検出エラーが発生する可能性もあります。  そのため、プロダクションで実行された整合性チェックから報告されるエラーを、管理者が評価または再チェックする必要があります。 多くの場合、さらに優れたオプションが存在します。  ストレージスナップショットまたはバックアップイメージを別のホストにマウントする方法です。そこでは、分離された Caché または IRIS インスタンスによって整合性チェックが実行されます。  こうすることで、誤検出の可能性が防止されるだけでなく、ストレージもプロダクションから分離されていれば、ストレージ帯域幅を最大限に利用してはるかに素早く完了するように整合性チェックを実行できます。  この方法は、整合性チェックがバックアップの検証に使用されているモデルによく適しており、検証されたバックアップによって、バックアップが作成された時点でのプロダクションが効果的に検証されます。  また、クラウドと可視化プラットフォームを使用すれば、さらに簡単にスナップショットから使用可能な分離環境を確立することができます。   * * * * 管理ポータルのインターフェース、整合性チェックタスク、および SYS.Database の IntegrityCheck メソッドはかなり多数のプロセス(CPU コアの数に等しい数)を選択するため、多くの状況で必要な制御ができなくなります。 管理ポータルとタスクも、同時更新によって発生した可能性のある誤検出を特定するために、エラーを報告したグローバルの完全な再チェックを実行します。 この再チェックは、整合性チェックアルゴリズムに組み込まれた誤検出対策を超えて行われ、時間がさらにかかるため、状況によっては望ましくない場合があります(再チェックは単一プロセスで実行され、グローバル全体をチェックします)。 この動作は今後変更される可能性があります。
記事
Shintaro Kaminaka · 2021年10月18日

FHIRリポジトリをカスタマイズしよう!パート2(カスタムOperation編)

## 特報!! この記事の中でご紹介している、FHIRオペレーションのデモを含め、FHIR PathやFHIRプロファイル対応などの2021.1のFHIR関連新機能をご紹介するウェビナーが、**2021年10月21日 12:30~13:00** に開催されます!!ご興味ある方はこちらからご登録ください!! ### [InterSystems IRIS 開発者向けウェビナーシリーズ](https://www.intersystems.com/jp/iris-tech-webinar/) 開発者の皆さん、こんにちは。 今日は前回の[FHIRリポジトリをカスタマイズしよう!パート1](https://jp.community.intersystems.com/node/504516)の記事に続き、パート2として、カスタムオペレーションの実装方法をご紹介したいと思います。この記事で紹介している内容のFHIRリポジトリカスタムオペレーションに関するドキュメントマニュアルは[こちら](https://docs.intersystems.com/irisforhealthlatest/csp/docbookj/DocBook.UI.Page.cls?KEY=HXFHIR_server_customize_operations)になります。 この記事はIRIS for Health 2021.1 をベースに記載しています。バージョンによって実装方法が異なるケースも考えられますので、該当のバージョンのドキュメントをご参照ください。場合によっては新しいバージョンへアップグレードもご検討ください。 ## FHIRのOperation(オペレーション)とは? まず、FHIRのOperationについて、簡単にご紹介したいと思います。 HL7 FHIR公式ページの[Operationのページ](http://hl7.org/fhir/operations.html)には以下のように記載されています。 > The RESTful API defines a set of common interactions (read, update, search, etc.) performed on a repository of typed resources. These interactions follow the RESTful paradigm of managing state by Create/Read/Update/Delete actions on a set of identified resources. **While this approach solves many use cases, there is some functionality that can be met more efficiently using an RPC-like paradigm, where named operations are performed with inputs and outputs (Execute).** FHIRにおけるデータのアクセスがRESTのCRUDを基本とするのはご存知の通りですが、RPC的なアプローチでより効率的なデータアクセス、データ処理を実現しようというアプローチがFHIRのOperationと言えます。 HL7 FHIR公式ページで規定されているOpeartionは[こちら一覧のページ](http://hl7.org/fhir/operationslist.html)に記載されています。 代表的な所では、Patientリソースで指定できる *$everything* オペレーションや、Observationリソースで指定できる *$lastn* オペレーションがありますので紹介します。 # $everything オペレーション *$everything* オペレーションはPatientリソースと組み合わせて使用します。詳細は[こちらのページ](http://hl7.org/fhir/patient-operation-everything.html)を参照してください。 IRIS for Health のFHIRリポジトリの場合は、リソースの論理IDまで指定して ``` GET /Patient/5/$everything ``` のように指定して実行できます。 この場合、Patientリソースの論理ID=5に紐づいた関連するリソース(Observation, MedicationRequest, Procedure, Encounter など)を自動的に収集してBundle形式でクライアントに返してくれます。 例えばある患者さんの診療情報を一覧として見せたい場合などには便利な機能です。 # $lastn オペレーション *$lastn* オペレーションはObservationリソースと組み合わせ使用します。詳細は[こちらのページ](http://hl7.org/fhir/observation-operation-lastn.html)を参照してください。 IRIS for Health のFHIRリポジトリの場合は以下のように指定できます。categoryおよびpatient(またsubject)は必須の指定パラメータとなっています。 ``` GET /Observation/$lastn?max=10&category=vital-signs&patient=Patient/123 ``` このクエリでは、PatientリソースのID=123の患者に関連した、「vital-signs」カテゴリーに含まれる、最新 **10件** のObservationリソースがBundle形式でクライアントに返されます。直近のデータだけを使ってグラフを表示したい、というようなニーズにはぴったりですね。 ## カスタムオペレーションを作成してみよう FHIRのオペレーションとはどのようなものか?具体例を2つ挙げてご紹介しました。 カスタムオペレーションはこのようなオペレーションを、プロジェクトのニーズに応じて、自分で定義して実装し利用することができるようになる機能です。定義したカスタムオペレーションはCapability Statementに含めて公開することができます。 以下の手順でカスタムオペレーションを構築することができます。 # 1. 3つのカスタムクラス(Interactions等)を用意する まず、最初の手順として、前回の[FHIRリポジトリをカスタマイズしよう!パート1](https://jp.community.intersystems.com/node/504516)で記載した、3つのカスタムクラスを用意します。詳しい内容はパート1の記事をご覧ください。 # 2. カスタムオペレーション用のクラスを用意し、Interactionsクラスから参照する Interactionsクラス等と同様に、カスタムオペレーション用のクラスを継承します。 HS.FHIRServer.Storage.BuiltInOperationsを継承し、任意の名称のクラスを作成します。この記事ではCustomFS.MyOperationとします。 (場合によっては、HS.FHIRServer.API.OperationHandlerクラスを継承して作成することもありますが、FHIRリポジトリを利用している場合は、HS.FHIRServer.Storage.BuiltInOperationsを継承し、$everythingなどの実装済みのオペレーションが引き続き使用できるようにする必要があります。詳細はドキュメントをご覧ください。) これでFHIRリポジトリのカスタマイズに関連して作成したクラスは4つになりましたね。 | ベースクラス | 継承して作成したクラス | |:----------|:------------| | HS.FHIRServer.Storage.Json.Interactions | CustomFS.MyInteractions | | HS.FHIRServer.Storage.Json.InteractionsStrategy | CustomFS.MyInteractionsStrategy | | HS.FHIRServer.Storage.Json.RepoManager | CustomFS.MyRepoManager | | (new!) **HS.FHIRServer.Storage.BuiltInOperations** | **CustomFS.MyOperation** | さらに、このFHIRリポジトリのサーバ処理でこのカスタムオペレーション用のクラスが使用されるように、InteractionsクラスのOperationHandlerClassパラメータでこのクラスを指定します。 ``` Class CustomFS.MyInteractions Extends HS.FHIRServer.Storage.Json.Interactions { Parameter OperationHandlerClass As %String = "CustomFS.MyOperations"; ``` # 3. カスタムオペレーションの処理を実装する いよいよ、具体的にカスタムオペレーションの処理内容を実装していきます。2.で作成した、CustomFS.MyOperationsクラス内にメソッドを作成して実装します。 まず作成するオペレーションは影響範囲の応じて3つに分けることができます。 この3つの影響範囲=Scope + オペレーション名により、作成するべきメソッド名が決まってきます。 ### メソッド名命名ルールについて メソッド名命名には以下のようなルールがあります。 FHIR*Scope*Op*OperationName* まずメソッド名の先頭は **FHIR** です。 次に *Scope* には以下の3つのタイプのいずれかが入ります。 | Scope | 説明 | |:----------|:------------| | **System** | "ベース" の FHIR エンドポイントに追加する操作を指定します (例えば、http://fhirserver.org/fhir)。これらの操作は、サーバ全体に適用されます。 | | **Type** | FHIR エンドポイントにリソース・タイプと共に追加する操作を指定します (例えば、http://fhirserver.org/fhir/Patient)。これらの操作は、指定されたリソース・タイプのすべてのインスタンスで動作します。 | | **Instance** | リソースの特定のインスタンスを指す FHIR エンドポイントに追加する操作を指定します (例えば、http://fhirserver.org/fhir/Patient/1)。これらの操作は、リソースの特定のインスタンスでのみ動作します。 | 以下の図も影響範囲の理解の参考になると思います。 ![image](/sites/default/files/inline/images/fhir_customize_part2_ss1.jpg) そして、"Op" に続き、先頭を大文字にしたオペレーション名が続きます。 例えば、「$deleteall」というカスタムオペレーションをSystemレベルで作成したいなら **FHIRSystemOpDeleteall** というメソッドを作成します。 「$anonymize」というカスタムオペレーションをInstanceレベルで作成したいなら **FHIRInstanceOpAnonymize** というメソッドを作成します。 つまり **"FHIR" _ (System or Type or Instance) _ "Op" _ (先頭大文字にしたオペレーション名)** という命名ルールですね。 ### メソッドの実装方法 では、実際に、Instanceレベルの$anonymizeオペレーションを作成していきましょう。このオペレーションの目的はPatientリソースのnameエレメントの中身を匿名化)(*******で埋める)を実装することです。 このメソッドは ``` GET /Patient/5/$anonymize ``` のような形で実装されることを想定しています。 上記の例ででてきたように、FHIRInstanceOpAnonymizeメソッドを以下のように実装します。サンプルなので詳細なエラーハンドリングまでは実装していません。 ``` ClassMethod FHIRInstanceOpAnonymize(pService As HS.FHIRServer.API.Service, pRequest As HS.FHIRServer.API.Data.Request, pResponse As HS.FHIRServer.API.Data.Response) { ///RestClientクラスを利用してFHIRサーバへのアクセスを実行。指定された論理IDのPatientリソースを取得する Set clientObj = ##class(HS.FHIRServer.RestClient.FHIRService).CreateInstance(pRequest.SessionApplication) Do clientObj.SetResponseFormat("JSON") set clientResponseObj=clientObj.Read(pRequest.RequestMethod,pRequest.Type,pRequest.Id) set pResponse.Json=clientResponseObj.Json set pResponse.Status=clientResponseObj.Status set pResponse.ETag=clientResponseObj.ETag set pResponse.LastModified=clientResponseObj.LastModified set pResponse.Location=clientResponseObj.Location set pResponse.IsPrettyOut=clientResponseObj.IsPrettyOut //匿名化処理を実行する if pResponse.Status="200" { //DynamicObjectからnameエレメントのIteratorを取得し繰り返し処理 set iter=pResponse.Json.name.%GetIterator() while iter.%GetNext(.key,.value) { do pResponse.Json.name.%Get(key).%Set("text","***********") do pResponse.Json.name.%Get(key).%Set("family","***********") do pResponse.Json.name.%Get(key).%Set("given","***********") } } } ``` パート1のカスタマイズ処理では、実際に検索(GET)されたデータや、送信(POST/PUT)されたデータに対してカスタム処理を実施しましたが、オペレーションの場合はベースとなる検索を実行する必要があります。もちろん、オペレーションの実装目的によっては、検索をする必要がない場合もあるでしょう。 このメソッドでは、得られた検索結果に対して、DynamicObjectのデータ操作を使用して、データを更新し匿名化を行っています。 # 4. 作成したカスタムオペレーションの定義をCapability Statementに追加する 次に、ロジックを作成したカスタムオペレーションの定義をCapability Statementに追加します。まず、先ほどと同じCustomFS.MyOperationクラスにCapability Statement追加用のAddSupportedOperationsメソッドを記述します。 ``` ClassMethod AddSupportedOperations(pMap As %DynamicObject) { Do ##super(pMap) Do pMap.%Set("anonymize","http://myfhirserver/fhir/OperationDefinition/patient-anonymize") } ``` メソッド内の、pMap.%Setの最初の引数は"オペレーション名"、2番目の引数はそのオペレーションの定義を表すURIを記載します。 2番目の引数は例えば、先述のPatient/[id]/$everything オペレーションであれば、[こちらのページ](http://hl7.org/fhir/patient-operation-everything.html)に記載されているように > http://hl7.org/fhir/OperationDefinition/Patient-everything となります。例えば、あるデータ連携プロジェクトに基づいて実装した場合は、そのプロジェクトの実装ガイド内で規定されたURIになるでしょうし、自プロジェクト内で利便性のために構築したということであれば、任意のURIを指定することもできます。 次にコマンドラインユーティリティを起動して、この変更を反映します。 以下はCUSTOMFSネームスペース内で実行した例になります。 ``` USER>zn "customfs" CUSTOMFS>d ##Class(HS.FHIRServer.ConsoleSetup).Setup() Query returns no results HS.FHIRServer.Installer:InstallNamespace Created FHIR web application HS.FHIRServer.Installer:InstallNamespace Created FHIR API web application What do you want to do? 0) Quit 1) Create a FHIRServer Endpoint 2) Add a profile package to an endpoint 3) Display a FHIRServer Endpoint Configuration 4) Configure a FHIRServer Endpoint 5) Decommission a FHIRServer Endpoint 6) Delete a FHIRServer Endpoint 7) Update the CapabilityStatement Resource 8) Index new SearchParameters for an Endpoint 9) Upload a FHIR metadata package 10) Delete a FHIR metadata package Choose your Option[1] (0-10): 7 For which Endpoint do you want to update the CapabilityStatement? 1) /csp/healthshare/customfs/fhir/r4 [enabled] (for Strategy 'CustomFS' and Metadata Set 'hl7.fhir.r4.core@4.0.1') Choose the Endpoint[1] (1-1): 1 Update the /csp/healthshare/customfs/fhir/r4 service CapabilityStatement to reflect the endpoint strategy. Proceed? (y/n): yes ``` 以上の手順を実行すると、FHIRリポジトリのCapability Statementにカスタムオペレーションのエントリが追加されます! Capability StatementはFHIRリポジトリに以下のリクエストをすると取得できます。anonymizeオペレーションがちゃんと追加されていますね。 ``` GET http://fhirserver/csp/healthshare/customfs/fhir/r4/metadata ``` ``` "operation": [ { "name": "everything", "definition": "http://hl7.org/fhir/OperationDefinition/Patient-everything" }, (略) { "name": "anonymize", "definition": "http://myfhirserver/fhir/OperationDefinition/patient-anonymize" }, ``` # 5. 実行して動作を確認してみよう 以上で、カスタムオペレーション $anoymize の実装は完了です。早速動作確認してみましょう! まずカスタムオペレーションなしで普通にPatientリソースのデータをリクエストしてみます。 ``` GET http://localhost:52785/csp/healthshare/customfs/fhir/r4/Patient/2 ``` 私のデモ環境では、以下のようなnameエレメントを持つデータが格納されていました。 ``` { "resourceType": "Patient", "id": "2", (略) "name": [ { "extension": [ { "url": "http://hl7.org/fhir/StructureDefinition/iso21090-EN-representation", "valueCode": "IDE" } ], "use": "official", "text": "山田 太郎", "family": "山田", "given": [ "太郎" ] }, { "extension": [ { "url": "http://hl7.org/fhir/StructureDefinition/iso21090-EN-representation", "valueCode": "SYL" } ], "use": "official", "text": "ヤマダ タロウ", "family": "ヤマダ", "given": [ "タロウ" ] } ``` 次に、実装した $anonymizeを追加して実行してみます! ``` GET http://localhost:52785/csp/healthshare/customfs/fhir/r4/Patient/2/$anonymize ``` 以下のように匿名化されたデータが取得できました! ``` { "resourceType": "Patient", "id": "2", (略) "name": [ { "extension": [ { "url": "http://hl7.org/fhir/StructureDefinition/iso21090-EN-representation", "valueCode": "IDE" } ], "use": "official", "text": "***********", "family": "***********", "given": "***********" }, { "extension": [ { "url": "http://hl7.org/fhir/StructureDefinition/iso21090-EN-representation", "valueCode": "SYL" } ], "use": "official", "text": "***********", "family": "***********", "given": "***********" } ], ``` # カスタマイズを実装する際のTips パート1、パート2とIRIS for HealthのFHIRリポジトリをカスタマイズする方法をご紹介してきました。 ここで、カスタマイズの際のTipsを一つご紹介します。 IRISのFHIRリポジトリ処理では、パフォーマンス最適化のために、個別のプロセス内でFHIR処理用のサービスインスタンスが起動され、再利用される仕組みになっています。そのため、条件によっては、サーバ側のカスタム処理を書き換えたのにそれが反映されないことがあります。そのような際にはいくつかの対応方法があります。 1. FHIR Server Configurationページで「New Service Instance」のチェックを有効にする 開発環境であれば、この方法をお勧めします。FHIRリクエスト毎に新しいService Instanceが立ち上がるので、必ず変更が反映されます。ただし、パフォーマンスへの影響を考えると、本番環境で設定することはお勧めしません。 ![image](/sites/default/files/inline/images/fhir_customize_part2_ss2.jpg) 2. Web Gateway Management 画面からすべてのセッションをクリアする  System Status画面ですべてのセッションをクリアすることによって、起動しているIRIS側のプロセスもすべて再起動されます。下記画像の黄色の部分をクリックします。 ![image](/sites/default/files/inline/images/fhir_customize_part2_ss3.jpg) 3. 再起動する(常に最強の手段) ## まとめ いかがでしたでしょうか? IRIS for HealthのFHIRリポジトリカスタマイズ機能を利用することによって、プロジェクト開発で求められる様々な要件に柔軟に対応することができます。もちろん、カスタマイズを多用することが、FHIRの持つ汎用性に影響を及ぼすことを考慮する必要がありますが、パート1/2の記事でご紹介したカスタマイズ機能を効果的に使えば、より高度なFHIRアプリケーションの構築も可能になります。 パート1、パート2の内容を含むIRISのクラスを[こちらのGitHubサイト](https://github.com/Intersystems-jp/FHIR_Customize)からダウンロードすることができます。 また新たなカスタマイズ手法が実装されたらこちらの開発者コミュニティで紹介したいと思います。
記事
Toshihiko Minamoto · 2021年1月14日

IRISにてMQTTブローカーから気象データを取得しデータベースに格納する

前回のつづきとして、いよいよIRISのインターオペラビリティ機能を使ってMQTTブローカーからメッセージを受信し、データベースに格納する方法について解説したいと思います。IRISのインターオペラビリティ機能につきましてはこちらをご参照ください。 ネームスペース作成 インストール時に作成されているUSERネームスペースはInteroperabilityに必要なライブラリを参照するためのマッピングができていません。そのため、新たにネームスペースを作成する必要があります。作成方法は、以下の通りです。 システム管理ポータルを起動し、「システム管理」「構成」「システム構成」「ネームスペース」をクリックします。 以下のようなネームスペース一覧画面が表示されますので、上にある「新規ネームスペース作成」ボタンをクリックします。 以下のような新規ネームスペース作成画面が表示されますので、「ネームスペース名」欄にネームスペースの名称を入力し、「グローバルのための既存のデータベースを選択」欄、「ルーチンのための既存のデータベースを選択」欄で共にデータベース「USER」を選択します。 「相互運用プロダクション用にネームスペースを有効化」欄にチェックが付いていることを確認の上、画面上の「保存」ボタンをクリックします。 以下のような処理ログが表示されますので、画面下の「閉じる」ボタンをクリックします。 以上でネームスペースが作成できました。 気象データテーブルの作成 以下のように観測地点、取得時刻、気温、湿度、気圧を格納するクラス(MQTT.Data.WeatherInfo)を作成します。 /// 気象データ Class MQTT.Data.WeatherInfo Extends %Persistent { /// 観測地点 (ClientID) Property PointName As %String; /// 取得時刻 Property MeasureTime As %TimeStamp; /// 気温 Property Temperature As %Numeric; /// 湿度 Property Humidity As %Numeric; /// 気圧 Property Pressure As %Numeric; Index PointDate On (PointName, MeasureTime); } 気象データ格納オペレーションの作成 以下のように、MQTT.BO.StoreDataというビジネスオペレーションクラスを作成し、MQTTメッセージ(EnsLib.MQTT.Message)からデータを取得しMQTT.Data.WeatherInfoクラスに格納するStoreData()メソッドを追加します。MessageMapの設定も忘れずに追加してください。 /// MQTTメッセージのデータベースへの保存 Class MQTT.StoreData Extends Ens.BusinessOperation [ Language = objectscript ] { Parameter INVOCATION = "Queue"; Method StoreData(pRequest As EnsLib.MQTT.Message, Output pResponse As Ens.Response) As %Status { set obj=##class(MQTT.Data.WeatherInfo).%New() set obj.MeasureTime=$zdatetime($horolog,3) set obj.Temperature=$piece(pRequest.StringValue,",") set obj.Humidity=$piece(pRequest.StringValue,",",2) set obj.Pressure=$piece(pRequest.StringValue,",",3) set obj.PointName=$piece(pRequest.Topic,"/",2) return obj.%Save() } XData MessageMap { <MapItems> <MapItem MessageType="EnsLib.MQTT.Message"> <Method>StoreData</Method> </MapItem> </MapItems> } } プロダクションの作成 システム管理ポータルより「Interoperability」「構成」「プロダクション」メニューをクリックします。以下のようにインターオペラビリティ機能を実行するネームスペースを聞いてきますので、先ほど作成したネームスペース(TEST)を選択します。 以下のようにプロダクション構成画面が表示されますので、画面中央上にある「プロダクション設定」リンクをクリックし、右にある「アクション」タブをクリック、「新規」ボタンをクリックします。 以下のようなダイアログボックスが表示されますので、パッケージ名、プロダクション名を入力し、「OK」ボタンをクリックします。 ビジネスオペレーションの作成 アイテムが無いプロダクション構成画面が表示されますので、画面上の「オペレーション」の右にある「+」ボタンをクリックします。 クリックしますと以下のようなダイアログボックスが表示されますので、「オペレーションクラス」欄に先ほど作成したMQTT.BO.StoreDataクラスを選択し、「オペレーション名」欄にオペレーション名(メッセージ保存)、「有効にする」にチェックを入れ、「OK」ボタンをクリックします。 ビジネスサービスの作成 MQTTブローカーからメッセージを受信するMQTTサービスを作成します。画面左上の「サービス」の右にある「+」ボタンをクリックしますと、以下のようなダイアログボックスが表示されます。 ここで「サービスクラス」欄にて「EnsLib.MQTT.Service.Passthrough」を選択します。 「サービス名」欄にサービス名(MQTTサービス)を入力し、「有効にする」をチェック、「OK」ボタンをクリックします。 MQTTに接続するための設定 最初の記事にて設定したMQTTブローカー(mosquitto)にアクセスするには認証や暗号化通信が必要です。認証に必要な認証情報は以下の手順で作成します。 管理ポータルより「Interoperability」「構成」「認証情報」メニューをクリックします。 以下の画面が表示されますので、「ID」欄にMQTTAccess、「ユーザ名」欄に「iris」、「パスワード」欄に最初の記事で入力したユーザirisのパスワードを入力し、保存ボタンをクリックします。 認証の次は暗号化です。暗号化通信を行うにはCAの証明書が必要になりますので、以下の手順でSSL/TLS構成を作成します。 管理ポータルより「システム管理」「セキュリティ」「SSL/TLS構成」メニューをクリックします。 以下のようにSSL/TLS構成一覧が表示されますので、画面上の「新規構成の作成」ボタンをクリックします。 SSL/TLS構成編集画面にて以下のように構成名(mqtt_srv)、タイプ(クライアントをチェック)、サーバ証明書の検証(必須をチェック)を入力し、「信頼済み認証局の証明書を含むファイル」欄に最初の記事の中で作成した自己認証局の証明書のファイルを設定、「保存」ボタンをクリックします。 サービスの設定 前のトピックで作成した認証情報やCAの証明書を使い、MQTTサービスの設定を行います。 以下のようなプロダクション構成画面にて「MQTTサービス」をクリックし、右にある「設定」をクリックします。 ここで以下の項目を設定し、画面上の「適用」をクリックします。 基本設定 - ターゲット構成:「メッセージ保存」 MQTT - ClientID:「MQTTSRV1」 MQTT - CredentialsName: 「MQTTAccess」 MQTT - SSLConfigName:「mqtt_srv」 MQTT - Topic:「point/#」 MQTT - Url:「ssl://localhost:8883」 プロダクションの起動 以上で設定は完了しましたので、プロダクション構成画面から「開始する」ボタンをクリックします。 管理ポータルより、「システムエクスプローラ」「SQL」メニューをクリックし、「クエリ実行」タブをクリック、以下のSQLを実行させて、1分おきにレコードが増えていれば成功です。 select * from MQTT_Data.WeatherInfo まとめ 3回にわたって、Mosquittoの設定やESP8266 ( arduino )などのマイコンのプログラミング、IRISのプログラム例を紹介しました。このことから、マイコンからInterSystems IRISにデータが渡せることをご理解いただけたかと思います。また、IRISの公開鍵基盤を使用して証明書等作成できることもご確認いただけたかと思います。 ご意見、ご質問等ございましたら、ご遠慮なくコメントに追加いただければと思います。最後までお読みいただきありがとうございました。
記事
Toshihiko Minamoto · 2020年12月1日

SSH 接続する %Net.SSH.Session の使用とデバッグ方法

%Net.SSH.Session クラスを使用すると、SSH を使ってサーバーに接続することができます。 一般的にはSFTP、特に FTP インバウンドアダプタとFTPアウトバウンドアダプタで使用されています。 この記事では、簡単な例を示しながら、このクラスを使用して SSH サーバーに接続する方法、認証のオプションを記述する方法、そして問題が発生した場合のデバッグ方法について説明します。 次は接続を行う例です。 ~~~ Set SSH = ##class(%Net.SSH.Session).%New() Set return=SSH.Connect("ftp.intersystems.com")​ ~~~ 上記のコードは新しい接続を作成してから、ftp.intersystems.com の SFTP サーバーにデフォルトのポートで接続します。 この時点で、クライアントとサーバーは暗号化アルゴリズムとオプションを選択済みですが、ユーザーはまだログインしていません。 接続したら、認証方法を選択できます。 選択できるメソッドには次の 3 つがあります。 - AuthenticateWithUsername - AuthenticateWithKeyPair - AuthenticateWithKeyboardInteractive 上記はそれぞれ異なる認証方式です。 各方式を簡単に説明します。 #### AuthenticateWithUsername これは、ユーザー名とパスワードを使用します。 #### AuthenticateWithKeyPair これは、公開鍵と秘密鍵のペアを使用します。 公開鍵は事前にサーバーに読み込まれている必要があり、それに一致する秘密鍵が必要となります。 秘密鍵がディスク上で暗号化されている場合、メソッドへの呼び出しで、それを復号化するためのパスフレーズを指定します。 注意: 秘密鍵を他人に送信してはいけません。 公開鍵は OpenSSH 形式であり、秘密鍵は PEM で暗号化されている必要があります。 OpenSSH の形式は次のような書式です。 ~~~ ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCfi2Vq+u0rtt2OC84pyrkq1k7WkrS+s76u3a+2gdD43KQ2Z3vSUUfksymJjp11JBZEpOtBVIAy221UKdc7j7Qk6sUjZaK8LIy+bzDVwMyFWgVvQge7EjdWjrJLBRCDXYML6y1Y25XexThkTWSGyXzGNdr+wfIHYn/mIt0hfvrusauvT/9Wz8K2MGAj4BL7UQZpFJrlXzGmewe6++6cZDQQYi0aztwLK798oc9j0LsccdMpqWrjqoU1uANFhYIuUu/T47TEhT+e6M+KFYK5TR998eJTO25IjdN2Tgw0feXhQFF/nngbol0bA4auSPaZQsgokKK+E+Q/8UtBdetEofuV user@hostname ~~~ PEM で暗号化されている秘密鍵には、ファイルの上部に次のようなヘッダーがあります。 ~~~ -----BEGIN RSA PRIVATE KEY----- ~~~ そして、最後に次の行があります。 ~~~ -----END RSA PRIVATE KEY----- ~~~ #### AuthenticateWithKeyboardInteractive これは、Cache 2018.1 以降で提供されている新しいオプションです。 チャレンジレスポンス認証を実行できます。 たとえば、テキストメッセージで送信されるか、Google 認証システムアプリで生成されたワンタイムパスワードを要求することがあるでしょう。 この認証方式を使用するには、サーバーが送信するプロンプトを処理するためのラムダ関数を記述する必要があります。 この認証方式を、ユーザーのパスワード認証と同じように、ユーザー名とパスワードのプロンプトのみで使用しているサーバーに遭遇することがあるかもしれませんが、 以下に説明する SSH デバッグフラグを使えば、これに遭遇しているかどうかを判定しやすくなります。 **認証に関する注意事項:** 1 つの接続で 2 つの認証方式の使用を検討している方は、Cache 2018.1 または InterSystems IRIS を使用してください。 これらのバージョンには、鍵ペアとユーザー名といった、複数の方式を使用できるようにするための更新があります。 ## 問題が発生した場合 ### 発生する可能性のある一般的なエラー #### バナーの取得に失敗しました(Failed getting banner) これは次のように表示されます。 ~~~ ERROR #7500: SSH Connect Error '-2146430963': SSH Error [8010100D]: Failed getting banner [FFFFFFFF8010100D] at Session.cpp:231,0 ~~~ SSH クライアントが最初に行うのは、バナーの取得です。 このエラーが発生した場合、適切なサーバーに接続しており、それが SFTP サーバーであることを確認してください。 たとえば、サーバーが実際には FTPS サーバーであった場合に、このエラーが発生します。 FTPS サーバーは SSH ではなく SSL を使用するため、%Net.SSH.Session クラスでは動作しません。 FTPS サーバーに接続するには、%Net.FtpSession クラスを使用してください。 #### 暗号化鍵を交換できません(Unable to exchange encryption keys) このエラーは次のように表示されます。 ~~~ ERROR #7500: SSH Connect Error '-2146430971': SSH Error [80101005]: Unable to exchange encryption keys [80101005] at Session.cpp:238,0 ~~~ このエラーは通常、クライアントとサーバーの暗号化または MAC アルゴリズムが合致しなかったことを指しています。 これが発生した場合は、新しいアルゴリズムのサポートを追加するために、クライアントかサーバーのいずれかをアップグレードする必要があるかもしれません。 2017.1 より前のバージョンの Cache を使用している場合は、2017.1 以降を使用することをお勧めします。 libssh2 ライブラリは 2017.1 でアップグレードされており、新しいアルゴリズムがいくつか追加されています。 詳細については、以下に説明するデバッグフラグが提供するログを参照してください。 #### 提供された公開鍵の署名が無効です(Invalid signature for supplied public key) ~~~ Error [80101013]: Invalid signature for supplied public key, or bad username/public key combination [80101013] at Session.cpp:418 ~~~ これは非常に誤解を招きやすいエラーです。 サーバーが 2 つの認証方式を必要としているにも関わらず、1 つしか提供しなかった場合に発生します。 この場合は、そのまま続けて次の方式を試しましょう! このエラーがあっても、すべてうまく動作する可能性があります。 #### Error -37 エラー -37 に関するメッセージが表示されることがあります。 たとえば、次のデバッグログを見てください。 ~~~ [libssh2] 0.369332 Failure Event: -37 - Failed getting banner ~~~ エラー -37 が示されている場合は必ず、失敗した操作が再試行されます。 このエラーが最終的な失敗の原因であることはありません。 ほかのエラーメッセージを確認してください。 ### SSH デバッグフラグ 接続に SSH デバッグフラグを使うと、SSH 接続の詳細なログを取得できます。 このフラグを有効にするには、SetTraceMethod メソッドを使います。 次に、このフラグを使った接続の例を示します。 ~~~ Set SSH = ##class(%Net.SSH.Session).%New() Do SSH.SetTraceMask(511,"/tmp/ssh.log") Set Status=SSH.Connect("ftp.intersystems.com")​ ~~~ SetTraceMask の最初の引数は、何を収集するかを指示します。 ビットの 10進表現です。 511 は 512 を除くすべてのビットを要求しており、最も一般的に使用される設定です。 各ビットに関する詳細については、%Net.SSH.Session クラスのクラスドキュメントをご覧ください。 2 つ目の引数は、接続に関するログ情報をどのファイルに格納するかを指示します。 この例では、/tmp/ssh.log ファイルを指定しましたが、任意の絶対または相対パスを使用できます。 上記の例では、Connect メソッドのみを実行しました。 認証に問題がある場合は、該当する認証方式も実行する必要があります。 テストを実行したら、ログファイルで情報を確認できます。 ログファイルの解釈に不安がある場合は、WRC をご覧ください。
記事
Toshihiko Minamoto · 2020年8月17日

VM Backups and Caché freeze/thaw scripts

この記事では、スナップショットを使用したソリューションとの統合の例を使って、_外部バックアップ_による Caché のバックアップ方法を紹介します。 このところ私が目にするソリューションの大半は、Linux の VMware にデプロイされているため、この記事の大半では、例として、ソリューションが VMware スナップショットテクノロジーをどのように統合しているかを説明しています。 ## Caché バックアップ - すぐ使えますか? Caché をインストールすると、Caché データベースを中断せずにバックアップできる Caché オンラインバックアップが含まれています。 しかし、システムがスケールアップするにつれ、より効率的なバックアップソリューションを検討する必要があります。 Caché データベースを含み、システムをバックアップするには、スナップショットテクノロジーに統合された_外部バックアップ_をお勧めします。 ## 外部バックアップに関して特別な考慮事項はありますか? 詳しい内容は[外部バックアップ](http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GCDI_backup#GCDI_backup_methods_ext)のオンラインドキュメンテーションに説明されていますが、 主な考慮事項は次のとおりです。 > 「スナップショットの整合性を確保するために、スナップショットが作成される間、Caché はデータベースへの書き込みをfreezeする方法を提供しています。 スナップショットの作成中は、データベースファイルへの物理的な書き込みのみがfreezeされるため、ユーザーは中断されることなくメモリ内で更新を実行し続けることができます。」 また、仮想化されたシステム上でのスナップショットプロセスの一部によって、バックアップされている VM にスタンタイムと呼ばれる短い無応答状態が発生することにも注意してください。 通常は 1 秒未満であるため、ユーザーが気付いたり、システムの動作に影響を与えたりすることはありませんが、状況によってはこの無応答状態が長引くことがあります。 無応答状態が Caché データベースミラーリングの QoS タイムアウトより長引く場合、バックアップノードはプライマリに障害が発生したとみなし、フェイルオーバーします。 この記事の後の方で、ミラーリング QoS タイムアウトを変更する必要がある場合に、スタンタイムをどのように確認できるかについて説明します。 [InterSystems データプラットフォームとパフォーマンスに関する他の連載記事のリストはこちらにあります。](https://jp.community.intersystems.com/node/477596/) この記事では、Caché オンラインドキュメンテーション『[Backup and Restore Guide](http://docs.intersystems.com/latestj/csp/docbook/DocBook.UI.Page.cls?KEY=GCDI_backup)(バックアップと復元ガイド)』も確認する必要があります。 # バックアップの選択肢 ## 最小限のバックアップソリューション - Caché Online Backup ほかのソリューションがない場合は、ダウンタイム無しでバックアップを行えるこのソリューションが InterSystems データプラットフォームに同梱されています。 _Caché オンラインバックアップ_は、Caché データベースファイルのみをバックアップするもので、データに割り当てられたデータベースのすべてのブロックをキャプチャし、出力をシーケンシャルファイルに書き込みます。 Caché Online Backup は累積バックアップと増分バックアップをサポートしています。 VMware の文脈では、Caché Online Backup はゲスト内で発生するバックアップソリューションです。 ほかのゲスト内ソリューションと同様に、Caché Online Backup の動作は、アプリケーションが仮想化されていようが、ホストで直接実行していようが、基本的に変わりません。 Caché Online Backup は、システムバックアップと連携しながら Caché のオンラインバックアップ出力ファイルを、アプリケーションが使用しているその他すべてのファイルシステムとともに、バックアップメディアにコピーします。 最小限のシステムバックアップには、インストールディレクトリ、ジャーナルおよび代替ジャーナルディレクトリ、アプリケーションファイル、およびアプリケーションが使用する外部ファイルを含むすべてのディレクトリを含める必要があります。 Caché Online Backup は、Caché データベースやアドホックバックアップのみをバックアップする低コストのソリューションを実装したいと考えている小規模サイト向けのエントリレベルのアプローチとして捉えてください。ミラーリングをセットアップする際のバックアップなどに役立てられます。 しかし、データベースのサイズが増加したり、Caché が顧客のデータランドスケープの一部でしかない場合は、_外部バックアップ_にスナップショットテクノロジーとサードパーティ製ユーティリティを合わせたソリューションがベストプラクティスとして推奨されます。非データベースファイルのバックアップ、より高速な復旧時間、エンタープライズ全体のデータビュー、より優れたカタログと管理用ツールなど、さまざまなメリットが得られます。 ## 推奨されるバックアップソリューション - 外部バックアップ VMware を例として使用します。VMware で仮想化すると、VM 全体を保護するための追加機能と選択肢が追加されます。 ソリューションの仮想化が完了した時点で、オペレーティングシステム、アプリケーション、データを含むシステムを .vmdk(とその他の)ファイル内に効果的にカプセル化したことになります。 これらのファイルの管理は非常に簡単で、必要となった場合にはシステム全体の復旧に使用できるため、オペレーティングシステム、ドライバ、サードパーティ製アプリケーション、データベースとデータベースファイルなどのコンポーネントを個別に復旧して構成する必要のある物理システムで同じような状況が発生した場合とは大きく異なります。 # VMware のスナップショット VMware の vSphere Data Protection(VDP)や、Veeam や Commvault などのサードパーティ製バックアップソリューションでは、VMware 仮想マシンスナップショットを使用してバックアップを作成しています。 VMware スナップショットの概要を説明しますが、詳細については、VMware ドキュメンテーションを参照してください。 スナップショットは VM 全体に適用されるものであり、オペレーティングシステムとすべてのアプリケーションまたはデータベースエンジンはスナップショットが発生していることを認識しないということに注意してください。 また、次のことにも注意してください。 > VMware スナップショット自体はバックアップではありません! スナップショットは、バックアップソフトウェアによるバックアップの作成を_可能にします_が、スナップショット自体はバックアップではありません。 VDP とサードパーティ製バックアップソリューションは、バックアップアプリケーションとともに VMware スナップショットプロセスを使用して、スナップショットの作成と、非常に重要となるその削除を管理します。 おおまかに見ると、VMware スナップショットを使用した外部バックアップのイベントのプロセスと順序は次のとおりです。 - サードパーティ製バックアップソフトウェアは ESXi ホストに対し、VMware スナップショットをトリガーするように要求します。 - VM の .vmdk ファイルは読み取り専用状態となり、各 VM の .vmdk ファイルに子 vmdk 差分ファイルが作成されます。 - 書き込み時コピーを使用して、VM へのすべての変更が差分ファイルに書き込まれます。 すべての読み取りは、最初に差分ファイルから行われます。 - バックアップソフトウェアは、読み取り専用の親 .vmdk ファイルからバックアップターゲットへのコピーを管理します。 - バックアップが完了すると、スナップショットがコミットされます(VM ディスクは、親に書き込まれた差分ファイルのブロックの書き込みと更新を再開します)。 - VMware スナップショットが削除されます。 バックアップソリューションは、変更ブロック追跡(CBT)などのほかの機能も使用し、増分または累積バックアップを可能にして速度と効率性(容量節約において特に重要)を実現します。また、一般的に、データの重複解除や圧縮、スケジューリング、整合性チェックなどで IP アドレスが更新された VM のマウント、VM とファイルレベルの完全復元、およびカタログ管理などの重要な機能性も追加します。 > 適切に管理されていない、または長期間実行されたままの VMware スナップショットは、ストレージを過剰に消費し(データの変更量が増えるにつれ、差分ファイルが増加し続けるため)、VM の速度を低下させてしまう可能性があります。 本番インスタンスで手動スナップショットを実行する前に、十分に検討する必要があります。 なぜ実行しようとしているのか、 スナップショットが作成された*時間に戻す*とどうなるか、 作成とロールバック間のすべてのアプリケーショントランザクションはどうなるか、といったことを検討してください。 バックアップソフトウェアがスナップショットを作成し、削除しても問題ありません。 スナップショットの存続期間は、短期間であるものなのです。 また、バックアップ戦略においては、ユーザーやパフォーマンスへの影響をさらに最小限に抑えられるように、システムの使用率が低い時間を選ぶことも重要です。 ## スナップショットに関する Caché データベースの考慮事項 スナップショットを作成する前に、保留中のすべての書き込みがコミットされ、データベースが一貫した状態になるように データベースを静止させる必要があります。 Caché は、スナップショットが作成される間、データベースへの書き込みをコミットして短時間フリーズ(停止)するメソッドと API を提供しています。 こうすることで、スナップショットの作成中は、データベースファイルへの物理的な書き込みのみがフリーズされるため、ユーザーは中断されることなくメモリ内で更新を実行し続けることができます。 スナップショットがトリガーされると、データベースの書き込みが再開し、バックアップはバックアップメディアへのデータのコピーを続行します。 フリーズからの復旧は、非常に短時間(数秒)で発生します。 書き込みを一時停止するのに加え、Caché Freeze は、ジャーナルファイルの切り替えとジャーナルへのバックアップマーカーの書き込みも処理します。 ジャーナルファイルは、物理データベースの書き込みがフリーズしている間、通常通りに書き込みを続けます。 物理データベースの書き込みがフリーズしている間にシステムがクラッシュした場合、データは、起動時に、通常通りジャーナルから復元されます。 以下の図は、整合性のあるデータベースイメージを使用してバックアップを作成するための、VMware スナップショットを使用した Freeze と Thaw の手順を示しています。 ![](https://community.intersystems.com/sites/default/files/inline/images/snapshot-timeline.png "スナップショットのタイムライン") > _Freeze から Thaw の時間が短いところに注目してください。読み取り専用の親をバックアップターゲットにコピーする時間でなく、スナップショットを作成する時間のみです。_ # Caché の Freeze と Thaw の統合 vSphere では、スナップショット作成のいずれか側で自動的にスクリプトを呼び出すことができ、この時に、Caché Freeze と Thaw が呼び出されます。 注意: この機能が正しく機能するために、ESXi ホストは _VMware ツール_を介してゲストオペレーティングシステムにディスクを静止するように要求します。 > VMware ツールは、ゲストオペレーティングシステムにインストールされている必要があります。 スクリプトは、厳密な命名規則と場所のルールに準じる必要があります。 ファイルの権限も設定されていなければなりません。 以下は、Linux の VMware の場合のスクリプト名です。 # /usr/sbin/pre-freeze-script # /usr/sbin/post-thaw-script 以下は、InterSystems のチームが内部テストラボインスタンスに対して、Veeam バックアップで使用する Freeze と Thaw のスクリプト例ですが、ほかのソリューションでも動作するはずです。 これらの例は、vSphere 6 と Red Hat 7 で検証され、使用されています。 > これらのスクリプトは例として使用でき、方法を示すものではありますが、各自の環境で必ず検証してください! ### Freeze 前スクリプトの例: #!/bin/sh # # Script called by VMWare immediately prior to snapshot for backup. # Tested on Red Hat 7.2 # LOGDIR=/var/log SNAPLOG=$LOGDIR/snapshot.log echo >> $SNAPLOG echo "`date`: Pre freeze script started" >> $SNAPLOG exit_code=0 # Only for running instances for INST in `ccontrol qall 2>/dev/null | tail -n +3 | grep '^up' | cut -c5- | awk '{print $1}'`; do echo "`date`: Attempting to freeze $INST" >> $SNAPLOG # Detailed instances specific log LOGFILE=$LOGDIR/$INST-pre_post.log # Freeze csession $INST -U '%SYS' "##Class(Backup.General).ExternalFreeze(\"$LOGFILE\",,,,,,1800)" >> $SNAPLOG $ status=$? case $status in 5) echo "`date`: $INST IS FROZEN" >> $SNAPLOG ;; 3) echo "`date`: $INST FREEZE FAILED" >> $SNAPLOG logger -p user.err "freeze of $INST failed" exit_code=1 ;; *) echo "`date`: ERROR: Unknown status code: $status" >> $SNAPLOG logger -p user.err "ERROR when freezing $INST" exit_code=1 ;; esac echo "`date`: Completed freeze of $INST" >> $SNAPLOG done echo "`date`: Pre freeze script finished" >> $SNAPLOG exit $exit_code ### Thaw スクリプトの例: #!/bin/sh # # Script called by VMWare immediately after backup snapshot has been created # Tested on Red Hat 7.2 # LOGDIR=/var/log SNAPLOG=$LOGDIR/snapshot.log echo >> $SNAPLOG echo "`date`: Post thaw script started" >> $SNAPLOG exit_code=0 if [ -d "$LOGDIR" ]; then # Only for running instances for INST in `ccontrol qall 2>/dev/null | tail -n +3 | grep '^up' | cut -c5- | awk '{print $1}'`; do echo "`date`: Attempting to thaw $INST" >> $SNAPLOG # Detailed instances specific log LOGFILE=$LOGDIR/$INST-pre_post.log # Thaw csession $INST -U%SYS "##Class(Backup.General).ExternalThaw(\"$LOGFILE\")" >> $SNAPLOG 2>&1 status=$? case $status in 5) echo "`date`: $INST IS THAWED" >> $SNAPLOG csession $INST -U%SYS "##Class(Backup.General).ExternalSetHistory(\"$LOGFILE\")" >> $SNAPLOG$ ;; 3) echo "`date`: $INST THAW FAILED" >> $SNAPLOG logger -p user.err "thaw of $INST failed" exit_code=1 ;; *) echo "`date`: ERROR: Unknown status code: $status" >> $SNAPLOG logger -p user.err "ERROR when thawing $INST" exit_code=1 ;; esac echo "`date`: Completed thaw of $INST" >> $SNAPLOG done fi echo "`date`: Post thaw script finished" >> $SNAPLOG exit $exit_code ### 権限の設定を必ず行ってください: # sudo chown root.root /usr/sbin/pre-freeze-script /usr/sbin/post-thaw-script # sudo chmod 0700 /usr/sbin/pre-freeze-script /usr/sbin/post-thaw-script ## Freeze と Thaw のテスト スクリプトが正しく動作することをテストするには、VM でスナップショットを手動で実行し、スクリプトの出力を確認することができます。 以下のスクリーンショットは、[Take VM Snapshot(VM スナップショットの作成)]ダイアログとオプションを示します。 ![](https://community.intersystems.com/sites/default/files/inline/images/snapshot-screen.png "手動スナップショットの例") **選択解除**- [Snapshot the virtual machine's memory(仮想マシンのメモリをスナップショットする)] **選択** - [Quiesce guest file system (Needs VMware Tools installed)(ゲストファイルシステムを静止する: VMware ツールのインストールが必要)]チェックボックス。スナップショットを作成する際にゲストオペレーティングシステムで実行中のプロセスを一時停止し、ファイルシステムのコンテンツが既知の整合性のある状態を保つようにします。 > 重要! テストの後、スナップショットを必ず削除してください!!!! スナップショットが作成される際に、静止フラグが真であり、仮想マシンがオンである場合、VMware ツールによって仮想マシンのファイルシステムが静止されます。 ファイルシステムの静止は、ディスク上のデータをバックアップに適した状態にするプロセスです。 このプロセスには、オペレーティングシステムのメモリ内キャッシュからディスクへのダーティバッファのフラッシュといった操作が含まれる場合があります。 以下の出力は、操作の一環としてスナップショットを含むバックアップを実行した後に、上記の Freeze/Thaw スクリプトの例で設定された `$SNAPSHOT` ログファイルのコンテンツを示しています。 Wed Jan 4 16:30:35 EST 2017: Pre freeze script started Wed Jan 4 16:30:35 EST 2017: Attempting to freeze H20152 Wed Jan 4 16:30:36 EST 2017: H20152 IS FROZEN Wed Jan 4 16:30:36 EST 2017: Completed freeze of H20152 Wed Jan 4 16:30:36 EST 2017: Pre freeze script finished Wed Jan 4 16:30:41 EST 2017: Post thaw script started Wed Jan 4 16:30:41 EST 2017: Attempting to thaw H20152 Wed Jan 4 16:30:42 EST 2017: H20152 IS THAWED Wed Jan 4 16:30:42 EST 2017: Completed thaw of H20152 Wed Jan 4 16:30:42 EST 2017: Post thaw script finished この例では、Freeze から Thaw までに 6 秒経過していることがわかります(16:30:36~16:30:42)。 この間、ユーザー操作は中断されていません。 _独自のシステムからメトリックを収集する必要があります_が、背景としては、この例は、IO ボトルネックがなく、平均 200 万 Glorefs/秒、17 万 Gloupds/秒、および毎秒あたり平均 1,100 個の物理読み取りと書き込みデーモン 1 サイクル当たりの書き込み 3,000 個の BM でアプリケーションベンチマークを実行しているシステムから得たものです。 > メモリはスナップショットの一部ではないため、再起動すると、VM は再起動して復元されることに注意してください。 データベースファイルは整合性のある状態です。 バックアップを「再開」するのではなく、ファイルを既知の時点の状態にする必要があります。 その後で、ファイルが復元されたら、ジャーナルと、アプリケーションとトランザクションの整合性に必要なその他の復元手順をロールフォワードできます。 その他のデータ保護を追加するには、[ジャーナルの切り替え](http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GCDI_journal#GCDI_journal_util_JRNSWTCH "Journal switch")を単独で実行することもでき、ジャーナルは、たとえば 1 時間ごとに別の場所にバックアップまたは複製されます。 以下は、上記の Freeze と Thaw スクリプトの `$LOGFILE` の出力で、スナップショットのジャーナルの詳細を示しています。 01/04/2017 16:30:35: Backup.General.ExternalFreeze: Suspending system Journal file switched to: /trak/jnl/jrnpri/h20152/H20152_20170104.011 01/04/2017 16:30:35: Backup.General.ExternalFreeze: Start a journal restore for this backup with journal file: /trak/jnl/jrnpri/h20152/H20152_20170104.011 Journal marker set at offset 197192 of /trak/jnl/jrnpri/h20152/H20152_20170104.011 01/04/2017 16:30:36: Backup.General.ExternalFreeze: System suspended 01/04/2017 16:30:41: Backup.General.ExternalThaw: Resuming system 01/04/2017 16:30:42: Backup.General.ExternalThaw: System resumed # VM スタンタイム VM スナップショットの作成時、バックアップが完了してスナップショットがコミットされた後、VM を短時間フリーズする必要があります。 この短時間のフリーズは、VM のスタンと呼ばれることがよくあります。 スタンタイムについてよく説明されたブログ記事は、[こちら](http://cormachogan.com/2015/04/28/when-and-why-do-we-stun-a-virtual-machine/ "Blog Post on stun times")をご覧ください。 以下に要約した内容を示し、Caché データベースの考慮事項に照らして説明します。 スタンタイムに関する記事より: 「VM スナップショットを作成するには、(i)デバイスの状態をディスクにシリアル化し、(ii)現在実行中のディスクを閉じてスナップショットポイントを作成するために、VM は「スタン」されます(無応答状態になります)。… 統合時、VM は、ディスクを閉じて統合に最適な状態にするために、「スタン」されます。」 スタンタイムは、通常数百ミリ秒です。ただし、コミットフェーズ中にディスクの書き込みアクティビティが非常に高い場合には、スタンタイムが数秒に長引くことがあります。 > VM が、Caché データベースミラーリングに参加するプライマリまたはバックアップメンバーであり、スタンタイムがミラーのサービス品質(QoS)タイムアウトより長引く場合、ミラーはプライマリ VM に失敗としてレポートし、ミラーのテイクオーバーを開始します。 **2018 年 3 月更新:** 同僚の Pter Greskoff から指摘されました。バックアップミラーメンバーは、VM スタン中またはプライマリミラーメンバーが利用不可である場合には、QoS タイムアウトの半分超という短時間でフェイルオーバーを開始することがあります。 QoS の考慮事項とフェイルオーバーのシナリオの詳細については、「[Quality of Service Timeout Guide for Mirroring](https://community.intersystems.com/post/quality-service-timeout-guide-mirroring)(ミラーリングのサービス品質タイムアウトに関するガイド)」という素晴らしい記事を参照できますが、以下に、VM スタンタイムと QoS に関する要約を示します。 > バックアップミラーが、QoS タイムアウトの半分の時間内にプライマリミラーからメッセージを受信しない場合、ミラーはプライマリが動作しているかどうかを確認するメッセージを送信します。 それからバックアップはさらに QoS タイムアウトの半分の時間、プライマリマシンからの応答を待機します。 プライマリからの応答がない場合、プライマリは停止しているとみなされ、バックアップがテイクオーバーします。 ビジー状態のシステムでは、プライマリからバックアップミラーにジャーナルが継続的に送信されるため、バックアップはプライマリが動作しているかどうかを確認する必要はありません。 ただし、バックアップが発生している可能性が高い静止時間中、アプリケーションがアイドル状態である場合、QoS タイムアウトの半分以上の時間、プライマリとバックアップミラーの間でメッセージのやり取りがない可能性があります。 これは Peter が提示した例ですが、このタイムフレームを、QoS タイムアウトが :08 秒で VM スタンタイムが :07 秒のアイドル状態にあるシステムで考えてみましょう。 - :00 プライマリは キープライブでアービターに ping し、アービターは即座に応答 - :01 バックアップメンバーはプライマリにキープアライブを送信し、プライマリは即座に応答 - :02 - :03 VM スタンの開始 - :04 プライマリはアービターにキープアライブを送信しようとするが、スタンが完了するまで到達しない - :05 QoS の半分の時間が経過したため、バックアップメンバーはプライマリに ping を送信 - :06 - :07 - :08 QoS タイムアウトが過ぎてもアービターはプライマリからの応答を受信しないため、接続を閉じる - :09 バックアップはプライマリからの応答を受信していないため、接続が失われたことをアービターに確認し、テイクオーバーを開始 - :10 VM スタンが終了するが、間に合わない!! 上記のリンク先の記事にある「_Pitfalls and Concerns when Configuring your Quality of Service Timeout_(サービス品質タイムアウトを構成する際の落とし穴と考慮事項)」のセクションもお読みください。QoS を必要な期間だけ確保する際のバランスが説明されています。 QoS が長すぎる場合、特に 30 秒を超える場合も問題を引き起こす可能性があります。 **2018 年 3 月更新の終了:** ミラーリングの QoS の詳細については、[ドキュメンテーション](https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GHA_mirror#GHA_mirror_set_tunable_params_qos)を参照してください。 > スタンタイムを最小限に抑える戦略には、データベースアクティビティが低い場合にバックアップを実行することと、ストレージを十分にセットアップすることが挙げられます。 上記で述べたように、スナップショットの作成時に指定できるオプションがいくつかあります。その 1 つは、スナップショットにメモリ状態を含めることです。_Caché データベースのバックアップにはメモリ状態は不要である_ことに注意してください。 メモリフラグが設定されている場合、仮想マシンの内部状態のダンプがスナップショットに含められます。 メモリスナップショットの作成には、もっと長い時間がかかります。 メモリスナップショットは、実行中の仮想マシンの状態を、スナップショットが作成された時の状態に戻すために使用されます。 これは、データベースファイルのバックアップには必要ありません。 > メモリスナップショットを作成する場合、仮想マシンの状態全体が停止しますが、**スタンタイムはさまざま**です。 前述のとおり、バックアップでは、整合性のある使用可能なバックアップを保証するために、手動スナップショットで、またはバックアップソフトウェアによって、静止フラグを true に設定する必要があります。 ## VMware ログでスタンタイムを確認 ESXi 5.0 より、スナップショットのスタンタイムは、以下のようなメッセージで仮想マシンのログファイル(vmware.log)に記録されます。 `2017-01-04T22:15:58.846Z| vcpu-0| I125: Checkpoint_Unstun: vm stopped for 38123 us` スタンタイムはミリ秒単位であるため、上記の例にある `38123 us` は 38123/1,000,000 秒または 0.038 秒となります。 スタンタイムが許容範囲内であることを確認するため、またはスタンタイムが長引くせいで問題が発生していると思われる場合にトラブルシューティングを実施するため、関心のある VM のフォルダから vmware.log ファイルをダウンロードして確認することができます。 ダウンロードしたら、以下の Linux コマンドの例を使うなどして、ログを抽出しソートできます。 ### vmware.log ファイルのダウンロード例 vSphere 管理コンソールまたは ESXi ホストコマンドラインから VMware サポートバンドルを作成するなど、サポートログのダウンロードにはいくつかの方法があります。 全詳細については VMware ドキュメンテーションを参照できますが、以下は、スタンタイムを確認できるように、`vmware.log` ファイルを含む非常に小さなサポートバンドルを作成して収集する簡単な方法です。 VM ファイルが配置されているディレクトリの正式な名称が必要となります。 ssh を使用してデータベース VM が実行している ESXi ホストにログオンし、コマンド `vim-cmd vmsvc/getallvms ` を使用して vmx ファイルとそれに関連付けられた一意の正式名称を一覧表示します。 たとえば、この記事で使用されているデータベース VM の正式な名称は次のように出力されます。 `26 vsan-tc2016-db1 [vsanDatastore] e2fe4e58-dbd1-5e79-e3e2-246e9613a6f0/vsan-tc2016-db1.vmx rhel7_64Guest vmx-11` 次に、ログファイルのみを収集してバンドルするコマンドを実行します。 `vm-support -a VirtualMachines:logs` コマンドによって、以下の例のように、サポートバンドルの場所が表示されます。 `To see the files collected, check '/vmfs/volumes/datastore1 (3)/esx-esxvsan4.iscinternal.com-2016-12-30--07.19-9235879.tgz'`. これで、sftp を使用してファイルをホストから転送し、さらに処理して確認できるようになりました。 この例では、サポートバンドルを解凍した後に、データベース VM の正式名称に対応するパスに移動します。 この場合は、 `/vmfs/volumes//e2fe4e58-dbd1-5e79-e3e2-246e9613a6f0` というパスになります。 そこで番号付きの複数のログファイルが表示されます。最新のログファイルには番号は付きません。つまり、`vmware.log` と示されます。 ログはわずか数百 KB ですが、たくさんの情報が記載されています。ただし、注目するのは stun/unstun の時間のみで、`grep` を使うと簡単に見つけ出すことができます。 次は、その記載例です。 $ grep Unstun vmware.log 2017-01-04T21:30:19.662Z| vcpu-0| I125: Checkpoint_Unstun: vm stopped for 1091706 us --- 2017-01-04T22:15:58.846Z| vcpu-0| I125: Checkpoint_Unstun: vm stopped for 38123 us 2017-01-04T22:15:59.573Z| vcpu-0| I125: Checkpoint_Unstun: vm stopped for 298346 us 2017-01-04T22:16:03.672Z| vcpu-0| I125: Checkpoint_Unstun: vm stopped for 301099 us 2017-01-04T22:16:06.471Z| vcpu-0| I125: Checkpoint_Unstun: vm stopped for 341616 us 2017-01-04T22:16:24.813Z| vcpu-0| I125: Checkpoint_Unstun: vm stopped for 264392 us 2017-01-04T22:16:30.921Z| vcpu-0| I125: Checkpoint_Unstun: vm stopped for 221633 us この例では、2つのグループのスタンタイムを確認できます。1 つはスナップショップ作成時、そしてもう 1 つは、各ディスクのスナップショットが削除/統合された 45 分後(バックアップソフトウェアが読み取り専用 vmx ファイルのコピーを完了したとき)のものです。 上記の例では、最初のスタンタイムは 1 秒をわずかに上回っていますが、ほとんどのスタンタイムは 1 秒未満であることがわかります。 短時間のスタンタイムは、エンドユーザーが気付くものではありませんが、 Caché データベースミラーリングなどのシステムプロセスは、インスタンスが「アライブ」であるかどうかを継続的に監視しています。 スタンタイムがミラーリング QoS タイムアウトを超える場合、ノードは接続不可能であり「停止」状態とみなされ、フェイルオーバーがトリガーされます。 _ヒント:_ すべてのログを確認するか、トラブルシューティングを実行する場合には、grep コマンドが役立ちます。すべての `vmware*.log` ファイルに対して grep を使用し、異常値、またはスタンタイムが QoS タイムアウトに達しているインスタンスを探してください。 以下のコマンドは、出力をパイプ処理し、awk で書式設定しています。 `grep Unstun vmware* | awk '{ printf ("%'"'"'d", $8)} {print " ---" $0}' | sort -nr` # 最後に 通常稼働時に定期的にシステムを監視し、スタンタイムと、ミラーリングなどの HA 向けの QoS タイムアウトへの影響を理解しておく必要があります。 前述のとおり、スタンタイムまたはスタン解除タイムを最小限に抑える戦略には、データベースとストレージのアクティビティが低い場合にバックアップを実行することと、ストレージを十分にセットアップすることが挙げられます。 常時監視の場合、ログは、VMware ログのインサイトなどのツールを使用して処理できるかもしれません。 InterSystems データプラットフォームのバックアップと復元操作について、今後の記事で再度取り上げる予定です。 それまでは、システムのワークフローに基づいたコメントや提案がある場合は、以下のコメントセクションに投稿してください。
記事
Toshihiko Minamoto · 2021年4月19日

仮想IPアドレスを使用しないデータベースミラーリング

**++更新日:2018年8月1日** Cachéデータベースミラーリングに組み込まれているInterSystems仮想IP(VIP)アドレスの使用には、特定の制限があります。 具体的に言うと、ミラーメンバーが同じネットワークサブネットに存在する場合にのみ使用できるというところです。 複数のデータセンターを使用した場合は、ネットワークの複雑さが増すため、ネットワークサブネットが物理的なデータセンターを越えて「延伸」されることはさほどありません(より詳細な説明は[こちら](https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GHA_mirror#GHA_mirror_set_comm_network_dual)です)。 同様の理由で、データベースがクラウドでホストされている場合、仮想IPは使用できないことがよくあります。 ロードバランサー(物理的または仮想)などのネットワークトラフィック管理のアプライアンスを使用して、クライアントアプリケーションやデバイスに単一のアドレスを提示することで、同レベルの透過性を実現できます。 ネットワークトラフィックマネージャは、クライアントを現在のミラープライマリの実際のIPアドレスに自動的にリダイレクトします。 この自動化は、災害後のHAフェイルオーバーとDRプロモーションの両方のニーズを満たすことを目的としています。  # ネットワークトラフィックマネージャーの統合 今日の市場には、ネットワークトラフィックのリダイレクトに対応する多数のオプションが存在します。  アプリケーション要件に基づいてネットワークフローを制御するために、これらのオプションはそれぞれ似たような方法論もしくは複数の方法論に対応しています。  これらの方法論を単純化するために、 _データベース_ _サーバー呼び出し型API、ネットワークアプライアンスポーリング、_または両方を組み合わせたものの、3つのカテゴリを検討していきます。   次のセクションでは、これらの方法論をそれぞれ概説し、各々をInterSystems製品と統合する方法について説明していきます。  すべてのシナリオでアービターは、ミラーメンバーが直接通信できない場合に安全なフェイルオーバーの判断を下すために使用されます。  アービターの詳細は、[こちら](http://docs.intersystems.com/cache20161/csp/docbook/DocBook.UI.Page.cls?KEY=GHA_mirror#GHA_mirror_set_arbiter)を参照してください。 この記事では、図の例は、プライマリ、バックアップ、およびDR非同期の3つのミラーメンバーを示すものとします。  ただし、ユーザーの構成には、ミラーメンバーがより多く含まれている場合、またはより少なく含まれている場合があるということは理解しております。 ## オプション1:ネットワークアプライアンスのポーリング(_推奨_) この方法では、ネットワーク負荷分散アプライアンスは、組み込みのポーリングメカニズムを使用して、両方のミラーメンバーと通信することでプライマリミラーメンバーを決定します。  2017.1で利用可能なCSP Gatewayの_mirror_status.cxw_ページを使用するポーリングメソッドは、ELBサーバープールに追加された各ミラーメンバーに対するELBヘルスモニターのポーリングメソッドとして使用できます。  プライマリミラーのみが「SUCCESS」と応答するため、ネットワークトラフィックはアクティブなプライマリミラーメンバーのみに転送されます。  このメソッドでは、^ZMIRRORにロジックを追加する必要はありません。  ほとんどの負荷分散ネットワークアプライアンスには、ステータスチェックの実行頻度に制限があることに注意してください。  通常、最高頻度は一般的にほとんどの稼働時間サービス水準合意書で許容される5秒以上に設定されています。 次のリソースへのHTTPリクエストは、【ローカル】キャッシュ構成のミラーメンバーのステータスをテストします。 **_ `/csp/bin/mirror_status.cxw`_** それ以外の場合、ミラーステータスリクエストのパスは、実際のCSPページのリクエストに使用されるのと同じ階層構造を使用し、適切なキャッシュサーバーとネームスペースに解決されます。 例:/csp/user/ パスにある構成を提供するアプリケーションのミラーステータスをテストする場合は次のようになります。 **_ `/csp/user/mirror_status.cxw`_** **注意:ミラーライセンスチェックを実行しても、CSPライセンスは消費されません。** ターゲットインスタンスがアクティブなプライマリメンバーであるかどうかに応じて、ゲートウェイは以下のCSP応答のいずれかを返します。 **** 成功(プライマリメンバーである)** _=============================== _ _   HTTP/1.1 200 OK_ _   Content-Type: text/plain_ _   Connection: close_ _   Content-Length: 7_ _   SUCCESS_ **** 失敗(プライマリメンバーではない)** _===============================_ _   HTTP/1.1 503 Service Unavailable_ _   Content-Type: text/plain_ _   Connection: close_ _   Content-Length: 6_ _   FAILED_ **** 失敗(キャッシュサーバーが_Mirror_Status.cxw_のリクエストをサポートしていない)** _===============================_ _   HTTP/1.1 500 Internal Server Error_ _   Content-Type: text/plain_ _   Connection: close_ _   Content-Length: 6_ _   FAILED_ ポーリングの例として、次の図を検討してみましょう。 ![](/sites/default/files/inline/images/picture4.png) フェイルオーバーは、同期フェイルオーバーミラーメンバー間で自動的に発生します: ![](/sites/default/files/inline/images/picture5.png) 次の図は、DR非同期ミラーメンバーの負荷分散プールへの昇格を表しています。これは通常、同じ負荷分散ネットワークアプライアンスがすべてのミラーメンバーにサービスを提供していることを前提としています(地理的に分割されたシナリオについては、この記事の後半で説明します)。 標準のDR手順に従って、災害復旧メンバーの昇格には、人間による決定およびデータベースレベルでの簡単な管理アクションが必要になります。 ただし、そのアクションが実行されると、ネットワークアプライアンスでの管理アクションは必要ありません。新しいプライマリが自動的に検出されます。 ![](/sites/default/files/inline/images/picture6.png) ## オプション2:データベースサーバー呼び出し型API この方法では、フェイルオーバーミラーメンバーと潜在的にDR非同期ミラーメンバーの両方で定義されたサーバープールがあり、ネットワークトラフィック管理アプライアンスが使用されます。   ![](/sites/default/files/inline/images/picture1.png) ミラーメンバーがプライマリミラーメンバーになると、優先度または重み付けを調整して、ネットワークトラフィックを新しいプライマリミラーメンバーに転送するようにネットワークアプライアンスにただちに指示を出すために、ネットワークアプライアンスに対してAPI呼び出しが実行されます。   ![](/sites/default/files/inline/images/picture2.png) 同様のモデルは、プライマリミラーメンバーとバックアップミラーメンバーの両方が利用できなくなった場合のDR非同期ミラーメンバーの昇格にも適用されます。 ![](/sites/default/files/inline/images/picture3.png) このAPIは、具体的には次のようにプロシージャコールの一部として^ZMIRRORルーチンで定義されています: **_$$CheckBecomePrimaryOK^ZMIRROR()_** このプロシージャコールの中に、REST API、コマンドラインインターフェイスなど該当するネットワークアプライアンスで利用可能なAPIロジックやメソッドを挿入します。 仮想IPの場合と同様に、これは唐突なネットワーク構成の変更であり、障害が発生したプライマリミラーメンバーと接続している既存のクライアントに対し、フェイルオーバーが発生していることを通知するアプリケーションロジックは必要としません。 障害の性質によっては、障害そのものや、アプリケーションのタイムアウトやエラー、新しいプライマリによる古いプライマリインスタンスの強制停止、あるいはクライアントが使用したTCPキープアライブタイマーの失効が原因でこれらの接続が終了する可能性があります。 その結果、ユーザーは再接続してログインする必要がでてくるかもしれません。  この動作はあなたのアプリケーションの動作によって決まります。 ## オプション3:地理的に分散された展開 複数のデータセンターを備えた構成や、複数のアベイラビリティーゾーンと地理的ゾーンを備えたクラウド展開など、地理的に分散された展開では、DNSベースの負荷分散とローカル負荷分散の両方を使用するシンプルでサポートしやすいモデルで地理的なリダイレクトの慣行を考慮する必要が生じます。 この組み合わせモデルでは、各データセンター、アベイラビリティーゾーン、またはクラウド地理的地域にあるネットワークロードバランサーと合わせて、Amazon Route 53、F5 Global Traffic Manager、Citrix NetScaler Global Server Load Balancing、Cisco Global SiteSelectorなどのDNSサービスと連携する追加のネットワークアプライアンスを導入します。 このモデルでは、前述のポーリング(_推奨_)またはAPIメソッドのいずれかが、ミラーメンバー(フェイルオーバーまたはDR非同期のいずれか)が稼働している場所に対してローカルで使用されます。  これは、トラフィックをいずれかのデータセンターに転送できるかどうかを地理的/グローバルネットワークアプライアンスに報告するために使用されます。  また、この構成では、ローカルネットワークトラフィック管理アプライアンスは、地理的/グローバルネットワークアプライアンスに独自のVIPを提示します。 通常の定常状態では、アクティブなプライマリミラーメンバーは、プライマリであることをローカルネットワークアプライアンスに報告し、「Up」ステータスを提供します。  この「Up」ステータスは、すべてのリクエストをこのアクティブなプライマリミラーメンバーに転送するためにDNSレコードを調整および維持するよう、地理的/グローバルアプライアンスに中継されます。 同じデータセンター内でフェイルオーバーが起きた場合(バックアップ同期ミラーメンバーがプライマリになった場合)は、APIまたはポーリング方式のいずれかがローカルロードバランサーで使用され、同じデータセンター内の新しいプライマリミラーメンバーにリダイレクトされます。  新しいプライマリミラーメンバーがアクティブであり、ローカルロードバランサーは引き続き「Up」ステータスで応答しているため、地理的/グローバルアプライアンスへの変更は行われません。 次の図で、ネットワークアプライアンスへのローカル統合のためにAPI方式を使用して、例を説明します。 ![](/sites/default/files/inline/images/picture7.png) APIまたはポーリング方式のいずれかを使用した別のデータセンターへのフェイルオーバーが起きた場合(代替データセンターの同期ミラーまたはDR非同期ミラーメンバーの場合)は、新しく昇格されたプライマリミラーメンバーがプライマリとしてローカルネットワークアプライアンスへ報告を開始します。 フェイルオーバー中は、かつてプライマリが含まれていたデータセンターは、ローカルロードバランサから地理的/グローバルへの「Up」を報告しなくなります。  地理的/グローバルアプライアンスは、トラフィックをそのローカルアプライアンスには転送しません。   代替データセンターのローカルアプライアンスは、地理的/グローバルアプライアンスに「Up」と報告し、DNSレコードの更新を呼び出して、代替データセンターのローカルロードバランサーによって提示された仮想IPに転送するようにします。 ![](/sites/default/files/inline/images/picture8.png) ## オプション4:多層的、および地理的に分散された展開 ソリューションをさらに一歩進めるには、プライベートWANの内部として、またはインターネット経由でアクセス可能なものとして、個別のWebサーバー層を導入します。  恐らくこのオプションは、大規模なエンタープライズアプリケーションの一般的な展開モデルです。  次の例では、複数のネットワークアプライアンスを使用して、Web層とデータベース層を安全に分離およびサポートする構成例を示しています。  このモデルでは、地理的に分散された2つの場所が使用され、1つは「プライマリ」場所と見なされ、もう1つはデータベース層用「災害復旧」専用の場所です。  データベース層災害復旧の場所は、プライマリな場所が何らかの理由で運転休止になった場合に使用されます。   さらに、この例のWeb層は、アクティブ - アクティブとして示されます。つまりユーザーは、最小の遅延、最小の接続数、IPアドレス範囲、または適切と思われるその他のルーティンルールなど、さまざまなルールに基づいていずれかの場所に転送されます。 ![](/sites/default/files/inline/images/picture9.png) 上記の例が示すように、同じ場所でフェイルオーバーが起きた場合は、自動フェイルオーバーが発生し、ローカルネットワークアプライアンスが新しいプライマリを指すようになります。  ユーザーは引き続きいずれかの場所のWebサーバーに接続し、Webサーバーは関連付けられたCSPゲートウェイで引き続き場所Aを指します。 次の例では、プライマリフェイルオーバーミラーメンバーとバックアップフェイルオーバーミラーメンバーの両方が稼働していないロケーションAでの完全フェイルオーバーまたは運転休止について検討します。  このような場合、DR非同期ミラーメンバーは、プライマリおよびバックアップフェイルオーバーミラーメンバーに手動で昇格されます。  昇格されると、新しく指定されたプライマリミラーメンバーにより、ロケーションBの負荷分散アプライアンスが前述のAPIメソッドを使用して「Up」を報告できるようになります(ポーリングメソッドもオプションの1つです)。  ローカルロードバランサーが「Up」を報告するようになった結果、DNSベースのアプライアンスはそれを認識し、データベースサーバーサービスのためにトラフィックを場所Aから場所Bにリダイレクトします。 ![](/sites/default/files/inline/images/picture10.png) ## まとめ 仮想IPを使用しないにミラーフェイルオーバーを設計するには、さまざまな組み合わせが考えられます。 これらのオプションは、最も単純な高可用性シナリオまたはフェイルオーバーとDR非同期ミラーメンバーの両方を含む複数の層を備えた複数の地域に渡る展開のいずれにも適用でき、アプリケーションの最高レベルの運用回復力を維持することを目的とした、可用性が高く災害に強いソリューションを実現できます。 この記事では、あなたのアプリケーションと可用性の要件に適したフェイルオーバーを備えたデータベースミラーリングを正常に展開するために可能なさまざまな組み合わせと活用事例に関して説明いたしました。
記事
Toshihiko Minamoto · 2020年12月22日

HealthShare の Apache HTTPD Web サーバー構成

HealthShare の理想的な Apache HTTPD Web サーバー構成に関するお問い合わせをよくいただいています。 この記事では、真っ先に推奨される HealthShare 製品の Web サーバー構成について概要を説明します。 何よりもまず第一に、Apache HTTPD バージョン 2.4.x(64ビット)を使用することをお勧めします。 2.2.x のような旧バージョンも使用できますが、HealthShare のパフォーマンスとスケーラビリティを確保するにはバージョン 2.2 はお勧めできません。 ## **Apache の構成** ### NSD を使用しない Apache API モジュール {#ApacheWebServer-ApacheAPIModulewithoutNSD} HealthShare では、NSD を使用しない Apache API モジュールをインストールオプションに指定する必要があります。 動的にリンクされるモジュールのバージョンは、Apache のバージョンによって異なります。 * CSPa24.so(Apache バージョン 2.4.x) Apache の httpd.conf での Caché Server Pages の構成は、このドキュメントで詳しく説明する HealthShare のインストールによって実行するのが最善です。 ただし、この設定は手動で実行することもできます。 詳細については、InterSystems のドキュメントに掲載されている Apache 構成ガイド「推奨オプション:NSD を使用しない Apache API モジュール(CSPa24.so)」を参照してください。 ## **Apache マルチプロセッシングモジュール(MPM)の推奨事項** {#ApacheWebServer-ApacheMulti-ProcessingModuleRecommendations} ### Apache Prefork MPM と Worker MPM {#ApacheWebServer-ApachePreforkMPMVs.WorkerMPM} Apache HTTPD Web サーバーには、Prefork / Worker / Event の 3 つのマルチプロセッシングモジュール(MPM)が付属しています。 MPM はマシンのネットワークポートへのバインド、リクエストの受理、およびリクエストを処理するように子プロセスに割り当てたりする役割を担います。Apache はデフォルトで通常はトランザクションが多い場合や同時接続による負荷が高い場合には適切に拡張できない Prefork MPM で構成されています。 HealthShare の本番システムでは、Apache MPM **_Worker_** を有効にしてパフォーマンスとスケーラビリティを確保する必要があります。 Worker MPM が推奨される理由は次のとおりです。 * Prefork MPM はそれぞれ 1 つのスレッドを持つ複数の子プロセスを使用し、各プロセスが一度に 1 つの接続を処理します。 Prefork を使用する場合は各プロセスが一度に 1 つのリクエストしか処理できないため、同時リクエストが発生した場合に支障が出ます。この場合、リクエストはサーバープロセスが解放されるまでキューに格納されます。 また、スケーリングするには大量のメモリを消費する Prefork の子プロセスがさらに必要になります。 * Worker MPM は、それぞれ多数のスレッドを持つ複数の子プロセスを使用します。 各スレッドが一度に 1 つの接続を処理することで同時実行性が大幅に向上し、メモリ要件が低くなります。 Worker の場合はビジー状態の可能性があるシングルスレッドの Prefork プロセスとは異なり、通常はリクエストの処理に使用できる空きスレッドがあるため、Prefork よりも高度に同時リクエストを処理できます。 ### Apache Worker MPM のパラメーター {#ApacheWebServer-ApacheWorkerMPMParameters} Worker はスレッドを使用してリクエストを処理するため、Prefork プロセスベースのサーバーよりも少ないシステムリソースで多数のリクエストを処理できます。 Worker MPM の制御に使用される最も重要なディレクティブは、各子プロセスが生成するスレッドの数を制御する **ThreadsPerChild** と起動可能なスレッドの最大数を制御する **MaxRequestWorkers** です。 推奨される Worker MPM 共通ディレクティブの値を以下の表に詳しく記載しています。 推奨される Apache HTTPD Web サーバーのパラメーター Apache Worker MPM のディレクティブ 推奨値 コメント MaxRequestWorkers  HealthShare Clinical Viewer の最大同時接続ユーザー数、または他の HealthShare コンポーネントの場合は定義されているすべての本番インターフェースの着信ビジネスサービスのプールサイズの合計値に設定されます。* 注意: 構成時に不明であれば「1000」で開始してください MaxRequestWorkers は同時に処理されるリクエストの数を制限します。つまり、クライアントにサービスを提供するために使用できるスレッドの総数を制限します。MaxRequestWorkers は低すぎる値に設定するとリソースが無駄になり、高すぎる値に設定するとサーバーのパフォーマンスに影響が出るため、正しく設定しなければなりません。Worker の数を超える接続があった場合、接続はキューに格納されてしまいます。 デフォルトのキューは、ListenBackLog ディレクティブで調整できます。   MaxSpareThreads 250 MaxSpareThreads はサーバー全体のアイドルなスレッドの数を制御します。 サーバー上にアイドルなスレッドが多すぎる場合、アイドルなスレッドの数がこの数より少なくなるまで子プロセスが強制終了されます。 スペアスレッドの量をデフォルトより多くすると、プロセスが再生成される確率が低くなります。 MinSpareThreads 75 MinSpareThreads はサーバー全体のアイドルなスレッドの数を制御します。 サーバー上にアイドルなスレッドが不足している場合、アイドルなスレッドの数がこの数より多くなるまで子プロセスが生成されます。 スペアスレッドの量をデフォルトより少なくすると、プロセスが再生成される確率が低くなります。   ServerLimit MaxRequestWorkers を ThreadsPerChild で割った値 サーバー稼働中における MaxRequestWorkers の最大値です。 ServerLimit はアクティブな子プロセス数の厳密な上限値であり、MaxRequestWorkers ディレクティブを ThreadsPerChild ディレクティブで割った値以上である必要があります。 worker では MaxRequestWorkers および ThreadsPerChild の設定で 16(デフォルト)以上のサーバープロセスが必要な場合にのみ、このディレクティブを使用してください。   StartServers 20 StartServers ディレクティブは起動時に生成される子サーバープロセスの数を設定します。 プロセス数は負荷に応じて動的に制御されるため、サーバーが起動時に大量の接続を処理できるようにする場合を除き、通常はこのパラメーターを調整する理由はほとんどありません。   ThreadsPerChild 25 このディレクティブは各子プロセスが生成するスレッドの数を設定します。デフォルトでは 25 です。 デフォルト値を増やすと単一のプロセスに過度に依存する可能性があるため、デフォルト値を維持することをお勧めします。 詳細については、関連する Apache バージョンのドキュメントを参照してください。 * [Apache 2.4 の MPM 共通ディレクティブ](http://httpd.apache.org/docs/2.4/mod/mpm_common.html) ### Apache 2.4 の Worker MPM 構成の例 {#ApacheWebServer-ExampleApache2.4WorkerMPMConfiguration} このセクションでは、最大 500 人の TrakCare ユーザーが同時接続できるようにするために必要な RHEL7 の Apache 2.4 Web サーバー用に Worker MPM の構成について詳しく説明します。 1. まず、以下のコマンドを使用して MPM を確認します。![](/sites/default/files/inline/images/images/apache1.png) 2. 必要に応じて、構成ファイル /etc/httpd/conf.modules.d/00-mpm.conf を編集します。コメント文字 # の追加や削除を行い、Worker MPM モジュールのみがロードされるようにしてください。 Worker MPM セクションを、以下と同じ順序で次の値に変更します。![](/sites/default/files/inline/images/images/Apache2.png) 3. Apache を再起動します。 4. Apache が正常に再起動したら、以下のコマンドを実行して worker プロセスを検証します。 次のような内容が表示され、httpd.worker プロセスを確認できます。![](/sites/default/files/inline/images/images/Apache3.png) ## **Apache の強化** {#ApacheWebServer-ApacheHardening} ### Apache に必要なモジュール {#ApacheWebServer-ApacheRequiredModules} 公式の Apache 配布パッケージをインストールすると、デフォルトで特定の Apache モジュールセットが有効になります。 Apache のこのデフォルト構成では、これらのモジュールが各 httpd プロセスにロードされます。 次の理由により、HealthShare に必要のないすべてのモジュールを無効にすることをお勧めします。 * httpd デーモンプロセスのメモリ使用量が削減されます。 * 不正なモジュールに起因するセグメンテーション違反の可能性が低下します。 * セキュリティの脆弱性が削減されます。 HealthShare に推奨される Apache モジュールの詳細を以下の表に記載しています。 以下に掲載されていないモジュールは無効にすることができます。 | モジュール名 | 説明 | | ----------- | ------------------------------------------------------------- | | alias | ホストファイルシステム内のさまざまな場所をドキュメントツリーにマッピングする機能と、URL リダイレクト機能を提供します。 | | authz_host | クライアントのホスト名、IPアドレスに基づいてアクセス制御を行います。 | | dir | 末尾のスラッシュを補完してリダイレクトする機能と、ディレクトリのインデックスファイルを扱う機能を提供します。 | | headers | HTTP リクエストとレスポンスヘッダーを制御および変更するためのモジュールです。 | | log_config | サーバーに対して発行されるリクエストのログを記録します。 | | mime | リクエストされたファイル名の拡張子をファイルの振る舞いと内容に関連付けます。 | | negotiation | クライアントの特性に応じて最適なドキュメントの内容を選択する機能を提供します。 | | setenvif | リクエストの特徴に基づいて環境変数を設定できるようにします。 | | status | サーバーのステータスとパフォーマンスに関する統計を表示します。 | ### モジュールを無効にする セキュリティの脆弱性を減らすように構成を強化するには、不要なモジュールを無効にする必要があります。 Web サーバーのセキュリティポリシーを管理するのはお客様の役割です。 少なくとも、以下のモジュールを無効にする必要があります。 | モジュール名 | 説明 | | --------- | -------------------------------------------------------------------------------- | | asis | 独自の HTTP ヘッダーを含むファイルを送信する機能を提供します。 | | autoindex | index.html ファイルが存在しない場合にディレクトリインデックスを生成し、ディレクトリをリスト表示する機能を提供します。 | | env | CGI スクリプトと SSI ページに渡される環境変数を変更する機能を提供します。 | | cgi | cgi - CGI スクリプトを実行する機能を提供します。 | | actions | メディアタイプまたはリクエストメソッドに基づいて CGI スクリプトを実行し、リクエストに応じてアクションをトリガーする機能を提供します。 | | include | サーバーで解析された HTML ドキュメント(サーバーサイドインクルード)を使用可能にするモジュールです。 | | filter | リクエストの高度なフィルタリング機能を提供します。 | | version | IfVersion を使用して構成ファイル内でバージョン情報を処理できるようにします。 | | userdir | リクエストをユーザー専用のディレクトリにマッピングする機能を提供します。 具体的には、URL の ~username がサーバー内のディレクトリに変換されます。 | ## **Apache SSL/TLS** {#ApacheWebServer-ApacheSSLTLS} 転送中のデータを保護し、機密性を確保して認証を行うため、InterSystems は HealthShare サーバーとクライアント間のすべての TCP/IP 通信を SSL/TLS で暗号化し、さらにはユーザーのブラウザクライアントと提案されたアーキテクチャの Web サーバーレイヤー間のすべての通信に HTTPS を使用することを推奨しています。 所属する組織に固有のセキュリティ要件に準拠していることを確認するには、必ず所属する組織のセキュリティポリシーを参照してください。 SSL/TLS 証明書を提供および管理するのはお客様の役割です。 SSL 証明書を使用している場合は、ssl\_module(mod\_ssl.so)を追加してください。 ## **追加の Apache 強化パラメーター** {#ApacheWebServer-AdditionalHardeningApacheParameters} Apache 構成をさらに強化するには、httpd.conf で次の変更を行ってください。 * 潜在的なクロスサイトトレーシングの問題を防ぐため、TraceEnable をオフにする必要があります。 ![](/sites/default/files/inline/images/images/Apache4.png) * Web サーバーのバージョンが表示されないようにするため、ServerSignature をオフにする必要があります。 ![](/sites/default/files/inline/images/images/Apache5.png) ## 補足的な Apache 構成パラメーター {#ApacheWebServer-SupplementalApacheConfigurationParameters} ### Keep-Alive {#ApacheWebServer-Keep-Alive} Apache の Keep-Alive 設定は、新しいリクエストのたびに新しい接続をオープンせず、同じ TCP 接続を使用して HTTP 通信を行えるようにするものです。 Keep-Alive はクライアントとサーバー間に持続的な接続を維持します。 Keep-Alive オプションを有効にすると、ネットワークの輻輳が軽減され、後続リクエストの遅延が少なくなり、同時接続のオープンに起因する CPU 消費が低下し、パフォーマンスが向上します。 Keep-Alive はデフォルトでオンになっており、HTTP v1.1 標準では当然オンにすることが求められています。 ただし、Keep-Alive を有効にする場合は注意が必要です。Internet Explorer は古いバージョンでの既知のタイムアウトの問題を回避するため、 IE10 以降でなければなりません。 また、ファイアウォール、ロードバランサー、プロキシなどの仲介者が「持続的なTCP接続」に干渉し、予期せず接続が閉じられてしまう可能性もあります。  Keep-Alive を有効にする場合は、Keep-Alive のタイムアウト値も設定する必要があります。 Apache デフォルトの Keep-Alive タイムアウト値は非常に小さく、壊れた AJAX(hyperevent などの)リクエストに関連して問題が発生する可能性があるため、ほとんどの構成では大きくする必要があります。 これらの問題は、サーバーの Keep-Alive タイムアウト値がクライアントのタイムアウト値よりも大きくなるように調整することで回避できます。 つまり、サーバーではなくクライアントがタイムアウトして接続を閉じるようにすべきです。 ブラウザが当然オープンしていると考えている接続を(特に POST する場合に)使用しようとすると、問題が発生します(ほとんどの場合は IE で発生し、他のブラウザではそれほど発生しません)。 HealthShare Web サーバーに推奨される KeepAlive と KeepAliveTimeout の値については、以下を参照してください。 Apache で KeepAlive を有効にするには、httpd.conf で以下のように変更を行ってください。 ![](/sites/default/files/inline/images/images/Apache6.png) ### CSP Gateway {#ApacheWebServer-CSPGateway} CSP Gateway の KeepAlive パラメーターについては、各リクエストの HTTP レスポンスヘッダーによって KeepAlive のステータスが決まるため、この値はデフォルトの「No Action」のままにしてください。
記事
Toshihiko Minamoto · 2023年8月15日

Docker による Apache Web ゲートウェイ

# Docker による Apache Web ゲートウェイ コミュニティの皆さん、こんにちは。 この記事では、以下を使用して、Docker でプログラムによって Apache Web ゲートウェイを構成します。 * HTTPS プロトコル * Web ゲートウェイと IRIS インスタンス間の安全な通信を確保する TLS/SSL ![画像](/sites/default/files/inline/images/net-schema-01.png) イメージには、Web ゲートウェイ用と IRIS インスタンス用の 2 つを使用します。 すべての必要なファイルは、こちらの [GitHub リポジトリ](https://github.com/lscalese/docker-webgateway-sample)で入手可能です。 では、git clone から始めましょう。 ```bash git clone https://github.com/lscalese/docker-webgateway-sample.git cd docker-webgateway-sample ``` ## システムの準備 権限に関する問題を回避するために、システムにユーザーとグループが必要です。 * www-data * irisowner コンテナと証明書ファイルの共有に必要です。 これらがシステムに存在しない場合は、以下を実行します。 ```bash sudo useradd --uid 51773 --user-group irisowner sudo groupmod --gid 51773 irisowner sudo useradd –user-group www-data ``` ## 証明書の生成 この例では、以下の証明書を使用します。 1. HTTPS Web サーバーの使用状況 2. Web ゲートウェイクライアントの TLS/SSL 暗号化 3. IRIS インスタンスの TLS/SSL 暗号化 これらを生成するためにすぐに使用できるスクリプトが用意されています。 ただし、証明書の件名はカスタマイズする必要がありますが、これは、 [gen-certificates.sh](https://github.com/lscalese/docker-webgateway-sample/blob/master/gen-certificates.sh) ファイルを編集するだけです。 以下は、OpenSSL `subj` 引数の構造です。 1. **C**: 国コード 2. **ST**: 州 3. **L**: 場所 4. **O**: 組織 5. **OU**: 組織ユニット 6. **CN**: コモンネーム(基本的に、ドメイン名またはホスト名) これらの値を自由に変更してください。 ```bash # sudo is needed due chown, chgrp, chmod ... sudo ./gen-certificates.sh ``` すべてが正しく設定されたら、証明書を含む `./certificates/` と `~/webgateway-apache-certificates/` という新しいディレクトリが 2 つ表示されます。 | ファイル | コンテナ | 説明 | | ------------------------------------------------------ | --------------- | ------------------------------------------ | | ./certificates/CA_Server.cer | webgateway、iris | 認証局サーバー証明書 | | ./certificates/iris_server.cer | iris | IRIS インスタンスの証明書(ミラーと webgateway の通信暗号化に使用) | | ./certificates/iris_server.key | iris | 関連する秘密鍵 | | ~/webgateway-apache-certificates/apache_webgateway.cer | webgateway | Apache Web サーバーの証明書 | | ~/webgateway-apache-certificates/apache_webgateway.key | webgateway | 関連する秘密鍵 | | ./certificates/webgateway_client.cer | webgateway | webgateway と IRIS の通信を暗号化するための証明書 | | ./certificates/webgateway_client.key | webgateway | 関連する秘密鍵 | 自己署名証明書がある場合、Web ブラウザにセキュリティ警告が表示されることに注意してください。 認証許可から配布された証明書がある場合はもちろん、自己署名証明書の代わりにそれを使用できます(特に Apache サーバー証明書の場合)。 ## Web ゲートウェイ構成ファイル 構成ファイルを見てみましょう。 ### CSP.INI CSP.INI ファイルは `webgateway-config-files` ディレクトリにあります。 イメージにプッシュされますが、コンテンツはランタイム時に変更可能です。 このファイルをテンプレートとして考えてください。 この例では、コンテナの起動時に、以下のパラメーターがオーバーライドされます。 * Ip_Address * TCP_Port * System_Manager 詳細は、[startUpScript.sh](https://github.com/lscalese/docker-webgateway-sample/blob/master/startUpScript.sh) をご覧ください。 大まかに言えば、`sed` コマンドラインで置換が実行されます。 また、このファイルには、IRIS インスタンスとの通信を保護する SSL/TLS 構成が含まれています。 ``` SSLCC_Certificate_File=/opt/webgateway/bin/webgateway_client.cer SSLCC_Certificate_Key_File=/opt/webgateway/bin/webgateway_client.key SSLCC_CA_Certificate_File=/opt/webgateway/bin/CA_Server.cer ``` これらは重要な行です。 証明書ファイルがコンテナで使用できることを確認する必要があります。 これは、後で `docker-compose` ファイルの volume で行います。 ### 000-default.conf これは、Apache 構成ファイルです。 HTTPS プロトコルの使用を許可し、HTTP 呼び出しを HTTPS にリダイレクトします。 証明書と秘密鍵ファイルはこのファイルにセットアップされます。 ``` SSLCertificateFile /etc/apache2/certificate/apache_webgateway.cer SSLCertificateKeyFile /etc/apache2/certificate/apache_webgateway.key ``` ## IRIS インスタンス IRIS インスタンスでは、Web ゲートウェイとの SSL/TLS 通信を許可するための最小限の要件のみを以下の手順で構成します。 1. `%SuperServer` SSL 構成。 2. SSLSuperServer セキュリティ設定を有効にします。 3. Web ゲートウェイサービスを使用できる IP のリストを制限します。 構成を容易にするために、config-api は単純な JSON 構成ファイルと合わせて使用されます。 ```json { "Security.SSLConfigs": { "%SuperServer": { "CAFile": "/usr/irissys/mgr/CA_Server.cer", "CertificateFile": "/usr/irissys/mgr/iris_server.cer", "Name": "%SuperServer", "PrivateKeyFile": "/usr/irissys/mgr/iris_server.key", "Type": "1", "VerifyPeer": 3 } }, "Security.System": { "SSLSuperServer":1 }, "Security.Services": { "%Service_WebGateway": { "ClientSystems": "172.16.238.50;127.0.0.1;172.16.238.20" } } } ``` 操作は必要ありません。 この構成はコンテナの起動時に自動的に読み込まれます。 ## tls-ssl-webgateway イメージ ### dockerfile ``` ARG IMAGEWEBGTW=containers.intersystems.com/intersystems/webgateway:2021.1.0.215.0 FROM ${IMAGEWEBGTW} ADD webgateway-config-files /webgateway-config-files ADD buildWebGateway.sh / ADD startUpScript.sh / RUN chmod +x buildWebGateway.sh startUpScript.sh && /buildWebGateway.sh ENTRYPOINT ["/startUpScript.sh"] ``` デフォルトのエントリポイントは `/startWebGateway` ですが、Web サーバーを起動する前にいくつかの操作を実行する必要があります。 CSP.ini ファイルは`テンプレート`であり、起動時にいくつかのパラメーター(IP、ポート、システムマネージャー)を変更する必要があることに注意してください。 これらの変更は `startUpScript.sh` によって行われ、その後で初期化エントリポイントのスクリプト `/startWebGateway` が実行されます。 ## コンテナの起動 ### docker-compose ファイル コンテナを起動する前に、`docker-compose.yml` ファイルを変更する必要があります。 * `**SYSTEM_MANAGER**` は **Web Gateway Management** の https://localhost/csp/bin/Systems/Module.cxw へのアクセスが許可された IP で設定する必要があります。基本的に、あなたの IP アドレスです(カンマ区切りのリストである場合があります)。 * `**IRIS_WEBAPPS**` は、あなたの CSP アプリケーションのリストで設定する必要があります。 リストはスペース区切りです(例: `IRIS_WEBAPPS=/csp/sys /swagger-ui`)。 デフォルトでは、`/csp/sys` のみが公開されます。 * ポート 80 と 443 はマッピングされています。 これらのポートがすでに使用されている場合は、他のポートに調整します。 ``` version: '3.6' services: webgateway: image: tls-ssl-webgateway container_name: tls-ssl-webgateway networks: app_net: ipv4_address: 172.16.238.50 ports: # change the local port already used on your system. - "80:80" - "443:443" environment: - IRIS_HOST=172.16.238.20 - IRIS_PORT=1972 # Replace by the list of ip address allowed to open the CSP system manager # https://localhost/csp/bin/Systems/Module.cxw # see .env file to set environement variable. - "SYSTEM_MANAGER=${LOCAL_IP}" # the list of web apps # /csp allow to the webgateway to redirect all request starting by /csp to the iris instance # You can specify a list separate by a space : "IRIS_WEBAPPS=/csp /api /isc /swagger-ui" - "IRIS_WEBAPPS=/csp/sys" volumes: # Mount certificates files. - ./volume-apache/webgateway_client.cer:/opt/webgateway/bin/webgateway_client.cer - ./volume-apache/webgateway_client.key:/opt/webgateway/bin/webgateway_client.key - ./volume-apache/CA_Server.cer:/opt/webgateway/bin/CA_Server.cer - ./volume-apache/apache_webgateway.cer:/etc/apache2/certificate/apache_webgateway.cer - ./volume-apache/apache_webgateway.key:/etc/apache2/certificate/apache_webgateway.key hostname: webgateway command: ["--ssl"] iris: image: intersystemsdc/iris-community:latest container_name: tls-ssl-iris networks: app_net: ipv4_address: 172.16.238.20 volumes: - ./iris-config-files:/opt/config-files # Mount certificates files. - ./volume-iris/CA_Server.cer:/usr/irissys/mgr/CA_Server.cer - ./volume-iris/iris_server.cer:/usr/irissys/mgr/iris_server.cer - ./volume-iris/iris_server.key:/usr/irissys/mgr/iris_server.key hostname: iris # Load the IRIS configuration file ./iris-config-files/iris-config.json command: ["-a","sh /opt/config-files/configureIris.sh"] networks: app_net: ipam: driver: default config: - subnet: "172.16.238.0/24" ``` ビルドして起動します。 ```bash docker-compose up -d --build ``` コンテナ `tls-ssl-iris と tls-ssl-webgateway` が起動します。 ## Web アクセスのテスト ### Apache のデフォルトページ [http://localhost](http://localhost) ページを開きます。 自動的に [https://localhost](https://localhost) にリダイレクトされます。 ブラウザにセキュリティ警告が表示されます。 これは、自己署名証明書の場合の通常の動作です。リスクを受け入れて続行してください。 ![image](/sites/default/files/inline/images/apache-web-gateway-with-docker-02.png) ### Web ゲートウェイ管理ページ [https://localhost/csp/bin/Systems/Module.cxw](https://localhost/csp/bin/Systems/Module.cxw) を開き、サーバー接続をテストします。 ![image](/sites/default/files/inline/images/apache-web-gateway-with-docker-03.png) ### 管理ポータル [https://localhost/csp/sys/utilhome.csp](https://localhost/csp/sys/utilhome.csp) を開きます。 ![画像](/sites/default/files/inline/images/apache-web-gateway-with-docker-04.png) 上出来です! Web ゲートウェイの例が動作しています! ## IRIS ミラーと Web ゲートウェイ 前回の記事では、ミラー環境を構築しましたが、Web ゲートウェイが不足していました。 今回は、それを改善できます。 Web ゲートウェイといくつかの改善が追加された新しい [iris-miroring-with-webgateway](https://github.com/lscalese/iris-mirroring-with-webgateway) リポジトリを利用できます。 1. 証明書はオンザフライではなく、別のプロセスで生成されるようになっています。 2. IP アドレスは、docker-compose と JSON 構成ファイルの環境変数に置き換えられています。 変数は '.env' ファイルで定義されています。 3. リポジトリをテンプレートとして使用できます。 以下のように環境を実行するには、リポジトリ [README.md](https://github.com/lscalese/iris-mirroring-with-webgateway) ファイルをご覧ください。 ![image](https://github.com/lscalese/iris-mirroring-with-webgateway/blob/master/img/network-schema-01.png?raw=true)
記事
Mihoko Iijima · 2022年2月28日

Embedded Python を使ってレシート(JPG)の中身を IRIS に登録してみました

開発者のみなさん、こんにちは。 今回は、スーパーやコンビニでもらうレシートを写真で撮り、OCR を使ってレシートの画像から文字列を切り出して IRIS に登録する流れを試してみました。 サンプルでは、Google の Vision API を利用してレシートの JPG 画像から購入物品をテキストで抽出しています。 サンプルコード一式 👉 https://github.com/Intersystems-jp/iris-embeddedpython-OCR 最初、オンラインラーニングで使っている 「tesseract-OCR」を使ってみようと思ったのですが、レシートには半角カナが混在していたりで、半カナがなかなかうまく切り出せず、あきらめました・・(半角カナがなかったら日本語もばっちり読めていたのですが・・) もし、tesseract-OCR で半カナを切り出す良い方法をご存知の方いらっしゃいましたら、ぜひ教えてください! 今回試すにあたり、Vision API の使い方を詳しく書いているページがありましたのでコードなど参考させていただきました。ありがとうございました。 ​​【Google Colab】Vision APIで『レシートOCR』 全体の流れですが、レシートの写真を JPG にし、Python の google-cloud-vision モジュールを使用して JPG を Vision API に渡し、テキストを切り出します。 切り出されたテキストを画像の位置に合わせて一旦ソートし、レシートに記載されているものが店名なのか、商品名なのか、金額なのか、など、IRIS に登録したい項目を Python の正規表現モジュール re を使用してチェックし IRIS に登録しています。 IRIS にデータを登録する部分はSQLでもできますが、今回のサンプルでは1対多のリレーションシップを使った永続クラスを利用しています。 (永続クラスに対してSQLでも操作ができるので、お好みの文法で操作できます) 1側クラス:Okaimono.Receipt レシートの基本情報を格納します。(店名、買い物時間、購入合計、割引金額など) 多側クラス:Okaimono.Item レシートに記載された詳細項目の項目名と金額を格納します。 サンプルの実行方法については、こちらをご参照ください。 以下、コードについて少しご紹介します。 Python 側のコード:receipt.py は、ほぼこちらの素晴らしい記事👉【Google Colab】Vision APIで『レシートOCR』 を参考にさせていただきましたので、詳しくは記事をご参照ください。 Vision API で切り出したテキストですが、IRISへ登録するために必要な情報を正規表現で取り出して Python の list に設定し、receiptIRIS.py に渡して IRIS に保存しています。 レシートの項目ですが、お店によって表記が様々だったため(半カナ混在だったり全角だけだったり、記号が付いたりつかなかったり、など)、ご紹介するサンプルでは「オーケー」のレシートに合った正規表現を利用しています。コンビニや他スーパーの場合、サンプルの正規表現に合わないと思いますので、receipt.py の 72 行目~ 80 行目辺りをご変更いただくことで、お好みのレシートを読めるようになります。ぜひお試しください。 ​​​今回、IRIS に登録するデータは、​​​1対多のリレーションシップクラスを利用しているので、データの登録には SQL ではなくオブジェクトの文法を利用しています(もちろんSQLでも登録できます)。 具体的にどんなコードを書いているかというと、前回の記事「Embedded Python 試してみました」と同様に、Python から IRIS 内のクラスを操作するための iris モジュールのインポートと、クラスの操作に使用する iris.cls() を利用しています。 Okaimono.Receipt のインスタンス生成は以下の通りです。 import iris receipt=iris.cls("Okaimono.Receipt")._New() receipt.StoreName="○×商店" そして、作成された Python の list を読みながら、レシートの詳細項目を登録します。 コードはこんな感じです。 Okaimono.Item のインスタンスを生成し、Name プロパティとPrice プロパティに値を登録し、 item=iris.cls("Okaimono.Item")._New() item.Name="チョコ" item.Price="100" Okaimono.Item のインスタンス と Okaimono.Receipt のインスタンスを関連付けます。(Okaimono.Item クラスの Receiptリレーションシッププロパティを利用して Okaimono.Receipt クラスのインスタンスを代入しています) item.Receipt=receipt この方法の他に、1側の Okaimono.Receipt の Items プロパティ(リレーションシッププロパティ)に提供される Insert() メソッドを使用して Okaimono.Item のインスタンスを Okaimono.Receipt のインスタンスに割り当てる方法もあります。(どちらか一方の割り当て方法で大丈夫です) receipt.Items.Insert(item) 上記操作をレシートに記載された購入品目分実行し、最後にレシートを IRIS に保存します。 st=receipt._Save() これで、Okaimono.Receipt に紐づく Okaimono.Item が一括で保存されます。 以下の文例は、2つの商品を購入したときのレシート登録例です。 USER>do ##class(%SYS.Python).Shell() Python 3.9.5 (default, Jan 25 2022, 13:57:42) [MSC v.1927 64 bit (AMD64)] on win32 Type quit() or Ctrl-D to exit this shell. >>> import iris >>> receipt=iris.cls("Okaimono.Receipt")._New() >>> receipt.StoreName="テストストア" >>> receipt.TotalPrice=778 >>> it1=iris.cls("Okaimono.Item")._New() >>> it1.Name="お弁当" >>> it1.Price=598 >>> receipt.Items.Insert(it1) 1 >>> it2=iris.cls("Okaimono.Item")._New() >>> it2.Name="ジュース" >>> it2.Price=180 >>> it2.Receipt=receipt >>> receipt._Save() 1 >>> 登録されたデータを確認します。 IRIS では、1対多のリレーションシップ定義を行った場合、多側クラス(Okaimono.Item)のリレーションシップ用プロパティ:Receipt が外部キーカラムのようにテーブルに投影されます。 以下、確認例です。 まずは、Okaimono.Receipt データを確認します。 SELECT * FROM Okaimono.Receipt 上記実行例では、「テストストア」のデータは ID=2 で登録されています。 続いて、Okaimono.Item データを確認します。 SELECT * FROM Okaimono.Item Receipt 列には、リレーションシッププロパティで定義した1側クラス(Okaimono.Receipt)の ID が登録されていることがわかります。 では、次に、Receipt が 2(Okaimono.Receipt の ID=2)の Okaimono.Item 全情報と Okaimono.Receipt の StoreName と TotalPrice を取得してみます。 SELECT *,Receipt->StoreName,Receipt->TotalPrice FROM Okaimono.Item Where Receipt=2 IRIS 独自の矢印構文(->)を利用しています。この構文はオブジェクトの定義によって作成された外部キー用カラムを利用して、参照先テーブルのカラムを指定できる文法で、Receipt->StoreName は、Okaimono.Item テーブルに紐づく Okaimono.Receipt テーブルの StoreName カラムを指定しています。 これは、1対多のリレーションシップやオブジェクト参照を利用している場合に利用できる方法で、内部的には左外部結合と一緒の処理を行っています。 IRIS 独自の書き方ではありますが、意外とすっきりと記述できるので見やすさ重視の場合に利用いただくケースもあります。 矢印構文について詳細はドキュメントもご参照ください。 ちなみに、Pythonシェル上で 1件の Okaimono.Receipt をオープンし、Okaimono.Receipt に紐づく Okaimono.Item を取得する場合のオブジェクトの文法は以下の通りです。 ID=2 の Okaimono.Receipt をオープンします。 >>> r1=iris.cls("Okaimono.Receipt")._OpenId(2) 何個の Okaimono.Item と紐づいているか確認するには、Okaimono.Receipt クラスのリレーションシッププロパティ=Items に対して Count() を使用します。 >>> r1.Items.Count() 2 1件目の Okaimono.Item を取得する例は以下の通りです。 >>> it1=r1.Items.GetAt(1) >>> it1.Name 'お弁当' >>> it1.Price 598 2件目も確認してみます。 >>> it2=r1.Items.GetAt(2) >>> it2.Name 'ジュース' >>> it2.Price 180 ​​​​​​ こんな感じで、SQLからもオブジェクトからも操作できることが確認できました。 Embedded Python の登場で、Python の便利なモジュールや公開されているサンプルコードが IRIS から実行しやすくなりました。 みなさんのお手元でもぜひお試しください! そして、お試しいただいた内容など、お気軽にコミュニティに投稿してみてください!お待ちしてます🔥
記事
Mihoko Iijima · 2022年4月14日

データベースのあるディスクの空き容量を確認し、指定サイズを下回る場合に通知する方法の例

これは、InterSystems FAQサイトの記事です。 アプリケーションモニタが提供する %Monitor.System.Diskspace(ディスク容量メトリック)を利用して指定サイズを下回る場合にメール通知を行うように設定を追加することができます。 アプリケーション・モニタのメトリック【IRIS】アプリケーション・モニタのメトリック システム提供のアプリケーションモニタは、デフォルトでは全て無効化されています。使用を開始するためには、対象のモニタを有効化し、システムモニタを再起動します。 アプリケーションモニタの有効/無効やシステムモニタの停止/開始は、システムルーチン ^%SYSMONMGR を利用します。 以下の例では、ディスクの空き容量が 100MB を下回る場合にメール通知を行う設定手順について説明します。 手順は以下の通りです。 1) ^%SYSMONMGR を起動し、アプリケーションモニタから %Monitor.System.Diskspace を有効化する 2) アラート対象とする閾値を変更する(例では、通知は最初の1回のみとしています) 3) Email通知設定を行う 4) システムモニタを再起動する 1) ^%SYSMONMGR を起動し、アプリケーションモニタから %Monitor.System.Diskspace を有効化する ドキュメントは以下ご参照ください。Manage Monitor Classes【IRIS】Manage Monitor Classes %SYS>do ^%SYSMONMGR 1) Start/Stop System Monitor 2) Set System Monitor Options 3) Configure System Monitor Classes 4) View System Monitor State 5) Manage Application Monitor 6) Manage Health Monitor 7) View System Data 8) Exit Option? 5   → 5 を入力してEnter押下 1) Set Sample Interval 2) Manage Monitor Classes 3) Change Default Notification Method 4) Manage Email Options 5) Manage Alerts 6) Exit Option? 2   → 2 を入力してEnter押下 1) Activate/Deactivate Monitor Class 2) List Monitor Classes 3) Register Monitor System Classes 4) Remove/Purge Monitor Class 5) Set Class Sample Interval 6) Debug Monitor Classes 7) Exit Option? 1   → 1 を入力してEnter押下 Class? ?   → ? を入力してEnter押下 Num MetricsClassName Activated 1) %Monitor.System.HistoryMemory N 2) %Monitor.System.HistoryPerf N 3) %Monitor.System.HistorySys N 4) %Monitor.System.HistoryUser N 5) %Monitor.System.AuditCount N 6) %Monitor.System.AuditEvents N 7) %Monitor.System.Clients N 8) %Monitor.System.Diskspace N 9) %Monitor.System.Freespace N 10) %Monitor.System.Globals N 11) %Monitor.System.Journals N 12) %Monitor.System.License N 13) %Monitor.System.LockTable N 14) %Monitor.System.Processes N 15) %Monitor.System.Routines N 16) %Monitor.System.Servers N 17) %Monitor.System.SystemMetrics N 18) %Monitor.System.CSPGateway N Class? 8 %Monitor.System.Diskspace   →上のリストの 8 を指定してEnter押下 Activate class? Yes => yes   → yes を入力してEnter押下 1) Activate/Deactivate Monitor Class 2) List Monitor Classes 3) Register Monitor System Classes 4) Remove/Purge Monitor Class 5) Set Class Sample Interval 6) Debug Monitor Classes 7) Exit Option?  →Enter押下(前のメニューに戻ります) 1) Set Sample Interval 2) Manage Monitor Classes 3) Change Default Notification Method 4) Manage Email Options 5) Manage Alerts 6) Exit Option? 2) アラート対象とする閾値を変更する(例では、通知は最初の1回のみとしています) ※以下実行例は、1) の続きで記述しています。^%SYSMONMGRの実行から始めている場合は、5) Manage Application Monitor 選択後の画面から開始してください。 ドキュメントは以下ご参照ください。Manage Alerts【IRIS】Manage Alerts 1) Set Sample Interval 2) Manage Monitor Classes 3) Change Default Notification Method 4) Manage Email Options 5) Manage Alerts 6) Exit Option? 5   → 5 を入力してEnter押下 1) Create Alert 2) Edit Alert 3) List Alerts 4) Delete Alert 5) Enable/Disable Alert 6) Clear NotifyOnce Alert 7) Exit Option? 1   → 1 を入力してEnter押下 Alert name? test disk free space alert → 任意のアラート名を入力してEnter押下 Application? %SYS (Enter '-' to reset) =>   → Enter押下 Action (0=default,1=email,2=method)? 0 => 1   → 1 を入力してEnter押下 Raise this alert during sampling? Yes => yes   → yes を入力してEnter押下 Class? ?   → ? を入力してEnter押下 Num MetricsClassName Activated 1) %Monitor.System.HistoryMemory N 2) %Monitor.System.HistoryPerf N 3) %Monitor.System.HistorySys N 4) %Monitor.System.HistoryUser N 5) %Monitor.System.AuditCount N 6) %Monitor.System.AuditEvents N 7) %Monitor.System.Clients N 8) %Monitor.System.Diskspace Y 9) %Monitor.System.Freespace N 10) %Monitor.System.Globals N 11) %Monitor.System.Journals N 12) %Monitor.System.License N 13) %Monitor.System.LockTable N 14) %Monitor.System.Processes N 15) %Monitor.System.Routines N 16) %Monitor.System.Servers N 17) %Monitor.System.SystemMetrics N 18) %Monitor.System.CSPGateway N Class? 8 %Monitor.System.Diskspace    → 上のリストの 8 を指定してEnter押下 Property? ?    → ? を入力してEnter押下 Num Name Activated 1) Database Y 2) Directory Y 3) Diskspace Y 4) Diskstatus Y Property? 3 Diskspace   → 上のリストの 3 を指定してEnter押下 Property? Properties list: Diskspace Evaluation expression (e.g., "%1=99")? %1<100 ←MB単位に指定します。例では「100MB未満の場合アラート」を指定してEnter押下 Expression expands to: If Diskspace<100. OK? Yes => Yes   → Yes を入力してEnter押下 Notify once only? No => yes   → yes を入力してEnter押下 1) Create Alert 2) Edit Alert 3) List Alerts 4) Delete Alert 5) Enable/Disable Alert 6) Clear NotifyOnce Alert 7) Exit Option?  →Enter押下(前のメニューに戻ります) 1) Set Sample Interval 2) Manage Monitor Classes 3) Change Default Notification Method 4) Manage Email Options 5) Manage Alerts 6) Exit Option?  →Enter押下(前のメニューに戻ります) 3) Email通知設定を行う 以下の例では、gmail を利用する例をご紹介しています。gmail は SSL構成を事前に作成する必要があります。管理ポータルの以下メニューから事前に作成してください。 管理ポータル > システム管理 > セキュリティ管理 > SSL/TLS構成 ※ 構成名以外はデフォルト値を利用します。 ※以下実行例は、2)の続きで記述しています。^%SYSMONMGR の実行から始めている場合は、5) Manage Application Monitor 選択後の画面から開始してください。 ドキュメントは以下ご参照ください。Manage Email Options【IRIS】Manage Email Options 1) Start/Stop System Monitor 2) Set System Monitor Options 3) Configure System Monitor Classes 4) View System Monitor State 5) Manage Application Monitor 6) Manage Health Monitor 7) View System Data 8) Exit Option? 5   → 5 を入力してEnter押下 1) Set Sample Interval 2) Manage Monitor Classes 3) Change Default Notification Method 4) Manage Email Options 5) Manage Alerts 6) Exit Option? 4   → 4 を入力してEnter押下 1) Enable/Disable Email 2) Set Sender 3) Set Server 4) Manage Recipients 5) Set Authorization 6) Test Email 7) Exit Option? 3   → 3 を入力してEnter押下 Mail server? smtp.gmail.com   → メールサーバを入力してEnter押下 Mail server port? 587   → メールサーバのポート番号を入力してEnter押下 Mail server SSLConfiguration? gmail   → 管理ポータルで設定したSSL構成名を入力してEnter押下 Mail server UseSTARTTLS? 0 => 1   → 1を入力してEnter押下 1) Enable/Disable Email 2) Set Sender 3) Set Server 4) Manage Recipients 5) Set Authorization 6) Test Email 7) Exit Option? 2   → 2 を入力してEnter押下 Sender? sendertest@gmail.com   → 差出人のメールアドレスを入力してEnter押下 1) Enable/Disable Email 2) Set Sender 3) Set Server 4) Manage Recipients 5) Set Authorization 6) Test Email 7) Exit Option? 5   → 5 を入力してEnter押下 User name? xxxabctestaccount@gmail.com   → 認証用アカウント名を入力してEnter押下 Password?   → パスワードを入力してEnter押下 1) Enable/Disable Email 2) Set Sender 3) Set Server 4) Manage Recipients 5) Set Authorization 6) Test Email 7) Exit Option? 4   → 4 を入力してEnter押下 1) List Recipients 2) Add Recipient 3) Remove Recipient 4) Exit Option? 2   → 2 を入力してEnter押下 Email Address? abc@testcorp.com   → 送信先メールアドレスを入力してEnter押下 1) List Recipients 2) Add Recipient 3) Remove Recipient 4) Exit Option?  →Enter押下(前のメニューに戻ります) 1) Enable/Disable Email 2) Set Sender 3) Set Server 4) Manage Recipients 5) Set Authorization 6) Test Email 7) Exit Option? 1   → 1 を入力してEnter押下 Email is currently OFF Change Email setting? No => yes   → yes を入力してEnter押下 1) Enable/Disable Email 2) Set Sender 3) Set Server 4) Manage Recipients 5) Set Authorization 6) Test Email 7) Exit Option? 6   → 6 を入力してEnter押下 Sending email on Mail Server smtp.gmail.com From: sendertest@gmail.com To: abc@testcorp.com 1) Enable/Disable Email 2) Set Sender 3) Set Server 4) Manage Recipients 5) Set Authorization 6) Test Email 7) Exit Option?  →Enter押下(前のメニューに戻ります) 1) Set Sample Interval 2) Manage Monitor Classes 3) Change Default Notification Method 4) Manage Email Options 5) Manage Alerts 6) Exit Option?  →Enter押下(前のメニューに戻ります) 1) Start/Stop System Monitor 2) Set System Monitor Options 3) Configure System Monitor Classes 4) View System Monitor State 5) Manage Application Monitor 6) Manage Health Monitor 7) View System Data 8) Exit Option?  →Enter押下(前のメニューに戻ります) 4) システムモニタを再起動する 設定を反映させるため、システムモニタを一度停止し、開始します。 ドキュメントは以下ご参照ください。Start/Stop System Monitor【IRIS】Start/Stop System Monitor %SYS>do ^%SYSMONMGR 1) Start/Stop System Monitor 2) Set System Monitor Options 3) Configure System Monitor Classes 4) View System Monitor State 5) Manage Application Monitor 6) Manage Health Monitor 7) View System Data 8) Exit Option? 1   → 1 を入力してEnter押下 1) Start System Monitor 2) Stop System Monitor 3) Exit Option? 2   → 2 を入力してEnter押下 Stopping System Monitor... System Monitor stopped 1) Start System Monitor 2) Stop System Monitor 3) Exit Option? 1   → 1 を入力してEnter押下 Starting System Monitor... System Monitor started 1) Start System Monitor 2) Stop System Monitor 3) Exit Option?  →Enter押下(前のメニューに戻ります) 1) Start/Stop System Monitor 2) Set System Monitor Options 3) Configure System Monitor Classes 4) View System Monitor State 5) Manage Application Monitor 6) Manage Health Monitor 7) View System Data 8) Exit Option?  →Enter押下(ネームスペースのプロンプトに戻ります) %SYS> この記事に関連する記事もあります。以下ご参照ください。 SYS.Database クラスの FreeSpace クエリを使用してデータベースのあるディスクの空き容量を確認する方法
記事
Toshihiko Minamoto · 2022年10月25日

組み込み Python におけるグローバルの使用

私が一番興味を持っているのは、組み込み Python におけるグローバルの使用についてです。そこで、提供されている公式ドキュメントを確認しました。 #1 グローバルの導入グローバルとは何かについての一般的な説明。 次の章につながっています。 #2 ObjectScript の詳細について組み込み Python の記述はありません。さらに先に進むと... #3 組み込み Python 3.1 組み込み Python の概要3.1.1 グローバルの使用グローバルを使ったことなければ、素晴らしい内容です。が、驚くほど原始的な例が使われています。3.2 組み込み Python の使用最後の望み: >>> でも、目に見えるものが何もありません。残念どころではありません! Python 用の IRIS Native API でさえ、もっと説明されています。何を期待していたかと言うと... グローバルノードの SET、GET、KILL Native API: 基本的なノード操作  そして $DATA()、$ORDER()、$QUERY() によるナビゲーション Native API: nextSubscript() と isDefined() によるイテレーションそこで、自分で調査し、リバースエンジニアリングを行って、実験しなければなりませんでした。 そしてわかったこと: すべての例は IRIS for Windows (x86-64) 2022.1 (Build 209U) にある Python Shell で説明されており、暗黙的な print() 関数を集中的に使用している。 グローバル 何をするにも、iris.gref クラスを使って、グローバルの参照オブジェクトを作成することから始める必要があります。グローバル名は、直接文字列として、またはCOS/ISOS の間接式のように変数として渡されます。グローバルを扱っていることが明確であるため、最初のキャレット (^) は不要です! >>> globalname='rcc' >>> nglob=iris.gref(globalname) >>> glob=iris.gref('rcc') >>> cglob=iris.gref('^rcc') 上記は、同じグローバルへの 3 つのグローバル参照です。単なる参照であり、このグローバルが存在するかことを示すものではありません。 対話式ドキュメント:  print(glob.__doc__)InterSystems IRIS グローバル参照オブジェクト。グローバルへの参照を取得するには、iris.gref() メソッドを使用します。   サブスクリプト すべてのグローバルサブスクリプトは、Py リストの [sub1,sub2] として渡されます。 COS/ISOS とあまり変わりません。トップレベルに特別な処理が必要なだけです。サブスクリプトなしを示すには、空のリストではなく、この [None] を使用します。 SET グローバルを設定するには、COS/ISOS と同様に「直接」行うことができます。 >>> glob[1,1]=11 または、gref.set() メソッドを使用することもできます。 >>> glob.set([1,3],13) 対話式ドキュメント:  print(glob.set.__doc__)グローバルのキーが指定されている場合、グローバルのそのキーに格納された値を設定します。  例: g.set([i,j], 10) は、グローバル g のキー i,j にあるノードの値を 10 に設定します。 グローバルノードのコンテンツにアクセスするには、COS/ISOS と同様に「直接」行うことができます。 >>> glob[1,3] 13 または、gref.get() メソッドを使用することもできます。 >>> glob.get([1,1]) 11 対話式ドキュメント: print(glob.get.__doc__)グローバルのキーが指定されている場合、グローバルのそのノードに格納された値を返します。例: x = g.get([i,j]) は x を、グローバル g のキー i,j に格納された値に設定します。 注意: これは COS/ISOS の $GET() ではありません。 >>> glob.get([1,99]) Traceback (most recent call last): File "", line 1, in <module> KeyError: 'Global Undefined' >>> ただし、直接使用すると、COS/ISOS の $GET() のように動作します。 >>> x=glob[1,99] >>> print(x) None >>> この None は、SQL が表現するところの NULL を指します。 後で、もう一度出現します。 KILL 期待される結果を達成する gref.kill() メソッドのみがあります。 >>> glob.kill([1,3]) >>> y=glob[1,3] >>> print(y) None >>> 対話式ドキュメント: print(glob.kill.__doc__)グローバルのキーが指定されている場合、グローバルのそのノードとサブツリーをキルします。例: g.kill([i,j]) は、グローバル g のキー i,j に格納されたノードとその子孫ノードをキルします。 $DATA() 関連するメソッドは gref.data() です。対話式ドキュメント: print(glob.data.__doc__)グローバルのキーが指定されている場合、その状態を返します。例: x = g.data([i,j]) は x を 0、1、10、11 に設定します。 0-if が未定義、1-定義済み、10-未定義で子孫あり、11-値と子孫あり期待どおりに動作します。 >>> glob.data() 10 >>> glob.data([None]) 10 >>> glob[None]=9 >>> glob.data([None]) 11 >>> glob.data([1,1]) 1 >>> glob.data([1,3]) 0 >>> $ORDER() この例では、グローバル ^rcc にノードをいくつか追加しました。 >zw ^rcc ^rcc=9 ^rcc(1,1)=11 ^rcc(1,2)=12 ^rcc(2,3,4)=234 ^rcc(2,3,5)=235 ^rcc(2,4,4)=244 ^rcc(7)=7 関連するメソッドは gref.order() です。対話式ドキュメント: print(glob.order.__doc__)グローバルのキーが指定されている場合、そのグローバルの次のキーを返します。例: j = g.order([i,j]) は j を、グローバル g の次の第 2 レベルのキーに設定します。つまり、以下のようになります。 >>> print(glob.order([])) 1 >>> print(glob.order([1])) 2 >>> print(glob.order([2])) 7 >>> print(glob.order([7])) None >>> print(glob.order([1,''])) 1 >>> print(glob.order([1,1])) 2 >>> print(glob.order([2,3,])) 4 >>> print(glob.order([2,3,""])) 4 >>> print(glob.order([2,3,4])) 5 >>> print(glob.order([2,4,4])) None >>> ここでは、参照として欠落しているサブスクリプトまたは空の文字列は同等です。 $QUERY() 関連するメソッドは gref.query() です。対話式ドキュメント: print(glob.query.__doc__)指定されたキーからグローバルをトラバースし、各キーと値をタプルとして返します。例: for (key, value) in g.query([i,j]) は、キー i,j から g をトラバースし、各キーと値を返します。 このメソッドの動作は COS/ISOS と異なります。 開始ノード以降のすべてのノードを返します。 格納されたコンテンツを含めます。 None と示されているコンテンツのない仮想ノードも返します。 ここでの小さな例は、次のようになります(読みやすいように囲んでいます)。 >>> print(list(glob.query())) [(['1'], None), (['1', '1'], 11), (['1', '2'], 12), (['2'], None), (['2', '3'], None), (['2', '3', '4'], 234), (['2', '3', '5'], 235), (['2', '4'], None), (['2', '4', '4'], 244), (['7'], 7)] >>> もっと読みやすくすると、次のようになります。 >>> for (key, value) in glob.query(): ... print(key,''.ljust(20-len(str(list(key))),'>'),value) ... ['1'] >>>>>>>>>>>>>>> None ['1', '1'] >>>>>>>>>> 11 ['1', '2'] >>>>>>>>>> 12 ['2'] >>>>>>>>>>>>>>> None ['2', '3'] >>>>>>>>>> None ['2', '3', '4'] >>>>> 234 ['2', '3', '5'] >>>>> 235 ['2', '4'] >>>>>>>>>> None ['2', '4', '4'] >>>>> 244 ['7'] >>>>>>>>>>>>>>> 7 >>> 絶対に ZWRITE ではありません! もう 1 つのオプションは、gref.keys() のみを使用してサブスクリプトを取得する方法です。対話式ドキュメント: print(glob.keys.__doc__)指定されたキーからグローバルをトラバースし、そのグローバルの各キーを返します。例: for key in g.keys([i, j]) は、キー i,j から g をトラバースし、各キーを返します。 >>> >>> list(glob.keys()) [['1'], ['1', '1'], ['1', '2'], ['2'], ['2', '3'], ['2', '3', '4'], ['2', '3', '5'], ['2', '4'], ['2', '4', '4'], ['7']] >>> そして、これで gref.orderiter() を見つけました。対話式ドキュメント: print(glob.orderiter.__doc__)指定されたキーからグローバルをトラバースし、次のキーと値をタプルとして返します。例: for (key, value) in g.orderiter([i,j]) は、キー i,j から g をトラバースし、次のキーと値を返します。 $QUERY() のようにコンテンツをフェッチして、そのコンテンツを次のサブノードに提供することも行う $ORDER() のように動作します。以下を見てください。 >>> list(glob.orderiter([])) [(['1'], None), (['1', '1'], 11)] >>> list(glob.orderiter([1])) [(['2'], None), (['2', '3'], None), (['2', '3', '4'], 234)] >>> list(glob.orderiter([2])) [(['7'], 7)] >>> 最後に、gref.getAsBytes() メソッドがあります。対話式ドキュメント: print(glob.getAsBytes.__doc__)グローバルのキーが指定されている場合、そのグローバルのそのノードに格納されている文字列をバイトで返します。例: x = g.getAsBytes([i,j]) は x をグローバル g のキー i,j に格納されている値をバイトとして設定します。 数値には失敗しますが、 文字列には有効です。 >>> glob[5]="robert" >>> glob.get([5]) 'robert' >>> glob.getAsBytes([5]) b'robert' また、COS/ISOS で set ^rcc(9)=$lB(99,"robert") を実行すると以下のようになります。 >>> glob[9] '\x03\x04c\x08\x01robert' >>> glob.getAsBytes([9]) b'\x03\x04c\x08\x01robert' >>> これらのメソッドを以下のようにして検出しました。 >>> for meth in glob.__dir__(): ... meth ... '__len__' '__getitem__' '__setitem__' '__delitem__' '__new__' 'data' 'get' 'set' 'kill' 'getAsBytes' 'order' 'query' 'orderiter' 'keys' '__doc__' '__repr__' '__hash__' '__str__' '__getattribute__' '__setattr__' '__delattr__' '__lt__' '__le__' '__eq__' '__ne__' '__gt__' '__ge__' '__init__' '__reduce_ex__' '__reduce__' '__subclasshook__' '__init_subclass__' '__format__' '__sizeof__' '__dir__' '__class__' >>> これで、組み込み Python からグローバルに直接アクセスする必要がある場合に、作業が楽になることを願っています。個人的に学んだこと: ほとんどの場合に、ドキュメントがあります。 . . . どこにあるかは別ですが。ただ、探し回る必要があるだけです。 動画デモ Traduction française
記事
Shintaro Kaminaka · 2021年4月19日

SUSHIを使ってFHIRプロファイルを作成しようパート1

開発者の皆さん、こんにちは。 このシリーズでは、IRIS for Healthの使い方ではなく、関連技術として、FHIRプロファイル作成ツールであるSUSHIの握り方使い方を紹介していきたいと思います。 このツールをうまく使うことで、FHIRプロジェクトのプロファイル情報(仕様や制限、拡張などの情報)をうまく整理し、公開することができます。 その前にSUSHIとは何でしょうか?簡単にですが、順番に説明していきたいと思います。 ## FHIR って? **FHIR**とは _Fast Healthcare Interoperability Resources_ の略であり、Web通信の一般的技術であるRESTを使用して、可読性が高く取り扱いがし易いJSON/XML形式の データの集合(=リソース)をやり取りする短期間で実装可能な**医療情報交換標準規格**、という定義になっています。 簡単に言えば、医療のデータの表現方法として皆で共通したフォーマットを使うことによって、システム間や施設間などでの情報の伝達や交換をやりやすいようにしよう!ということですね。 FHIRには様々な[リソース](http://hl7.org/fhir/resourcelist.html)が定義されています。例えば患者さんの情報には[Patientリソース](http://hl7.org/fhir/patient.html)という定義があり、これを使って表現されます。 FHIR公式サイトには多くの[サンプル](http://hl7.org/fhir/patient-examples.html)が掲載されていますので、一部抜粋してみます。 例えばこのようなJSON形式で表現されます。患者番号(Identifier)、氏名(name)、性別(gender)などが表現されています。 ``` { "resourceType": "Patient", "id": "pat1", "text": { "status": "generated", "div": "\n \n Patient Donald DUCK @ Acme Healthcare, Inc. MR = 654321\n \n " }, "identifier": [ { "use": "usual", "type": { "coding": [ { "system": "http://terminology.hl7.org/CodeSystem/v2-0203", "code": "MR" } ] }, "system": "urn:oid:0.1.2.3.4.5.6.7", "value": "654321" } ], "active": true, "name": [ { "use": "official", "family": "Donald", "given": [ "Duck" ] } ], "gender": "male", "以下略" } ``` ## FHIRプロファイルって? FHIRではJSONやXMLという表現形式だけではなく、何の情報をどのようなJSONキー名称で記載するか、どのようなコードを使用するか、どのような構造で表現するかいった決まりが存在します。それを[FHIRプロファイル](http://hl7.org/fhir/profiling.html)と呼んでいます。 プロファイルは用語として色々な意味で使われています。 広義では・・・ FHIRリソースおよびFHIRサーバに関する制約の定義の集合。それを表すアーティファクト(成果物)。 狭義では・・・ あるリソースに対して、特定の制約を適用したコンフォーマンス・リソース(適合性リソース) 。 この場合、プロファイルはリソース単位に存在する(例)Pateintプロファイル、Observationプロファイル…                     詳細については、こちらの[FHIRプロファイルに関するJapan Virtual Summit 2021動画](https://youtu.be/B-B6ge_0nHg)をご覧ください。(約20分) FHIRの公式Webサイトでは各リソースについて既定の仕様が開示されています。ですが、各リソースの使い方の自由度がとても高く、そのままでは実際に相互運用性のあるデータ交換をすることはこ困難です。ですので、事前の「申し合わせ」にもとづいて、リソースの記述に「規則」を改めて設ける必要があります。この「申し合わせ」「規則」に相当するのは、実装ガイドライン(Implementation Guide)とプロファイル(Profile)に相当します。 実装ガイドラインは主に文章で記述されたもので、WordやExcel、HTML等でも記述されています。一方、ProfileはFHIRのStructureDefinitionリソースを使って計算可能なJSON形式で記述をしています。このFHIRのプロファイル自体もFHIRのリソースで表現できる、というのがFHIRの特徴の一つでもあります。例えばIRIS for Healthのような製品でその定義を取り込んで、機能拡張ができるように、JSON形式で仕様まで表現できるようになっているのです。 実装ガイドラインは様々なツールで作れますが、米国HL7協会はProfileから実装ガイドラインを自動的に生成するIG Publisherを公開しています。このツールを使えば、米国HL7協会が出しているフォーマットで実装ガイドラインのHTMLファイル等を生成することができます。この記事後半ではその方法についても紹介しています。 例えばこれは、US Coreと呼ばれる米国で標準的に使用されることが推奨されたPatientリソースの記法上の規約を表現した、「StructureDefinition」というリソースです。 ([引用元](https://www.hl7.org/fhir/us/core/StructureDefinition-us-core-patient.json.html)) ``` { "resourceType" : "StructureDefinition", "id" : "us-core-patient", "text" : { "status" : "extensions", "div" : "省略" }, "url" : "http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient", "version" : "3.1.1", "name" : "USCorePatientProfile", "title" : "US Core Patient Profile", "status" : "active", "experimental" : false, "date" : "2020-06-27", "publisher" : "HL7 US Realm Steering Committee", "contact" : [ { "telecom" : [ { "system" : "url", "value" : "http://www.healthit.gov" } ] } ], "以下略" ``` FHIRプロファイルを表現されるリソースとしては他にも[ImplementationGuide](http://hl7.org/fhir/implementationguide.html)やFHIRサーバの一連の機能をまとめた[CapabilityStatement](http://hl7.org/fhir/capabilitystatement.html)などがあります。 ## FHIR Shorthand とは? というわけで、ではFHIRプロファイルを作成するには↑のJSON構造を作っていけばいいんだな!?ということになる訳ですが、これを手作業でやるのはどう考えて難しいし煩雑ですよね。間違えそうです。 これを補助するためのアプリケーションやツールが公開されており、商用製品やオープンソースなどいくつかの選択肢があります。 こちらの[ページ](https://confluence.hl7.org/pages/viewpage.action?pageId=35718864#ProfileTooling-Editing&AuthoringProfiles)をご覧ください。 例えばオランダのFirely社のForgeなどは有名ですが、最近では**FHIR Shorthand** ([リンク](https://build.fhir.org/ig/HL7/fhir-shorthand/index.html))という**FHIRアーティファクトを定義するためのドメイン固有の言語**も広く使われるようになってきています。 FHIR Shorthandは言語の一種であり、例えば以下のような定義ファイル=FSH(フィッシュ)ファイルを作成しながら、FHIRプロファイルを作成することができます。 以下にサンプルのFSHファイルを例示します。[引用元](https://build.fhir.org/ig/HL7/fhir-shorthand/overview.html#fsh-line-by-line-walkthrough) 例えば、このプロファイルの名前(Profile: CancerDiseaseStatus)、ベースとなる元のFHIRリソース(Parent: Observation)、カーディナリティを変更するエレメントの指定(bodySite 0..0)などの内容を含んでいます。 ``` Alias: LNC = http://loinc.org Alias: SCT = http://snomed.info/sct Profile: CancerDiseaseStatus Parent: Observation Id: mcode-cancer-disease-status Title: "Cancer Disease Status" Description: "A clinician's qualitative judgment on the current trend of the cancer, e.g., whether it is stable, worsening (progressing), or improving (responding)." * ^status = #draft * extension contains EvidenceType named evidenceType 0..* * extension[evidenceType].valueCodeableConcept from CancerDiseaseStatusEvidenceTypeVS (required) * status and code and subject and effective[x] and valueCodeableConcept MS * bodySite 0..0 * specimen 0..0 * device 0..0 * referenceRange 0..0 * hasMember 0..0 * component 0..0 * interpretation 0..1 * subject 1..1 * basedOn only Reference(ServiceRequest or MedicationRequest) (省略) ``` ## SUSHIって? FHIR/FHIRプロファイル/FHIR Shorthandと順に説明してきましたが、ついにSUSHIの説明です。 SUSHI (an acronym for “SUSHI Unshortens SHorthand Inputs”) (4) is a reference implementation of a FSH compiler that translates FSH into FHIR artifacts such as profiles, extensions, and value sets. SUSHI is installed on your own computer and runs locally from the command line. ([引用元](https://build.fhir.org/ig/HL7/fhir-shorthand/overview.html#sushi)) > (訳)SUSHI("SUSHI Unshortens SHorthand Inputs "の略)は、FSHファイルをプロファイル、エクステンション、バリューセットなどのFHIRアーティファクトに変換するFSHコンパイラのリファレンス実装である。SUSHIは自分のコンピュータにインストールされ、コマンドラインからローカルに実行される。 つまり、**先ほどのFHIR Shorthandを記述したFSH(フィッシュ)ファイルを、SUSHIで処理すると、StructureDefinitionなどのファイルが生成される**、ということです。 この仕組みを説明したわかりやいようで、ちょっとわかりにくい一枚の絵があります![引用元](https://build.fhir.org/ig/HL7/fhir-shorthand/overview.html#fsh-in-practice) ![image](https://build.fhir.org/ig/HL7/fhir-shorthand/Workflow.png) (この絵では、魚を処理(=コンパイル)して、寿司ができるようなイメージで書かれてるんですが、実際はコンパイルをしているのが「SUSHIコンパイラ」で、できあがるのは「プロファイルなどのFHIRアーティファクト」なのでちょっと違うと思うんですよね・・・。お寿司の説明にProfilesやExtensions等の記載はありますけども。) 駆け足でSUSHIとは何か、までご紹介してきましたがご理解いただけたでしょうか? ## FSH Schoolに行こう 肝心なSUSHIのインストール方法や基本的な使い方ですが、それらについてはここで説明するよりも、非常に丁寧に紹介されたオフィシャルサイトがありますので、そちらをご紹介したいと思います。 その名も[FSH School](https://fshschool.org/)です。 SUSHIを使って生成されるのは、StrudctureDefinitionなどのリソース(JSONファイル)ですが、同じくこのサイトで紹介されている、"IG Publisherツール"を使うことによって、それらを取りまとめたHTMLのソースまで生成することができます。 ![image](/sites/default/files/inline/images/sushi_part1_ss1.jpg) まずはこの[SUSHI Tutorial](https://fshschool.org/docs/tutorials/basic/)に内容に沿って、基本的な機能の確認をされることをお勧めします。 うまくいかないときは、ダウンロードできるフォルダに含まれる完成版FSH Tank(!)であるFishExampleCompleteディレクトリを参照されると良いと思います。 私はWindows環境で試しました。Node.jsもインストールされていなかったので、[こちらのサイト](https://blog.katsubemakito.net/nodejs/install-windows10)の情報を参考にさせていただきました。 また、チュートリアルに以下の記載がある通り、IG Publisherを使ったHTMLファイルの出力には Jekyll というツールが必要になります。 >Warning Before proceeding to the next command: If you have never run the IG Publisher, you may need to install Jekyll first. See Installing the IG Publisher for details. こちらの[サイト](http://jekyll-windows.juthilo.com/1-ruby-and-devkit/)からJekyllのキット等は入手できます。 ## SUSHI実行例 私の環境で、チュートリアルの完成版を使ったsushiコマンド実行結果を掲載します。 コマンド等の詳細はこちらのサイト([Running SUSHI](https://fshschool.org/docs/sushi/running/))をご覧ください。 ``` >sushi . info Running SUSHI v1.2.0 (implements FHIR Shorthand specification v1.1.0) info Arguments: info C:\Users\kaminaka\Documents\Work\FHIR\SUSHI\fsh-tutorial-master\FishExampleComplete info No output path specified. Output to . info Using configuration file: C:\Users\kaminaka\Documents\Work\FHIR\SUSHI\fsh-tutorial-master\FishExampleComplete\sushi-config.yaml info Importing FSH text... info Preprocessed 2 documents with 3 aliases. info Imported 4 definitions and 1 instances. info Checking local cache for hl7.fhir.r4.core#4.0.1... info Found hl7.fhir.r4.core#4.0.1 in local cache. info Loaded package hl7.fhir.r4.core#4.0.1 (node:26584) Warning: Accessing non-existent property 'INVALID_ALT_NUMBER' of module exports inside circular dependency (Use `node --trace-warnings ...` to show where the warning was created) (node:26584) Warning: Accessing non-existent property 'INVALID_ALT_NUMBER' of module exports inside circular dependency info Converting FSH to FHIR resources... info Converted 3 FHIR StructureDefinitions. info Converted 1 FHIR ValueSets. info Converted 1 FHIR instances. info Exporting FHIR resources as JSON... info Exported 5 FHIR resources as JSON. info Assembling Implementation Guide sources... info Generated ImplementationGuide-fish.json info Assembled Implementation Guide sources; ready for IG Publisher. ╔════════════════════════ SUSHI RESULTS ══════════════════════════╗ ║ ╭──────────┬────────────┬───────────┬─────────────┬───────────╮ ║ ║ │ Profiles │ Extensions │ ValueSets │ CodeSystems │ Instances │ ║ ║ ├──────────┼────────────┼───────────┼─────────────┼───────────┤ ║ ║ │ 2 │ 1 │ 1 │ 0 │ 1 │ ║ ║ ╰──────────┴────────────┴───────────┴─────────────┴───────────╯ ║ ║ ║ ╠═════════════════════════════════════════════════════════════════╣ ║ It doesn't get any betta than this! 0 Errors 0 Warnings ║ ╚═════════════════════════════════════════════════════════════════╝ ``` 実行するとFSHファイルのコンパイルが実行され、最後にいくつのProfilesやExtensionが生成されたか、表示されます。問題なければ、"info"だけが表示されますが、FSHファイルの定義に誤りがあると、WarningやErrorも表示されます。エラーメッセージは比較的親切で何が問題が把握しやすいと思います。(個人的には最後の表に掲載される、なぞの「魚一言?」みたいな一文が楽しみです。) 実行後には、プロジェクトフォルダ内のfsh-generatedフォルダにStructureDefinitionのJSONファイルが生成されているのが確認できます。 続いて、「_updatePublisher」コマンドで、IG Publisherツールを入手し、「_genonce」コマンドでIG Publisherを起動し、HTMLファイル群も生成してみます。この実行ログは長いので割愛します。 実行後、同じプロジェクトフォルダ内の output フォルダを確認すると多くのファイルが生成されているのがわかります。index.htmlファイルを開くと以下のようなページが生成されていることが確認できます。 ![image](/sites/default/files/inline/images/sushi_part1_ss2.jpg) このようなFHIR公式サイトでも見慣れた、リソースの説明ページなども自動生成されます。 ![image](/sites/default/files/inline/images/sushi_part1_ss3.jpg) ## Implementation Guide(実装ガイド)を書いてみよう 私もこのツール群を触り始めて日が浅いですが、簡単なスタートアップとして、実装ガイドを記述していく方法をご紹介したいと思います。 詳細な使い方についてはFSH Schoolサイト内の情報をご覧ください。[こちら](https://fshschool.org/downloads/)で紹介されているのFHIR DevDaysのスライド等も大変参考になると思います。 まず sushi --init コマンドでプロジェクト構造のひな型を作りましょう。 ``` C:\Users\kaminaka\Documents\Work\FHIR\SUSHI\TestProject>sushi --init ╭───────────────────────────────────────────────────────────╮ │ This interactive tool will use your answers to create a │ │ working SUSHI project configured with your project's │ │ basic information. │ ╰───────────────────────────────────────────────────────────╯ Name (Default: ExampleIG): MyFirstSUSHIProject Id (Default: fhir.example): myfirstsushi Canonical (Default: http://example.org): http://example.org/myfirstsushi Status (Default: draft): Version (Default: 0.1.0): Initialize SUSHI project in C:\Users\kaminaka\Documents\Work\FHIR\SUSHI\TestProject\MyFirstSUSHIProject? [y/n]: y Downloading publisher scripts from https://github.com/HL7/ig-publisher-scripts (node:13972) Warning: Accessing non-existent property 'INVALID_ALT_NUMBER' of module exports inside circular dependency (Use `node --trace-warnings ...` to show where the warning was created) (node:13972) Warning: Accessing non-existent property 'INVALID_ALT_NUMBER' of module exports inside circular dependency ╭───────────────────────────────────────────────────────────╮ │ Project initialized at: ./MyFirstSUSHIProject │ ├───────────────────────────────────────────────────────────┤ │ Now try this: │ │ │ │ > cd MyFirstSUSHIProject │ │ > sushi . │ │ │ │ For guidance on project structure and configuration see │ │ the SUSHI documentation: https://fshschool.org/docs/sushi │ ╰───────────────────────────────────────────────────────────╯ ``` 実行すると必要最低限の設定ファイルやFSHファイルが作成されます。 次に少し修正をしてみましょう。 その前にエディタの紹介です。fshファイルを修正するための[Extension](https://marketplace.visualstudio.com/items?itemName=kmahalingam.vscode-language-fsh)が公開されているので、Visual Studio Codeの使用がおすすめです。 せっかくなので、日本語の情報を入力してどのように反映されるか見ていきたいと思います。 まず、sushi-config.yaml を修正します。実装ガイドのタイトルを追加し、メニュー画面も日本語表記に変更した上で、コンテンツ一覧ページ(tuc.html)とカスタムページ(mycustompage.html)を追加しています。 sushi-config.yaml ``` # ╭──────────────────────────────────────ImplementationGuide───────────────────────────────────────╮ # │ The properties below are used to create the ImplementationGuide resource. For a list of │ # │ supported properties, see: https://fshschool.org/sushi/configuration/ │ # ╰────────────────────────────────────────────────────────────────────────────────────────────────╯ id: myfirstsushi canonical: http://example.org/myfirstsushi name: MyFirstSUSHIProject # titleを追加して、ページ上部に表示されるようにします。 title: ○○FHIRプロジェクト 実装ガイド status: draft publisher: InterSystems Japan/S.Kaminaka description: SUSHIを使ったFHIRプロジェクト実装ガイドのサンプルです。 version: 0.1.0 fhirVersion: 4.0.1 copyrightYear: 2021+ releaseLabel: ci-build # ╭────────────────────────────────────────────menu.xml────────────────────────────────────────────╮ # │ To use a provided input/includes/menu.xml file, delete the "menu" property below. │ # ╰────────────────────────────────────────────────────────────────────────────────────────────────╯ # メニューを日本語表示されるように変更します。 menu: 実装ガイドホーム: index.html コンテンツ一覧: toc.html FHIRアーティファクトサマリ: artifacts.html カスタムページ: mycustompage.html ``` インデックスページや、カスタムページはマークダウンで記述できます。 index.md ``` # MyFirstSUSHIProject Feel free to modify this index page with your own awesome content! ### プロジェクトの背景 pagecontent/index.md ファイルを変更して、htmlファイル内の記載内容を変更できます。 ページを記述にはマークダウン記法を使用することができます。 ### 参考情報へのリンク (略) ``` mycustompage.md ``` ## これはカスタムページです。 マークダウンファイルを用意しておくとhtmlファイルが生成されます。 プロジェクトに応じたページを生成し、実装ガイドに含めることができます。 ``` 最後に最も重要なFSHファイルを修正します。このひな形には、Patientプロファイル用のFSHファイルが含まれているので、それを少しだけ修正しました。 patient.fsh ``` // This is a simple example of a FSH file. // This file can be renamed, and additional FSH files can be added. // SUSHI will look for definitions in any file using the .fsh ending. Profile: MyPatient Parent: Patient Title: "○○プロジェクトのPatientプロファイル" * name 1..* MS // ^shortを変更して、一覧表示画面の説明部分を変更できます。 * name ^short = "患者さんの氏名を格納します。" * name ^definition = "患者さんの氏名を格納するエレメント。NeXEHRS JP COREに準拠した漢字・カナ記法を使用します。" ``` それでは、以下のコマンドを実行して、生成された実装ガイドページを確認してみましょう。 > sushi. > _updatePublisher > _genonce 以下のような情報を含むページが簡単に生成できます。 あわせてStructureDefinitionやImplementationGuideなどのJSONファイルももちろん生成されています。 ![image](/sites/default/files/inline/images/sushi_part1_ss4.jpg) ![image](/sites/default/files/inline/images/sushi_part1_ss5.jpg) ## まとめ いかがでしたでしょうか? 単にFHIRプロファイルのJSONファイルを生成するだけでなく、HTMLファイルを生成する機能も付随しているので、このツールをうまく使えばFHIRの仕様を分かりやすく伝えることが可能なコンテンツが簡単に作成できるのではないかと考えています。 このツール自体はInterSystemsとは直接関係ない製品ではありますが、FHIRプロジェクトの情報交換に役立つツールということで、この開発者コミュニティでご紹介させていただきました。 この記事を見て試していただいた方、あるいはすでに使いこなしている方、使い方のコツや便利な機能やシンタックスなどをご紹介いただけると嬉しく思います。 次回のこのシリーズでは、SUSHIで生成したSearch Parameterの定義ファイルをIRIS for Healthで読み込んで、検索パラメータを拡張する内容に取り組んでみたいと考えています。 (2021/4/20 特にプロファイルの説明について、説明が曖昧な箇所をご指摘いただきましたので修正しました。ご指摘ありがとうございました。)
記事
Tomohiro Iwamoto · 2020年12月10日

Google Kubernetes Engine にデプロイされた IRIS ベースのサービスに TLS と DNS を追加する

この記事は、GitHub Actions を使って GKE に InterSystems IRIS Solution をデプロイするの継続記事で、そこではGitHub Actions パイプラインを使って、 Terraform で作成された Google Kubernetes クラスタにzpm-registry をデプロイしています。 繰り返しにならないよう、次の項目を満たしたものを開始点とします。 訳者注) 上記の記事を読まれてから、本記事に進まれることをお勧めしますが、GKE上のサービスにドメイン名を紐づける方法を解説した単独記事としてもお読みいただけます。 リポジトリ Github Actions + GKE + zpm example をフォーク済みで、フォークでの Actions を許可していること。 この記事を通して、ルートディレクトリは <root_repo_dir>として参照されます。 Terraform ファイルのプレースホルダを置換済みであること。 GitHub Actions を使って GKE に InterSystems IRIS Solution をデプロイする の唯一の表に記載されているすべてのシークレットを(GitHub Actions Secrets ページで)作成済みであること。 コピーペースト作業を単純化するために、すべてのコードサンプルが、GitHub-GKE-TLS リポジトリに保存されるようになっていること。 上記のすべてを満たしていることを前提に、先に進みましょう。 はじめに 前回、zpm-registry への接続は、次のように行いました。 curl -XGET -u _system:SYS 104.199.6.32:52773/registry/packages/-/all IP アドレスの前にプロトコルがない場合は HTTP を使用していることを示します。つまり、トラフィックは非暗号化であるため、かの悪名高いイブ によってパスワードを盗み聞きされる可能性があります。 イブが盗聴できないようにするには、トラフィックを暗号化する、つまり HTTPS を使用する必要があります。 それは可能なことなのでしょうか。 104.199.6.32:52773/registry/packages → https://104.199.6.32:52773/registry/packages 概して言えば、可能です。 IP アドレスの証明書を取得すればよいのですが、 このソリューションには欠点があります。 詳細については、Using an IP Address in an SSL Certificate と SSL for IP Address を読んでいただきたいのですが、 要約すると、静的 IP アドレスが必要であり、その機能を備えた証明書プロバイダーは無料ではありません。 メリットについても、疑わしい部分があります。 一般的な無料プロバイダーは、9 Best Free SSL Certificate Sources にも紹介されているように、幸いにも存在はします。 その 1 つは Let’s Encrypt ですが、証明書を発行するのはドメイン名に対してのみです。ちなみに、証明書に IP アドレスを追加する計画は上がってはいます。 したがって、トラフィックを暗号化するには、まず、ドメイン名を取得する必要があります。 ドメイン名をすでにお持ちの方は、次のセクションにスキップしてください。 ドメイン名の取得 ドメインレジストラからドメイン名を購入します。 かなりの数のレジストラが存在し、 価格はドメイン名やサービスレベルによって異なります。 開発の目的には、たとえば .dev のドメインを使うことができますし、おそらく安価でもあります。 ここでは、ドメイン登録プロセスには触れませんが、それほど複雑なものではありません。これ以降では、登録済みのドメイン名を example.com として説明することにします。 これを自分のドメインに置き換えてください。 ドメイン登録プロセスが完了すると、ドメイン名とドメインゾーンを得られますが、 これらは別々のものとして考える必要があります。 Definition - Domains vs. Zones の説明と短い DNS Zones の動画を見て、この違いを理解してください。 簡単に説明すると、ドメインを組織と考えた場合、ゾーンはその組織内の部署として捉えることができます。 このチュートリアルでは、ドメインは example.com であり、ゾーンも同様に example.com と呼んでいます。 (小さな組織では、部署が 1 つしかない場合があります。) 各 DNS ゾーンには、ゾーン内の IP アドレスとドメイン名を認識する特別なサーバーが必要です。 これらのリンクは、リソースレコード(RR)と呼ばれており、 それぞれに種類が異なる場合があります(DNS Record types をご覧ください)。 最も広く使用されているのは、A レコードです。 「ネームサーバー」は、ドメインレジストラが提供する特別なサーバーです。 たとえば、私が契約しているレジストラからは、次の 2 つのネームサーバーが提供されています。 ns39.domaincontrol.com ns40.domaincontrol.com 次のようなリソースレコード(サーバードメイン名 = IP アドレス)を作成する必要があります。 zpm.example.com = 104.199.6.32 これは、ゾーン example.com に A レコードを作成して行います。 このレコードを保存すると、世界中にあるほかの DNS サーバーによってこの更新内容が認識され、最終的に、 zpm-registry を zpm.example.com:52773/registry/ という名前で参照できるようになります。 ドメインと kubernetes 覚えているかと思いますが、zpm サービスの IP アドレスは、Kubernetes Service(Load Balancer タイプ)をデプロイ中に作成されました。 zpm-registry を試して削除した後にもう一度 zpm-registry をデプロイすることにした場合は、別の IP アドレスが割り当てられる可能性があります。 その場合は、もう一度 DNS レジストラの Web コンソールにアクセスして、zpm.example.com の IP アドレスを新たに設定してください。 これには、もう 1 つの方法があります。 Kubernetes のデプロイ中に、External DNS という、Kubernetes Services または Ingress から新しく作成された IP アドレスを取得して対応する DNS レコードを作成する、ヘルパーツールをデプロイできます。 このツールはすべてのレジストラをサポートしているわけではありませんが、DNS ゾーン、ネームサーバーの提供、およびリソースレコードの保存を行える、Google Cloud DNS をサポートしています。 Google Cloud DNS を使用するには、レジストラの Web コンソールで、DNS ゾーンの example.com の管理を Google Cloud DNS に移行する必要があります。 これを行うには、ドメインレジストラが提供したネームサーバーを Google Cloud DNS が提供するものに変更します。 Google コンソールに example.com ゾーンを作成し、Google が提供するネームサーバーをコピーして貼り付けてください。 詳細は以下を参照してください。 コードに外部 DNS を追加して Google Cloud DNS を作成する方法を見てみましょう。 ただし、スペースを節約するために、ここではコードの一部のみを記載します。 前述のとおり、完全なサンプルは、 GitHub GKE TLS リポジトリにあります。 外部 DNS の追加 このアプリケーションを GKE にデプロイするには、Helm を利用します。 これについては、「An Introduction to Helm, the Package Manager for Kubernetes」と公式ドキュメント が役立つでしょう。 パイプラインファイルの「kubernetes-deploy」ステージの最後のジョブとして、次の行を追加してください。 また、「env」セクションには、新しい変数もいくつか追加します。 $ cat <root_repo_dir>/.github/workflows/workflow.yaml ... env: ... DNS_ZONE: example.com HELM_VERSION: 3.1.1 EXTERNAL_DNS_CHART_VERSION: 2.20.6 ... jobs: ... kubernetes-deploy: ... steps: ... - name: Install External DNS run: | wget -q https://get.helm.sh/helm-v${HELM_VERSION}-linux-amd64.tar.gz tar -zxvf helm-v${HELM_VERSION}-linux-amd64.tar.gz cd linux-amd64 ./helm version ./helm repo add bitnami https://charts.bitnami.com/bitnami gcloud container clusters get-credentials ${GKE_CLUSTER} --zone ${GKE_ZONE} --project ${PROJECT_ID} echo ${GOOGLE_CREDENTIALS} > ./credentials.json kubectl create secret generic external-dns --from-file=./credentials.json --dry-run -o yaml | kubectl apply -f - ./helm upgrade external-dns bitnami/external-dns \ --install \ --atomic \ --version=${EXTERNAL_DNS_CHART_VERSION} \ --set provider=google \ --set google.project=${PROJECT_ID} \ --set google.serviceAccountSecret=external-dns \ --set registry=txt \ --set txtOwnerId=k8s \ --set policy=sync \ --set domainFilters={${DNS_ZONE}} \ --set rbac.create=true --set が設定するパラメータについては、External DNS チャートのドキュメントを参照してください。 とりあえず上記の行を追加して、次に進みましょう。 クラウド DNS の作成 まず、<root_repo_dir>/terraform/ ディレクトリに新しいファイルを追加します。 あなたのドメインゾーンを使用してください。 $ cat <root_repo_dir>/terraform/clouddns.tf resource "google_dns_managed_zone" "my-zone" { name = "zpm-zone" dns_name = "example.com." description = "My DNS zone" } また、Terraform に代わって機能するユーザーには、少なくとも次のロールが与えられていることを確認してください(DNS 管理者および Kubernetes Engine 管理者ロールに注意してください)。 GitHub Actions パイプラインを実行している場合は、これらが作成されます。 External DNS とCloud DNS の準備ができたら(実質的に準備できた時点で)、zpm-service をロードバランサーサービスタイプとは異なる方法で公開する方法を検討できるようになります。 Kubernetes zpm-service は、通常の Kubernetes サービスロードバランサーを使って公開されています。 ファイル <root_repo_dir>/k8s/service.yaml を参照してください。 Kubernetes Service についての詳細は、「Service を使用したアプリケーションの公開」をお読みください。 重要なのは、ロードバランサーサービスにはドメイン名を設定する機能がないため、Kubernetes Services リソースが作成した実際の Google ロードバランサーが TCP/UDP レベルの OSI を操作するということです。 このレベルは、HTTP と証明書について何も関知していないため、 Google ネットワークロードバランサーを HTTP ロードバランサーに置き換える必要があります。 このようなロードバランサーを作るには、Kubernetes Service の代わりに Kubernetes Ingress リソースを使用できます。 ここで、「Kubernetes NodePort vs LoadBalancer vs Ingress? When should I use what?」を読んでおくと良いでしょう。 では、先に進みましょう。 コードでの Ingress の使用とはどいうことでしょうか。 <root_repo_dir>/k8s/ ディレクトリに移動し、次の変更を行います。 Service のタイプは NodePort です。 $ cat <root_repo_dir>/k8s/service.yaml apiVersion: v1 kind: Service metadata: name: zpm-registry namespace: iris spec: selector: app: zpm-registry ports: - protocol: TCP port: 52773 targetPort: 52773 type: NodePort 次に、Ingress マニフェストを追加する必要があります。 $ cat <root_repo_dir>/k8s/ingress.yaml apiVersion: extensions/v1beta1 kind: Ingress metadata: annotations: kubernetes.io/ingress.class: gce networking.gke.io/managed-certificates: zpm-registry-certificate external-dns.alpha.kubernetes.io/hostname: zpm.example.com name: zpm-registry namespace: iris spec: rules: - host: zpm.example.com http: paths: - backend: serviceName: zpm-registry servicePort: 52773 path: /* また、太字で示されている行をワークフローファイルに追加します。 $ cat <root_repo_dir>/.github/workflows/workflow.yaml ... - name: Apply Kubernetes manifests working-directory: ./k8s/ ... kubectl apply -f service.yaml kubectl apply -f ingress.yaml このマニフェストをデプロイすると、Google Cloud コントローラによって、外部 HTTP ロードバランサーが作成されます。これは、ホストである zpm.example.com へのトラフィックをリスンし、このトラフィックを、Kubernetes NodePort Service デプロイ中に開かれたポート経由で、すべての Kubernetes ノードに送信します。 このポートは任意ですが、完全に自動化されているため、気にする必要はありません。 アノテーションを使用すると、Ingress のより詳細な構成を定義することができます。 annotations: kubernetes.io/ingress.class: gce networking.gke.io/managed-certificates: zpm-registry-certificate external-dns.alpha.kubernetes.io/hostname: zpm.example.com 最初の行は、"gce" Ingress コントローラを使用することを示します。 このエンティティは、Ingress リソースに従って HTTP ロードバランサーを作成します。 2 行目は、証明書に関連する行です。 この設定については、後で説明します。 3 行目は、指定されたホスト名(zpm.example.com)を HTTP ロードバランサーの IP アドレスにバインドする外部 DNS を設定します。 このマニフェストを実装した場合、(約 10 分後に)Ingress が作成されてはいても、ほかのすべてが機能しているわけではないことがわかります。 "Backend services"とは何でしょうか。このうちの 1 つはうまく機能していないようです。 "k8s-be-31407-..." や "k8s-be-31445-..."などの名前がありますか? これらは、1 つの Kubernetes ノードで開かれているポートです。 ポートの番号はそれぞれ異なります。 31407 は、ヘルスチェック用に開かれているポートで、ノードが連続してアライブであるように、HTTP ロードバランサーが送信するポートです。 Kubernetes に接続して、ノードポート 31407 をプロキシすると、ヘルスチェックの結果を確認できます。 $ gcloud container clusters get-credentials <CLUSTER_NAME> --zone <LOCATION> --project <PROJECT_ID> $ kubectl proxy & $ curl localhost:8001/healthz ok $ fg ^Ctrl+C もう 1 つの 31445 ポートは、zpm-registry サービス用に開かれている NodePort です。 $ kubectl -n iris get svc NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE zpm-registry NodePort 10.23.255.89 <NONE> 52773:31445/TCP 24m また、デフォルトのヘルスチェックでは、HTTPロードバランサーはこのサービスが停止しているというレポートを送信します。 本当にそうなのでしょうか? それらのヘルスチェックの詳細を確認する必要があります。 Backend service 名をクリックし、 下に少しスクロールして、ヘルスチェック名を確認してください。 詳細を確認するには、ヘルスチェック名をクリックします。 ヘルスチェックの "/" パスを "/csp/sys/UtilHome.csp" のように、IRIS が理解できるパスに置き換える必要があります。 $ curl -I localhost:52773/csp/sys/UtilHome.csp Handling connection for 52773 HTTP/1.1 200 OK では、ヘルスチェックに新しいパスを設定するには、どうすればよいのでしょうか。 デフォルトの "/" パスが存在する場合は、その代わりに、Readiness/Liveness probesを使用してください。 Kubernetes StatefulSet マニフェストにプローブを追加してみましょう。 $ cat <root_repo_dir>/k8s/statefulset.tpl ... containers: - image: DOCKER_REPO_NAME:DOCKER_IMAGE_TAG ... ports: - containerPort: 52773 name: web readinessProbe: httpGet: path: /csp/sys/UtilHome.csp port: 52773 initialDelaySeconds: 10 periodSeconds: 10 livenessProbe: httpGet: path: /csp/sys/UtilHome.csp port: 52773 periodSeconds: 10 volumeMounts: - mountPath: /opt/zpm/REGISTRY-DATA name: zpm-registry-volume - mountPath: /mount-helper name: mount-helper ここまでで、いくつかの変更を加えて、メインイベントである証明書への扉を開くことができました。 では、ラストスパートに取り掛かるとしましょう。 証明書の取得 Kubernetes の SSL/TLS 証明書を取得するさまざまな方法を説明した次の動画をぜひご覧ください。 Create a Kubernetes TLS Ingress from scratch in Minikube Automatically Provision TLS Certificates in K8s with cert-manager Use cert-manager with Let's Encrypt® Certificates Tutorial: Automatic Browser-Trusted HTTPS Super easy new way to add HTTPS to Kubernetes apps with ManagedCertificates on GKE 要約すると、証明書を取得するにはいくつかの方法があり、openssl 自己証明書、Let’s Encrypt の certbot(手動)、Let's Encrypt に接続した cert-manager(自動)、そしてネイティブの Google アプローチである Managed Certificate を使用できます。ここでは、単純にするために、最後の Managed Certificate を使用します。 では追加しましょう。 $ cat <root_repo_dir>/k8s/managed-certificate.yaml apiVersion: networking.gke.io/v1beta1 kind: ManagedCertificate metadata: name: zpm-registry-certificate namespace: iris spec: domains: - zpm.example.com 太字で示された行をデプロイパイプラインに追加します。 $ cat <root_repo_dir>/.github/workflows/workflow.yaml ... - name: Apply Kubernetes manifests working-directory: ./k8s/ run: | gcloud container clusters get-credentials ${GKE_CLUSTER} --zone ${GKE_ZONE} --project ${PROJECT_ID} kubectl apply -f namespace.yaml kubectl apply -f managed-certificate.yaml kubectl apply -f service.yaml ... Ingress での有効化は、Ingress アノテーションとして先に行いましたが、覚えていますか? $ cat <root_repo_dir>/k8s/ingress.yaml ... annotations: kubernetes.io/ingress.class: gce networking.gke.io/managed-certificates: zpm-registry-certificate ... これで、すべての変更をリポジトリにプッシュする準備が整いました。 $ git add .github/ terraform/ k8s/$ git commit -m "Add TLS to GKE deploy"$ git push 15 分ほどすると(クラスタプロビジョニングを実行する必要があります)、「緑信号」の Ingress を確認できるでしょう。 次に、Google が提供した少なくとも 2 つのネームサーバーをドメイン名レジストラコンソールで設定する必要があります(Google Domains 以外のレジストラを使用している場合)。 このプロセスはレジストラによって異なるため、ここでは説明しません。通常、レジストラのドキュメントで詳しく説明されています。 Google は、External DNS が自動的に作成した新しいリソースレコードをすでに認識しています。 $ dig +short @ns-cloud-b1.googledomains.com. zpm.example.com34.102.202.2 このレコードが世界中に伝搬されるまでにはしばらく時間がかかりますが、 とはいえ、最終的には次のようになります。 $ dig +short zpm.example.com34.102.202.2 証明書のステータスを確認することをお勧めします。 $ gcloud container clusters get-credentials <CLUSTER_NAME> --zone <LOCATION> --project <PROJECT_ID> $ kubectl -n iris get managedcertificate zpm-registry-certificate -ojson | jq '.status' { "certificateName": "mcrt-158f20bb-cdd3-451d-8cb1-4a172244c14f", "certificateStatus": "Provisioning", "domainStatus": [ { "domain": "zpm.myardyas.online", "status": "Provisioning" } ] } さまざまなステータスの意味については、「Google マネージド SSL 証明書の使用」のページをご覧ください。 証明書を初めてプロビジョニングする場合は、1 時間ほどかかることがあります。 domainStatus "FailedNotVisible" が発生することがありますが、 この場合は、Google ネームサーバーを DNS レジストラコンソールで実際に追加していることを確認してください。 certificateStatus と domainStatus の両方が利用可能になるまで待つことをお勧めします。「Google マネージド SSL 証明書の使用」で説明されているとおり、しばらく時間がかかることがありますが、 最終的には、次のようにして zpm-registry を呼び出せるようになるでしょう。 curl -XGET -u _system:SYS https://zpm.example.com/registry/packages/-/all まとめ Google は、Kubernetes リソースに基づいて、必要なすべての Google リソースを作成することに長けています。 また、Google マネージド証明書は、証明書の取得を大幅に単純化できる優れた機能です。 Google リソース(GKE、CloudDNS)の維持には費用が掛かります。そのため、いつものように不要になったら忘れずに削除するようにしてください。
記事
Mihoko Iijima · 2022年3月29日

データベース空き容量の監視方法について

これは、InterSystems FAQサイトの記事です。 データベースの空き容量は、システムモニタを使用して監視することができます。 システムモニタは、システム開始時に自動開始され、予め設定された閾値に対してアラートが通知されます。 システムの閾値については以下ドキュメントをご参照ください。システム・モニタのステータスおよびリソース・メトリック【IRIS】システム・モニタのステータスおよびリソース・メトリック データベースの空き容量については、システムデフォルトでは 50 MBを下回る場合にアラートが通知され、メッセージログ(コンソールログ)にアラート(深刻度 2)として記録され、alerts.log ファイルにも出力されます。 データベースの空き容量を任意サイズで監視したい場合、システムモニタに含まれる「アプリケーションモニタ」を利用して設定します。注意:アプリケーションモニタでは、アラート対象となる情報があってもメッセージログ(コンソールログ)に出力しないため、メール通知/メソッド実行 を使用して通知するように設定します。 例えば、空き容量が 100MB を下回った時にアラートを通知したい場合は、アプリケーションモニタが提供する %Monitor.System.Sample.Freespace(空き容量メトリック)を利用します。 その他のアプリケーションモニタの閾値(メトリック)については、以下ドキュメントをご参照ください。アプリケーション・モニタのメトリック【IRIS】アプリケーション・モニタのメトリック システム提供のアプリケーションモニタは、デフォルトでは全て無効化されています。使用を開始するためには、対象のモニタを有効化し、システムモニタを再起動します。 アプリケーションモニタの有効/無効やシステムモニタの停止/開始は、システムルーチン ^%SYSMONMGR を利用します。 以下の例では、データベースの空き容量が 100MB を下回る場合にメール通知を行う設定手順について説明します。 手順は以下の通りです。 1) ^%SYSMONMGR を起動し、アプリケーションモニタから %Monitor.System.Freespace を有効化する 2) アラート対象とする閾値を変更する(例では、通知は最初の1回のみとしています) 3) Email通知設定を行う 4) システムモニタを再起動する 1) ^%SYSMONMGR を起動し、アプリケーションモニタから %Monitor.System.Freespace を有効化する ドキュメントは以下ご参照ください。Manage Monitor Classes【IRIS】Manage Monitor Classes %SYS>do ^%SYSMONMGR 1) Start/Stop System Monitor 2) Set System Monitor Options 3) Configure System Monitor Classes 4) View System Monitor State 5) Manage Application Monitor 6) Manage Health Monitor 7) View System Data 8) Exit Option? 5   → 5 を入力してEnter押下 1) Set Sample Interval 2) Manage Monitor Classes 3) Change Default Notification Method 4) Manage Email Options 5) Manage Alerts 6) Exit Option? 2   → 2 を入力してEnter押下 1) Activate/Deactivate Monitor Class 2) List Monitor Classes 3) Register Monitor System Classes 4) Remove/Purge Monitor Class 5) Set Class Sample Interval 6) Debug Monitor Classes 7) Exit Option? 1   → 1 を入力してEnter押下 Class? ?   → ? を入力してEnter押下 Num MetricsClassName Activated 1) %Monitor.System.HistoryMemory N 2) %Monitor.System.HistoryPerf N 3) %Monitor.System.HistorySys N 4) %Monitor.System.HistoryUser N 5) %Monitor.System.AuditCount N 6) %Monitor.System.AuditEvents N 7) %Monitor.System.Clients N 8) %Monitor.System.Diskspace N 9) %Monitor.System.Freespace N 10) %Monitor.System.Globals N 11) %Monitor.System.Journals N 12) %Monitor.System.License N 13) %Monitor.System.LockTable N 14) %Monitor.System.Processes N 15) %Monitor.System.Routines N 16) %Monitor.System.Servers N 17) %Monitor.System.SystemMetrics N 18) %Monitor.System.CSPGateway N Class? 9 %Monitor.System.Freespace   →上のリストの 9 を指定してEnter押下 Activate class? Yes => yes   → yes を入力してEnter押下 1) Activate/Deactivate Monitor Class 2) List Monitor Classes 3) Register Monitor System Classes 4) Remove/Purge Monitor Class 5) Set Class Sample Interval 6) Debug Monitor Classes 7) Exit Option?  →Enter押下(前のメニューに戻ります) 1) Set Sample Interval 2) Manage Monitor Classes 3) Change Default Notification Method 4) Manage Email Options 5) Manage Alerts 6) Exit Option? 2) アラート対象とする閾値を変更する(例では、通知は最初の1回のみとしています) ※以下実行例は、1) の続きで記述しています。^%SYSMONMGRの実行から始めている場合は、5) Manage Application Monitor 選択後の画面から開始してください。 ドキュメントは以下ご参照ください。Manage Alerts【IRIS】Manage Alerts 1) Set Sample Interval 2) Manage Monitor Classes 3) Change Default Notification Method 4) Manage Email Options 5) Manage Alerts 6) Exit Option? 5   → 5 を入力してEnter押下 1) Create Alert 2) Edit Alert 3) List Alerts 4) Delete Alert 5) Enable/Disable Alert 6) Clear NotifyOnce Alert 7) Exit Option? 1   → 1 を入力してEnter押下 Alert name? test database free space alert → 任意のアラート名を入力してEnter押下 Application? %SYS (Enter '-' to reset) =>   → Enter押下 Action (0=default,1=email,2=method)? 0 => 1   → 1 を入力してEnter押下 Raise this alert during sampling? Yes => yes   → yes を入力してEnter押下 Class? ?   → ? を入力してEnter押下 Num MetricsClassName Activated 1) %Monitor.System.HistoryMemory N 2) %Monitor.System.HistoryPerf N 3) %Monitor.System.HistorySys N 4) %Monitor.System.HistoryUser N 5) %Monitor.System.AuditCount N 6) %Monitor.System.AuditEvents N 7) %Monitor.System.Clients N 8) %Monitor.System.Diskspace N 9) %Monitor.System.Freespace Y 10) %Monitor.System.Globals N 11) %Monitor.System.Journals N 12) %Monitor.System.License N 13) %Monitor.System.LockTable N 14) %Monitor.System.Processes N 15) %Monitor.System.Routines N 16) %Monitor.System.Servers N 17) %Monitor.System.SystemMetrics N 18) %Monitor.System.CSPGateway N Class? 9 %Monitor.System.Freespace    → 上のリストの 9 を指定してEnter押下 Property? ?    → ? を入力してEnter押下 Num Name Activated 1) CurSize Y 2) DBName Y 3) Directory Y 4) DiskFreeSpace Y 5) FreeSpace Y 6) MaxSize Y Property? 5 FreeSpace   → 上のリストの 5 を指定してEnter押下 Property? Properties list: FreeSpace Evaluation expression (e.g., "%1=99")? %1<100 ←MB単位に指定します。例では「100MB未満の場合アラート」を指定してEnter押下 Expression expands to: If FreeSpace<100. OK? Yes => Yes   → Yes を入力してEnter押下 Notify once only? No => yes   → yes を入力してEnter押下 1) Create Alert 2) Edit Alert 3) List Alerts 4) Delete Alert 5) Enable/Disable Alert 6) Clear NotifyOnce Alert 7) Exit Option?  →Enter押下(前のメニューに戻ります) 1) Set Sample Interval 2) Manage Monitor Classes 3) Change Default Notification Method 4) Manage Email Options 5) Manage Alerts 6) Exit Option?  →Enter押下(前のメニューに戻ります) 3) Email通知設定を行う 以下の例では、gmail を利用する例をご紹介しています。gmail は SSL構成を事前に作成する必要があります。管理ポータルの以下メニューから事前に作成してください。 管理ポータル > システム管理 > セキュリティ管理 > SSL/TLS構成 ※以下実行例は、2)の続きで記述しています。^%SYSMONMGR の実行から始めている場合は、5) Manage Application Monitor 選択後の画面から開始してください。 ドキュメントは以下ご参照ください。Manage Email Options【IRIS】Manage Email Options 1) Start/Stop System Monitor 2) Set System Monitor Options 3) Configure System Monitor Classes 4) View System Monitor State 5) Manage Application Monitor 6) Manage Health Monitor 7) View System Data 8) Exit Option? 5   → 5 を入力してEnter押下 1) Set Sample Interval 2) Manage Monitor Classes 3) Change Default Notification Method 4) Manage Email Options 5) Manage Alerts 6) Exit Option? 4   → 4 を入力してEnter押下 1) Enable/Disable Email 2) Set Sender 3) Set Server 4) Manage Recipients 5) Set Authorization 6) Test Email 7) Exit Option? 3   → 3 を入力してEnter押下 Mail server? smtp.gmail.com   → メールサーバを入力してEnter押下 Mail server port? 587   → メールサーバのポート番号を入力してEnter押下 Mail server SSLConfiguration? gmail   → 管理ポータルで設定したSSL構成名を入力してEnter押下 Mail server UseSTARTTLS? 0 => 1   → 1を入力してEnter押下 1) Enable/Disable Email 2) Set Sender 3) Set Server 4) Manage Recipients 5) Set Authorization 6) Test Email 7) Exit Option? 2   → 2 を入力してEnter押下 Sender? sendertest@gmail.com   → 差出人のメールアドレスを入力してEnter押下 1) Enable/Disable Email 2) Set Sender 3) Set Server 4) Manage Recipients 5) Set Authorization 6) Test Email 7) Exit Option? 5   → 5 を入力してEnter押下 User name? xxxabctestaccount@gmail.com   → 認証用アカウント名を入力してEnter押下 Password?   → パスワードを入力してEnter押下 1) Enable/Disable Email 2) Set Sender 3) Set Server 4) Manage Recipients 5) Set Authorization 6) Test Email 7) Exit Option? 4   → 4 を入力してEnter押下 1) List Recipients 2) Add Recipient 3) Remove Recipient 4) Exit Option? 2   → 2 を入力してEnter押下 Email Address? abc@testcorp.com   → 送信先メールアドレスを入力してEnter押下 1) List Recipients 2) Add Recipient 3) Remove Recipient 4) Exit Option?  →Enter押下(前のメニューに戻ります) 1) Enable/Disable Email 2) Set Sender 3) Set Server 4) Manage Recipients 5) Set Authorization 6) Test Email 7) Exit Option? 1   → 1 を入力してEnter押下 Email is currently OFF Change Email setting? No => yes   → yes を入力してEnter押下 1) Enable/Disable Email 2) Set Sender 3) Set Server 4) Manage Recipients 5) Set Authorization 6) Test Email 7) Exit Option? 6   → 6 を入力してEnter押下 Sending email on Mail Server smtp.gmail.com From: sendertest@gmail.com To: abc@testcorp.com 1) Enable/Disable Email 2) Set Sender 3) Set Server 4) Manage Recipients 5) Set Authorization 6) Test Email 7) Exit Option?  →Enter押下(前のメニューに戻ります) 1) Set Sample Interval 2) Manage Monitor Classes 3) Change Default Notification Method 4) Manage Email Options 5) Manage Alerts 6) Exit Option?  →Enter押下(前のメニューに戻ります) 1) Start/Stop System Monitor 2) Set System Monitor Options 3) Configure System Monitor Classes 4) View System Monitor State 5) Manage Application Monitor 6) Manage Health Monitor 7) View System Data 8) Exit Option?  →Enter押下(前のメニューに戻ります) 4) システムモニタを再起動する 設定を反映させるため、システムモニタを一度停止し、開始します。 ドキュメントは以下ご参照ください。Start/Stop System Monitor【IRIS】Start/Stop System Monitor %SYS>do ^%SYSMONMGR 1) Start/Stop System Monitor 2) Set System Monitor Options 3) Configure System Monitor Classes 4) View System Monitor State 5) Manage Application Monitor 6) Manage Health Monitor 7) View System Data 8) Exit Option? 1   → 1 を入力してEnter押下 1) Start System Monitor 2) Stop System Monitor 3) Exit Option? 2   → 2 を入力してEnter押下 Stopping System Monitor... System Monitor stopped 1) Start System Monitor 2) Stop System Monitor 3) Exit Option? 1   → 1 を入力してEnter押下 Starting System Monitor... System Monitor started 1) Start System Monitor 2) Stop System Monitor 3) Exit Option?  →Enter押下(前のメニューに戻ります) 1) Start/Stop System Monitor 2) Set System Monitor Options 3) Configure System Monitor Classes 4) View System Monitor State 5) Manage Application Monitor 6) Manage Health Monitor 7) View System Data 8) Exit Option?  →Enter押下(ネームスペースのプロンプトに戻ります) %SYS>
記事
Toshihiko Minamoto · 2023年11月15日

医師と患者の会話: AI を使用した文字起こしおよび要約

![](/sites/default/files/inline/images/4_25.png)   **前の記事** - [AI による臨床文書の保管、取得、検索の単純化](https://community.intersystems.com/post/using-ai-simplify-clinical-documents-storage-retrieval-and-search) この記事では、AI を使用した文字起こしと要約によってヘルスケアに変革を起こす OpenAI の高度な言語モデルの可能性を探ります。 OpenAPI の最先端 API を活用して、録音データを文字起こしし、自然言語処理アルゴリズムを使って簡潔な要約を生成するための重要なインサイトを抽出するプロセスを掘り下げていきます。 似たような機能は Amazon Medical Transcibe や Medvoice などの既存のソリューションでも提供されていますが、この記事では、OpenAI テクノロジーを使用してこれらの強力な機能を InterSystems FHIR に実装することに焦点を当てています。 ## Vue.js の録音データ Vue.js アプリのボイスレコーダーは、完全にネイティブであり、[Mediarecorder](https://developer.mozilla.org/en-US/docs/Web/API/MediaRecorder) インターフェースを使って JavaScript で記述されています。 これは、アプリケーションを軽量に維持しながら、録音オプションを完全に制御できるようにすることを目的としています。 以下は、録音入力の開始と停止を行うスニペットです。 // オーディオストリームをチャンクとして保存する録音開始メソッド async startRecording() { try { const stream = await navigator.mediaDevices.getUserMedia({ audio: true, }); this.mediaRecorder = new MediaRecorder(stream); this.mediaRecorder.start(); this.mediaRecorder.ondataavailable = (event) => { this.chunks.push(event.data); }; this.isRecording = true; } catch (error) { console.error("Error starting recording:", error); } } // 停止後にブロブを作成する(そして転写メソッドを呼び出す)録画停止メソッド stopRecording() { if (this.mediaRecorder) { this.isLoading = true; this.mediaRecorder.stop(); this.mediaRecorder.onstop = async () => { const blob = new Blob(this.chunks, { type: "audio/webm;codecs=opus", }); await this.sendAudioToWhisper( new File([blob], `file${Date.now()}.m4a`) ); this.getSummary(this.transcription); }; } } ## 文字起こしコンポーネント OpenAI の Whisper モデルを使った音声データの文字起こしには、いくつかの基本コンポーネントが使用されます。 以下のコードスニペットは、文字起こしプロセスに関わるステップを示します。 const apiKey = process.env.OPENAI_API_KEY; const formData = new FormData(); formData.append("file", blob); formData.append("model", "whisper-1"); formData.append("response_format", "json"); formData.append("temperature", "0"); formData.append("language", "en"); try { const response = await fetch( "https://api.openai.com/v1/audio/transcriptions", { method: "POST", headers: { Accept: "application/json", Authorization: `Bearer ${apiKey}`, }, body: formData, redirect: "follow", } ); const data = await response.json(); if (data.text) { this.transcription = data.text; } } catch (error) { console.error("Error sending audio to Whisper API:", error); } return this.transcription; 1. **API キー** - `OPENAI_API_KEY` は、OpenAI API にアクセスするために必要な認証トークンです。 2. **フォームデータ** - 文字起こしされる音声ファイルは、`FormData` オブジェクトに追加されます。 選択されたモデル(`whisper-1`)、レスポンス形式(`json`)、体温(``)、および言語(`en`)などの追加パラメーターも含まれています。 3. **API リクエスト** - OpenAI API エンドポイント `https://api.openai.com/v1/audio/transcriptions` への POST リクエストには、ヘッダーとフォームデータを含むボディを指定して、`fetch` メソッドで送信されています。 4. **レスポンス処理** - API からのレスポンスがキャプチャされ、文字起こしされたテキストが `data` オブジェクトから抽出されます。 文字起こしを変数 `this.transcription` に割り当てて、さらに処理するか使用することができます。 ## 要約コンポーネント 以下のコードスニペットは、OpenAI の `text-davinci-003` モデルを使用したテキスト要約プロセスに関わる基本コンポーネントを示しています。 response = openai.Completion.create( model="text-davinci-003", prompt="Summarize the following text and give title and summary in json format. \ Sample output - {\"title\": \"some-title\", \"summary\": \"some-summary\"}.\ Input - " + text, temperature=1, max_tokens=300, top_p=1, frequency_penalty=0, presence_penalty=1 ) return response["choices"][0]["text"].replace('\n', '') 1. **モデルの選択** - `model` パラメーターは `text-davinci-003` に設定されており、OpenAI のテキスト補完モデルが要約に使用されていることを示します。 2. **プロンプト** - モデルに提供されるプロンプトは、望ましい結果を指定しています。これは入力テキストを要約して JSON 形式でタイトルと要約を返します。 入力テキストは、プロンプトに連結して処理されます。 OpenAI を通じてレスポンス変換を処理できるところに興味深いポイントがあります。 受信側での検証のみで十分であり、将来的にはコンバーターがほとんど必要なくなる可能性があります。 3. **生成パラメーター** - 生成された要約の動作と品質を制御するために、`temperature`、`max_tokens`、`top_p`、`frequency_penalty`、`presence_penalty` などのパラメーターが設定されます。 4. **API リクエストとレスポンスの処理** - API リクエストを行うために、`openai.Completion.create()` メソッドが呼び出されます。 レスポンスがキャプチャされ、生成された要約テキストがレスポンスオブジェクトから抽出されます。 要約テキストに含まれる改行文字(`\n`)は、最終結果を返す前に取り除かれます。 ## FHIR のドキュメント参照 OpenAI テクノロジーを使用して医師と患者の会話の文字起こしと要約を実装する文脈においては、FHIR 規格内での診療記録の保管を考慮することが重要です。 FHIR は、診療記録などの医療情報を様々な医療システムやアプリケーション間で交換するための構造化された標準アプローチです。 FHIR の [DocumentReference](https://build.fhir.org/documentreference.html) リソースは、診療記録や関連文書を保管するための専用のセクションとして機能します。 文字起こしと要約機能を医師と患者の会話ワークフローに統合する場合、生成される文字起こしと要約は、FHIR Documents リソース内の診療記録として保管できます。 これにより、生成されたインサイトへのアクセス、取得、およびヘルスケアプロバイダーやその他の承認機関の間での共有を簡単に行えます。 { "resourceType": "Bundle", "id": "1a3a6eac-182e-11ee-9901-0242ac170002", "type": "searchset", "timestamp": "2023-07-01T16:34:36Z", "total": 1, "link": [ { "relation": "self", "url": "http://localhost:52773/fhir/r4/Patient/1/DocumentReference" } ], "entry": [ { "fullUrl": "http://localhost:52773/fhir/r4/DocumentReference/1921", "resource": { "resourceType": "DocumentReference", "author": [ { "reference": "Practitioner/3" } ], "subject": { "reference": "Patient/1" }, "status": "current", "content": [ { "attachment": { "contentType": "application/json", "data": "" } } ], "id": "1921", "meta": { "lastUpdated": "2023-07-01T16:34:33Z", "versionId": "1" } }, "search": { "mode": "match" } } ] } ## 試してみましょう 1. **プロジェクトをクローン** - 次の GitHub リンクからプロジェクトリポジトリをクローンします: 。 2. **ローカルでセットアップ** - 提供された指示に従って、プロジェクトをローカルマシン上にセットアップします。 セットアップ中に問題が発生した場合は、お知らせください。 3. **患者を選択** - プロジェクト内の提供されたサンプルリストから患者を選択します。 この患者は、文字起こしと要約に使用される医師と患者の会話と関連付けられます。 4. **対話ページ** - 患者が選択されたら、プロジェクト内の対話ページに移動します。 このページで、「Take Notes」オプションを見つけてクリックし、医師と患者の会話の文字起こしプロセスを開始します。 5. **文字起こしの表示と編集** - 文字起こしプロセスが完了したら、生成された文字起こしを表示するオプションが表示されます。 さらに整理してわかりやすくするために、文字起こしに関連付けられたタイトルと要約を編集することもできます。 6. **FHIR DocumentReference に保存** - タイトルと要約の処理が完了し、変更を保存すると、FHIR DocumentReference 内に自動的に保管されます。 これにより、関連する診療記録がキャプチャされ、それぞれの患者の記録に確実に関連付けられます。 現時点では、このプロジェクトは文字起こしテキスト全体を保存しませんが、 完全な文字起こしの補完を含めるように変更することもできます。 ## デモ アプリケーション全体のデモはこちらでご覧ください: ## 今後の方向性 AI を活用した文字起こしと要約の応用を遠隔医療通信に拡大することには、計り知れない可能性が秘められています。 これらの機能を Zoom、Teams、Google Meet などの一般的な会議プラットフォームに統合することで、医師と患者のリモート対話を合理化できる可能性があります。 遠隔医療セッションの自動文字起こしと要約機能には、正確な文書作成や分析の強化といったメリットがあります。 ただし、データプライバシーが重大な課題として残されます。 これに対応するためには、外部サーバーにデータを送信する前に、個人を特定できる情報(PII)をフィルターまたは匿名化する対策を実装する必要があります。 今後の方向性としては、ローカルで処理するためのオンデバイス AI モデルの調査、多言語コミュニケーションのサポートの改善、プライバシー維持した手法の進歩が挙げられます。 **有用な実装だと思われた方は、Grand Prix 2023 で[このアプリに投票](https://openexchange.intersystems.com/package/IRIS-FHIR-Transcribe-Summarize-Export)してください。**