文章 Qiao Peng · 一月 10, 2021 9m read

Swift-FHIR-Iris

iOS应用程序支持将HealthKit数据导入InterSystems IRIS医疗版(或任何FHIR资源仓库库)

main

目录

演示目的

目的是创建FHIR协议的端到端演示。

这里的端到端指的是从一个信息源到另一个信息源,例如iPhone。 苹果HealthKit将收集到的健康数据转换为FHIR,再发送到InterSystems IRIS 医疗版存储库。

必须通过web接口访问这些信息。

TL;DR: iPhone -> InterSystems FHIR -> web界面.

如何运行此演示

先决条件

  • 客户端 (iOS)
    • Xcode 12
  • 服务器和Web应用程序
    • Docker

安装 Xcode

这里没有太多要说的,打开AppStore,搜索Xcode,安装。

打开SwiftUi project

Swift是苹果在iOS、Mac、Apple TV和Apple Watch中使用的一种编程语言,是objective-C的替代品。

双击Swift-FHIR-Iris.xcodeproj

单击左上角的箭头打开模拟器。

xcode

配置模拟器

打开Health

点击“Steps”

添加数据

simulator

启动InterSystems FHIR服务器

在该git的根目录下,运行以下命令:

docker-compose up -d

构建过程结束时,你将连接到FHIR资源仓库:

http://localhost:32783/fhir/portal/patientlist.html

portal

该门户网站由@diashenrique创建.

为处理Apple活动足迹,进行了一些修改。

在iOS应用程序上操作

iOS应用程序首先会请求你同意分享部分信息。

点击授权

authorize

然后点击“Save and test server”对FHIR服务器进行测试

默认设置指向docker配置。

操作成功后,就可以输入患者信息。

名字、姓氏、生日、性别。

将患者信息保存到Fhir。弹出窗口将显示唯一的Fhir ID。

savepatient

可在门户网站查阅该患者信息:

访问: http://localhost:32783/fhir/portal/patientlist.html

在这里我们可以看到,增加了一个新的病人“Toto”,0个活动。

patient portal

发送她的活动信息:

回到iOS应用程序,点击“Step count”。

这里显示的是一周的步数。在我们的案例中有2条记录。

现在可以单击发送,将这些数据发送到InterSystems IRIS FHIR。

ios send

从门户网站上查询新的活动记录:

现在我们可以看到Toto有两条新的观察和活动消息。

portal activites

你还可以单击“chart”按钮以图表格式显示。

portal charts

工作原理

iOS

该demo大部分是基于SwiftUI构建的。

https://developer.apple.com/xcode/swiftui/

iOS和co的最新框架。

如何检查健康数据的授权

它在SwiftFhirIrisManager 类中。

该类采用单例模式,可使用@EnvironmentObject对应用程序中进行的所有操作进行注释。

更多信息请访问 : https://www.hackingwithswift.com/quick-start/swiftui/how-to-use-environmentobject-to-share-data-between-views

调用requestAuthorization的方法如下:

    // Request authorization to access HealthKit.
    func requestAuthorization() {
        // Requesting authorization.
        /// - Tag: RequestAuthorization
        
        let writeDataTypes: Set<HKSampleType> = dataTypesToWrite()
        let readDataTypes: Set<HKObjectType> = dataTypesToRead()
        
        // requset authorization
        healthStore.requestAuthorization(toShare: writeDataTypes, read: readDataTypes) { (success, error) in
            if !success {
                // Handle the error here.
            } else {
                
                DispatchQueue.main.async {
                    self.authorizedHK = true
                }
                
            }
        }
    }

其中healthStore是HKHealthStore()的对象。

HKHealthStore类似于iOS中的healthdata数据库。

dataTypesToWrite和dataTypesToRead是我们想要在数据库中查询的对象。

授权的目的可以通过在Info.plist xml文件中添加以下内容完成:

    <key>NSHealthClinicalHealthRecordsShareUsageDescription</key>
    <string>Read data for IrisExporter</string>
    <key>NSHealthShareUsageDescription</key>
    <string>Send data to IRIS</string>
    <key>NSHealthUpdateUsageDescription</key>
    <string>Write date for IrisExporter</string>

如何连接FHIR资源仓库

对于这一部分,我使用了从Smart-On-FHIR网站下载的FHIR包 : https://github.com/smart-on-fhir/Swift-FHIR

使用的类是FHIROpenServer。.

    private func test() {
        
        progress = true
        
        let url = URL(string: self.url)

        swiftIrisManager.fhirServer = FHIROpenServer(baseURL : url! , auth: nil)
        
        swiftIrisManager.fhirServer.getCapabilityStatement() { FHIRError in
            
            progress = false
            showingPopup = true
            
            if FHIRError == nil {
                showingSuccess = true
                textSuccess = "Connected to the fhir repository"
            } else {
                textError = FHIRError?.description ?? "Unknow error"
                showingSuccess = false
            }
            
            return
        }
 
    }

这一步将在单例swiftIrisManager中创建一个新的对象fhirServer。

接下来使用getCapabilityStatement()

如果能够检索到FHIR服务器的capabilityStatement,则意味着已成功连接到FHIR资源仓库。

这个资源仓库不在HTTPS下,默认情况下Apple会阻止这种通信。

想要获取HTTP支持,可以对Info.plist xml文件进行如下编辑:

    <key>NSAppTransportSecurity</key>
    <dict>
        <key>NSExceptionDomains</key>
        <dict>
            <key>localhost</key>
            <dict>
                <key>NSIncludesSubdomains</key>
                <true/>
                <key>NSExceptionAllowsInsecureHTTPLoads</key>
                <true/>
            </dict>
        </dict>
    </dict>

如何将患者信息保存到FHIR资源仓库

基本操作:首先检查存储库中是否已经存在该患者的信息

Patient.search(["family": "\(self.lastName)"]).perform(fhirServer)

搜索具有相同姓氏的患者。

在这里,我们可以想象一下其他场景,比如使用Oauth2和JWT令牌加入patientId及其令牌。但在这个演示中,我们简单操作即可。

如果该患者信息已经存在,可以对其进行检索;否则,则创建新的患者信息 :

    func createPatient(callback: @escaping (Patient?, Error?) -> Void) {
        // Create the new patient resource
        let patient = Patient.createPatient(given: firstName, family: lastName, dateOfBirth: birthDay, gender: gender)
        
        patient?.create(fhirServer, callback: { (error) in
            callback(patient, error)
        })
    }

如何从HealthKit中提取数据

通过查询healthkit商店 store(HKHealthStore())即可完成。

这里我们查询一下步数。

使用predicate做好查询准备。

        //Last week
        let startDate = swiftFhirIrisManager.startDate
        //Now
        let endDate = swiftFhirIrisManager.endDate

        print("Collecting workouts between \(startDate) and \(endDate)")

        let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: HKQueryOptions.strictEndDate)

然后,会根据数据类型(HKQuantityType.quantityType(forIdentifier: .stepCount))和predicate内容进行查询。

func queryStepCount(){
        
        //Last week
        let startDate = swiftFhirIrisManager.startDate
        //Now
        let endDate = swiftFhirIrisManager.endDate

        print("Collecting workouts between \(startDate) and \(endDate)")

        let predicate = HKQuery.predicateForSamples(withStart: startDate, end: endDate, options: HKQueryOptions.strictEndDate)

        let query = HKSampleQuery(sampleType: HKQuantityType.quantityType(forIdentifier: .stepCount)!, predicate: predicate, limit: HKObjectQueryNoLimit, sortDescriptors: nil) { (query, results, error) in
            
            guard let results = results as? [HKQuantitySample] else {
                   return
            }
       
            process(results, type: .stepCount)
        
        }

        healthStore.execute(query)

    }

如何将HealthKit数据转换为FHIR

在这部分,我们使用了微软软件包HealthKitToFHIR

https://github.com/microsoft/healthkit-to-fhir

这个包很有用,为开发商提供了将HKQuantitySample转换为FHIR Observation的功能。

     let observation = try! ObservationFactory().observation(from: item)
      let patientReference = try! Reference(json: ["reference" : "Patient/\(patientId)"])
      observation.category = try! [CodeableConcept(json: [
          "coding": [
            [
              "system": "http://terminology.hl7.org/CodeSystem/observation-category",
              "code": "activity",
              "display": "Activity"
            ]
          ]
      ])]
      observation.subject = patientReference
      observation.status = .final
      print(observation)
      observation.create(self.fhirServer,callback: { (error) in
          if error != nil {
              completion(error)
          }
      })

其中item是HKQuantitySample,在我们的例子中是stepCount类型。

这个factory完成了大部分工作,将“unit”和“type”转换为FHIR codeableConcept,并将“value”转换为FHIR valueQuantity。

对PatientId的引用是通过强制转换json fhir引用手动完成的。

let patientReference = try! Reference(json: ["reference" : "Patient/\(patientId)"])

对类别进行同样的操作 :

      observation.category = try! [CodeableConcept(json: [
          "coding": [
            [
              "system": "http://terminology.hl7.org/CodeSystem/observation-category",
              "code": "activity",
              "display": "Activity"
            ]
          ]
      ])]

最后,在fhir资源仓库中创建observation :

      observation.create(self.fhirServer,callback: { (error) in
          if error != nil {
              completion(error)
          }
      })

后端 (FHIR)

没什么好说的,它基于InterSystems社区的fhir模板 :

https://openexchange.intersystems.com/package/iris-fhir-template

前端

基于Henrique作品,Henrique是使用jquery制作的FHIR资源仓库的一个很好的前端。

https://openexchange.intersystems.com/package/iris-fhir-portal

0
0 431
文章 Jeff Liu · 一月 8, 2021 3m read

关注开发者社区全栈竞赛的朋友会知道,我提交了一个名为qewd-conduit的参赛作品。我想总结一下,为什么我认为您应该花点时间来看看这个作品。

qewd-conduit 使用基于 Node.js QEWD 框架和 IRIS,可以为 RealWorld Conduit 应用程序实现后端 REST API

https://github.com/gothinkster/realworld

这个方案很酷,它提供了一个平台,让很多人可以为特定应用程序的后端和前端,实现不同的技术解决方案。而qewd-conduit只是符合相同REST API后端规范的众多解决方案之一。同样,要实现完全相同的UI/UX,您可以尝试使用众多不同前端客户端中的任何一个,并通过REST与包括QEWD-Conduit在内的任何Conduit后端集成。

这样就可以用各种不同的框架和技术,去执行完全相同的任务,从而对不同的框架和技术进行比较和对比。

RealWorld应用程序很好地平衡了相关性和非琐碎性(不仅仅是ToDo应用程序!),并且也不是太复杂,无论是在UI/UX还是在后端API方面。因此便于展示和说明如何使用特定技术来实现RealWorld的指定功能。

0
0 152
文章 Jeff Liu · 一月 8, 2021 5m read

你好!

本文简单介绍一款工具,帮您理解InterSystems产品(从IRISCachéEnsemble以及HealthShare)中的类及其结构。

简言之,它将类或整个包可视化,显示类之间的关系,并向开发人员和团队领导提供各种信息,而无需到 Studio 中检查代码。

如果您正在学习InterSystems产品,经常查看项目,或只对InterSystems技术解决方案中的新内容感兴趣,欢迎阅读ObjectScript类浏览器概述!

InterSystems 产品简介

IRIS(之前称为Caché) 是一个多模型DBMS。您可以使用SQL查询来访问它,也可以通过各种编程语言可用的接口与存储的对象和过程进行交互。但最多的还是使用DBMS原生内置语言--ObjectScript (COS) 开发应用程序。

Caché支持DBMS级别的类。有两种主要的类类型:Persistent(可以存储在数据库中)和 Registered(不存储在数据库中,扮演程序和处理程序的角色)。还有几种特殊的类类型:Serial(可集成到持久类中用于创建复杂数据类型(如:地址)的类),DataType(用于创建用户定义的数据类型)、IndexView Stream

进入类浏览器

0
1 473
文章 Nicky Zhu · 一月 8, 2021 2m read

我最近看到有人称 ECP 为魔术。 它似乎确实如此,并且它在许多工程中发挥了相当有趣的作用。 下列各图表简单显示了分布式架构中检索和使用数据的方式。

有关 ECP(包括容量计划)的更多信息,请单击以下链接:数据平台及性能 - 第 7 部分 性能、可伸缩性和可用性 ECP

开始

  • 在磁盘 ^ A、^ B 和 ^ C 上有 3 个globals。
  • Global ^ B 等于 “ B”
  • 有 1 个数据服务器和 2 个或多个应用程序服务器。
  • 下图显示了每个服务器上的缓存(全局缓冲区)。


应用程序服务器 1 上的用户请求 ^ B 的内容,然后序列开始,看看是否可以继续。
















有关 ECP(包括容量计划)的更多信息,请单击以下链接:数据平台及性能 - 第 7 部分 性能、可伸缩性和可用性 ECP

0
0 243
文章 Nicky Zhu · 一月 8, 2021 6m read

调用 Web 服务的过程中,在期望的时间内未返回响应时,后续发生的情况由业务操作的几个设置来控制。(请注意,这也与非 SOAP 简单 HTTP 调用等有关)

3 个主要设置为:

  • 响应超时
  • 指定从远程 Web 服务器获取响应的超时时间。

  • 重试间隔
  • 尝试与 Ensemble 之外的目标进行连接之间等待的秒数。

  • 故障超时
  • 尝试与 Ensemble 之外的目标保持连接的总秒数。 经过此秒数时间后,业务操作将丢弃消息数据并返回错误代码。

    归纳一下就是这样:

    我们将等待 Web 服务器的响应,时间为“响应超时”所用的时间。 如果此时间过后未收到响应,我们将在“重试间隔”时间过后再次调用 Web 服务器。 如此继续尝试,直到时间(从第一次尝试算起)达到“故障超时”设置的时间秒数。

    以下举例进行说明:

    假定以下设置:

    就是说:

    响应超时 - 等待 7 秒以响应

    重试间隔 - 每 10 秒重试一次

    故障超时 – 30 秒后“放弃”重试

    假定在 8 秒后返回响应,则情况如下:

  • 在 00:00,我们进行第一次调用
  • 在 00:07,由于未返回任何响应,我们在内部确认发生了“响应超时”错误(并在“事件日志”中记录“错误事件”),并根据重试策略和设置再次尝试 – “故障超时”尚未到达,因此引发了“需要重试标志”。
  • [在 00:08,Web 服务器返回一个响应,但由于我们已经将其记录为超时错误,因此我们不会收到此响应]
  • 在 00:10,重试间隔时间已到,并且由于引发了“需要重试标志”,我们将再次调用 Web 服务。
  • 在 00:17,如果仍未返回任何响应,我们将再次达到“响应超时”时间(请注意,在上面的“00:08/第 3 段中,返回的响应已被“忽略/丢弃”),因此我们再次在内部将此认为是错误(但这次不会再添加一个“错误事件日志”条目,只会在第一次尝试时记录此错误,而不是每次重试失败时都记录),由于我们尚未达到“故障超时”时间,因此需要再次引发“需要重试标志”。
  • [在 00:18,Web 服务器返回一个响应,这次我们还是接收不到]
  • 在 00:20,又达到重试间隔时间,我们将尝试第 3 次调用。
  • 在 00:27,仍无响应,再次发生“响应超时”错误,需要重试(仍未达到“故障超时”)。
  • [在 00:28,服务器未发回响应]
  • 在 00:30,再次达到重试间隔时间,我们进行第 4 次尝试(也是最后一次)。
  • 在 00:37,“响应超时”再次发生 – 这次,已达到“故障超时”时间,因此我们不会引发“需要重试标志”,而是放弃 – 我们在事件日志中记录一个错误事件,指出已达到故障超时时间,并且返回业务操作调用错误。
  • 以下是上述示例的调用“证据”。

    首先是服务器端 [来自 SOAP 日志] – 可以看到,其收到了 4 次调用/请求,均相隔 10 秒,每次在请求发出 8 秒后返回一个响应:


    05/31/2016 14:18:45 *********************
    Input to Web service with SOAP action = http://tempuri.org/Test.WSTimeouts.WebService.GetResponse
    ...
    05/31/2016 14:18:53 *********************
    Output from Web service with SOAP action = http://tempuri.org/Test.WSTimeouts.WebService.GetResponse
    ...
    05/31/2016 14:18:55 *********************
    Input to Web service with SOAP action = http://tempuri.org/Test.WSTimeouts.WebService.GetResponse
    ...
    05/31/2016 14:19:03 *********************
    Output from Web service with SOAP action = http://tempuri.org/Test.WSTimeouts.WebService.GetResponse
    ...
    05/31/2016 14:19:05 *********************
    Input to Web service with SOAP action = http://tempuri.org/Test.WSTimeouts.WebService.GetResponse
    ...
    05/31/2016 14:19:13 *********************
    Output from Web service with SOAP action = http://tempuri.org/Test.WSTimeouts.WebService.GetResponse
    ...
    05/31/2016 14:19:15 *********************
    Input to Web service with SOAP action = http://tempuri.org/Test.WSTimeouts.WebService.GetResponse
    ...
    05/31/2016 14:19:23 *********************
    Output from Web service with SOAP action = http://tempuri.org/Test.WSTimeouts.WebService.GetResponse
    ...

     

    现在,从 Ensemble BO/客户端,可以看到,有 4 次尝试,均相隔 10 秒,每次在 7 秒后记录响应超时错误。

    客户端

    05/31/2016 14:18:45 *********************
    Output from Web client with SOAP action = http://tempuri.org/Test.WSTimeouts.WebService.GetResponse
    ...
     
    05/31/2016 14:18:52 *********************
    Input to Web client with SOAP action = http://tempuri.org/Test.WSTimeouts.WebService.GetResponse
    ERROR #5922: Timed out waiting for response
    string**** SOAP client return error. method=GetResponse, action=http://tempuri.org/Test.WSTimeouts.WebService.GetResponse
         ERROR #5922: Timed out waiting for response
     
    05/31/2016 14:18:55 *********************
    Output from Web client with SOAP action = http://tempuri.org/Test.WSTimeouts.WebService.GetResponse
    ...
     
    05/31/2016 14:19:02 *********************
    Input to Web client with SOAP action = http://tempuri.org/Test.WSTimeouts.WebService.GetResponse
    ERROR #5922: Timed out waiting for response
    string**** SOAP client return error. method=GetResponse, action=http://tempuri.org/Test.WSTimeouts.WebService.GetResponse
         ERROR #5922: Timed out waiting for response
     
    05/31/2016 14:19:05 *********************
    Output from Web client with SOAP action = http://tempuri.org/Test.WSTimeouts.WebService.GetResponse
    ...
     
    05/31/2016 14:19:12 *********************
    Input to Web client with SOAP action = http://tempuri.org/Test.WSTimeouts.WebService.GetResponse
    ERROR #5922: Timed out waiting for response
    string**** SOAP client return error. method=GetResponse, action=http://tempuri.org/Test.WSTimeouts.WebService.GetResponse
         ERROR #5922: Timed out waiting for response
     
    05/31/2016 14:19:15 *********************
    Output from Web client with SOAP action = http://tempuri.org/Test.WSTimeouts.WebService.GetResponse
    ...
     
    05/31/2016 14:19:22 *********************
    Input to Web client with SOAP action = http://tempuri.org/Test.WSTimeouts.WebService.GetResponse
    ERROR #5922: Timed out waiting for response
    string**** SOAP client return error. method=GetResponse, action=http://tempuri.org/Test.WSTimeouts.WebService.GetResponse
         ERROR #5922: Timed out waiting for response

    以下是对 Ensemble 的可视化跟踪:

    以下是事件日志条目:

    以下为跟踪事件的日志示例[您可能需要放大以更好地读取文字]:

    由此,可以看到上述示例的一些“内部运作”:

    在日志行 ID #684,执行了首次调用 – 时间:17:09:16。

    然后,在 7 秒之后 (09:23),我们收到响应超时错误 (#685)。 然后,操作记录了此错误 (#687),并确定等待 3 秒钟,直到达到重试间隔时间;10 秒重试间隔时间减去 7 秒响应超时时间 (#688-#690)。

    经过 3 秒等待( 09:26;#691)之后,进行第 2 次尝试 (#692),结果相同,继续重复操作,直到第 4 次尝试 (#704)。 在第 4 次尝试失败(09:53;#705)之后,由于达到超时时间(30 秒),因此未进行另一次尝试。

    0
    0 334
    文章 Nicky Zhu · 一月 8, 2021 3m read

    我打算基于实例中的数据实现业务智能。 怎样才是设置数据库和环境来使用 DeepSee 的最佳方法呢?

    本教程通过 3 个 DeepSee 架构示例来解决此问题。 首先,我们从基本架构模型开始,并重点说明其局限性。 对于复杂程度中等的业务智能应用,建议使用下一个模型,对于大多数用例而言,该模型应该足矣。 在本教程的最后,我们将说明如何增强架构的灵活性以管理高级实现。

    本教程中的每个示例都介绍了新的数据库和全局映射,并讨论了为何以及何时设置它们。 在构建架构时,则重点说明更灵活的示例提供的好处。

    开始前

    主服务器和分析服务器

    为了使数据高度可用,InterSystems 通常建议使用镜像或映射,并将 DeepSee 实现基于镜像/映射服务器。 承载数据原始副本的机器称为“主服务器”,而承载数据副本和业务智能应用程序的计算机通常称为“分析服务器”(有时称为“报告服务器”)。

    拥有主服务器和分析服务器至关重要,主要原因是避免任一台服务器出现性能问题。 请查阅有关推荐架构的文档。

    数据和应用程序代码

    通常,将源数据和代码存储在同一数据库中仅对小型应用程序有效。 对于更大型的应用程序,建议将源数据和代码存储在两个专用数据库中,这样您就可以与运行 DeepSee 的所有命名空间共享代码,同时保持数据分离。 源数据的数据库应从生产服务器镜像。 该数据库可以为只读,也可为读写。 建议为此数据库持续启用日志功能。

    源类和自定义应用程序应存储在生产和分析服务器上的专用数据库中。 请注意,这两个用于源代码的数据库不需要同步,甚至不需要运行相同的 Caché 版本。 只要定期将代码备份到其他地方,通常就不需要日志。

    在本教程中,我们采用以下配置。 分析服务器上的 APP 命名空间有 APP-DATA 和 APP-CODE 作为默认数据库。 APP-DATA 数据库可以访问主服务器上的源数据数据库中的数据(源表类及其事实数据)。 APP-CODE 数据库存储 Caché 代码(.cls 和 .INT 文件)以及其他自定义代码。 数据和代码的这种分离是一种典型的架构,这允许用户,例如,有效地部署 DeepSee 代码和自定义应用程序。

    在不同的命名空间上运行 DeepSee

    使用 DeepSee 的业务智能实现通常在不同的命名空间中运行。 在本文中,我们将说明如何设置单个的 APP 命名空间,但是相同的过程适用于运行业务智能应用程序的所有名称空间。

    文档

    建议熟悉文档页面执行初始设置。 该页面的内容包括:设置 Web 应用程序,如何将 DeepSee 全局变量放置在单独的数据库中,以及 Deepeep 全局变量的替代映射列表。


    在本系列的第二部分中,我们将阐述基本架构模型的实现

    0
    0 331
    文章 Louis Lu · 一月 8, 2021 3m read

    在本篇短文中,我们将讨论如何让 Yape 在 docker 容器中运行,从而避免在本地计算机上安装设置 python。

    距离本系列的上一篇文章已经有一段时间了,让我们快速回顾一下。

    我们讨论了使用 matplotlib 创建基本图形。 之后我们介绍了使用 bokeh 生成动态图形。 在第三部分中,我们讨论了使用 monlbl 数据生成热图

    在通过各种渠道获得的反馈中,有一个相同的难题是设置一个环境来运行上面的例子。 所以我们决定让实现变得更容易一些,我与 Murray 合作为他的优秀工具 Yape 创建了一个 Dockerfile。 Github 页面

    当然,您必须在您的计算机上安装并运行 docker

    Dockerfile

    一个相当简单的基于官方 python 映像的 docker 定义:

    FROM python:3
    
    WORKDIR .
    
    COPY requirements.txt ./
    RUN pip install --no-cache-dir -r requirements.txt
    
    COPY . .
    

    源码

    Requirements.txt 包含运行 yape 所需的包:

    altgraph==0.10.2
    py-dateutil==2.2
    bdist-mpkg==0.5.0
    certifi==2017.7.27.1
    cffi==1.10.0
    chardet==3.0.4
    idna==2.5
    bokeh==0.12.6
    macholib==1.5.1
    matplotlib==2.0.2
    pandas==0.20.3
    modulegraph==0.10.4
    numpy==1.13.1
    py2app==0.7.3
    pycparser==2.18
    pyparsing==2.0.1
    python-dateutil==1.5
    pytz==2013.7
    requests==2.18.3
    six==1.4.1
    urllib3==1.22
    zope.interface==4.1.1
    

    源码

    要构建映像,只需从github 中check out,然后运行 docker build:

    git clone https://github.com/murrayo/yape.git
    docker build -t yape .
    

    (在pull request被合并之前,使用 https://github.com/kazamatzuri/yape.git

    这将需要几分钟的时间,具体取决于您的计算机/互联网连接的速度。

    之后可以使用如下命令对 pButtons 文件运行 yape:

    docker run -v `pwd`/in:/data  --rm --name yape-test yape  \
    ./extract_pButtons.py -o /data \ 
    /data/pButtons.html
    
    docker run -v `pwd`/in:/data  --rm --name yape-test yape  \ 
    ./graph_pButtons.py -o /data/charts /data
    

    我们在当前工作目录中使用

        /in
    

    并将其映射到容器中的 /data。 我们将从该目录获得 pButtons.html,同时图形也将输出到该目录。

    注意

    我必须向脚本添加参数,我们要将它们合并到官方 yape 仓库中(pull request

    0
    0 174
    公告 Nicky Zhu · 一月 8, 2021

    现在,InterSystems 系统警报和监视(简称 InterSystems SAM)第 1 版 (v1.0) 发布了预览版本。
      
    InterSystems SAM v1.0 为基于 InterSystems IRIS 的产品提供现代化的监视解决方案。 其可对集群进行高级别查看,并且能够以单节点方式可视化深入探视指标,同时提供警报通知。 该第 1 个版本提供对一百多个 InterSystems IRIS 内核指标的可视化,并且用户可以根据自己的喜好扩展默认提供的 Grafana 模板。

    V1.0 旨在成为简单直观的基准。 请进行尝试并向我们发送反馈,帮助我们使其变得更棒!

    从版本 2019.4 开始,SAM 可以显示来自基于 InterSystems 的实例中的信息

    SAM 仅以容器格式提供。 您将需要 SAM 管理器容器,以及一小组额外的开源_组件_(Prometheus 和 Grafana),它们由组合文件自动添加。

    可从以下位置获取 SAM 组件和 SAM 管理器社区版

    如果您正在旅行,或偏爱通过语音收听有关什么是 SAM 方面的提问与回答,我们为您准备了以下播客:

    <iframe class="castos-iframe-player" frameborder="0" height="160" scrolling="no" src="https://5e18edf067eb59-03854285.castos.com/player/198587" width="100%"></iframe>

    可在此处找到 SAM 文档

    0
    0 181
    文章 Qiao Peng · 一月 8, 2021 9m read

    众所周知,InterSystems IRIS 提供了很多的工具来提升应用系统可伸缩性。尤其在提升数据并行处理能力方面,InterSystems 做了很多努力,例如在 SQL 查询中使用并行处理,以及在 IRIS中引入最具吸引力的特征:分片(sharding)。然而,许多成熟的开发成果最初是在 Caché中完成的,而且已经迁移到 IRIS 中。这些成熟的开发成果大都使用 DBMS(数据库管理系统)的多模型功能,实现在单独的数据库中共存不同的数据模型。例如, HIS qMS 数据库同时包含语义关系(电子病历)、传统关系(与 PACS 的交互)和层次数据模型(实验室数据以及与其他系统的集成)。这些数据模型大多是通过 SP.ARM 的 qWORD 工具(一种直接访问 Global的小型数据库管理系统)实现的。遗憾的是,由于查询未使用 IRIS SQL,无法利用并行查询处理的新功能进行扩展。

    而且,随着数据库规模的不断增长,大型关系型数据库所固有的大多数问题开始出现在非关系型数据库中。这就是我们关注可用于扩展的并行数据处理技术的一个主要原因。

    在本文中,我将围绕多年来在解决任务时用到的并行数据处理展开多方位讨论,而这些是我在大数据问题探讨中很少提到的。我将重点讨论数据库的技术改造,或者更确切地说,是数据库转换技术。

    众所周知,在系统开发的早期阶段(通常远远早于项目完成的时间)就已经选择好了数据模型、存储架构以及软件和硬件平台。但是在系统完成部署几年后,通常会因为这样或那样的原因需要对数据进行迁移。下面是一些常见的任务(所有示例均为真实案例):

    1. 一家公司正计划走向国际市场,必须将其 8 位编码的数据库转换为 Unicode 格式。
    2. 将过时的服务器替换为新的服务器时,但是由于许可限制,无法在服务器之间进行日志的无缝传输(使用 IRIS 的系统功能 Mirroring 或 Shadowing),或者当在您尝试处理任务时,缺少满足如 1 提出的这种需求。
    3. 你需要更改数据库之间的 Global 分配,例如将一个包含图像的较大的 Global 迁移到单独的数据库。

    你可能会问,这些方案有那么难吗?只需要停止旧系统,导出数据,然后导入到新系统中就可以了。但是,如果你正在处理的是几百 GB(甚至几 TB)的数据库,而且系统在 7x24 运行,那么就无法使用标准的 IRIS 工具解决上述这些任务了。

    实现任务并行处理的基本方法

    "垂直" 并行

    假设可以将一个任务分解成几个组件。幸运的话,你会发现可以将其中一些并行解决。例如:

    • 准备报告数据(计算、数据聚合…)
    • 应用样式规则
    • 打印报告

    可以让多个报告同时执行所有操作:一个报告正处在准备阶段,同时另一个报告已经开始打印,等等。这种方法并不新鲜。早在 60 年前批量数据处理技术出现时,它就开始发挥作用了。虽然这不是一个新的概念,但是非常有用。然而,只有当所有子任务的执行时间具有可比性时,才会实现显著的加速效果,实际情况却并非总是如此。

    "水平" 并行

    当任务的操作顺序可以按任意顺序执行并迭代时,它们可以同时执行。例如:

    • 全局范围内的上下文搜索:
      • 把 Global 分解成多个部分($order 作为首个索引).
      • 分别对其进行搜索.
      • 合成搜索结果.
    • 通过套接字或 ECP 将 Global 传输到另一台服务器:
      • 把 Global 分解成几个部分.
      • 分别进行传输.

    这些任务具有以下共同特点:

    • 相同的子任务处理过程(包括共享相同的参数),
    • 最终结果的正确性不受子任务的执行顺序影响,
    • 生成结果报告的过程中不需要任何资源密集型操作,因此仅在此过程中子任务和“父”任务之间存在弱连接。

    这些简单的示例表明,水平并行在数据转换任务中是常用到的,事实也的确如此。在接下来的内容中,我们将重点关注此类并行处理。

    "水平" 并行

    方法之一:MapReduce

    MapReduce 是由谷歌引入的一种分布式计算模型。它在处理大量信息的同时也会执行此类操作。目前流行的开源项目构建在 Apache Hadoop和[Mahout](https://ru.bmstu.wiki/index.php?title=Map&amp;action=edit&amp;redlink=1.bmstu.wiki/index.php?title=Map&action=edit&redlink=1)(在处理程序之间分配任务)、实际处理和归约(合并处理结果)。

    对此感兴趣的读者如果想了解更多信息,我推荐 Timur Safin 的系列文章,他在《Caché MapReduce——大数据和 MapReduce 概念简介》(第一部分)中介绍了在 IRIS/Caché中创建MapReduce 工具的方法。

    请注意,因为 IRIS 具有将数据快速写入数据库的"先天能力",所以归约这一步通常是微不足道的,类似 WordCount 分布式版本中的情况。在处理数据库转换任务时,可能完全没有必要进行这一步。例如,使用并行处理程序将一个大型的 Global 移动到单独的数据库,则不需要任何其他操作。

    需要多少台服务器?

    并行计算模型的创建者(例如 MapReduce)通常将其扩展到多个服务器,即所谓的数据处理节点,但是在数据库转换任务中,通常一个这样的节点就足够了。事实上,连接多个处理节点(例如,通过企业缓存协议(ECP))是没有意义的,因为数据转换所需的 CPU 负载相对较小——这里不用考虑处理过程中的数据量。在这种情况下,初始数据仅使用一次,也就意味着无法通过分布式缓存带来任何性能提升。

    经验表明,比较方便的做法是使用两个角色不对称的服务器。下面稍微进行一下简化:

    • 将源数据库安装在一台服务器(源数据库)上。
    • 将转换后的数据库安装在第二台服务器(目标数据库)上。
    • 只在其中一台服务器上配置水平并行数据处理;此服务器上的操作进程作为主进程执行。
    • 相应的,在第二台服务器上运行的进程作为从属进程;在使用 ECP 时,这些是 DBMS 系统进程(ECPSrvR、ECPSrvW 和 ECPWork),而当使用面向套接字的数据传输机制时,这些是TCP 连接的子进程。

    可以说,这种分配任务的方法结合了水平并行(用于在主服务器内分配负载)和垂直并行(用于在主服务器和从属服务器之间分配“职责”)。

    任务和工具

    让我们思考一下最普通的数据库转换任务:将全部或部分数据从源数据库传输到目标数据库,同时可能对 Global 执行某种重新编码(可以是编码更改、排序规则的更改等等)。在这种情况下,新旧数据库是保存在本地的不同数据库服务器上的。下面列出的是架构师和开发人员需要解决的子任务:

    1. 给服务器分配角色。
    2. 选择数据传输机制。
    3. 选择 Global 转移策略。
    4. 选择在多个进程之间分配任务的工具。

    接下来我们逐个进行分析。

    给服务器分配角色

    众所周知,即使 IRIS 以 Unicode 方式安装,它也可以挂载 8 位数据库(本地和远程)。但反之则不行:8 位版本的 IRIS 无法支持 Unicode 数据库,否则会出现<WIDE CHAR>错误。在决定将哪个服务器(源服务器或目标服务器)作为主服务器时,必须考虑到数据转换过程中字符编码是否发生了更改。然而,想要决定最终的解决方案,还需要考虑下一个任务,那就是:

    选择数据传输机制

    你有以下几个选项:

    1. 如果两台服务器上的许可证和 DBMS 版本均支持 ECP,则应选择 ECP 作为传输机制。
    2. 如果不支持,最简单的解决方案就是在目标服务器上本地处理两个数据库(源数据库和目标数据库)。这时必须利用任何可用的文件传输工具将源数据库文件复制到适当的服务器。当然,这个过程将占用额外的时间(通过网络复制数据库文件)和空间(存储数据库文件的副本)。
    3. 为了(至少)避免把时间浪费在复制文件上,你可以通过 TCP 套接字机制实现服务器进程之间的数据交换。这种方法支持以下情况:
      • 由于某些原因无法使用 ECP,例如,为源数据库和目标数据库提供服务的 DBMS 版本不兼容(比如源 DBMS 安装的是非常旧的版本),
      • 或者:用户无法停止在源系统上工作,则源数据库在传输过程中发生的数据修改必须反映在目标数据库中。

    在选择方法时,我的优先级非常明确:如果 ECP 可用,并且在传输期间源数据库保持静态,则选择方法 1;如果 ECP 不可用,但数据库保持静态,则选择方法 2;如果修改了源数据库,则选择方法 3。结合这些情况及主服务器的选择条件,我们可以生成如下可能性矩阵:

    传输期间源数据库是静态的吗?ECP 协议是否可用?源数据库的位置主系统
    目标系统远程目标
    目标系统本地(副本)目标
    不重要,因为我们将使用TCP 套接字机制传输数据.源系统本地(原始)

    选择 Global 转移策略

    乍一看,似乎可以简单地通过读取全局目录逐个传递 Global。但是,同一个数据库中的Global 的大小可能相差很大:我最近遇到的一个生产数据库中的 Global 的大小范围在 1MB -600GB 之间。假设我们有多工作进程(nWorkers)可供使用,并且至少有一个 Global(Globals)^Big 符合下面条件:

    ^Big 的大小 >(所有^ Globals 的大小)/ nWorkers

    然后,无论分布式 Global 转移过程中的其他任务完成的多么顺利,最终分配给^Big 的处理任务将一直保持忙碌,并且可能在其他进程完成之后很久才能完成其任务。如果想要改善这种情况,你可以预先按照大小对 Global 进行排序,并从最大的 Global 开始处理。但是如果^Big的大小明显偏离所有 Global 的平均值(这是 MIS qMS 数据库的典型情况):

    ^Big 的大小 >>(所有^ Globals 的大小)/ nWorkers

    这个策略不会提供太大的帮助,因为它必定会产生好几个小时的延迟。因此,需要将大型Global 拆分成多个部分,通过多个并行进程对其进行处理。我想强调的是,这个任务(列表中的第 3 项任务)是本文讨论的最难的任务,而且花费了我(而不是 CPU!)很多时间。

    选择在多个进程之间分配任务的工具

    与并行处理机制进行交互的方式如下:

    • 创建一个后台工作进程池。
    • 为这个后台工作进程池创建一个队列。
    • 发起程序(我们称其为本地管理器)将工作单元放入队列(这是在步骤 3 中预先准备好的计划)。工作单元通常包括某类方法的名称和实际参数。
    • 工作进程从队列中检索工作单元并执行处理,这里可以理解成调用了一个类方法,将实际参数传递给工作单元。
    • 本地管理器在接收到队列中工作单元已处理完毕的确认信息后,将释放并按需结束这些工作进程。

    幸运的是,IRIS 提供了一个非常适合该方案的、出色的并行处理引擎(可以通过%SYSTEM.WorkMgr 类实现)。我们将在运行的实例中应用改引擎,并在计划发表的系列文章中进行深入探讨。

    在下一篇文章中,我将更加详细地阐述任务 3 的解决方案。

    在第三篇文章中(如果大家对我的文章感兴趣的话),我将讨论任务 4 中的细微差别,包括%SYSTEM.WorkMgr 的局限性及其解决方案。

    0
    0 422
    文章 Nicky Zhu · 一月 8, 2021 5m read

    在本文中,我们将讨论孤立消息。

    什么是孤立消息

    每个消息正文都与一个保存元数据的消息标头相关联。 标头保存源配置名称、目标配置名称、创建时间、处理时间、关联的消息正文引用、会话信息、消息正文类名、消息状态等信息。 当有消息正文记录没有相应的标头记录时,这些消息正文称为孤立消息正文。 我们将讨论可能导致孤立消息正文产生的原因。

    仅清除标头

    在清除任务设置中,BodiesToo 设置用于指定是否将消息正文与消息标头一起清除。 如果关闭此设置,清除任务将只删除消息标头,而保留消息正文。 这些消息正文将成为孤立记录,因为所引用的标头已被删除。 如果清除消息标头但保留消息正文,则管理门户将无法清除孤立消息正文。 在这种情况下,必须以编程方式清除消息正文。

     

    请参阅有关清除任务的文档

    http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=EGMG_purge#EGMG_purge_basic

    复杂的消息正文类(对象值属性)

    当 Ensemble 清除某条消息正文时,不一定删除该消息正文的对象值属性。 具体来说,只有当其他对象是序列对象或子对象(由关系定义)时,才会删除这些对象。 对于其他对象,必须通过在消息正文类中定义删除触发器或实现 %OnDelete() 方法来适当地处理删除。

    OnDelete 实现的示例代码

    Class Sample.Address Extends %Persistent{
    /// The street address.
    Property Street As %String(MAXLEN = 80);
    /// The city name.
    Property City As %String(MAXLEN = 80);
    /// The 2-letter state abbreviation.
    Property State As %String(MAXLEN = 2);
    /// The 5-digit U.S. Zone Improvement Plan (ZIP) code.
    Property Zip As %String(MAXLEN = 5);
    }
    Class Sample.Person Extends %Persistent{
    /// Person's name.
    Property Name As %String [ Required ];
    /// Person's Social Security number. This is validated using pattern match.
    Property SSN As %String(PATTERN = "3N1""-""2N1""-""4N") [ Required ];
    /// Person's Date of Birth.
    Property DOB As %Date;
    /// Person's home address.
    Property Home As Address;
    /// Person's office address.
    Property Office As Address;
    ///Callback for object deletion
    ClassMethod %OnDelete(oid As %ObjectIdentity) As %Status [ Private ]{
          // Delete the property object references.
          Set tSC = $$$OK, tThis = ##class(Sample.Person).%Open(oid)
          If $ISOBJECT(tThis.Home) Set tSC = ##class(Sample.Address).%DeleteId(tThis.Home.%Id())
          If $ISOBJECT(tThis.Office) Set tSC = ##class(Sample.Address).%DeleteId(tThis.Office.%Id())
          Quit tSC
    }
    ///Callback/Trigger for SQL delete
    Trigger OnDelete [ Event = DELETE ]{
          // Delete the property object references. {%%ID} holds the id of the record being deleted.
          Set tID={%%ID}
          Set tThis = ##class(Sample.Person).%OpenId(tID)
          If $ISOBJECT(tThis.Home) Do ##class(Sample.Address).%DeleteId(tThis.Home.%Id())
          If $ISOBJECT(tThis.Office) Do ##class(Sample.Address).%DeleteId(tThis.Office.%Id())
          Quit
    }
    }
    

    已创建但从未发送到其他主机的消息对象

    当一条消息被发送/转发到其他主机时,Ensemble 会创建一个新的消息标头,并关联相应的消息正文。 如果在业务服务/流程中创建的消息正文/对象实例已保存到磁盘/数据库,但从未在生产过程中发送到其他主机,它将没有关联的标头,并保留为孤立消息正文。 最佳实践是不创建消息正文,除非它将被转发,或者不对该对象实例调用 %Save()(在将消息放入目标配置队列之前,SendRequestSync/SendRequestAsync API 将保存该对象实例)。 这样,除非将消息正文对象发送到其他主机,否则它将不会持久化。

    此问题的最常见原因是开发人员:

    1. 克隆了消息正文,且从未转发克隆的消息正文
    2. 在上下文变量 (BPL) 中创建了消息正文对象,且从未转发。

    孤立消息的影响

    孤立消息不会被清除任务清除。 这些消息将占用磁盘空间,并且随着它们数量的增长,磁盘使用量也会成比例增加。 不仅消息正文数据使用磁盘空间,每条孤立消息正文记录的任何索引/搜索表条目也都占用磁盘空间。

    识别孤立消息

    可以通过查询消息标头和正文来确定孤立消息是否存在。 每个消息标头都引用相应的消息正文。 消息正文对象 Id 引用存储在标头的 MessageBodyId 属性中,消息正文类名存储在标头的 MessageBodyClassName 属性中。

    在 HL7 消息表中查找孤立消息的示例查询:

    SELECT HL7.Id  FROM EnsLib_HL7.Message HL7

       LEFT JOIN Ens.MessageHeader hdr

       ON HL7.Id=hdr.MessageBodyId

       WHERE hdr.MessageBodyId IS NULL

    上面的查询将返回所有没有相应标头的 HL7 消息。 可以将该查询修改为查询任何其他消息类型,只需替换消息正文表名即可。

    清除孤立消息

    管理门户无法提供清除孤立消息正文的方法。 在这种情况下,必须以编程方式清除消息正文。 在 ENSDEMO 数据库中,类 Demo.Util.CleanupSet 提供了一个如何执行此操作的示例。 该例程也执行深度清除,同时处理对象属性引用。

    还可以参考另一个例程来清除孤立消息,但该例程不执行深度清除,只对删除消息正文有帮助。 我在下面附上可下载源码的 github 链接:

    https://gist.github.com/suriyasv/2ed7f2dbcfd8c79f3b9938762c17c0b5

    最佳做法是始终:

    1. 避免编程错误(如前面所讨论)以防止出现孤立消息
    2. 只有需要正文并且知道只能以编程方式清除这些消息正文时,才将清除任务设置成关闭 BodiesToo 设置。
    3. 实施关系或针对持久对象属性实现 OnDelete。

    我希望本文对您构建生产环境有所帮助。 如果您有任何问题或疑虑,请联系我们。 谢谢。

    0
    0 239
    文章 Louis Lu · 一月 7, 2021 4m read

    在 Caché 中处理 SOAP 请求时,有时需要通过直接访问(有时是编辑)所发送的 XML(即 SOAP 请求和随后的 SOAP 响应)来调试错误。 如果要调试 Caché Web 服务,使用 SoapUI (https://www.soapui.org/) 之类的工具手动创建和控制 SOAP 请求通常很有用,这样可以很容易地在 Caché Web 服务上看到调整的效果。

    但是如果已经有 Web 服务(可能不是 Caché),并且想要调试相关的 Caché Web 客户端该怎么办? 您可能已将 SOAP 响应 XML 保存在文件中(例如 Caché SOAP 日志),您需要一个“虚拟”Web 服务将其发送到 Caché Web 客户端,就像实际的 Web 服务一样操作。

    由于我经常在技术支持的过程中需要调试客户的 Caché Web 客户端,我创建了这样一个“虚拟”的Web 服务 – 见下文:

    Class JSUtil.DummyWebService Extends %CSP.Page
    {
    
    /// Mimic a SOAP Web Service by sending the specified SOAP Response XML.
    /// Typically this XML will be copied-and-pasted from a SOAP log.
    Parameter CONTENTTYPE = "text/xml";
    
    /// File containing the SOAP Response XML:
    Parameter XMLFILENAME = "C:\data\soapresponse.txt";
    
    ClassMethod OnPage() As %Status
       {
                    set XML=""
                    set stream = ##class(%Stream.FileCharacter).%New()
                    set sc = stream.LinkToFile(..#XMLFILENAME)
    
                    while 'stream.AtEnd {
                     set XML = XML_stream.Read()
                    }
    
        write XML
       quit $$$OK
       }
    
    }
    

    要使用 JSUtil.DummyWebService 类:

  • 1.将参数 XMLFILENAME 的值更改为包含来自 Web 服务的 SOAP 响应的 XML 的位置。 通常,此文件可内容可通过手动剪切和粘贴 Caché SOAP 日志中的响应 XML 消息来创建。
  • 2.使用 Studio 的“View Web Page”获取此 CSP 页面的 URL,它应显示响应的XML消息内容。
  • 3.将上面的 URL 粘贴到 Caché Web 客户端的 LOCATION 参数中。
  • 现在,当调用 Caché Web 客户端时,它将收到参数 XMLFILENAME 指向的 SOAP 请求 XML。

    我已经多次使用这种方法来帮助调试 Caché Web 客户端。 参考以下示例:

    SOAP 日志的“Web 客户端的输入”中包含以下错误:

    ERROR #6203: Unexpected Element

    (完整的 SOAP 日志可在此处找到:https://github.com/ISC-schulman/InterSystems/raw/master/soaplog.txt

    我们还有 Web 服务的 WSDL (https://github.com/ISC-schulman/InterSystems/raw/master/example.wsdl),但无法访问 Web 服务本身。 (虽然这对于 InterSystems 支持来说很常见,但不可否认,对于客户可能并不常见 – 这只是一个简单的示例,说明如何使用 DummyWebService。)

    首先,使用 DummyWebService 重现错误:

  • 1.使用 SOAP 向导从提供的 WSDL 生成 Web 客户端。 所有参数均使用默认值(尽管您可以指定包名称。)
  • 2.查看 SOAP 日志,然后将 Web 服务响应的XML(“Input to Web client”)剪切并粘贴到文件中: OK 
  • 3.通过 JSUtil.DummyWebService 中的参数 XMLFILENAME 指向此文件。
  • 4.使用 Studio 的“Display Web Page”查看 DummyWebService – 它应显示步骤 2 中创建的文件内容。
  • 5.将步骤 4 中的 URL 剪切并粘贴到步骤 1 中生成的 Web 客户端的 LOCATION 参数中。
  • 6.调用 Web 客户端,例如
  •  set client = ##class(MyWebService.RequestWSSoapHttpPort).%New()  do client.createAsynchronuosRequest("x") quit
  • 7. 验证(例如通过 SOAP 日志)是否发生相同错误,即“ERROR #6203: Unexpected Element”。
  •   接下来我们解决这个错误。 这里会经历一些过程或反复试验,但同样只是为了说明如何使用 DummyWebService。

  • 1.像之前一样使用 SOAP 向导和提供的 WSDL 生成 Web 客户端 – 指定不同的包名称以防止覆盖第一个 Web 客户端。 另外,参数全部采用默认值,除了一处: 在 SOAP 向导的步骤 3 中选择“对于文档样式的 Web 方法使用未包装的消息格式(Use unwrapped message format for document style web methods)”
  • 2.重复上面的步骤 5 和 6。
  • 3.验证(例如通过 SOAP 日志)Web 客户端错误是否已修正。
  • (注意:使用“未包装的消息格式(unwrapped message format)”是解决 Web 客户端问题的常见解决方案 – 有关详细信息,请参见我们的文档中的“使用 SOAP 向导”。)

    总结

    可以使用 DummyWebService 类将指定的 SOAP 响应(例如,从 SOAP 日志)发送到 Caché Web 客户端,以模拟 Web 服务的响应。

    0
    0 309
    文章 Louis Lu · 一月 7, 2021 3m read

    本文介绍了 InterSystems 客户围绕 SDDC 和 HCI 解决方案的注意事项。

    采用软件定义数据中心 (SDDC) 和超融合基础架构 (HCI) 解决方案的 InterSystems 客户需要重点关注的事项

    越来越多的 IT 组织正在探究使用SDDC 和 HCI 解决方案的可行性。 这些解决方案看上去很有吸引力,其市场定位为跨异构数据中心和云基础设施可以使得 IT 管理更容易、投入的成本花费更少。 对于 IT 组织来说,潜在的好处是巨大的,许多 InterSystems 客户正在拥抱 SDDC、HCI 或两者兼有。

    如果您正在考虑 SDDC 或 HCI 解决方案,请联系您的销售客户经理或销售工程师,安排与技术架构师的通话。 这对于确保成功非常重要。

    这些解决方案具有高度的可配置性,组织可以从许多软件和硬件的组合中自由选择。 我们看到了我们的客户使用各种 SDDC 和 HCI 解决方案,通过这些经验,我们意识到,仔细考虑解决方案配置以避免风险是非常重要。 在某些情况下,有些客户的实施不符合关键事务型数据库系统所需的性能和弹性需求。 这导致了应用性能不佳和意外停机的出现。 如果客户的目标是为关键事务型数据库系统提供高弹性和低延迟的存储能力,则组件的选择和配置需要针对您的情况进行仔细考虑和规划,包括

    • 选择适当的组件
    • 正确配置这些组件
    • 使用适当的操作步骤

    SDDC 和 HCI 提供了灵活性和易管理性,它们在操作系统和物理存储层之间的管理程序层内或旁路运行。 这会增加不同程度的开销。 如果配置错误,会从根本上影响磁盘延迟,这对于应用的性能而言是灾难性的。

    InterSystems IRIS、Caché 和 Ensemble 的设计注意事项

    以下最低要求和设计注意事项列表基于我们对 SDDC 和 HCI 解决方案的内部测试。 请注意,这不是一个参考架构,意味着您的应用需求将根据您的实际情况和性能目标有所更改。

    网络

    • 每节点拥有两个或更多的 10Gb NIC 接口,专门用于存储流量。
    • 本地两台无阻塞速率 10Gb 交换机,实现交换机的弹性连接。
    • 当然也可以选择 25、40、50 或 100Gb 而不是 10Gb速率,将其作为对 HCI 的前瞻性投资,以满足特定基准和测量应用程序的要求。

    计算

    • 至少一个六节点群集,以便在维护和故障期间提供更高的弹性和可预测的性能。
    • 英特尔可扩展 Gold 或 Platinum 处理器或更高版本,2.2Ghz 或更高主频。
    • 以每个 CPU 插槽 6 个 DDR4-2666 DIMM 为一组的形式安装 RAM(最少 384GB)。

    存储

    • 全闪存存储。 这是唯一推荐的存储选项。 InterSystems 强烈建议不要将混合或分层 HCI 存储用于生产工作负载。
    • 每个物理节点至少两个磁盘组。 每个磁盘组应支持至少三个大容量驱动器。
    • 独占使用写入密集型 12Gbps SAS SSD 或 NVMe SSD。
    • 对于具有缓存和容量层的全闪存解决方案,建议将 NVMe 用于缓存层,将写入密集型 12Gbps SAS 用于容量层。
    • 对 Linux 虚拟机使用 LVM PE 条带化,从而将 IO 分布在多个磁盘组(请联系 InterSystems 获得指南)。
    • 对于 Linux 虚拟机上的所有数据库和写入映像日志 (WIJ) 文件使用异步 IO 及 rtkaio 库。 这样可以绕过文件系统缓存并降低写入延迟(请参见文档或与 WRC 联系以获取有关在 Linux 上正确启用异步 IO 的帮助)。

    这些最低要求建议已证明可以减轻 SDDC 和 HCI 的开销,但并不确保应用性能。 与任何新技术一样,测试您自己的应用的性能和弹性对于任何成功部署都是至关重要的。

    重申一次,如果您正在考虑 SDDC 或 HCI 解决方案,请联系您的销售客户经理或销售工程师,他们会为你安排与技术架构师的通话。这对于确保成功至关重要。

    0
    0 265
    文章 Jeff Liu · 一月 7, 2021 28m read

    Google Cloud Platform (GCP) 为基础架构即服务 (IaaS) 提供功能丰富的环境,其作为云提供完备的功能,支持所有的 InterSystems 产品,包括最新的 InterSystems IRIS 数据平台。 与任何平台或部署模型一样,必须留心以确保考虑到环境的各个方面,例如性能、可用性、操作和管理程序。 本文将详细阐述所有这些方面。

    以下概述和详细内容由谷歌提供,可在此处找到。

    概述

    GCP 资源

    GCP 由一系列物理资产(例如计算机和硬盘驱动器)和虚拟资源(例如虚拟机(VM))组成,它们分布于谷歌遍布全球的数据中心。 每个数据中心的位置都是一个泛区域。 每个区域都是地区的集合,这些地区在该区域内彼此分离。 每个地区都通过一个名称标识,名称由字母标识符和相应区域的名称组成。

    这种资源分配带来众多优势,包括发生故障时提供冗余,以及通过将资源配置在客户端附近来减少延迟。 这种分配也引入一些有关如何统筹资源的规则。

    访问 GCP 资源

    在云计算中,物理硬件和软件变成了服务。 这些服务提供对基础资源的访问。 在 GCP 上开发基于 InterSytems IRIS 的应用程序时,您可混合和匹配这些服务,组合它们来提供您所需的基础架构,然后添加您的代码来实现您要构建的方案。 有关可用服务的详细信息, 可在此处找到。

    项目

    您分配和使用的任何 GCP 资源必须属于一个项目。 项目由设置、权限和其他描述应用程序的元数据组成。 根据区域和地区规则,单个项目中的资源能够轻松协作,例如通过内部网络进行通信。 每个项目包含的资源在项目边界上保持独立;您只能通过外部网络连接来互连它们。

    服务交互

    GCP 提供 3 种与服务和资源交互的基本方法。

    控制台

    Google Cloud Platform 控制台提供基于 web 的图形用户界面,供您管理 GCP 项目和资源。 使用 GCP 控制台,您可创建新项目,或选择现有项目,可使用您在项目环境中创建的资源。 您可以创建多个项目,因此您可以使用项目以任何对您有意义的方式分开您的工作。 例如,如果您想确保只有某些团队成员可以访问项目中的资源,而所有团队成员可以继续访问另一个项目中的资源,则可以开始一个新项目。

    命令行界面

    如果您喜欢在终端窗口中工作,Google Cloud SDK 提供 gcloud 命令行工具,让您可以访问所需的命令。 gcloud 工具可用于管理您的开发工作流程和 GCP 资源。 有关 gcloud 的详细内容可在此处找到。

    GCP 也提供 Cloud Shell,一种基于浏览器的 GCP 交互 shell 环境。 可从 GCP 控制台访问 Cloud Shell。 Cloud Shell 提供:

  • 临时计算引擎虚拟机实例。
  • 从 web 浏览器通过命令行访问实例。
  • 内置代码编辑器。
  • 5 GB 持久性磁盘存储。
  • 预安装 Google Cloud SDK 和其他工具。
  • 支持 Java、Go、Python、Node.js、PHP、Ruby 和 .NET 语言。
  • Web 预览功能。
  • 访问 GCP 控制台项目和资源的内置授权。
  • 客户端库

    Cloud SDK 拥有客户端库,让您轻松创建和管理资源。 GCP 客户端库公开 API 有两个主要目的:

    • 应用 API 提供对服务的访问。 应用 API 针对支持的语言(例如 Node.js 和 Python )进行了优化。 客户端库围绕服务隐喻而设计,因此您可以更自然地使用服务,并编写更少的样板代码。 客户端库还提供身份验证和授权助手。 有关详细信息可在此处找到。
    • 管理 API 提供资源管理功能。 例如,如果您想构建自己的自动化工具,可以使用管理 API。

    您还可以使用 Google API 客户端库来访问产品的 API,如 Google Map、Google Drive 和 YouTube。 有关 GCP 客户端库的详细信息可在此处找到。

    InterSystems IRIS 示例体系结构

    本文部分内容阐述了面向 GCP 的 InterSystems IRIS 部署示例,旨在为特定应用程序的部署抛砖引玉。 这些示例可用作很多部署方案的指南。 此参考体系结构拥有非常强大的部署选项,从最小规模的部署,到满足计算和数据需求的大规模可扩展工作负载,不一而足。

    本文还介绍了高可用性和灾难恢复选项以及其他建议的系统操作。 个体可对这些进行相应的修改以支持其组织的标准实践和安全策略。

    针对您的特定应用,就基于 GCP 的 InterSystems IRIS 部署,您可联系 InterSystems 进一步探讨。


    示例参考体系结构

    以下示例体系结构按照容量和功能逐步升级的顺序讲述了几种不同的配置, 分别为小型开发/生产/大型生产/分片集群生产。先从中小型配置讲起,然后讲述具有跨地区高可用性以及多区域灾难恢复的大规模可扩展性解决方案。 此外,还讲述了一个将 InterSystems IRIS 数据平台的新分片功能用于大规模处理并行 SQL 查询的混合工作负载的示例。

     

    小型开发配置

    在本示例中,显示了一个能支持 10 名开发人员和 100GB 数据的小型开发环境,这基本是最小规模的配置。 只要适当地更改虚拟机实例类型并增加持久性磁盘存储,即可轻松支持更多的开发人员和数据。

    这足以支持开发工作,并让您熟悉 InterSystems IRIS 功能以及 Docker 容器的构建和编排(如果需要的话)。 小型配置通常不采用具有高度可用性的数据库镜像,但是如果需要高可用性,则可随时添加。

    小型配置示例图

    示例图 2.1.1-a 显示了图表 2.1.1-b 中的资源。 其中包含的网关只是示例,可做相应地调整以适应您组织的标准网络实践。

    下列 GCP VPC 项目资源是针对最小规模的配置提供的。 可根据需求添加或删除 GCP 资源。

    小型配置 GCP 资源

    下表提供了小型配置 GCP 资源的示例。

    需要考虑适当的网络安全和防火墙规则,以防止对 VPC 的不必要访问。 谷歌提供网络安全最佳做法供您入门使用,可在此处找到。

    注意:VM 实例需要公共 IP 地址才能访问 GCP 服务。 谷歌建议使用防火墙规则来限制这些 VM 实例的传入,尽管这种做法可能会引起一些问题。

    如果您的安全策略确实需要内部 VM 实例,则您需要在网络上手动设置 NAT 代理和相应的路由,以便内部实例可以访问互联网。 务必要明确,您无法使用 SSH 直接完全连接到内部 VM 实例。 要连接到此类内部机器,必须设置具有外部 IP 地址的堡垒实例,然后建立隧道通过它。 可以配置堡垒主机,以提供进入 VPC 的外部入口点。

    有关堡垒主机的详细信息,可在此处找到。

    产品配置

    在本示例中,展示了一个规模较大的产品配置,其采用 InterSystems IRIS 数据库镜像功能来支持高可用性和灾难恢复。

    此配置包括 InterSystems IRIS 数据库服务器同步镜像对,该镜像服务器在区域 1 内分为两个地区,用于自动故障转移,在区域 2 内的第三个 DR 异步镜像成员用于灾难恢复,以防万一整个 GCP 区域脱机 。

    InterSystems Arbiter 和 ICM 服务器部署在单独的第三个地区,以提高弹性。  此示例体系结构还包括一组可选的负载均衡 web 服务器,用于支持启用 Web 的应用程序。 这些使用 InterSystems 网关的 web 服务器可以根据需要进行缩放。

    产品配置示例图

    示例图 2.2.1-a 显示了图表 2.2.1-b 中的资源。 其中包含的网关只是示例,可做相应地调整以适应您组织的标准网络实践。

    建议将以下 GPC VPC 项目中的资源作为分片集群部署的最低配置。 可根据需求添加或删除 GCP 资源。

    产品配置 GCP 资源

    下表提供了产品配置 GCP 资源的示例。

    大型产品配置

    在本示例中,提供了一个大规模可缩放性配置。该配置通过扩展 InterSystems IRIS 功能也引入使用 InterSystems 企业缓存协议 (ECP:EnterpriseCacheProtocol) 的应用程序服务器,实现对用户的大规模横向缩放。 本示例甚至包含了更高级别的可用性,因为即使在数据库实例发生故障转移的情况下,ECP 客户端也会保留会话细节。 多个 GCP 地区与基于 ECP 的应用程序服务器和部署在多个区域中的数据库镜像成员一起使用。 此配置能够支持每秒数千万次的数据库访问和数万亿字节数据。

    大型产品配置示例图

    示例图 2.3.1-a 显示了图表 2.3.1-b 中的资源。  其中包含的网关只是示例,可做相应地调整以适应您组织的标准网络实践。

    此配置中包括一个故障转移镜像对,四个或更多的 ECP 客户端(应用程序服务器),以及每个应用程序服务器对应一个或多个 Web 服务器。 故障转移数据库镜像对在同一区域中的两个不同 GCP 地区之间进行划分,以提供故障域保护,而 InterSystems Arbiter 和 ICM 服务器则部署在单独的第三地区中,以提高弹性。

    灾难恢复扩展至第二个 GCP 区域和地区,与上一示例中的情况类似。 如果需要,可以将多个 DR 区域与多个 DR 异步镜像成员目标一起使用。

    建议将以下 GPC VPC 项目中的资源作为大型生产部署的最低配置。 可根据需求添加或删除 GCP 资源。

    大型产品配置 GCP 资源

    下表提供了大型产品配置 GCP 资源的示例。

    采用 InterSystems IRIS 分片集群的生产配置

    在此示例中,提供了一个针对 SQL 混合工作负载的横向缩放性配置,其包含 InterSystems IRIS 的新分片集群功能,可实现 SQL 查询和表跨多个系统的大规模横向缩放。 本文后面将详细讨论 InterSystems IRIS 分片集群及其功能。

    采用 InterSystems IRIS 分片集群的生产配置

    示例图 2.4.1-a 显示了图表 2.4.1-b 中的资源。  其中包含的网关只是示例,可做相应地调整以适应您组织的标准网络实践。

    此配置中包括四个镜像对,它们为数据节点。 每个故障转移数据库镜像对在同一区域中的两个不同 GCP 地区之间进行划分,以提供故障域保护,而 InterSystems Arbiter 和 ICM 服务器则部署在单独的第三地区中,以提高弹性。

    此配置允许从集群中的任何数据节点使用所有的数据库访问方法。 大型 SQL 表数据在物理上跨所有数据节点进行分区,以实现查询处理和数据卷的大规模并行。 将所有这些功能组合在一起,就可以支持复杂的混合工作负载,比如大规模分析 SQL 查询及引入的新数据,所有这一切均在一个 InterSystems IRIS 数据平台中执行。

    注意,上面图表中以及下表“资源类型”列中的术语“计算[Engine]”是一个表示 GCP(虚拟)服务器实例的 GCP 术语,将在本文的 3.1节中做进一步介绍。 它并不表示或暗示本文后面所描述的集群体系结构中对“计算节点”的使用。

    建议将以下 GPC VPC 项目中的资源作为分片集群部署的最低配置。 可根据需求添加或删除 GCP 资源。

    使用分片集群配置 GCP 资源的产品

    下表提供了分片集群配置 GCP 资源的示例。


    云概念简介

    Google Cloud Platform (GCP) 为基础架构即服务 (IaaS) 提供功能丰富的云环境,使其具备完备的功能,支持所有的 InterSystems 产品,包括支持基于容器的 DevOps 及最新的 InterSystems IRIS 数据平台。 与任何平台或部署模型一样,必须留心以确保考虑到环境的各个方面,例如性能、可用性、系统操作、高可用性、灾难恢复、安全控制和其他管理程序。 本文档将介绍所有云部署涉及的三个主要组件:计算、存储和网络。

    计算引擎(虚拟机)

    GCP 中存在数个针对计算引擎资源的选项,以及众多虚拟 CPU 和内存规范及相关存储选项。 在 GCP 中值得注意的一点是,对给定机器类型中 vCPU 数量的引用等于一个 vCPU,其是虚拟机监控程序层上物理主机中的一个超线程。

    就本文档的目的而言,将使用 n1-standard * 和 n1-highmem * 实例类型,这些实例类型在大多数 GCP 部署区域中广泛可用。 但是,对于将大量数据缓存在内存中的大型工作数据集而言,使用 n1-ultramem * 实例类型是不错的选择。 除非另有说明,否则使用默认实例设置(例如实例可用性策略)或其他高级功能。 有关各种机器类型的详细信息,可在此处找到。

    磁盘存储

    与 InterSystems 产品最直接相关的存储类型是持久性磁盘类型,但是,只要了解并适应数据可用性限制,本地存储可以用于高水平的性能。 还有其他一些选项,例如云存储(存储桶),但是这些选项更特定于单个应用程序的需求,而非支持 InterSystems IRIS 数据平台的操作。

    与大多数其他云提供商一样,GCP 对可与单个计算引擎关联的持久性存储施加了限制。 这些限制包括每个磁盘的最大容量、关联到每个计算引擎的持久性磁盘的数量,以及每个持久性磁盘的 IOPS 数量,对单个计算引擎实例 IOPS 设置上限。 此外,对每 GB 磁盘空间设有 IOPS 限制,因此有时需要调配更多磁盘容量才能达到所需的 IOPS 速率。

    这些限制可能会随着时间而改变,可在适当时与谷歌确认。

    磁盘卷有两种类型的持久性存储类型:“标准持久性”磁盘和“SSD 持久性”磁盘。 SSD 持久性磁盘更适合于那些要求低延迟 IOPS 和高吞吐量的生产工作负载。 标准持久性磁盘对于非生产开发和测试或归档类型的工作负载,是一种更经济的选择。

    有关各种磁盘类型及限制的详细信息,可在此处找到。

    VPC 网络

    强烈建议采用虚拟私有云 (VPC) 网络来支持 InterSystems IRIS 数据平台的各个组件,同时提供正确的网络安全控制、各种网关、路由、内部 IP 地址分配、网络接口隔离和访问控制。 本文档中提供了一个详细的 VPC 示例。

    有关 VPC 网络和防火墙的详细信息,可在此处找到。


    虚拟私有云 (VPC) 概述

    GCP VPC 与其他云提供商略有不同,其更加简单和灵活。 可在此处找到各概念的比较。

    在 GCP 项目中,每个项目允许有数个 VPC(目前每个项目最多允许 5 个),且创建 VPC 网络有两个选项——自动模式和自定义模式。

    此处提供每个类型的详细信息。

    在大多数大型云部署中,采用多个 VPC 将各种网关类型与以应用为中心的 VPC 进行隔离,并利用 VPC 对等进行入站和出站通信。 有关适合您的公司使用的子网和任何组织防火墙规则的详细信息,强烈建议您咨询您的网络管理员。 本文档不阐述 VPC 对等方面的内容。

    在本文档提供的示例中,使用 3 个子网的单一 VPC 用于提供各种组件的网络隔离,以应对各种 InterSystems IRIS 组件的可预测延迟和带宽以及安全性隔离。

    网络网关和子网定义

    本文档的示例中提供了两种网关,以支持互联网和安全 VPN 连接。 要求每个入口访问都具有适当的防火墙和路由规则,从而为应用程序提供足够的安全性。 有关如何使用路由的详细信息,可在此处找到。

    提供的示例体系结构中使用了 3 个子网,它们专与 InterSystems IRIS 数据平台一起使用。 这些单独的网络子网和网络接口的使用为上述 3 个主要组件的每一个提供了安全控制、带宽保护和监视方面的灵活性。 有关各种用例的详细信息,可在此处找到。

    有关创建具有多个网络接口的虚拟机实例的详细信息,可在此处找到。

    这些示例中包含的子网:

  • 用户空间网络用于入站连接用户和查询
  • 分片网络用于分片节点之间的分片间通信
  • 镜像网络通过同步复制和单个数据节点的自动故障转移实现高可用性。
  • 注意:仅在单个 GCP 区域内具有低延迟互连的多个地区之间,才建议进行故障转移同步数据库镜像。 区域之间的延迟通常太高,无法提供积极的用户体验,特别是对于具有高更新率的部署更如此。

    内部负载均衡器

    大多数 IaaS 云提供商缺乏提供虚拟 IP (VIP) 地址的能力,这种地址通常用在自动化数据库故障转移设计中。 为了解决这一问题,InterSystems IRIS 中增强了几种最常用的连接方法,尤其是 ECP 客户端和 Web 网关,从而不再依赖 VIP 功能使它们实现镜像感知和自动化。

    xDBC、直接 TCP/IP 套接字等连接方法,或其他的直接连接协议,均需要使用类 VIP 地址。 为了支持这些入站协议,InterSystems 数据库镜像技术使用称作<span class="Characteritalic" style="font-style:italic">mirror_status.cxw</span>的健康检查状态页面为 GCP 中的这些连接方法提供自动化故障转移,以与负载均衡器进行交互,实现负载均衡器的类 VIP 功能,仅将流量重定向至活动的主镜像成员,从而在 GCP 内实现完整且强大的高可用性设计。

    此处提供了使用负载均衡器实现类 VIP 功能的详细信息。

    示例 VPC 拓扑

    下图 4.3-a 中的 VPC 布局组合了所有组件,具有以下特点:

  • 利用一个区域内的多个地区实现高可用性
  • 提供两个区域进行灾难恢复
  • 利用多个子网进行网络隔离
  • 包括分别用于互联网和 VPN 连接的单独网关
  • 使用云负载均衡器进行镜像成员的 IP 故障转移

  • 持久性存储概述

    如简介中所述,建议使用 GCP 持久性磁盘,尤其 SSD 持久性磁盘类型。 之所以推荐 SSD 持久性磁盘,是由于其拥有更高的读写 IOPS 速率以及低的延迟,适合于事务性和分析性数据库工作负载。 在某些情况下,可使用本地 SSD,但值得注意的是,本地 SSD 的性能提升会在可用性、耐用性和灵活性方面做出一定的权衡。

    可在此处找到本地 SSD 数据持久性方面的详细信息,您可了解何时保存本地 SSD 数据以及何时不保存它们。

    LVM 条带化

    与其他的云提供商一样,GCP 在每个虚拟机实例的 IOPS、空间容量和设备数量方面都施加了众多存储限制。 有关当前的限制,请查阅 GCP 文档,可在此处找到。

    由于这些限制的存在,使用 LVM 条带化实现数据库实例的单个磁盘设备的 IOPS 最大化变得非常必要。 在提供的此示例虚拟机实例中,建议使用以下磁盘布局。 与 SSD 持久性磁盘相关的性能限制可在此处找到。

    注意:目前,每个虚拟机实例最多有 16 个持久性磁盘,但 GCP 近期的方案则增至 128 个(测试),这将是令人欣慰的提高。

    LVM 条带化的优势在于可以将随机的 IO 工作负载分散到更多的磁盘设备并继承磁盘队列。 以下是如何在 Linux 中将 LVM 条带化用于数据库卷组的示例。 本示例在一个 LVM PE 条带中使用 4 个磁盘,物理盘区 (PE) 大小为 4MB。 或者,如果需要,可以使用更大的 PE 容量。

    • 步骤 1:根据需要创建标准性磁盘或 SSD 持久性磁盘
    • 步骤 2:使用“lsblk -do NAME,SCHED”将每个磁盘设备的 IO 调度器设置为 NOOP
    • 步骤 3:使用“lsblk -do KNAME,TYPE,SIZE,MODEL”识别磁盘设备
    • 步骤4:使用新的磁盘设备创建磁盘卷组
      • vgcreate s 4M  
      • 示例vgcreate -s 4M vg_iris_db /dev/sd[h-k]
    • 步骤 4:创建逻辑卷
      • lvcreate n -L -i -I 4MB
      • 示例lvcreate -n lv_irisdb01 -L 1000G -i 4 -I 4M vg_iris_db
    • 步骤 5:创建文件系统
      • mkfs.xfs K
      • 示例mkfs.xfs -K /dev/vg_iris_db/lv_irisdb01
    • 步骤 6:装载文件系统
      • 使用以下装载条目编辑 /etc/fstab
        • /dev/mapper/vg_iris_db-lv_irisdb01    /vol-iris/db    xfs  defaults 0 0
        • 装载 /vol-iris/db

    使用上表,每个 InterSystems IRIS 服务器将具有以下配置:2 个 SYS 磁盘、4 个 DB 磁盘、2 个主日志磁盘、2 个备用日志磁盘。

    为了增长,LVM 允许在需要的情况下不中断地扩展设备和逻辑卷。 有关持续管理和扩展 LVM 卷的最佳做法,请查阅 Linux 文档。

    注意 0>:强烈建议同时为数据库和写入映像日志文件启用异步 IO。 有关在 Linux 上启用的详细信息,请参阅下列社区文章:https://community.intersystems.com/post/lvm-pe-striping-maximize-hyper-converged-storage-throughput

    配置

    InterSystems IRIS 新增了 InterSystems Cloud Manager (ICM)。 ICM 执行众多任务,并提供许多用于配置 InterSystems IRIS 数据平台的选项。 ICM 作为 Docker 映像提供,其拥有配置强大的、基于 GCP 云的解决方案所需的一切。

    ICM 当前支持以下平台上的配置:

    • Google Cloud Platform (GCP)
    • Amazon Web Services,包括 GovCloud (AWS / GovCloud)
    • Microsoft Azure Resource Manager,包括 Government (ARM / MAG)
    • VMware vSphere (ESXi)

    ICM 和 Docker 可以从台式机/笔记本电脑工作站运行,也可以具有中央专用的适度“配置”服务器和中央存储库。  

    ICM 在应用程序生命周期中的作用是“定义->配置->部署->管理”

    有关安装和使用 ICM 及 Docker 的详细信息,可在此处找到。

    注意:任何云部署都非必须使用 ICM。 完全支持传统的 tar-ball 分布式安装和部署方法。 但是,建议使用 ICM,以简化云部署中的配置和管理。

    容器监视

    ICM 包含基本的监视工具,其使用 Weave Scope 进行基于容器的部署。 默认情况下不会部署该工具,需要在默认的文件中使用监视器字段指定它。

    有关使用 ICM 进行监视、编排和调度的详细信息,可在此处找到。

    有关 Weave Scope 的概述和该文档,可在此处找到。


    高可用性

    InterSystems 数据库镜像可在任何云环境中提供最高级别的可用性。  有一些选项可以直接在实例级别提供虚拟机弹性。 有关 GCP 中可用的各种政策的详细信息,可在此处找到。

    上文中已讨论了云负载均衡器如何通过数据库镜像为虚拟 IP(类 VIP)功能提供自动化 IP 地址故障转移。  云负载均衡器使用<span class="Characteritalic" style="font-style:italic">mirror_status.cxw</span>健康检查状态页面,上文内部负载均衡器部分提到过该页面。  数据库镜像有两种模式——自动故障转移同步镜像、异步镜像。 在本示例中,将介绍同步故障转移镜像。 有关镜像的详细信息,可在此处找到。

    最基本的镜像配置是仲裁器控制配置中的一对故障转移镜像成员。 仲裁器放置在同一区域内的第三个地区中,以防止潜在的地区中断影响仲裁器和其中一个镜像成员。

    在网络配置中,有多种方法专供设置镜像。 在本示例中,我们将使用本文档前述网络网关和子网定义部分中定义的网络子网。 下一部分内容将提供 IP 地址方案示例,并且基于本部分内容,将仅描述网络接口和指定的子网。


    灾难恢复

    InterSystems 数据库镜像将支持灾难恢复的高可用性功能扩展到另一个 GCP 地理区域,以在整个 GCP 区域万一脱机的情况下支持操作弹性。 应用程序如何耐受此类中断取决于恢复时间目标 (RTO) 和恢复点目标 (RPO)。 这些将为设计适当的灾难恢复计划进行的分析提供初始框架。 以下链接中的指南提供了您在为自己的应用程序制定灾难恢复计划时要考虑的事项。 https://cloud.google.com/solutions/designing-a-disaster-recovery-planhttps://cloud.google.com/solutions/disaster-recovery-cookbook

    异步数据库镜像

    InterSystems IRIS 数据平台的数据库镜像提供强大的功能,可在 GCP 地区和区域之间异步复制数据,以帮助支持您的灾难恢复计划的 RTO 和 RPO 目标。 有关异步镜像成员的详细信息,可在此处找到。

    与上述高可用性部分中讲述的内容相似,云负载均衡器也使用上文内部负载均衡器部分中提到过的<span class="Characteritalic" style="font-style:italic">mirror_status.cxw</span>健康检查状态页面为虚拟 IP(类 VIP)功能提供自动化 IP 地址故障转移,以进行 DR 异步镜像。

    在本示例中,将介绍 DR 异步故障转移镜像,并介绍 GCP 全局负载均衡服务,以便为上游系统和客户端工作站提供单个任播 IP 地址,不分您的 InterSystems IRIS 部署是否在哪个区域或地区中运行。

    GCP 的其中一个发展就是负载均衡器的诞生,这是一种软件定义的全局资源,并且不受制于特定的区域。 由于其不是基于实例或设备的解决方案,因此它具有跨区域利用单个服务的独特功能。 有关通过单个任播 IP 进行 GCP 全局负载均衡的详细信息,可在此处找到。

    在上述示例中,所有 3 个 InterSystems IRIS 实例的 IP 地址都提供给了 GCP 全局负载均衡器,它会将流量仅定向到承担主要镜像的镜像成员,而不论其位于哪个地区或区域。


    分片集群

    InterSystems IRIS 拥有一系列全面的功能来缩放您的应用程序,您可以根据自己工作负载的性质以及所面临的特定性能挑战来单独或组合应用这些功能。 分片功能是这些功能中的一种,可跨多个服务器对数据及其关联的缓存进行分区,从而为查询和数据引入提供灵活、高性价比的性能扩展,同时通过高效的资源利用最大化基础架构的价值。 InterSystems IRIS 分片群集可以为各种应用提供显著的性能优势,尤其对于工作负载包括以下一项或多项的应用更是如此:

    • 大容量或高速数据引入,或两者的组合。
    • 相对较大的数据集、返回大量数据的查询,或两者。
    • 执行大量数据处理的复杂查询,例如扫描磁盘上大量数据或涉及大量计算工作的查询。

    这些因素分别都会影响分片的潜在优势,但组合起来使用它们可能会增加优势。 例如,这 3 个因素的组合——快速引入大量数据、大型数据集、检索和处理大量数据的复杂查询——使得当今的许多分析性工作负载非常适合进行分片。

    注意,这些特征都与数据有关;InterSystems IRIS 分片的主要功能是缩放数据量。 不过,当涉及某些或所有这些与数据相关的因素的工作负载也经历大量用户的超高查询量时,分片群集也能提供用户量缩放功能。 分片也可以与纵向缩放相结合。

    操作概述

    分片架构的核心是跨多个系统对数据及其关联的缓存进行分区。 分片集群跨多个 InterSystems IRIS 实例以行方式(称为数据节点)对大型数据库表进行物理上的横向分区,同时允许应用通过任何节点透明地访问这些表,但仍将整个数据集看作一个逻辑并集。 该架构具有 3 个优点:

    • 并行处理查询在数据节点上并行运行,然后将结果进行合并和组合后,由节点作为完整查询结果返回给连接的应用。许多情况下,这大大提高了执行速度。
    • 分区缓存:每个数据节点都有自己的缓存,专用于它存储的分片表数据分区,再不是单个实例的缓存服务于整个数据集,这大大降低了缓存溢出的风险,并强制执行性能降低式磁盘读取。
    • 并行加载:数据可以并行加载到数据节点,从而减少了引入工作负载和查询工作负载之间的缓存和磁盘争用,提高了两者的性能。

    有关 InterSystems IRIS 分片集群的详细信息,可在此处找到。

    分片元素和实例类型

    分片集群包含至少一个数据节点,如果特定性能或工作负载有需要,则可添加一定数量的计算节点。 这两种节点类型提供简单的构建块,从而实现简单、透明和高效的调整模型。

    数据节点

    数据节点存储数据。 在物质层面,分片表[1]数据分布在集群中的所有数据节点上,非分片表数据仅物理存储在第一个数据节点上。 这种区分对用户是透明的,唯一可能的例外是,第一个节点的存储消耗可能比其他节点略高,但是由于分片表数据通常会超出非分片表数据至少一个数量级,因此这种差异可以忽略不计。

    需要时,可以跨集群重新均衡分片表数据,这通常发生在添加新的数据节点后。 这将在节点之间移动数据的“存储桶”,以实现数据的近似均匀分布。

    在逻辑层面,未分片的表数据和所有分片的表数据的并集在任何节点上都可见,因此客户端会看到整个数据集,这与其连接哪个节点无关。 元数据和代码也会在所有数据节点之间共享。

    分片集群的基本架构图仅由在集群中看起来统一的数据节点组成。 客户端应用程序可以连接到任何节点,并且可以像在本地一样体验数据。


    [1]为方便起见,术语“分片表数据”在整个文档中用于表示支持分片的任何数据模型的“盘区”数据(标记为已分片)。 术语“未分片表数据”和“未分片数据”用于表示处于可分片盘区但却未这样标记的数据,或表示尚不支持分片的数据模型。

    数据节点

    对于要求低延迟(可能存在不断涌入数据的冲突)的高级方案,可以添加计算节点以提供用于服务查询的透明缓存层。

    计算节点缓存数据。 每个计算节点都与一个数据节点关联,为其缓存相应的分片表数据,此外,它还根据需要缓存非分片表数据,以满足查询的需要。

    由于计算节点物理上并不存储任何数据,其只是支持查询执行,因此可对其硬件配置文件进行调整以满足需求,例如通过强调内存和 CPU 并将存储空间保持在最低限度。 当“裸露”应用程序代码在计算节点上运行时,引入数据会被驱动程序 (xDBC, Spark) 直接或被分片管理器代码间接转发到数据节点。


    分片集群说明

    分片集群部署有多种组合。 下列各图说明了最常见的部署模型。 These diagrams do not include the networking gateways and details and provide to focus only on the sharded cluster components.

    基本分片集群

    下图是在一个区域和一个地区中部署了 4 个数据节点的最简单分片群集。 GCP 云负载均衡器用于将客户端连接分发到任何分片集群节点。

    在此基本模型中,除了 GCP 为单个虚拟机及其连接的 SSD 持久性存储提供的弹性或高可用性外,没有其他弹性或高可用性。 建议使用两个单独的网络接口适配器,一则为入站客户端连接提供网络安全隔离,二则为客户端流量和分片集群通信之间提供带宽隔离。

    具有高可用性的基本分片集群

    下图是在一个区域中部署了 4 个镜像数据节点的最简单分片集群,每个节点的镜像在地区之间进行了划分。 GCP 云负载均衡器用于将客户端连接分发到任何分片集群节点。

    InterSystems 数据库镜像的使用带来了高可用性,其会在该区域内的第二地区中维护一个同步复制的镜像。

    建议使用 3 个单独的网络接口适配器,一方面为入站客户端连接提供网络安全隔离,另一方面为客户端流量、分片集群通信、节点对之间的同步镜像流量之间提供带宽隔离。

    此部署模型也引入了本文前面所述的镜像仲裁器。

    具有单独计算节点的分片集群

    下图采用单独的计算节点和 4 个数据节点扩展了分片集群,以此来应对大量的用户/查询并发。 云负载均衡器服务器池仅包含计算节点的地址。 更新和数据引入将像以前一样继续直接更新到数据节点,以维持超低延迟性能,并避免由于实时数据引入而在查询/分析工作负载之间造成资源的干扰和拥挤。

    使用此模型,可以根据计算/查询和数据引入的规模单独微调资源分配,从而在“适时”需要的地方提供最佳资源,实现经济而简单的解决方案,而非只是进行计算或数据的调整,浪费不必要的资源。

    计算节点非常适合直接使用 GCP 自动缩放分组(亦称自动缩放),允许基于负载的增加或减少自动从托管实例组添加或删除实例。 自动缩放的工作原理为:负载增加时,将更多的实例添加到实例组(扩展);对实例的需求降低时将其删除(缩减)。

    有关 GCP 自动缩放的详细信息,可在此处找到。

    自动缩放可帮助基于云的应用程序轻松应对流量增加的情况,并在资源需求降低时降低成本。 只需简单地定义自动缩放策略,自动缩放器就会根据测得的负载执行自动缩放。


    备份操作

    备份操作有多个选项。 以下 3 个选项可供您通过 InterSystems IRIS 进行 GCP 部署。

    下面的前 2 个选项(下文详细说明)采用快照类型的过程,该过程会在创建快照之前将数据库写入操作挂起到磁盘上,然后在快照成功后恢复更新。

    可采取以下高级别步骤通过任一快照方法来创建洁净的备份:

    • 通过数据库外部冻结 API 调用暂停对数据库的写入。
    • 创建操作系统和数据磁盘的快照。
    • 通过外部解冻 API 调用恢复数据库写入。
    • 将设施存档备份到备份位置

    有关外部冻结/解冻 API 的详细信息,可在此处找到。

    注意:本文档未包含备份示例脚本,但您可定期检查发布到 InterSystems 网站上开发者社区的示例。 请访问 www.community.intersystems.com

    第三个选项是 InterSystems 在线备份。 这是小型部署的入门级方法,具有非常简单的用例和界面。 但是,随着数据库的增大,建议将使用快照技术的外部备份作为最佳做法,因为其具有以下优势:备份外部文件、更快的恢复时间,以及企业范围的数据和管理工具。

    可以定期添加诸如完整性检查之类的其他步骤,以确保洁净且一致的备份。

    决定使用哪种选项取决于您组织的运营要求和策略。 InterSystems 可与您详细讨论各种选项。

    GCP 持久性磁盘快照备份

    可以使用 GCP gcloud 命令行 API 以及 InterSystems 外部冻结/解冻 API 功能实现备份操作。 这允许实现真正的 24x7 全天候操作弹性,并确保洁净常规备份。 有关管理、创建和自动化 GCP 持久性磁盘快照的详细信息,可在此处找到。

    逻辑卷管理器 (LVM) 快照

    或者,可以在 VM 本身中部署单个备份代理,利用文件级备份,并结合逻辑卷管理器 (LVM) 快照,来使用市面上的许多第三方备份工具。

    该模型的主要优点之一是能够对基于 Windows 或 Linux 的 VM 进行文件级恢复。 此解决方案需要注意的几点是,由于 GCP 和大多数其他 IaaS 云提供商都不提供磁带媒体,因此所有的备份存储库对于短期归档均基于磁盘,并能够利用 Blob 或存储桶类型的低成本存储来进行长期保留 (LTR)。 强烈建议您使用此方法来使用支持重复数据删除技术的备份产品,以最有效地利用基于磁盘的备份存储库。

    这些具有云支持的备份产品的示例包括但不限于:Commvault、EMC Networker、HPE Data Protector 和 Veritas Netbackup。

    注意:InterSystems 不会验证或认可一种备份产品是否优于其他产品。 选择备份管理软件的责任由客户个人决定。

    在线备份

    对于小型部署,内置在线备份工具也是可行的选择。 该 InterSystems 数据库在线备份实用工具通过捕获数据库中的所有块来备份数据库文件中的数据,然后将输出写入顺序文件。 这种专有的备份机制旨在使生产系统的用户不停机。 有关在线备份的详细信息,可在此处找到。

    在 GCP 中,在线备份完成后,必须将备份输出文件和系统正在使用的所有其他文件复制到该虚拟机实例之外的其他存储位置。 存储桶/对象存储是对其很好的命名。

    使用 GCP 存储桶有两种选择。

    • 直接使用 gcloud 脚本 API 来复制和操作新创建的在线备份(和其他非数据库)文件。 有关详细信息可在此处找到。
    • 尽管云存储桶属于对象存储,但将存储桶装载为文件系统,并将其用作类似持久性磁盘的功能足以。

    有关装载云存储桶(使用云存储 FUSE )的详细信息,可在此处找到。

    0
    0 1097
    文章 Jeff Liu · 一月 7, 2021 20m read

    假设你想了解 InterSystems 在数据分析方面能提供什么。 你研究了理论,现在想要进行一些实践。 幸运的是,InterSystems 提供了一个项目:Samples BI,其中包含了一些很好的示例。 从 README 文件开始,跳过任何与 Docker 相关的内容,直接进行分步安装。 启动虚拟实例 安装 IRIS,按照说明安装 Samples BI,然后用漂亮的图表和表格让老板眼前一亮。 到目前为止还不错。

    但是不可避免地,你需要进行更改。

    事实证明,自己保留虚拟机存在一些缺点,交给云服务商保管是更好的选择。 Amazon 看起来很可靠,你只需创建一个 AWS 帐户(入门免费),了解到使用 root 用户身份执行日常任务是有害的,然后创建一个常规的具有管理员权限的 IAM 用户

    点击几下鼠标,就可以创建自己的 VPC 网络、子网和虚拟 EC2 实例,还可以添加安全组来为自己开放 IRIS Web端口 (52773) 和 ssh 端口 (22)。 重复 IRIS 和 Samples BI 的安装。 这次使用 Bash 脚本,如果你喜欢,也可以使用 Python。 再一次让老板刮目相看。

    但是无处不在的 DevOps 运动让你开始了解基础架构即代码,并且你想要实现它。 你选择了 Terraform,因为它是众所周知的,而且它的方法非常通用,只需微小调整即可适合各种云提供商。 使用 HCL 语言描述基础架构,并将 IRIS 和 Samples BI 的安装步骤转换到 Ansible。 然后再创建一个 IAM 用户使 Terraform 正常工作。 全部运行一遍。 获得工作奖励。

    渐渐地你会得出结论,在我们这个微服务时代,不使用 Docker 就太可惜了,尤其是 InterSystems 还会告诉你怎么做。 返回到 Samples BI 安装指南并阅读关于 Docker 的几行内容,似乎并不复杂:

    $ docker pull intersystemsdc/iris-community:2019.4.0.383.0-zpm
    $ docker run --name irisce -d --publish 52773:52773 intersystemsdc/iris-community:2019.4.0.383.0-zpm
    $ docker exec -it irisce iris session iris
    USER>zpm
    zpm: USER>install samples-bi

    将浏览器定向到 http://localhost:52773/csp/user/_DeepSee.UserPortal.Home.zen?$NAMESPACE=USER 后,再次去老板那里,因为做得好而获得一天假期。

    然后你开始明白,“docker run”只是开始,至少需要使用 docker-compose。 没问题:

    $ cat docker-compose.yml
    version: "3.7"
    services:
    irisce:
    container_name: irisce
    image: intersystemsdc/iris-community:2019.4.0.383.0-zpm
    ports:
    - 52773:52773
    $ docker rm -f irisce # We don’t need the previous container
    $ docker-compose up -d

    这样你使用 Ansible 安装了 Docker 和 docker-compose,然后运行了容器,如果机器上还没有映像,则会下载一个映像。 最后安装了 Samples BI。

    你一定喜欢 Docker,因为它是各种内核素材的又酷又简单的接口。 你开始在其他地方使用 Docker,并且经常启动多个容器。 还发现容器必须经常互相通信,这就需要了解如何管理多个容器。

    终于,你发现了 Kubernetes

    从 docker-compose 快速切换到 Kubernetes 的一个方法是使用 kompose。 我个人更喜欢简单地从手册中复制 Kubernetes 清单,然后自己编辑,但是 kompose 在完成小任务方面做得很好:

    $ kompose convert -f docker-compose.yml
    INFO Kubernetes file "irisce-service.yaml" created
    INFO Kubernetes file "irisce-deployment.yaml" created

    现在你有了可以发送到某个 Kubernetes 集群的部署和服务文件。 你发现可以安装 minikube,它允许你运行一个单节点 Kubernetes 集群,这正是你现阶段所需要的。 在摆弄一两天 minikube 沙盒之后,你已经准备好在 AWS 云中的某处使用真实的 Kubernetes 部署

    设置

    我们一起来进行吧。 此时,我们做以下几个假设:

    首先,我们假设你有一个 AWS 帐户,你知道其 ID,并且未使用 root 凭据。 你创建了一个具有管理员权限且只能以编程方式访问的 IAM 用户(我们称之为“my-user”),并存储了其凭据。 你还创建了另一个具有相同权限的 IAM 用户,名为“terraform”:

    Terraform 将以它的名义进入你的 AWS 帐户,并创建和删除必要资源。 这两个用户的广泛权限将通过演示来说明。 你在本地保存了这两个 IAM 用户的凭据:

    $ cat ~/.aws/credentials
    [terraform]
    aws_access_key_id = ABCDEFGHIJKLMNOPQRST
    aws_secret_access_key = ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890123
    [my-user]
    aws_access_key_id = TSRQPONMLKJIHGFEDCBA
    aws_secret_access_key = TSRQPONMLKJIHGFEDCBA01234567890123

    注意:不要复制和粘贴上面的凭据。 它们在这里作为示例提供,不再存在。 请编辑 ~/.aws/credentials 文件并引入你自己的记录。

    其次,我们将在文中使用虚拟的 AWS 帐户 ID (01234567890) 和 AWS 区域“eu-west-1”。 可以随意使用其他区域

    第三,我们假设你知道 AWS 不是免费的,你需要为使用的资源付费。

    接下来,您已经安装了 AWS CLI 实用程序,以便与 AWS 进行命令行通信。 你可以尝试使用 aws2,但你需要在 kube 配置文件中特别设置 aws2 的用法,如这里所述。

    你还安装了 kubectl 实用程序来与 AWS Kubernetes 进行命令行通信。

    并且你也针对 docker-compose.yml 安装了 kompose 实用程序,来转换 Kubernetes 清单。

    最后,你创建了一个空的 GitHub 仓库,并将其克隆到主机上。 我们将其根目录引用为 。 在此仓库中,我们将创建并填充三个目录:.github/workflows/、k8s/ 和 terraform/。

    请注意,所有相关代码都在 github-eks-samples-bi 仓库中复制,以简化拷贝和粘贴。

    我们继续。

    AWS EKS 预置

    我们已经在文章使用 Amazon EKS 部署简单的基于 IRIS 的 Web 应用程序中知道了 EKS。 那时,我们以半自动方式创建了一个集群。 即,我们在一个文件中描述集群,然后从本地机器手动启动 eksctl 实用程序,该实用程序根据我们的描述创建集群。

    eksctl 是为创建 EKS 集群而开发的,它非常适合概念验证实现,但对于日常使用来说,最好使用更通用的工具,例如 Terraform。 AWS EKS 简介是一个非常好的资源,其中介绍了创建 EKS 集群所需的 Terraform 配置。 花一两个小时熟悉一下,决不会是浪费时间。

    你可以在本地操作 Terraform。 为此,你需要一个二进制文件(在撰写本文时,我们使用最新的 Linux 版本 0.12.20),并且 IAM 用户“terraform”需要有足够的权限才能让 Terraform 进入 AWS。 创建目录 /terraform/ 以存储 Terraform 代码:

    $ mkdir /terraform
    $ cd /terraform

    你可以创建一个或多个 .tf 文件(它们会在启动时合并)。 只需复制并粘贴 AWS EKS 简介中的代码示例,然后运行如下命令:

    $ export AWS_PROFILE=terraform
    $ export AWS_REGION=eu-west-1
    $ terraform init
    $ terraform plan -out eks.plan

    你可能会遇到一些错误。 如果遇到的话,可以在调试模式下操作,但记得稍后关闭该模式:

    $ export TF_LOG=debug
    $ terraform plan -out eks.plan

    $ unset TF_LOG

    这个经验会很有用,你很可能会启动一个 EKS 集群(使用“terraform apply”进行该操作)。 在 AWS 控制台中查看:

    觉得厌烦时就清理掉:

    $ terraform destroy

    然后进入下一阶段,开始使用 Terraform EKS 模块,尤其它也基于同一 EKS 简介。 在 examples/ 目录中,你将看到如何使用它。 你还会在那里找到其他示例

    我们对示例进行了一定的简化。 以下是主文件,其中调用了 VPC 创建和 EKS 创建模块:

    $ cat /terraform/main.tf
    terraform {
      required_version = ">= 0.12.0"
      backend "s3" {
        bucket         = "eks-github-actions-terraform"
        key            = "terraform-dev.tfstate"
        region         = "eu-west-1"
        dynamodb_table = "eks-github-actions-terraform-lock"
      }
    }

    provider "kubernetes" {
      host                   = data.aws_eks_cluster.cluster.endpoint
      cluster_ca_certificate = base64decode(data.aws_eks_cluster.cluster.certificate_authority.0.data)
      token                  = data.aws_eks_cluster_auth.cluster.token
      load_config_file       = false
      version                = "1.10.0"
    }

    locals {
      vpc_name             = "dev-vpc"
      vpc_cidr             = "10.42.0.0/16"
      private_subnets      = ["10.42.1.0/24", "10.42.2.0/24"]
      public_subnets       = ["10.42.11.0/24", "10.42.12.0/24"]
      cluster_name         = "dev-cluster"
      cluster_version      = "1.14"
      worker_group_name    = "worker-group-1"
      instance_type        = "t2.medium"
      asg_desired_capacity = 1
    }

    data "aws_eks_cluster" "cluster" {
      name = module.eks.cluster_id
    }

    data "aws_eks_cluster_auth" "cluster" {
      name = module.eks.cluster_id
    }

    data "aws_availability_zones" "available" {
    }

    module "vpc" {
      source               = "git::https://github.com/terraform-aws-modules/terraform-aws-vpc?ref=master"

      name                 = local.vpc_name
      cidr                 = local.vpc_cidr
      azs                  = data.aws_availability_zones.available.names
      private_subnets      = local.private_subnets
      public_subnets       = local.public_subnets
      enable_nat_gateway   = true
      single_nat_gateway   = true
      enable_dns_hostnames = true

      tags = {
        "kubernetes.io/cluster/${local.cluster_name}" = "shared"
      }

      public_subnet_tags = {
        "kubernetes.io/cluster/${local.cluster_name}" = "shared"
        "kubernetes.io/role/elb" = "1"
      }

      private_subnet_tags = {
        "kubernetes.io/cluster/${local.cluster_name}" = "shared"
        "kubernetes.io/role/internal-elb" = "1"
      }
    }

    module "eks" {
      source = "git::https://github.com/terraform-aws-modules/terraform-aws-eks?ref=master"
      cluster_name     = local.cluster_name
      cluster_version  = local.cluster_version
      vpc_id           = module.vpc.vpc_id
      subnets          = module.vpc.private_subnets
      write_kubeconfig = false

      worker_groups = [
        {
          name                 = local.worker_group_name
          instance_type        = local.instance_type
          asg_desired_capacity = local.asg_desired_capacity
        }
      ]

      map_accounts = var.map_accounts
      map_roles    = var.map_roles
      map_users    = var.map_users
    }

    我们再仔细看一下 main.tf 中的“terraform”块:

    terraform {
      required_version = ">= 0.12.0"
      backend "s3" {
        bucket         = "eks-github-actions-terraform"
        key            = "terraform-dev.tfstate"
        region         = "eu-west-1"
        dynamodb_table = "eks-github-actions-terraform-lock"
      }
    }

    这里需要指出,我们将遵守不低于 Terraform 0.12 的语法(与早期版本相比有了很大变化),同时,Terraform 不应该将其状态存储在本地,而是远程存储在 S3 存储桶中。

    不同的人可以从不同的地方更新 terraform 代码确实很方便,这意味着我们需要能够锁定用户的状态,因此我们使用 dynamodb 表添加了一个锁。 有关锁定的更多信息,请参见状态锁定页面。

    由于存储桶的名称在整个 AWS 中应该是唯一的,因此你不能再使用名称“eks-github-actions-terraform”。 请想一个你自己的名称,并确保它没有被占用(应该收到 NoSuchBucket 错误):

    $ aws s3 ls s3://my-bucket
    调用 ListObjectsV2 操作时发生错误 (AllAccessDisabled):对此对象的所有访问均已禁用
    $ aws s3 ls s3://my-bucket-with-name-that-impossible-to-remember
    调用 ListObjectsV2 操作时发生错误 (NoSuchBucket):指定的存储桶不存在

    想好一个名称,创建存储桶(我们这里使用 IAM 用户“terraform”。 它拥有管理员权限,因此可以创建存储桶),并为其启用版本管理(这在配置出错时能让你省心):

    $ aws s3 mb s3://eks-github-actions-terraform --region eu-west-1
    make_bucket: eks-github-actions-terraform
    $ aws s3api put-bucket-versioning --bucket eks-github-actions-terraform --versioning-configuration Status=Enabled
    $ aws s3api get-bucket-versioning --bucket eks-github-actions-terraform
    {
      "Status": "Enabled"
    }

    对于 DynamoDB,不需要唯一性,但你需要先创建一个表:

    $ aws dynamodb create-table                                                                                     \
      --region eu-west-1                                                                                                           \
      --table-name eks-github-actions-terraform-lock                                              \
      --attribute-definitions AttributeName=LockID,AttributeType=S                \
      --key-schema AttributeName=LockID,KeyType=HASH                                   \
      --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5

    注意,如果 Terraform 操作失败,你可能需要从 AWS 控制台手动删除锁。 但这样做时要小心。

    对于 main.tf 中的 eks/vpc 模块,引用 GitHub 上提供的模块很简单:

    git::https://github.com/terraform-aws-modules/terraform-aws-vpc?ref=master

    现在看一下另外两个 Terraform 文件(variables.tf 和 outputs.tf)。 第一个文件保存了 Terraform 变量:

    $ cat /terraform/variables.tf
    variable "region" {
      default = "eu-west-1"
    }

    variable "map_accounts" {
      description = "Additional AWS account numbers to add to the aws-auth configmap. See examples/basic/variables.tf for example format."
      type        = list(string)
      default     = []
    }

    variable "map_roles" {
      description = "Additional IAM roles to add to the aws-auth configmap."
      type = list(object({
        rolearn  = string
        username = string
        groups   = list(string)
      }))
      default = []
    }

    variable "map_users" {
      description = "Additional IAM users to add to the aws-auth configmap."
      type = list(object({
        userarn  = string
        username = string
        groups   = list(string)
      }))
      default = [
        {
          userarn  = "arn:aws:iam::01234567890:user/my-user"
          username = "my-user"
          groups   = ["system:masters"]
        }
      ]
    }

    这里最重要的部分是将 IAM 用户“my-user”添加到 map_users 变量中,但你应该使用自己的帐户 ID 替换 01234567890。

    这有什么用? 当通过本地 kubectl 客户端与 EKS 通信时,它会向 Kubernetes API 服务器发送请求,每个请求都要经过身份验证和授权过程,这样 Kubernetes 就可以知道谁发送了请求,以及它们可以做什么。 因此 Kubernetes 的 EKS 版本会要求 AWS IAM 帮助进行用户身份验证。 如果发送请求的用户列在 AWS IAM 中(这里我们指向其 ARN),请求将进入授权阶段,该阶段将由 EKS 自己处理,但要依据我们的设置。 这里要指出的是,IAM 用户“my-user”非常酷(组“system: masters”)。

    最后,output.tf 文件描述了 Terraform 在完成工作后应该打印的内容:

    $ cat /terraform/outputs.tf
    output "cluster_endpoint" {
      description = "Endpoint for EKS control plane."
      value       = module.eks.cluster_endpoint
    }

    output "cluster_security_group_id" {
      description = "Security group ids attached to the cluster control plane."
      value       = module.eks.cluster_security_group_id
    }

    output "config_map_aws_auth" {
      description = "A kubernetes configuration to authenticate to this EKS cluster."
      value       = module.eks.config_map_aws_auth
    }

    Terraform 部分的描述完成。 我们很快就会回来,看看如何启动这些文件。

    Kubernetes 清单

    到目前为止,我们已经解决了在哪里启动应用程序的问题。 现在我们来看看要运行什么

    回想一下 /k8s/ 目录中的 docker-compose.yml(我们重命名了服务,添加了几个不久就会被 kompose 用到的标签)

    $ cat /k8s/docker-compose.yml
    version: "3.7"
    services:
      samples-bi:
        container_name: samples-bi
        image: intersystemsdc/iris-community:2019.4.0.383.0-zpm
        ports:
        - 52773:52773
        labels:
          kompose.service.type: loadbalancer
          kompose.image-pull-policy: IfNotPresent

    运行 kompose,然后添加下面突出显示的内容。 删除注释(使内容更容易理解):

    $ kompose convert -f docker-compose.yml --replicas=1
    $ cat /k8s/samples-bi-deployment.yaml
    apiVersion: extensions/v1beta1
    kind: Deployment
    metadata:
      labels:
        io.kompose.service: samples-bi
      name: samples-bi
    spec:
      replicas: 1
      strategy:
        type: Recreate
      template:
        metadata:
          labels:
            io.kompose.service: samples-bi
        spec:
          containers:
          - image: intersystemsdc/iris-community:2019.4.0.383.0-zpm
            imagePullPolicy: IfNotPresent
            name: samples-bi
            ports:
            - containerPort: 52773
            resources: {}
            lifecycle:
              postStart:
                exec:
                  command:
                  - /bin/bash
                  - -c
                  - |
                    echo -e "write\nhalt" > test
                    until iris session iris < test; do sleep 1; done
                    echo -e "zpm\ninstall samples-bi\nquit\nhalt" > samples_bi_install
                    iris session iris < samples_bi_install
                    rm test samples_bi_install

            restartPolicy: Always

    我们使用 Recreate 更新策略,这意味着先删除 pod,然后重新创建。 这对于演示目的是允许的,让我们可以使用更少的资源。
    我们还添加了 postStart 挂钩,该挂钩在 pod 启动后立即触发。 我们等待至 IRIS 启动,然后从默认的 zpm-repository 安装 samples-bi 包。
    现在我们添加 Kubernetes 服务(同样没有注释):

    $ cat /k8s/samples-bi-service.yaml
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        io.kompose.service: samples-bi
      name: samples-bi
    spec:
      ports:
      - name: "52773"
        port: 52773
        targetPort: 52773
      selector:
        io.kompose.service: samples-bi
      type: LoadBalancer

    是的,我们将在“默认”命名空间中部署,该命名空间适合演示。

    好了,现在我们知道了运行_位置_和_内容_。 还剩下_方式_需要了解。

    GitHub Actions 工作流程

    我们不需要每件事都从头开始做,而是创建一个工作流程,类似于使用 GitHub Actions 在 GKE 上部署 InterSystems IRIS 解决方案中所述的工作流程。 这次,我们不必担心构建容器。 GKE 特定的部分已替换为特定于 EKS。 粗体部分与接收提交消息和在条件步骤中使用它有关:

    $ cat /.github/workflows/workflow.yaml
    name: Provision EKS cluster and deploy Samples BI there
    on:
      push:
        branches:
        - master

    # Environment variables.
    # ${{ secrets }} are taken from GitHub -> Settings -> Secrets
    # ${{ github.sha }} is the commit hash
    env:
      AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
      AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
      AWS_REGION: ${{ secrets.AWS_REGION }}
      CLUSTER_NAME: dev-cluster
      DEPLOYMENT_NAME: samples-bi

    jobs:
      eks-provisioner:
        # Inspired by:
        ## https://www.terraform.io/docs/github-actions/getting-started.html
        ## https://github.com/hashicorp/terraform-github-actions
        name: Provision EKS cluster
        runs-on: ubuntu-18.04
        steps:
        - name: Checkout
          uses: actions/checkout@v2

        - name: Get commit message
          run: |
            echo ::set-env name=commit_msg::$(git log --format=%B -n 1 ${{ github.event.after }})

        - name: Show commit message
          run: echo $commit_msg

        - name: Terraform init
          uses: hashicorp/terraform-github-actions@master
          with:
            tf_actions_version: 0.12.20
            tf_actions_subcommand: 'init'
            tf_actions_working_dir: 'terraform'

        - name: Terraform validate
          uses: hashicorp/terraform-github-actions@master
          with:
            tf_actions_version: 0.12.20
            tf_actions_subcommand: 'validate'
            tf_actions_working_dir: 'terraform'

        - name: Terraform plan
          if: "!contains(env.commit_msg, '[destroy eks]')"
          uses: hashicorp/terraform-github-actions@master
          with:
            tf_actions_version: 0.12.20
            tf_actions_subcommand: 'plan'
            tf_actions_working_dir: 'terraform'

        - name: Terraform plan for destroy
          if: "contains(env.commit_msg, '[destroy eks]')"
          uses: hashicorp/terraform-github-actions@master
          with:
            tf_actions_version: 0.12.20
            tf_actions_subcommand: 'plan'
            args: '-destroy -out=./destroy-plan'
            tf_actions_working_dir: 'terraform'

        - name: Terraform apply
          if: "!contains(env.commit_msg, '[destroy eks]')"
          uses: hashicorp/terraform-github-actions@master
          with:
            tf_actions_version: 0.12.20
            tf_actions_subcommand: 'apply'
            tf_actions_working_dir: 'terraform'

        - name: Terraform apply for destroy
          if: "contains(env.commit_msg, '[destroy eks]')"
          uses: hashicorp/terraform-github-actions@master
          with:
            tf_actions_version: 0.12.20
            tf_actions_subcommand: 'apply'
            args: './destroy-plan'
            tf_actions_working_dir: 'terraform'

      kubernetes-deploy:
        name: Deploy Kubernetes manifests to EKS
        needs:
        - eks-provisioner
        runs-on: ubuntu-18.04
        steps:
        - name: Checkout
          uses: actions/checkout@v2

        - name: Get commit message
          run: |
            echo ::set-env name=commit_msg::$(git log --format=%B -n 1 ${{ github.event.after }})

        - name: Show commit message
          run: echo $commit_msg

        - name: Configure AWS Credentials
          if: "!contains(env.commit_msg, '[destroy eks]')"
          uses: aws-actions/configure-aws-credentials@v1
          with:
            aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
            aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
            aws-region: ${{ secrets.AWS_REGION }}

        - name: Apply Kubernetes manifests
          if: "!contains(env.commit_msg, '[destroy eks]')"
          working-directory: ./k8s/
          run: |
            aws eks update-kubeconfig --name ${CLUSTER_NAME}
            kubectl apply -f samples-bi-service.yaml
            kubectl apply -f samples-bi-deployment.yaml
            kubectl rollout status deployment/${DEPLOYMENT_NAME}

    当然,我们需要设置“terraform”用户的凭据(从 ~/.aws/credentials 文件中获取),让 Github 使用它的机密:

    注意工作流程的突出显示部分。 我们可以通过推送包含短语“[destroy eks]”的提交消息来销毁 EKS 集群。 请注意,我们不会使用这样的提交消息来运行“kubernetes apply”。
    运行管道,但首先要创建一个 .gitignore 文件:

    $ cat /.gitignore
    .DS_Store
    terraform/.terraform/
    terraform/*.plan
    terraform/*.json

    $ cd
    $ git add .github/ k8s/ terraform/ .gitignore
    $ git commit -m "GitHub on EKS"
    $ git push

    在 GitHub 仓库页面的“Actions”选项卡上监视部署过程。 请等待成功完成。

    第一次运行工作流程时,“Terraform apply”步骤需要 15 分钟左右,大约与创建集群的时间一样长。 下次启动时(如果未删除集群),工作流程会快很多。 你可以将此签出:

    $ cd
    $ git commit -m "Trigger" --allow-empty
    $ git push

    当然,最好检查一下我们做了什么。 这次可以在你的笔记本电脑上使用 IAM“my-user”的凭据:

    $ export AWS_PROFILE=my-user
    $ export AWS_REGION=eu-west-1
    $ aws sts get-caller-identity
    $ aws eks update-kubeconfig --region=eu-west-1 --name=dev-cluster --alias=dev-cluster
    $ kubectl config current-context
    dev-cluster

    $ kubectl get nodes
    NAME                                                                               STATUS   ROLES      AGE          VERSION
    ip-10-42-1-125.eu-west-1.compute.internal   Ready          6m20s     v1.14.8-eks-b8860f

    $ kubectl get po
    NAME                                                       READY        STATUS      RESTARTS   AGE
    samples-bi-756dddffdb-zd9nw    1/1               Running    0                      6m16s

    $ kubectl get svc
    NAME                   TYPE                        CLUSTER-IP        EXTERNAL-IP                                                                                                                                                         PORT(S)                    AGE
    kubernetes        ClusterIP               172.20.0.1                                                                                                                                                                                443/TCP                    11m
    samples-bi         LoadBalancer     172.20.33.235    a2c6f6733557511eab3c302618b2fae2-622862917.eu-west-1.elb.amazonaws.com    52773:31047/TCP  6m33s

    访问 _http://a2c6f6733557511eab3c302618b2fae2-622862917.eu-west-1.elb.amazonaws.com:52773/csp/user/_DeepSee.UserPortal.Home.zen?$NAMESPACE=USER _(将链接替换为你的外部 IP),然后输入“_system”、“SYS”并更改默认密码。 您应该看到一系列 BI 仪表板:

    点击每个仪表板的箭头可以深入了解:

    记住,如果重启 samples-bi pod,所有更改都将丢失。 这是有意的行为,因为这是演示。 如果你需要保留更改,我在 github-gke-zpm-registry/k8s/statefulset.tpl 仓库中创建了一个示例。

    完成后,删除你创建的所有内容:

    $ git commit -m "Mr Proper [destroy eks]" --allow-empty
    $ git push

    结论

    在本文中,我们将 eksctl 实用程序替换成 Terraform 来创建 EKS 集群。 这是向“编纂”您的所有 AWS 基础架构迈出的一步。
    我们展示了如何使用 Github Actions 和 Terraform 通过 git push 轻松部署演示应用程序。
    我们还向工具箱中添加了 kompose 和 pod 的 postStart 挂钩。
    这次我们没有展示 TLS 启用。 我们将在不久的将来完成这项任务。

    0
    0 473
    文章 Jeff Liu · 一月 7, 2021 6m read

    这次我想谈一谈不专门针对 InterSystems IRIS 的东西,不过如果你想使用 Docker,并且你工作环境是安装了 Windows 10 专业版或企业版的 PC 或笔记本电脑,那么我认为这个很重要。

    你可能知道,容器技术基本上来自于 Linux 世界,如今在 Linux 主机上发挥出最大潜能。 那些平常使用 Windows 的人会看到,Microsoft 和 Docker 在过去的几年做出了重要的努力,让我们可以在 Windows 系统上以非常简单的方式运行基于 Linux 映像的容器... 但是生产系统不支持这种方式,这是个大问题,如果我们要将持久性数据保留在主机系统中的容器之外,这样做非常不可靠... 这主要是由于 Windows 和 Linux 文件系统之间的巨大差异导致的。 最终,_Docker for Windows 自身使用了一个小型 linux 虚拟机 (MobiLinux) 来运行容器... 此操作对于 Windows 用户是透明的,而且效果完美,只要你不需要你的数据库比容器存活的时间更长...

    0
    0 1018
    文章 Jeff Liu · 一月 7, 2021 2m read

    最近,我需要从持久类和序列类生成一个 Swagger 规范,所以我发布了我的代码(它并不完整 - 你仍然需要处理应用程序的细节,但这是一个开始)。 代码在这里

    假设你有下面的类:

     

    你可以通过以下代码自动生成此 Swagger 定义:

     REST.Test.Person:
       type: "object"
       properties:
         Age:
           type: "integer"
         DOB:
           type: "string"
         FavoriteColors:
           type: "array"
           items:
             type: "string"
         FavoriteNumbers:
           type: "object"
         Home:
           $ref: "#/definitions/REST.Test.Address"
         Name:
           type: "string"
         Office:
           $ref: "#/definitions/REST.Test.Address"
         SSN:
           type: "string"
         Spouse:
           $ref: "#/definitions/REST.Test.Person"
     REST.Test.Address:
       type: "object"
       properties:
         City:
           type: "string"
         State:
           type: "string"
         Street:
           type: "string"
         Zip:
           type: "string"
    

    主方法:Utils.YAML:GenerateClasses

    测试运行:do ##class(Utils.YAML).Test()

    0
    0 269
    公告 Jeff Liu · 一月 7, 2021

    现在,InterSystems IRIS、IRIS for Health 和 IRIS Studio 的 2020.4 版发布了预览版本。由于是预览版本,因此我们渴望在下个月正式发布之前了解您对新版本的体验。

    **InterSystems IRIS 数据平台 2020.4 **使开发、部署和管理增强型应用程序和业务流程(桥接数据和应用程序孤岛)变得更加容易。 其拥有众多新功能,包括:

    面向应用程序和界面开发者的增强功能,包括:

    • 使用 Oracle OpenJDK 和 AdoptOpenJDK 时均支持 Java SE 11 LTS
    • 支持 JDBC 连接池
    • 分段虚拟文档的路由规则新增“foreach”操作

    面向数据库和系统管理员的增强功能,包括:

    • ICM 现在支持部署系统警报和监视 (SAM) 以及 InterSystems API 管理器(IAM)
    • 常见管理任务的 SQL 语法得到扩展
    • InterSystems 报告的部署得到简化

    ** InterSystems IRIS for Health 2020.4 **包括 InterSystems IRIS 的所有增强功能。 另外,此版本还包括:

    • 增强的 FHIR 支持,包括对 FHIR 配置文件的支持
    • 支持 RMD IHE 配置文件
    • 在 HL7 迁移工具中支持 DataGate

    有关这些功能的更多详细信息,请参见产品文档:

    由于这是 CD 版本,因此仅以 OCI(开放容器计划) 亦即 Docker 容器格式提供。  容器映像可用于面向 Linux x86-64 和 Linux ARM64 的 OCI 兼容运行时间引擎,如支持的平台文档中详述。

    企业版容器映像及其所有相应组件都可以使用以下命从 InterSystems 容器注册表中获得:

    docker pull containers.intersystems.com/intersystems/iris:2020.4.0.521.0
    docker pull containers.intersystems.com/intersystems/irishealth:2020.4.0.521.0

    有关可用映像的完整列表,请参阅 ICR 文档

    也可以使用以下命令从 Docker 存储库提取社区版的容器映像:

    docker pull store/intersystems/iris-community:2020.4.0.521.0
    docker pull store/intersystems/iris-community-arm64:2020.4.0.521.0
    docker pull store/intersystems/irishealth-community:2020.4.0.521.0
    docker pull store/intersystems/irishealth-community-arm64:2020.4.0.521.0

    另外,可以通过 WRC 的预览版本下载网站获取所有容器映像的 tarball 版本。

    InterSystems IRIS Studio 2020.4 是 Microsoft Windows 支持的独立开发映像。 其可以与 InterSystems IRIS 和 IRIS for Health 版本 2020.4 及更低版本一起使用,还可以与 Caché 和 Ensemble 一起使用。 可以通过 WRC 的预览下载网站进行下载。

    此预览版本的内部版本号是 2020.4.0.521.0。

    0
    0 138
    公告 Claire Zheng · 一月 7, 2021

    亲爱的社区用户,您好!

    您知道吗,在 Global Masters,您可以兑换关于以下任何 InterSystems 产品的 InterSystems 专家咨询:InterSystems IRIS数据平台、IRIS医疗版、互操作平台 (Ensemble)、IRIS Analytics (DeepSee)、Caché、HealthShare统一的健康档案。

    我们还有一个振奋人心的消息要分享,我们现在可以提供以下语言的咨询:

    英语、葡萄牙语、俄语、德语、法语、意大利语、西班牙语、日语、汉语

    而且! 咨询时长延长到 1.5 小时,让您与专家深入探讨主题。

    0
    0 120
    文章 Jeff Liu · 一月 7, 2021 5m read

    非常高兴地宣布,InterSystems 容器注册表现在可以使用了。 这为客户访问基于容器的版本及预览提供了新的渠道。 所有的社区版像都可在公共存储库中找到,且无需登录。 所有完整发布的像(IRIS、IRIS for Health、Health Connect、System Alerting and Monitoring、InterSystems Cloud Manager)和实用程序镜像(例如,仲裁器、Web 网关和 PasswordHash)都需要登录令牌,该令牌从 WRC 帐户生成。WRC 发布网站暂时将继续以 tarball 方式提供已发布像。 不过,您现在可以配置 CI/CD 管道以直接从 InterSystems 容器注册表“docker pull”镜像。
    可通过 https://containers.intersystems.com 访问该注册表。 有关完整的使用说明,请参阅下文或参阅文档(使用 InterSystems 容器注册表)。如果您遇到任何问题或有任何反馈要分享,请在下面的评论中告知我们,或联系 support@intersystems.com。
    --------------------------------------------------------------

    使用 InterSystems 容器注册表

    本文档列出了 InterSystems 容器注册表 (ICR) 中可用的像,并提供了使用说明。该注册表位于 containers.intersystems.com 上。

    可以使用 docker pull 命令下载 ICR 中的像,例如:

    docker pull containers.intersystems.com/intersystems/iris-community:2020.3.0.221.0

    本文档包含以下部分:

    • 公共像
    • 受限访问镜像
    • 对 ICR 进行身份验证
    • 列出 ICR 清单

    公共镜像

    以下 ICR 像是公开可用的,无需身份验证即可拉取:

    InterSystems IRIS

    IntegratedML

    2020.3

    containers.intersystems.com/intersystems/iris-ml-community:2020.3.0.302.0

    Community Edition

    2020.3

    containers.intersystems.com/intersystems/iris-community:2020.3.0.221.0

    2020.3 ARM64

    containers.intersystems.com/intersystems/iris-community-arm64:2020.3.0.221.0

    InterSystems IRIS for Health

    IntegratedML2020.3containers.intersystems.com/intersystems/irishealth-ml-community:2020.3.0.302.0
    Community Edition

    2020.3

    containers.intersystems.com/intersystems/irishealth-community:2020.3.0.221.0

    2020.3 ARM64

    containers.intersystems.com/intersystems/irishealth-community-arm64:2020.3.0.221.0

    System Alerting and Monitoring

     

    1.0

    containers.intersystems.com/intersystems/sam:1.0.0.115

    以下 ICR 镜像仅对经过身份验证的用户可用:受限访问镜像

    以下 ICR 像是公开可用的,无需身份验证即可拉取:

    Arbiter

    2020.1

    containers.intersystems.com/intersystems/arbiter:2020.1.0.215.0

    2020.2

    containers.intersystems.com/intersystems/arbiter:2020.2.0.211.0

    2020.3

    containers.intersystems.com/intersystems/arbiter:2020.3.0.210.0

    Health Connect

    2020.1

    containers.intersystems.com/intersystems/healthconnect:2020.1.0.215.0

    InterSystems Cloud Manager (ICM)

    2020.1

    containers.intersystems.com/intersystems/icm:2020.1.0.215.0

    2020.2

    containers.intersystems.com/intersystems/icm:2020.2.0.211.0

    2020.3

    containers.intersystems.com/intersystems/icm:2020.3.0.221

    InterSystems IRIS

    2020.1

    containers.intersystems.com/intersystems/iris:2020.1.0.215.0

    2020.2

    containers.intersystems.com/intersystems/iris:2020.2.0.211.0

    2020.3

    containers.intersystems.com/intersystems/iris:2020.3.0.221.0

    2020.1 ARM64

    containers.intersystems.com/intersystems/iris-arm64:2020.1.0.215.0

    2020.2 ARM64

    containers.intersystems.com/intersystems/iris-arm64:2020.2.0.211.0

    2020.3 ARM64

    containers.intersystems.com/intersystems/iris-arm64:2020.3.0.221.0

    2020.3 IntegratedMLcontainers.intersystems.com/intersystems/iris-ml:2020.3.0.302.0

    InterSystems IRIS for Health

    2020.1

    containers.intersystems.com/intersystems/irishealth:2020.1.0.217.1

    2020.2

    containers.intersystems.com/intersystems/irishealth:2020.2.0.211.0

    2020.3

    containers.intersystems.com/intersystems/irishealth:2020.3.0.221.0

    2020.1 ARM64

    containers.intersystems.com/intersystems/irishealth-arm64:2020.1.0.217.1

    2020.2 ARM64

    containers.intersystems.com/intersystems/irishealth-arm64:2020.2.0.211.0

    2020.3 ARM64

    containers.intersystems.com/intersystems/irishealth-arm64:2020.3.0.221.0

    2020.3 IntegratedMLcontainers.intersystems.com/intersystems/irishealth-ml:2020.3.0.302.0

    PasswordHash

    1.0

    containers.intersystems.com/intersystems/passwordhash:1.0

    Web Gateway

    2020.2

    containers.intersystems.com/intersystems/webgateway:2020.2.0.211.0

    2020.3

    containers.intersystems.com/intersystems/webgateway:2020.3.0.221.0


    要登录至 ICR,请执行以下步骤:对 ICR 进行身份验证

    • 在您的浏览器中加载 https://containers.intersystems.com/,然后使用您的 InterSystems/WRC 凭据登录。
    • 检索您的 Docker 登录令牌或完整的登录命令。
    • 在 Docker 界面(例如,PowerShell 窗口或 Linux 命令行)中,使用提供的凭据对 ICR 进行身份验证。 您可以通过复制并粘贴显示的完整 docker login 命令来执行此操作,例如:
    docker login -u="bbinstoc" -p="provided_password" containers.intersystems.com

    但是,出于安全原因,您可能想要输入命令 docker login container.intersystems.com,然后在 Username 提示符下输入用户名并将密码粘贴到 Password: 提示符下。

    注意:如果您登录到另一个 Docker 注册表,则 docker login 命令可能会导致错误;登录到 container.intersystems.com 之前,请先注销其他注册表。

    1. 现在,您可以从 ICR 中拉取镜像,例如:
    docker pull containers.intersystems.com/intersystems/iris:2020.3.0.221.0

    列出 ICR 清单

    API 可用于列出 Docker 注册表中的镜像和标签。 可用于列出注册表清单的开源第三方实用程序的一个示例是 docker-ls ,其可从 https://github.com/mayflower/docker-ls 获取。

    获取此实用程序的方法有几种。 你可以:

    • 下载用于各种平台的预编译 docker-ls 二进制文件
    • 直接在某些平台上安装该实用程序,例如,在 Linux 系统上使用以下命令进行安装:
    sudo snap install docker-ls
    • 在 Linux 平台上拉取并运行镜carinadigital/docker-ls:latest 以安装该实用程序,例如:
    docker run --rm carinadigital/docker-ls:latest

    安装 docker-ls 后,您可以使用以下命令列出 ICR 中的存储库:

    docker-ls repositories --registry https://containers.intersystems.com --user username --password password

    注意:使用 --interactive-password 选项提示输入密码,不要在命令行中输入密码。

    要仅列出公开可用的像,请为 -user --password 选项提供空字符串 ("") 作为参数, 例如,以下仅列出了公共 InterSystems IRIS for Health 镜像的标签:

    docker-ls tags --registry https://containers.intersystems.com --user "" --password "" intersystems/irishealth-community

    如果希望看到非公共像的完整列表,则无论是否登录 container.intersystems.com,都需要向该实用程序提供用户名和密码。

    可访问 https://github.com/mayflower/docker-ls 了解其他示例。

    0
    0 178
    文章 Claire Zheng · 一月 7, 2021 2m read

    亲爱的社区用户,您好! 我们诚挚邀请所有社区成员加入InterSystems Global Masters倡导中心,以便了解最新动态,获取对开发者社区)的贡献积分,并获得奖励!请浏览本文并了解如何加入,有哪些福利可以期待!

    点击此处:现在加入


    ▶️  什么是 Global Masters?

    Global Masters 是一个游戏化平台,您可以在其中完成与InterSystems技术相关的挑战(任务),赢取徽章和积分,并用积分兑换各种奖励!

    0
    0 202
    文章 Louis Lu · 一月 7, 2021 2m read

    RHEL V7.2 上的 Caché 进程故障

    InterSystems WRC 处理了几个有关进程错误引发的问题,这些问题可以归因于 Red Hat Linux 最近的一次更新。

    RHEL V7.2 (systemd-219-19.el7.x86_64) 中实现的一个新功能可能导致操作系统 IPC(进程间通信)信号量在 非系统用户注销时被解除分配(系统用户,即 UID 编号小于 1000 的用户除外)。

    Caché 在内部利用 IPC 信号量来控制 Caché 进程的运行(例如,当尝试唤醒 Caché 进程时)。 这通过“semop”系统服务来实现,如果操作系统意外删除了 Caché 用于进行 IPC 通讯的信号量,则进程可能会出现错误。 如果发生这种情况,在 cconsole.log 中会找到以下证据: “System error while trying to wake-up a process, code = 22”(尝试唤醒进程时系统出错,代码 = 22) 以及在 Caché SYSLOG 中也会记录相应的错误,例如以下典型示例: Err   Process    Date/Time           Mod Line  Routine            Namespace 22    39761      09/29/2016 04:41:27PM 61  359   BF0+1359^Ens.Queue.1 HSBUS 这最终可能导致 Caché 的运行实例处于挂起状态。

    以下是 Redhat 提供的一篇文章的链接,文中给出了有关此功能的详细信息以及禁用该功能的方法: https://access.redhat.com/solutions/2062273
     

    此问题已在 systemd-219-19.el7_2.4(通过 RHBA-2016-0199 发布 (https://rhn.redhat.com/errata/RHBA-2016-0199.html))中修复。

    0
    0 162
    公告 Claire Zheng · 一月 7, 2021

    亲爱的社区用户,您好!

    您可能知道,您在 Open Exchange 上每发布一个应用程序都会获得 Global Masters 积分奖励。 最近,我们针对 ZPM 应用程序推出了附加积分。 **现在,您的每个 ZPM 应用程序都会为您赢得额外的 400 积分!**积分将自动调整。
    立即查看 Global Masters 上的积分和可用奖励!

    如果您对 Global Masters 有任何疑问,欢迎在下面的评论中提问。


    关于 Global Masters 的其他信息:

    什么是 Global Masters? 从这里开始
    如何在 InterSystems Global Masters 上获得积分

    0
    0 111
    文章 Qiao Peng · 一月 5, 2021 4m read

    各位开发者们大家好!

    此前,我向各位介绍了一个非常好用的运行分析监控面板,它能使消息处理过程中的关键指标可视化,例如入站/出站消息的数量和平均处理时间等。  

    现在,我想用一项许多人已熟悉的工作流程,来展示一个增强型日志监视器——将警告信息作为Production中的消息来处理。我们可以通过创建路由规则来实现对告警消息的过滤和路由,并运用预先构建的组件(例如电子邮件适配器等)来发送粒度级别的通知。  

    如你所知,监视和管理警告信息是确保任何应用程序平稳运行的关键。对诸如HealthShare和IRIS医疗版这样支撑医疗系统运转的一级应用程序和集成引擎来说对告警信息的处理更显得尤为重要。

    让我们先来梳理一下InterSystems产品中已经附带的警告信息监视和管理工具:

    0
    0 263
    文章 Stefan Wittmann · 一月 4, 2021 4m read

    最近我一直在发布对 JSON 功能的一些更新,我很高兴许多人提供了反馈。 今天,我想将重点放在另一个方面:使用 SQL 查询生成 JSON。

    显然,SQL 是从关系模型中检索记录的重要概念。 假设你要查询数据并将其以简单 JSON 结构的形式公开给 REST 服务, 通常,你必须查询数据,然后对结果集进行遍历,最后为每条记录构造一个 JSON 结构。 你需要编写自定义代码。

    我们添加了标准 SQL 函数 JSON_OBJECTJSON_ARRAY,这样可以更容易地直接从 SQL 查询生成 JSON,而无需编写代码。 这两个函数是 Caché 2016.2 开始新增的。

    以下表 Baking.Pastry 为例:

    <td>
      类型
    </td>
    
    <td>
      说明
    </td>
    
    <td>
      Choux Pastry
    </td>
    
    <td>
      A light pastry that is often filled with cream
    </td>
    
    <td>
      Puff Pastry
    </td>
    
    <td>
      Many layers that cause the pastry to expand or puff when baked
    </td>
    
    <td>
      Filo Pastry
    </td>
    
    <td>
      Multiple layers of a paper-thin dough wrapped around a filling
    </td>
    
    1
    2
    3

    JSON_OBJECT

    JSON_OBJECT 是一个接受多个键值对并生成 JSON 对象的函数。

    SELECT JSON_OBJECT('pastry_type' : Type, 'pastry_description' : Description) AS pastryJSON FROM Baking.Pastry
    
    Row    pastryJSON
    
    ----   ---------------
    
    1      {"pastry_type" : "Choux Pastry", "pastry_description" : "A light pastry that is often filled with cream"}
    
    2      {"pastry_type" : "Puff Pastry", "pastry_description" : "Many layers that cause the pastry to expand or puff when baked"}
    
    3      {"pastry_type" : "Filo Pastry", "pastry_description" : " Multiple layers of a paper-thin dough wrapped around a filling"}
    

    在此例中,JSON_OBJECT 函数为每条记录生成一个 JSON 对象。 每个对象都包含两个属性 pastry_typepastry_description,因为我们为函数提供了两个参数。 每个参数由两部分组成,用冒号分隔:

    1. 应注入到JSON对象中的键的名称
    2. 与该键关联的字段值

    此示例设置了静态键,因为我只提供了字符串文字,例如“pastry_type”。 对于字段值(我指的是列),例如 Type,无论该列的内容是什么,都将设置为关联键的值。 这是构造 JSON 对象的常见用例,但是通过为键传递列,还可以动态创建键。

    JSON_ARRAY

    JSON_ARRAY 的工作方式类似。 它构造一个 JSON 数组,每传递一个参数都会将相应的值推送到数组中。

    SELECT JSON_ARRAY(Type, Description) AS pastryJSON FROM Baking.Pastry
    
    
    Row  pastryJSON
    
    ---- ---------------
    
    1    ["Choux Pastry" , "A light pastry that is often filled with cream"]
    
    2    ["Puff Pastry" , "Many layers that cause the pastry to expand or puff when baked"]
    
    3    ["Filo Pastry" , "Multiple layers of a paper-thin dough wrapped around a filling"]
    

    JSON_ARRAY 是一个非常简单的函数。 此示例创建一个数组,其中每行包含两个元素。 第一项由列 Type 的值填充,而第二项由列 Description 的值填充。

    高级方案

    也许你需要创建一个更复杂的 JSON 结构。 值参数可以是嵌套的 JSON_ARRAYJSON_OBECT 函数调用,从而可以构造嵌套的 JSON 结构。 我们回到第一个示例,将 JSON 对象包装在标头结构中:

    SELECT JSON_OBJECT('food_type' : 'pastry', 'details' : JSON_OBJECT('type' : Type, 'description' : Description)) AS pastryJSON FROM Baking.Pastry
    
    
    Row  pastryJSON
    
    ---- ---------------
    
    1    {"food_type" : "pastry", "details" : {"type" : "Choux Pastry", "description" : "A light pastry that is often filled with cream"}}
    
    2    {"food_type" : "pastry", "details" : {"type" : "Puff Pastry", "description" : " Many layers that cause the pastry to expand or puff when baked"}}
    
    3    {"food_type" : "pastry", "details" : {"type" : "Filo Pastry", "description" : " Multiple layers of a paper-thin dough wrapped around a filling"}}
    

    我们计划在将来的版本中实现更多的 JSON SQL 函数,但这两个函数是坚实的开始。 主要用例是从关系型数据构造简单的 JSON 元素,而无需编写代码。 这样即使无法更改后端代码,也可以从系统直接发布 JSON。

    要创建更复杂的结构,使用新的复合接口可以更高效地构建,该接口允许将Persistent/Registered对象转换为动态对象/数组。 然后可以根据需要轻松修改结构,最后通过 $toJSON() 调用将其导出为 JSON 字符串。 我会在将来的帖子中更详细地介绍这个主题。

    0
    3 950