搜索​​​​

清除过滤器
文章
Louis Lu · 四月 15, 2021

第 4 天:使用 InterSystems Objects 和 SQL 进行开发

我正在参加 Joel Solon 讲授的“使用 InterSystems Objects 和 SQL 进行开发”课程。 课程非常好,我将在这里分享一些从培训中总结的提示。 第 4 天的提示: 1. 所有数据都存储在global中,global名称以 ^ 开头。 global示例:^animal。 global可以有多个数据位置(“子数据”)。 示例:^animal("大象","吃草")。 2. 可从任意系统范围(命名空间)访问 ^%* global。 3. global使 IRIS 能够支持多模型数据(对象、关系、文档、多维等)。 4. 要查看global,请转到 Management Portal > Explorer > Globals > Select Global > View,或者在终端中输入 do ^%G 或 zwrite ^global。 5. 在持久类和 SQL 表之间有自动对应关系: 包对应于是 SQL Schema; 类是Table; 属性是列; 方法是存储过程(使用 sqlProc 时); 类之间的关系是 SQL 外键约束(必须为双向)。 对象是行。 6. 一个表可以对应多个类,但序列类serial是持久类表的一部分(没有特定的表)。 7. 一个类可以对应多个表。 8. 我们有一些类类型: Non-registered:不是类对象(仅限方法的容器); Registered:瞬态对象; Persistent:类似于SQL表中持久化保存; Serial:嵌入主持久化表中的持久表(Serial为嵌入式); Datatype:非类对象用于执行新的验证和转换为基础数据类型。 9. 类的组成可包括: 属性; 方法; Class queries:SQL Select 语句; Parameters:配置类行为的用户常量或系统常量; 外键:参照完整性; 索引:提高性能并创建独特值; 触发器:触发与持久性事件关联的方法; XData:与该类关联的 XML 或 JSON 定义; 存储:数据存储的描述。 10. 按照惯例,类的首字母大写。 示例:CountryOrigin。 参数均为大写。 示例:COLORNUMBER。 11. 类特性限定/配置一个类。 示例 [SqlTableName = Animal] 可设置SQL表名。 [Final] 不允许继承。 [Private] 不允许为非子类调用方法或使用属性。 12. IRIS 在内部生成 Get 和 Set 属性,这些属性不可见,但可以通过声明改变行为。 13. 可以重写超类的方法,为此,请重复类名、参数。 可以增加参数的数量,不可减少。 14. 使用 ##super() 调用基类方法。 15. 要创建抽象类,请使用 [Abstract] 并防止实例化。 16. 可以继承多个类。 例如,Class Person extends (%Persistent, %Animal)。 (Persistent 必须是 extends 中的第一个类,参见评论中 joel 的提示) 17. REST 是表述性状态转移。 它基于 HTTP 协议。 使用 HTTP 谓词:GET(选择)、POST(插入)、PUT(更新)和 DELETE(删除)。 18. 要将您的类作为 REST 资源公开,请从 %CSP.REST 扩展。 19. 在 XData 块中使用 URLMap 配置 REST 服务的路由。 使用门户,创建一个 Web 应用程序,启用 REST 并指定 Dispatch 类。 20. %JSONAdaptor 提供了对象与 JSON 之间的转换。 使用 obj.%JSONImport(jsonObj) 将 DynamicObject 分配到对象。 使用 obj.%JSONExportToString(.jsonString) 将 JSON 字符串写入对象。 21. %JSON.Formatter 格式化 JSON 字符串以便人类阅读。
文章
Michael Lei · 五月 24, 2021

InterSystems 最佳实践系列之数据平台和性能 - 第 6 部分 Caché 存储 IO 配置文件

我本人和其他技术架构师经常需要向客户和供应商说明 Caché IO 要求以及 Caché 应用程序使用存储系统的方式。 在向客户和供应商说明典型的 Caché IO 配置文件和事务性数据库应用程序的要求时,下面的表格很有用。  原始表格由 Mark Bolinsky 创建。 在以后的帖子中,我将讨论更多关于存储 IO 的内容,所以现在贴上这些表格也作为将来文章的参考。  * * * [本系列其他帖子的列表](https://cn.community.intersystems.com/post/intersystems-数据平台的容量规划和性能系列文章)   * * * 拥有设置良好的存储(如存储阵列)以提供可预测的磁盘 IO 性能,支持高可用性功能并为应用程序提供存储冗余、可伸缩性和可靠性,这几点至关重要。 ## Caché 存储 IO 配置文件 根据所选的存储阵列技术,物理层的磁盘存储可分为池或磁盘组。 如果可能,出于可用性和性能考虑,应根据预期的 IO 配置文件对存储进行分区。 例如,数据和日志(事务日志)应该在不同的物理磁盘组上,因为它们有不同的 IO 配置文件,这也是出于可用性考虑,因为数据磁盘组中的损坏可以通过与损坏隔离的单独磁盘组中的日志来恢复。 同样,备份应该在单独的磁盘组中。 存储配置有多种选择,具体取决于操作系统、存储供应商和阵列型号。 具体要求因应用程序而异,需要特别注意物理和逻辑配置,包括物理和逻辑组或池的分配、RAID 类型、文件系统类型和并发性、分配的 GB 空间等。 下表详细介绍了 Caché 的读写 IO 配置文件: ![](/sites/default/files/inline/images/2016-11-14_09-45-42.png) ## Caché 存储 IO 要求 我发现存储瓶颈是影响数据库系统性能的最常见问题之一。 一个常见的问题是只针对 GB 容量来调整存储大小,而不是分配足够多的独立磁盘来支持预期的每秒输入/输出操作数 (IOPS)。 尽管 SSD 和分层存储现在更加常见,但必须小心以确保 IOPS 可用。 为了保证可被最终用户接受的响应时间,需要具有最低 IO 性能配置文件的磁盘阵列。 根据是否使用单独的应用程序 (ECP) 服务器,要求会略有不同。 下表详细说明了预期的存储响应时间和关于 IO 配置文件的备注。   ![](/sites/default/files/inline/images/2016-11-14_09-45-09.png) ## 缺少了什么? 在与供应商交谈之前,您需要估计您的应用程序预期将驱动的 IOPS ,以便配置存储选项以满足上述要求。 本系列的第 1 和第 2 部分给出了如何收集指标的示例。
文章
Jingwei Wang · 十月 28, 2021

IRIS 2021 技术文档 First Look 26 InterSystems API 管理器

html {overflow-x: initial !important;}:root { --bg-color: #ffffff; --text-color: #333333; --select-text-bg-color: #B5D6FC; --select-text-font-color: auto; --monospace: "Lucida Console",Consolas,"Courier",monospace; --title-bar-height: 20px; } .mac-os-11 { --title-bar-height: 28px; } html { font-size: 14px; background-color: var(--bg-color); color: var(--text-color); font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; -webkit-font-smoothing: antialiased; } body { margin: 0px; padding: 0px; height: auto; inset: 0px; font-size: 1rem; line-height: 1.42857143; overflow-x: hidden; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: inherit; tab-size: 4; background-position: inherit; background-repeat: inherit; } iframe { margin: auto; } a.url { word-break: break-all; } a:active, a:hover { outline: 0px; } .in-text-selection, ::selection { text-shadow: none; background: var(--select-text-bg-color); color: var(--select-text-font-color); } #write { margin: 0px auto; height: auto; width: inherit; word-break: normal; word-wrap: break-word; position: relative; white-space: normal; overflow-x: visible; padding-top: 36px; } #write.first-line-indent p { text-indent: 2em; } #write.first-line-indent li p, #write.first-line-indent p * { text-indent: 0px; } #write.first-line-indent li { margin-left: 2em; } .for-image #write { padding-left: 8px; padding-right: 8px; } body.typora-export { padding-left: 30px; padding-right: 30px; } .typora-export .footnote-line, .typora-export li, .typora-export p { white-space: pre-wrap; } .typora-export .task-list-item input { pointer-events: none; } @media screen and (max-width: 500px) { body.typora-export { padding-left: 0px; padding-right: 0px; } #write { padding-left: 20px; padding-right: 20px; } .CodeMirror-sizer { margin-left: 0px !important; } .CodeMirror-gutters { display: none !important; } } #write li > figure:last-child { margin-bottom: 0.5rem; } #write ol, #write ul { position: relative; } img { max-width: 100%; vertical-align: middle; image-orientation: from-image; } button, input, select, textarea { color: inherit; font-family: inherit; font-size: inherit; font-style: inherit; font-variant-caps: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; } input[type="checkbox"], input[type="radio"] { line-height: normal; padding: 0px; } *, ::after, ::before { box-sizing: border-box; } #write h1, #write h2, #write h3, #write h4, #write h5, #write h6, #write p, #write pre { width: inherit; } #write h1, #write h2, #write h3, #write h4, #write h5, #write h6, #write p { position: relative; } p { line-height: inherit; } h1, h2, h3, h4, h5, h6 { break-after: avoid-page; break-inside: avoid; orphans: 4; } p { orphans: 4; } h1 { font-size: 2rem; } h2 { font-size: 1.8rem; } h3 { font-size: 1.6rem; } h4 { font-size: 1.4rem; } h5 { font-size: 1.2rem; } h6 { font-size: 1rem; } .md-math-block, .md-rawblock, h1, h2, h3, h4, h5, h6, p { margin-top: 1rem; margin-bottom: 1rem; } .hidden { display: none; } .md-blockmeta { color: rgb(204, 204, 204); font-weight: 700; font-style: italic; } a { cursor: pointer; } sup.md-footnote { padding: 2px 4px; background-color: rgba(238, 238, 238, 0.7); color: rgb(85, 85, 85); border-top-left-radius: 4px; border-top-right-radius: 4px; border-bottom-right-radius: 4px; border-bottom-left-radius: 4px; cursor: pointer; } sup.md-footnote a, sup.md-footnote a:hover { color: inherit; text-transform: inherit; text-decoration: inherit; } #write input[type="checkbox"] { cursor: pointer; width: inherit; height: inherit; } figure { overflow-x: auto; margin: 1.2em 0px; max-width: calc(100% + 16px); padding: 0px; } figure > table { margin: 0px; } tr { break-inside: avoid; break-after: auto; } thead { display: table-header-group; } table { border-collapse: collapse; border-spacing: 0px; width: 100%; overflow: auto; break-inside: auto; text-align: left; } table.md-table td { min-width: 32px; } .CodeMirror-gutters { border-right-width: 0px; background-color: inherit; } .CodeMirror-linenumber { } .CodeMirror { text-align: left; } .CodeMirror-placeholder { opacity: 0.3; } .CodeMirror pre { padding: 0px 4px; } .CodeMirror-lines { padding: 0px; } div.hr:focus { cursor: none; } #write pre { white-space: pre-wrap; } #write.fences-no-line-wrapping pre { white-space: pre; } #write pre.ty-contain-cm { white-space: normal; } .CodeMirror-gutters { margin-right: 4px; } .md-fences { font-size: 0.9rem; display: block; break-inside: avoid; text-align: left; overflow: visible; white-space: pre; background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: inherit; position: relative !important; background-position: inherit; background-repeat: inherit; } .md-fences-adv-panel { width: 100%; margin-top: 10px; text-align: center; padding-top: 0px; padding-bottom: 8px; overflow-x: auto; } #write .md-fences.mock-cm { white-space: pre-wrap; } .md-fences.md-fences-with-lineno { padding-left: 0px; } #write.fences-no-line-wrapping .md-fences.mock-cm { white-space: pre; overflow-x: auto; } .md-fences.mock-cm.md-fences-with-lineno { padding-left: 8px; } .CodeMirror-line, twitterwidget { break-inside: avoid; } .footnotes { opacity: 0.8; font-size: 0.9rem; margin-top: 1em; margin-bottom: 1em; } .footnotes + .footnotes { margin-top: 0px; } .md-reset { margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: top; text-decoration: none; text-shadow: none; float: none; position: static; width: auto; height: auto; white-space: nowrap; cursor: inherit; line-height: normal; font-weight: 400; text-align: left; box-sizing: content-box; direction: ltr; background-position: 0px 0px; } li div { padding-top: 0px; } blockquote { margin: 1rem 0px; } li .mathjax-block, li p { margin: 0.5rem 0px; } li blockquote { margin: 1rem 0px; } li { margin: 0px; position: relative; } blockquote > :last-child { margin-bottom: 0px; } blockquote > :first-child, li > :first-child { margin-top: 0px; } .footnotes-area { color: rgb(136, 136, 136); margin-top: 0.714rem; padding-bottom: 0.143rem; white-space: normal; } #write .footnote-line { white-space: pre-wrap; } @media print { body, html { border: 1px solid transparent; height: 99%; break-after: avoid; break-before: avoid; font-variant-ligatures: no-common-ligatures; } #write { margin-top: 0px; padding-top: 0px; border-color: transparent !important; } .typora-export * { -webkit-print-color-adjust: exact; } .typora-export #write { break-after: avoid; } .typora-export #write::after { height: 0px; } .is-mac table { break-inside: avoid; } .typora-export-show-outline .typora-export-sidebar { display: none; } } .footnote-line { margin-top: 0.714em; font-size: 0.7em; } a img, img a { cursor: pointer; } pre.md-meta-block { font-size: 0.8rem; min-height: 0.8rem; white-space: pre-wrap; background-color: rgb(204, 204, 204); display: block; overflow-x: hidden; } p > .md-image:only-child:not(.md-img-error) img, p > img:only-child { display: block; margin: auto; } #write.first-line-indent p > .md-image:only-child:not(.md-img-error) img { left: -2em; position: relative; } p > .md-image:only-child { display: inline-block; width: 100%; } #write .MathJax_Display { margin: 0.8em 0px 0px; } .md-math-block { width: 100%; } .md-math-block:not(:empty)::after { display: none; } .MathJax_ref { fill: currentcolor; } [contenteditable="true"]:active, [contenteditable="true"]:focus, [contenteditable="false"]:active, [contenteditable="false"]:focus { outline: 0px; box-shadow: none; } .md-task-list-item { position: relative; list-style-type: none; } .task-list-item.md-task-list-item { padding-left: 0px; } .md-task-list-item > input { position: absolute; top: 0px; left: 0px; margin-left: -1.2em; margin-top: calc(1em - 10px); border: none; } .math { font-size: 1rem; } .md-toc { min-height: 3.58rem; position: relative; font-size: 0.9rem; border-top-left-radius: 10px; border-top-right-radius: 10px; border-bottom-right-radius: 10px; border-bottom-left-radius: 10px; } .md-toc-content { position: relative; margin-left: 0px; } .md-toc-content::after, .md-toc::after { display: none; } .md-toc-item { display: block; color: rgb(65, 131, 196); } .md-toc-item a { text-decoration: none; } .md-toc-inner:hover { text-decoration: underline; } .md-toc-inner { display: inline-block; cursor: pointer; } .md-toc-h1 .md-toc-inner { margin-left: 0px; font-weight: 700; } .md-toc-h2 .md-toc-inner { margin-left: 2em; } .md-toc-h3 .md-toc-inner { margin-left: 4em; } .md-toc-h4 .md-toc-inner { margin-left: 6em; } .md-toc-h5 .md-toc-inner { margin-left: 8em; } .md-toc-h6 .md-toc-inner { margin-left: 10em; } @media screen and (max-width: 48em) { .md-toc-h3 .md-toc-inner { margin-left: 3.5em; } .md-toc-h4 .md-toc-inner { margin-left: 5em; } .md-toc-h5 .md-toc-inner { margin-left: 6.5em; } .md-toc-h6 .md-toc-inner { margin-left: 8em; } } a.md-toc-inner { font-size: inherit; font-style: inherit; font-weight: inherit; line-height: inherit; } .footnote-line a:not(.reversefootnote) { color: inherit; } .md-attr { display: none; } .md-fn-count::after { content: "."; } code, pre, samp, tt { font-family: var(--monospace); } kbd { margin: 0px 0.1em; padding: 0.1em 0.6em; font-size: 0.8em; color: rgb(36, 39, 41); background-color: rgb(255, 255, 255); border: 1px solid rgb(173, 179, 185); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; box-shadow: rgba(12, 13, 14, 0.2) 0px 1px 0px, rgb(255, 255, 255) 0px 0px 0px 2px inset; white-space: nowrap; vertical-align: middle; } .md-comment { color: rgb(162, 127, 3); opacity: 0.8; font-family: var(--monospace); } code { text-align: left; } a.md-print-anchor { white-space: pre !important; border: none !important; display: inline-block !important; position: absolute !important; width: 1px !important; right: 0px !important; outline: 0px !important; text-shadow: initial !important; background-position: 0px 0px !important; } .md-inline-math .MathJax_SVG .noError { display: none !important; } .html-for-mac .inline-math-svg .MathJax_SVG { vertical-align: 0.2px; } .md-fences-math .MathJax_SVG_Display, .md-math-block .MathJax_SVG_Display { text-align: center; margin: 0px; position: relative; text-indent: 0px; max-width: none; max-height: none; min-height: 0px; min-width: 100%; width: auto; overflow-y: visible; display: block !important; } .MathJax_SVG_Display, .md-inline-math .MathJax_SVG_Display { width: auto; margin: inherit; display: inline-block !important; } .MathJax_SVG .MJX-monospace { font-family: var(--monospace); } .MathJax_SVG .MJX-sans-serif { font-family: sans-serif; } .MathJax_SVG { display: inline; font-style: normal; font-weight: 400; line-height: normal; text-indent: 0px; text-align: left; text-transform: none; letter-spacing: normal; word-spacing: normal; word-wrap: normal; white-space: nowrap; float: none; direction: ltr; max-width: none; max-height: none; min-width: 0px; min-height: 0px; border: 0px; padding: 0px; margin: 0px; zoom: 90%; } #math-inline-preview-content { zoom: 1.1; } .MathJax_SVG * { transition: none; } .MathJax_SVG_Display svg { vertical-align: middle !important; margin-bottom: 0px !important; margin-top: 0px !important; } .os-windows.monocolor-emoji .md-emoji { font-family: "Segoe UI Symbol", sans-serif; } .md-diagram-panel > svg { max-width: 100%; } [lang="flow"] svg, [lang="mermaid"] svg { max-width: 100%; height: auto; } [lang="mermaid"] .node text { font-size: 1rem; } table tr th { border-bottom-width: 0px; } video { max-width: 100%; display: block; margin: 0px auto; } iframe { max-width: 100%; width: 100%; border: none; } .highlight td, .highlight tr { border: 0px; } mark { background-color: rgb(255, 255, 0); color: rgb(0, 0, 0); } .md-html-inline .md-plain, .md-html-inline strong, mark .md-inline-math, mark strong { color: inherit; } .md-expand mark .md-meta { opacity: 0.3 !important; } mark .md-meta { color: rgb(0, 0, 0); } @media print { .typora-export h1, .typora-export h2, .typora-export h3, .typora-export h4, .typora-export h5, .typora-export h6 { break-inside: avoid; } } .md-diagram-panel .messageText { stroke: none !important; } .md-diagram-panel .start-state { fill: var(--node-fill); } .md-diagram-panel .edgeLabel rect { opacity: 1 !important; } .md-require-zoom-fix foreignObject { font-size: var(--mermaid-font-zoom); } .md-fences.md-fences-math { font-size: 1em; } .md-fences-math .MathJax_SVG_Display { margin-top: 8px; cursor: default; } .md-fences-advanced:not(.md-focus) { padding: 0px; white-space: nowrap; border: 0px; } .md-fences-advanced:not(.md-focus) { background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: inherit; background-position: inherit; background-repeat: inherit; } .typora-export-show-outline .typora-export-content { max-width: 1440px; margin: auto; display: flex; flex-direction: row; } .typora-export-sidebar { width: 300px; font-size: 0.8rem; margin-top: 80px; margin-right: 18px; } .typora-export-show-outline #write { --webkit-flex: 2; flex: 2 1 0%; } .typora-export-sidebar .outline-content { position: fixed; top: 0px; max-height: 100%; overflow: hidden auto; padding-bottom: 30px; padding-top: 60px; width: 300px; } @media screen and (max-width: 1024px) { .typora-export-sidebar, .typora-export-sidebar .outline-content { width: 240px; } } @media screen and (max-width: 800px) { .typora-export-sidebar { display: none; } } .outline-content li, .outline-content ul { margin-left: 0px; margin-right: 0px; padding-left: 0px; padding-right: 0px; list-style: none; } .outline-content ul { margin-top: 0px; margin-bottom: 0px; } .outline-content strong { font-weight: 400; } .outline-expander { width: 1rem; height: 1.428571429rem; position: relative; display: table-cell; vertical-align: middle; cursor: pointer; padding-left: 4px; } .outline-expander::before { content: ''; position: relative; font-family: Ionicons; display: inline-block; font-size: 8px; vertical-align: middle; } .outline-item { padding-top: 3px; padding-bottom: 3px; cursor: pointer; } .outline-expander:hover::before { content: ''; } .outline-h1 > .outline-item { padding-left: 0px; } .outline-h2 > .outline-item { padding-left: 1em; } .outline-h3 > .outline-item { padding-left: 2em; } .outline-h4 > .outline-item { padding-left: 3em; } .outline-h5 > .outline-item { padding-left: 4em; } .outline-h6 > .outline-item { padding-left: 5em; } .outline-label { cursor: pointer; display: table-cell; vertical-align: middle; text-decoration: none; color: inherit; } .outline-label:hover { text-decoration: underline; } .outline-item:hover { border-color: rgb(245, 245, 245); background-color: var(--item-hover-bg-color); } .outline-item:hover { margin-left: -28px; margin-right: -28px; border-left-width: 28px; border-left-style: solid; border-left-color: transparent; border-right-width: 28px; border-right-style: solid; border-right-color: transparent; } .outline-item-single .outline-expander::before, .outline-item-single .outline-expander:hover::before { display: none; } .outline-item-open > .outline-item > .outline-expander::before { content: ''; } .outline-children { display: none; } .info-panel-tab-wrapper { display: none; } .outline-item-open > .outline-children { display: block; } .typora-export .outline-item { padding-top: 1px; padding-bottom: 1px; } .typora-export .outline-item:hover { margin-right: -8px; border-right-width: 8px; border-right-style: solid; border-right-color: transparent; } .typora-export .outline-expander::before { content: "+"; font-family: inherit; top: -1px; } .typora-export .outline-expander:hover::before, .typora-export .outline-item-open > .outline-item > .outline-expander::before { content: '−'; } .typora-export-collapse-outline .outline-children { display: none; } .typora-export-collapse-outline .outline-item-open > .outline-children, .typora-export-no-collapse-outline .outline-children { display: block; } .typora-export-no-collapse-outline .outline-expander::before { content: "" !important; } .typora-export-show-outline .outline-item-active > .outline-item .outline-label { font-weight: 700; } :root { --side-bar-bg-color: #fafafa; --control-text-color: #777; } @include-when-export url(https://fonts.loli.net/css?family=Open+Sans:400italic,700italic,700,400&subset=latin,latin-ext); /* open-sans-regular - latin-ext_latin */ /* open-sans-italic - latin-ext_latin */ /* open-sans-700 - latin-ext_latin */ /* open-sans-700italic - latin-ext_latin */ html { font-size: 16px; } body { font-family: "Open Sans","Clear Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; color: rgb(51, 51, 51); line-height: 1.6; } #write { max-width: 860px; margin: 0 auto; padding: 30px; padding-bottom: 100px; } @media only screen and (min-width: 1400px) { #write { max-width: 1024px; } } @media only screen and (min-width: 1800px) { #write { max-width: 1200px; } } #write > ul:first-child, #write > ol:first-child{ margin-top: 30px; } a { color: #4183C4; } h1, h2, h3, h4, h5, h6 { position: relative; margin-top: 1rem; margin-bottom: 1rem; font-weight: bold; line-height: 1.4; cursor: text; } h1:hover a.anchor, h2:hover a.anchor, h3:hover a.anchor, h4:hover a.anchor, h5:hover a.anchor, h6:hover a.anchor { text-decoration: none; } h1 tt, h1 code { font-size: inherit; } h2 tt, h2 code { font-size: inherit; } h3 tt, h3 code { font-size: inherit; } h4 tt, h4 code { font-size: inherit; } h5 tt, h5 code { font-size: inherit; } h6 tt, h6 code { font-size: inherit; } h1 { font-size: 2.25em; line-height: 1.2; border-bottom: 1px solid #eee; } h2 { font-size: 1.75em; line-height: 1.225; border-bottom: 1px solid #eee; } /*@media print { .typora-export h1, .typora-export h2 { border-bottom: none; padding-bottom: initial; } .typora-export h1::after, .typora-export h2::after { content: ""; display: block; height: 100px; margin-top: -96px; border-top: 1px solid #eee; } }*/ h3 { font-size: 1.5em; line-height: 1.43; } h4 { font-size: 1.25em; } h5 { font-size: 1em; } h6 { font-size: 1em; color: #777; } p, blockquote, ul, ol, dl, table{ margin: 0.8em 0; } li>ol, li>ul { margin: 0 0; } hr { height: 2px; padding: 0; margin: 16px 0; background-color: #e7e7e7; border: 0 none; overflow: hidden; box-sizing: content-box; } li p.first { display: inline-block; } ul, ol { padding-left: 30px; } ul:first-child, ol:first-child { margin-top: 0; } ul:last-child, ol:last-child { margin-bottom: 0; } blockquote { border-left: 4px solid #dfe2e5; padding: 0 15px; color: #777777; } blockquote blockquote { padding-right: 0; } table { padding: 0; word-break: initial; } table tr { border: 1px solid #dfe2e5; margin: 0; padding: 0; } table tr:nth-child(2n), thead { background-color: #f8f8f8; } table th { font-weight: bold; border: 1px solid #dfe2e5; border-bottom: 0; margin: 0; padding: 6px 13px; } table td { border: 1px solid #dfe2e5; margin: 0; padding: 6px 13px; } table th:first-child, table td:first-child { margin-top: 0; } table th:last-child, table td:last-child { margin-bottom: 0; } .CodeMirror-lines { padding-left: 4px; } .code-tooltip { box-shadow: 0 1px 1px 0 rgba(0,28,36,.3); border-top: 1px solid #eef2f2; } .md-fences, code, tt { border: 1px solid #e7eaed; background-color: #f8f8f8; border-radius: 3px; padding: 0; padding: 2px 4px 0px 4px; font-size: 0.9em; } code { background-color: #f3f4f4; padding: 0 2px 0 2px; } .md-fences { margin-bottom: 15px; margin-top: 15px; padding-top: 8px; padding-bottom: 6px; } .md-task-list-item > input { margin-left: -1.3em; } @media print { html { font-size: 13px; } table, pre { page-break-inside: avoid; } pre { word-wrap: break-word; } } .md-fences { background-color: #f8f8f8; } #write pre.md-meta-block { padding: 1rem; font-size: 85%; line-height: 1.45; background-color: #f7f7f7; border: 0; border-radius: 3px; color: #777777; margin-top: 0 !important; } .mathjax-block>.code-tooltip { bottom: .375rem; } .md-mathjax-midline { background: #fafafa; } #write>h3.md-focus:before{ left: -1.5625rem; top: .375rem; } #write>h4.md-focus:before{ left: -1.5625rem; top: .285714286rem; } #write>h5.md-focus:before{ left: -1.5625rem; top: .285714286rem; } #write>h6.md-focus:before{ left: -1.5625rem; top: .285714286rem; } .md-image>.md-meta { /*border: 1px solid #ddd;*/ border-radius: 3px; padding: 2px 0px 0px 4px; font-size: 0.9em; color: inherit; } .md-tag { color: #a7a7a7; opacity: 1; } .md-toc { margin-top:20px; padding-bottom:20px; } .sidebar-tabs { border-bottom: none; } #typora-quick-open { border: 1px solid #ddd; background-color: #f8f8f8; } #typora-quick-open-item { background-color: #FAFAFA; border-color: #FEFEFE #e5e5e5 #e5e5e5 #eee; border-style: solid; border-width: 1px; } /** focus mode */ .on-focus-mode blockquote { border-left-color: rgba(85, 85, 85, 0.12); } header, .context-menu, .megamenu-content, footer{ font-family: "Segoe UI", "Arial", sans-serif; } .file-node-content:hover .file-node-icon, .file-node-content:hover .file-node-open-state{ visibility: visible; } .mac-seamless-mode #typora-sidebar { background-color: #fafafa; background-color: var(--side-bar-bg-color); } .md-lang { color: #b4654d; } /*.html-for-mac { --item-hover-bg-color: #E6F0FE; }*/ #md-notification .btn { border: 0; } .dropdown-menu .divider { border-color: #e5e5e5; opacity: 0.4; } .ty-preferences .window-content { background-color: #fafafa; } .ty-preferences .nav-group-item.active { color: white; background: #999; } .menu-item-container a.menu-style-btn { background-color: #f5f8fa; background-image: linear-gradient( 180deg , hsla(0, 0%, 100%, 0.8), hsla(0, 0%, 100%, 0)); } :root {--mermaid-font-zoom:1em ;} @media print { @page {margin: 0 0 0 0;} body.typora-export {padding-left: 0; padding-right: 0;} #write {padding:0;}} 目录 技术概要:InterSystems API 管理器InterSystems API管理器是如何工作的?试一试!在 InterSystems IRIS 中设置 REST API 在 IAM 中为您的 REST API 创建服务在 IAM 中创建路由 从 REST 客户端调用您的 API添加速率限制插件添加您的 REST 规范到 IAM了解有关 InterSystems API Manager 的更多信息 技术概要:InterSystems API 管理器 本文档将向您介绍InterSystems API管理器(InterSystems API Manager ,IAM),解释了它的工作原理,并让您开始在自己的实例上探索它的功能。 InterSystems API管理器是如何工作的? InterSystems API管理器是 InterSystems IRIS®数据平台的一个组件,它允许您利用由 InterSystems IRIS 应用程序暴露或消费的微服务和 API。作为 InterSystems IRIS的 服务器和应用程序之间的 API 网关(gateway),API 管理器使您能够更有效地监视和控制服务器端 API 和客户端应用程序之间的调用流量。 要了解有关 InterSystems API管理器的更多信息,您可以观看这个概述视频。 试一试! InterSystems API管理器(InterSystems API Manager ,IAM)是与 InterSystems IRIS 实例分开安装的。要获得自己的 IAM 安装包,您可以从 InterSystems WRC 软件分发(Software Distribution)网站下载 ,或者联系您的 InterSystems 销售工程师。安装包包括一个脚本(iam-setup),用于设置 IAM 并将它与您的 InterSystems IRIS 实例连接。 这个练习假定您有 InterSystems IRIS 和 IAM 的实例,并且已经运行了安装脚本来连接它们。本练习使用 IAM 2.3 版本进行展示。 在 InterSystems IRIS 中设置 REST API 从位于 https://github.com/intersystems/FirstLook-IAM 的 GitHub 存储库中,将以下内容导入 InterSystems IRIS: /cls/cmAPI 包括使用 API 管理服务生成的三个类文件,以及一个coffeemaker对象定义: impl.cls disp.cls spec.cls coffeemaker.cls 要导入,请打开 InterSystems IRIS 管理门户(Management Portal),并导航到 Classes 页面(System Explorer(系统资源管理器) > Classes(类));如果您不在 USER 命名空间中,请使用左边的选择器来更改为它,如下图所示: 选择上面列出的四个类并点击 Import(导入)。这将 REST API 导入 InterSystems IRIS,同时导入相应的类,应用程序将使用这些类访问存储在数据库中的coffermakers集合。 /gbl/coffeemakers.gof。 通过进入管理门户(Management Portal),并点击 System Explorer(系统资源管理器)> Globals > Import(导入)来导入。查找 coffeemakers.gof。导入到 User.cmAPI.coffeemaker 模式。 接下来,设置一个 Web 应用程序(Web Application),指向您刚刚导入的 REST 类。Web 应用程序层为自定义和安全提供了额外的机会。在管理门户(Management Portal)中,选择 System Administration(系统管理) > Security(安全) > Applications(应用程序)> Web Applications(Web 应用程序)。点击 Create New Web Application(新建Web 应用程序) 并填写以下设置: Name(名称): /rest/coffeemakerapp Namespace(命名空间): USER Enable Application(启用应用程序):选中此复选框 Enable(启用):选择 REST Dispatch Class(分派类): cmAPI.disp 安全设置 - Allowed Authentication Methods(允许的身份认证方法): Unauthenticated ,Password 在 IAM 中为您的 REST API 创建服务 正如您在 IAM 概述视频中所看到的,在 IAM 工作流中,有三个主要组件在发挥作用------消费者(Consumers)、路由(Route)和服务(Service)。IAM 中的服务是为您存在于 InterSystems IRIS 中的 API 创建的。在这种情况下,我们将为您的coffeemaker API 创建一个服务。 您从 WRC 下载的 IAM 包还包括一个脚本(iam-test),用于设置示例服务和路由。如果您运行了这个脚本,您将能够查看 test-iris 服务。 我们将取得类似的结果,使用 IAM 门户添加您的Coffeemakers服务。 iam-setup.sh是用来启动 IAM 的,可以通过输入iam-setup.sh 脚本中指定的门户的 URL 来启动 IAM 管理门户(management portal)。默认情况下,URL 是: http://localhost:8002 选择 default Workspace(默认工作区)。如果默认工作区不可见,而且管理门户(Management Portal)似乎是空的,那么可能是您没有输入 iam-setup.sh 定义的确切 URL。 选择 API Gateway(API 网关) 中的 Services(服务),并选择 New Service(新的服务)。请按以下方式填写表格: Name(名称): 咖啡机服务(CoffeemakerService) 选择 Add using Protocol, Host and Path(添加使用协议、主机和路径) Protocol(协议): http Host(主机):[插入您的 InterSystems IRIS 实例的 IP 地址。为避免 DNS 问题,使用 IP 地址的数字形式。] Path(路径): /rest/coffeemakerapp Port(端口): [插入您的实例的 webserver 端口,默认为 52773,或者如果实例是在容器中,您已经映射到 web 服务器(webserver) 端口的主机端口] 不要选择"查看 6 个高级字段(View 6 Advanced Fields)"。 选择 Create(创建)。 一旦创建了服务,您就可以查看服务,并需要创建路由。 在 IAM 中创建路由 当您在查看服务时,选择 "添加路由(Add a Route)"。请按以下方式填写表格: Sevice(服务):此字段已正确地用服务的十六进制的 ID 初始化。 Name(名称): 可以留空 Protocols(协议):http Hosts(主机): 可以留空 Methods(方法):GET、POST、PUT、DELETE Paths(路径):select(选择) "+添加路径(Add Path)"并输入 /rest/coffeemakerapp Headers(标题): 可以留空 HTTPS Redirect Status Code(HTTPS 重定向状态代码): 426(这是默认值) Tags(标签): 可以留空 不要选择 "查看 4 个高级字段(View 4 Advanced Fields)"。 选择 Create(创建)。 一旦创建了路由,您将通过从 REST 客户端进行简单的 API 调用来测试您的路由和服务。 从 REST 客户端调用您的 API 使用 REST 客户端------可以使用Postman 或来自 Google Chrome 的高级 REST 客户端(Advanced REST Client)------在 InterSystems IRIS 中对您的咖啡机(Coffeemakers) API 进行一个简单的 API 调用。要做到这一点,创建一个请求 URL,其中包括您的 IAM 实例的 IP 地址和端口号,以及您的服务的路径和请求的端点。请务必使用用户名和密码授权您的请求。下面是一个示例;注意,默认情况下,IAM 处理 8000 端口上的代理请求。例如: POST http://localhost:8000/rest/coffeemakerapp/coffeemakers 一旦您成功地进行了调用,您可以导航回您的 IAM 仪表板(Dashboard),查看来自所进行的调用的统计数据和其他信息。从这个仪表板上,您可以看到许多不同的信息集,这些信息将帮助您监控和控制客户端应用程序和 InterSystems IRIS 内的服务之间的流量。 添加速率限制插件 有效地监测您的 API 流量是有益的,但仅限于使用该信息适当地控制和优化流量。IAM 使您能够使用一些不同的插件来提高您控制客户端和 API 之间流量的能力。 在 IAM 管理门户(Management Portal)中,选择 API Gateway(API 网关) 中的 Plugins(插件) ,并选择 New Plugin(新的插件)。在 Traffic Control(流量控制) 类别中,找到 Rate Limiting(速率限制) 插件,并选择 Enable(启用)。 在这个插件的配置屏幕上: 选择 Scoped(范围)。 在 Service(服务) 中选择咖啡机服务(CoffeeMakerService)。 试一试! 其他大部分字段保留它们的默认值,但将 Config.Limit By 设置为服务(Service),将 Config.Minute 设置为 5。 这将限制所有消费者每分钟只能调用 5 次服务中所有路由。 选择 Create(创建)。 您可以通过返回 REST 客户端并进行示例调用来测试这个速率限制插件。客户端超过限制后,它将得到一个 429 返回错误,并带有"超过 API 速率限制"的信息 添加您的 REST 规范到 IAM REST 开发的最佳实践方法是规范优先,因此很可能您已经有了自己的 REST 规范。对于这个练习,您可以使用您从 github 下载 FirstLook-IAM 存储库时,spec 目录下的 swagger_100419.json 文件。您也可以直接从 GitHub 存储库的 spec 文件夹中下载 JSON 规范。 https://github.com/intersystems/FirstLook-IAM/blob/master/spec/swagger_100419.json 注意: 有关记录和管理 REST API 规范的更多信息,请参见 Creating REST Services(《创建 REST 服务》)中的 Discovering and Documenting REST APIs(发现和记录 REST API)。 一旦下载,您就能将您的规范添加到 IAM 中: 从 IAM 管理门户(management portal),选择 Workspaces(工作区) 标签并选择默认工作区。 为咖啡机服务(CoffeemakerService)服务选择 View(查看)。 在 Documents(文档) 区域(面板的底部)选择 Add a document(添加一个文档)到这个服务。 点击下面的文件选择器文本框 Or upload a new spec instead...(或者上传一个新的规范代替...) ,然后选择您下载的 swagger_100419.json 文件。 您现在可以查看咖啡机服务(CoffeemakerService)的 OpenAPI 规范。外部开发者也可以访问这个规范,这允许他们开发对它的 REST 调用。由于 curl 命令没有指定正确的服务,所以 "试一试(Try it Out)"选项将无法工作。 了解有关 InterSystems API管理器 的更多信息 注意: 如果没有设置默认的开发门户(dev portal),选择 Set up Dev Portal(设置开发门户)。如果默认的开发门户(Dev Portal)被禁用,选择 Enable Developer Portal(启用开发门户)。它可能需要几分钟的时间来设置。 了解有关 InterSystems API Manager 的更多信息 InterSystems 提供了一些参考资料来了解有关 IAM 的更多信息: API Manager Introduction(《API Manager 介绍》) (演示) What is InterSystems API管理器?(《什么是 InterSystems API管理器?》)(视频) IAM Guide(《IAM 指南》) (文档) 如果您想了解有关如何开发咖啡机服务(CoffeemakerService) REST 服务的更多详细信息,请参见 《技术概要:在 InterSystems 产品中开发 REST 接口》。
文章
Nicky Zhu · 九月 22, 2021

IRIS 2021 技术文档 First Look 2--InterSystems IRIS基础知识:安装

1 安装基础知识:目的 本指南可帮助您成功在桌面或虚拟机上运行一个经授权许可的 InterSystems IRIS®。适用于我们在技术概要 (First Look)操作指南里所提及的技术。我们提供的说明包括64位 Windows 10, Red Hat 企业版Linux7,以及Apple macOS10.13. 注: InterSystems 云管理器(ICM)提供了一种简单、直观的方法来配置云或虚拟基础架构,用户可在该基 础架构上部署所需的 InterSystems IRIS架构以及其他服务。 请勿使用本指南安装生产实例或任何自定义安装配置;如需帮助,请参阅InterSystems Cloud Manager Guide(《InterSystems 云管理器指南》)或Installation Guide(《安装指南》)。 2 用前须知 在开始安装 InterSystems IRIS之前,请确保:• 计算机上的完整管理员权限或sudo权限。• 访问InterSystems IRIS的单文件的可执行安装文件(Windows)或工具包(Linux和macOS)。 • 在IRIS可访问的文件夹下存放有效的许可证密钥文件,通常命名为iris.key。 您正在使用的技术概要(First Look)中对安装有特定要求;例如,可能需要“正常”安全性。在遵循以下说 明之前,请务必查看技术概要中“用前须知”章节。 注: 安装了 InterSystems 的IRIS之后,您可以在InterSystems IRIS Basics: Connecting an IDE (《InterSystems IRIS基础:连接一个IDE》)中,查找介绍如何将一个IDE连接到InterSystems IRIS上的实例过程。 3 在Windows10系统安装 InterSystems IRIS 要在Windows10上安装 InterSystems IRIS: 在Windows资源管理器中,右键单击 InterSystems IRIS安装可执行文件,然后选择“Run as administrator(以管理员身份运行)”。在生成的Windows用户帐户控制对话框中,选择“YES”。 如果出现“Select instance(选择实例)”对话框,请选择“New Instance(新建实例)”。 勾选接受许可协议,然后单击“Next(下一步)”。 在“InterSystems IRIS Instance Name(InterSystems IRIS实例名称)”对话框中为你的实例起 名,InterSystems IRIS实例名称仅可使用字母数字字符和下划线。然后单击“Next(下一步)”。 如果目标文件夹显示可安装,请单击“Next(下一步)”。如不可安装,请单击“Change(更改)”以选 择其他文件夹。请使用计算机上的文件夹,而不是映射的网络驱动器。 在“Setup Type(安装类型)”对话框中,接受默认的Development,然后单击“Next(下一步)”。 在“Initial Security Settings(初始安全设置)”对话框中,选择技术概要(First Look)中所推荐的 安全类型。通常应选用Normal(正常)类型。如未找到推荐的安全类型,请使用Minimal(最小值),然后 单击“Next(下一步)”。 (仅限正常和锁定安全类型)在“Enter Credentials(输入凭据)”对话框中,选择在defined Username account(定义的用户名账号)下运行InterSystems IRIS,确认Windows用户名和域名正确,并输入 Windows密码。然后单击“Next(下一步)”。 (仅限正常和锁定安全类型)在InterSystems IRIS Users configuration(InterSystems IRIS用户配 置)对话框中,输入并再次确认8-32个字符的密码(允许使用字母数字和标点符号)。请注意此密码将在 登录InterSystems IRIS主要管理工具(management tools)时使用。然后单击“Next(下一步)”。 (仅限正常和锁定安全类型)输入CSPSystem Account的密码时(Enter password for CSPSystem account),请输入并再次确认8-32个字符的密码(允许使用字母数字和标点符号)。请记住此密码。然后 单击“Next(下一步)”。 在“Ready to Install the Program(准备安装程序)”对话框中,单击“License(许可证)”,然后选 择许可证密钥文件。然后单击“Install(安装)”,此安装过程需要几分钟时间。 要访问新安装,请右键单击上箭头 4 在Linux系统安装 InterSystems IRIS 在Linux系统上安装 InterSystems IRIS须知: 在Linux中创建一个组,并添加您的用户账号。 提取安装文件。 跳转至安装文件。 运行命令“sudo ./irisinstall”,它将出现一系列提示 如果系统提示您要输入平台的编号,请输入为Red Hat Enterprise Linux列出的编号。 “Enter instance name(输入实例名称)”,请输入用户名。仅使用字母数字字符和下划线。 按Enter键确认名称。 “Enter a destination directory for the new instance(为新实例输入目标目录)”,请输入 InterSystems IRIS系统文件的目录名称,您的计算机上不存在目录,不要使用符号链接 (symlink)。 按Enter确认需要创建的新目录(或使用输入的现有目录)。 “Setup type<1>(安装程序类型<1>)”,按Enter键接受默认安装类型(Development)。 “Initial Security settings(初始安全设置)”,请输入技术概要(First Look)中所推荐的安全 类型的编号,通常应选择Normal(正常)类型。如果没有,请按Enter接受默认值1(Minimal)。 (仅限正常和锁定安全类型)“Which user should be the owner of this instance?(本实例的用户 是?)”请输入您的用户账户名称。 (仅限正常和锁定安全类型)“Please enter the common password for _SYSTEM...(请输入 _SYSTEM...的通用密码)”,输入(然后再次确认)8-32个字符的密码(允许使用字母数字和标点符 号)。请注意此密码,因为您将在登录到InterSystems IRIS主要管理工具(management tools)时使 用此密码。 (仅限正常和锁定安全类型)“Please enter the common password for CSPSystem...(请输入 CSPSystem...的通用密码)”,输入(然后再次确认)8-32个字符的密码(允许使用字母数字和标点 符号)。请记住此密码。 “What group should be allowed to start and stop this instance?(应该允许哪个组启动和停 止此实例?)”请输入您在上面的步骤1中创建的组的名称。 “Do you want to enter a license key(您是否需要输入一个license key?)”输入y,然后输入许 可证密钥的完整路径名(例如, /home/user/iris/iris.key)。 该脚本会显示您在继续之前选择的安装选项。按Enter键选择继续安装。 请注意安装结束时显示的URL:它是管理门户(Management Portal)的URL,也是 InterSystems IRIS的系 统管理用户界面。 要检查新安装实例的状态并查看其他信息,请在Linux命令行下输入“iris list”查看实例列表。 5 在macOS系统安装InterSystems IRIS 要使用bashshell在macOS上安装 InterSystems IRIS: 在macOS中创建一个组,并添加您的用户账户。 提取安装文件。 跳转至安装文件。 运行命令“sudo ./irisinstall”,它将出现一系列提示。 如果系统提示您要输入平台的编号,请输入macOS列出的编号。 “Enter instance name(输入实例名称)”,请输入用户名。仅使用字母数字字符和下划线。 按Enter键确认实例名称。 “Enter a destination directory for the new instance(为新实例输入目标目录)”请输入 InterSystems IRIS系统文件的目录名称,您的计算机上不存在目录,不要使用符号链接 (symlink)。 按Enter确认需要创建的新目录(或使用输入的现有目录)。 “Setup type<1>(安装程序类型<1>)”,按Enter键接受默认安装类型(Development)。 “Initial Security settings(初始安全设置)”,请输入技术概要(First Look)中所推荐的安全 类型的编号。通常应选择Normal(正常)安全类型。如果没有,请按Enter接受默认值1(Minimal)。 (仅限正常和锁定安全)“Which user should be the owner of this instance?(本实例的用户 是?)”请输入您的用户账户名称。 (仅限正常和锁定安全类型)“Please enter the common password for _SYSTEM...(请输入 _SYSTEM...的通用密码)”,输入(然后再次确认)密码(包含字母和数字)。请注意此密码,因为 您将在登录到主要InterSystems IRIS管理工具(management tools)时使用此密码。 (仅限正常和锁定安全类型)“Please enter the common password for CSPSystem...(请输入 CSPSystem...的通用密码)”,输入(然后再次确认)密码(包含字母和数字)。请记住此密码。 “What group should be allowed to start and stop this instance?(应该允许哪个组启动和停 止此实例?)”请输入您在上面的步骤1中创建的组的名称。 “Do you want to enter a license key(您是否需要输入一个license key?)”输入y,然后输入许 可证密钥的完整路径名(例如, /home/user/iris/iris.key)。 该脚本会显示您在继续之前选择的安装选项。按Enter键选择继续安装 请注意安装结束时显示的URL:它是管理门户(Management Portal)的URL,也是 InterSystems IRIS的系统管理用户界面。 要检查新安装实例的状态并查看其他信息,请进入 命令行并输入“iris list”查看实例列表。
文章
Louis Lu · 十一月 2, 2021

IRIS 2021 技术文档 First Look 30 -- 使用 InterSystems 产品进行文本分析

本技术概览( First Look )介绍了 InterSystems IRIS® 数据平台 支持使用 Natural Language Processing(NLP,自然语言处理 )文本分析的能力,NLP文本分析以各种自然语言对非结构化文本数据进行语义分析。能让您发现有关大量文本文档内容的有用信息,而无需事先了解文本内容。 本技术概览( First Look )介绍了 InterSystems IRIS Natural Language Processing(自然语言处理),并介绍了一些与索引文本数据相关的初始任务,以进行语义文本分析。完成这些任务后,您将对一组文本建立索引并执行分析,以确定这些文本中最常见的实体(entity)、关于这些实体的度量指标、实体之间的各种关联,以及查看实体在源文本的表现形式。这些活动仅设置使用默认设置和功能,以便您熟悉 NLP 文本分析的基础知识。有关Text Analytics(文本分析)的完整文档,请参阅InterSystems IRIS Natural Language Processing (NLP) Guide (《InterSystems IRIS 自然语言处理 (NLP) 指南》)。 处理非结构化文本的一个相关但独立的工具是InterSystems IRIS SQL Search。SQL Search允许您search(搜索)这些相同的实体,以及多个文本中的单个单词、正则表达式(regular expression)和其他结构。本质上,搜索解决方案的前提是您知道自己要寻找的目标。NLP 文本分析旨在帮助您发现内容和内容实体之间的联系,而无需明确要寻找的目标。 要浏览技术概要(First Look)的所有内容,包括可以在InterSystems IRIS的免费评估实例上执行的许多内容 , 请参阅InterSystems First Looks (《InterSystems 技术概要》)。 为什么 NLP 文本分析很重要 企业逐渐累积的越来越多的非结构化文本数据,远远超出了他们阅读或记载这些文本的能力。通常,企业可能对这些文本文档的内容知之甚少。基于纯search(搜索)技术传统的“自上而下”文本分析,对这些文本的内容做出假设,可能会遗漏重要内容。 InterSystems IRIS Natural Language Processing (NLP)可以在预先不了解这些文本的主题的情况下,对这些文本进行文本分析。它通过应用识别语义实体的特定语言规则来实现这项功能。由于这些规则是专门针对语言而非内容,因此 NLP 可以在不使用字典或本体的情况下提供对文本内容的深入分析。 InterSystems IRIS 如何实施 NLP 文本分析 要为 NLP 分析准备文本,您必须将这些文本加载到domain(域)中,然后构建域。基于对这些文本的分析,NLP为该域构建索引, NLP可以使用域快速分析大量文本。文本可以从各种数据位置输入,包括 SQL 表、文本文件、strings(字符串)、globals 和 RSS 数据。 NLP 支持以下功能: Language models(语言模型):识别单词之间的语义关系是专门针对语言的。NLP 包含十种自然语言的语义规则(语言模型),可以分析用该语言编写的任何主题的文本。如果指定的语言不止一种,NLP 通过确定每个文本中的每个句子与指定语言之间的最佳匹配来执行自动语言识别。NLP 分析不需要预先创建或关联字典或本体,尽管您可以通过添加它们来扩展其功能。 Entity analysis(实体分析):一个或多个单词的语义群,被称为实体,NLP对其进行操作。实体被定义为Concepts(包括名词和名词短语)或Relations(包括动词和介词)。通常,要考虑的最相关实体是Concepts,但也可以分析Relations。句子和单词始终泾渭分明。忽略字母大小写。 Path analysis(路径分析):NLP 将Concepts和Relations的连贯序列分组为Paths。一个句子通常由一个单独的 Path 组成。Path 反映了实体之间的联系。 Attributes(属性):NLP 标记语义属性,例如否定,以便您可以区分肯定的文本序列(“结构损坏的证据”)和否定的文本序列(“没有结构损坏的证据”)。 Frequency、Spread 和 Dominance:这些是为实体计算的度量指标。Frequency是实体在一组文本中出现的次数。Spread是包含该实体的文本数。Dominance 是一个更细微的指标,通过将实体重复出现次数相对于每个文本的长度、具有共同单词的其他实体的重复出现次数以及其他因素考虑在内,形成该指标。实体通常按这些指标按降序排列。通过这些指标可以了解文本内容,您能更加深入地分析特定实体。 Similar Entities、 Related Concepts 和 Proximity Profile。给定一个实体,这些功能可以发现其他相关实体。例如,给定一个简短的实体,相似的实体将包括域中包含相同词的其他更长的实体,从而是比种子实体更具体的实体。给定一个实体,相关实体是同一句子中通过单个Relation与指定实体相关联的其他实体。给定一个实体,Proximity 指标度量计算指定实体与其他实体之间在路径内的距离。 Dictionaries(字典):您可以添加可选的字典来识别实体的同义词。 Summarization(摘要):您可以使用 NLP 生成文本摘要,要求摘要按整体文本的一定百分比生成。例如,50% 的摘要将包含原始文本中一半的句子,NLP 会选择那些被计算为与整个源文本最相关的句子。 亲自尝试 NLP 文本分析 使用 InterSystems IRIS 文本分析很容易。这个简单的程序将引导您按基本步骤生成NLP 度量指标。 提供此示例是为了让您初步体验InterSystems IRIS Natural Language Processing。不应将此示例用作开发实际应用程序的基础。如要在真实情况下使用 NLP,您应该充分研究该软件提供的可用选项,然后开发您的应用程序以生成稳健且高效的代码。 用前须知 要使用该程序,您需要一个正在运行的 InterSystems IRIS 实例。您的选择包括多种类型的已授权的和免费的评估实例;该实例不需要在您工作的系统中(尽管它们必须相互具有网络访问权限)。如果您还没有一个可以使用的实例,如何部署每种类型实例的有关信息,请参阅InterSystems IRIS Basics: Connecting an IDE(《INTERSYSTEMS IRIS 基础:连接一个IDE》)中的Deploying InterSystems IRIS(部署 InterSystems IRIS)。 您还需要获取 Aviation.Event SQL 表,该表可在 GitHub 上找到,网址为https://github.com/intersystems/Sam-ples-Aviation。按照First Look: SQL Search with InterSystems Products(《技术概览:使用 InterSystems 产品进行 SQL 搜索》)中的Downloading and Setting up the Sample Files(下载和设置示例文件)提供的说明下载和设置文件 创建域并添加数据位置 所有 NLP 分析都发生在一个域内。将多个文本关联到一个域。然后构建域,创建 NLP 查询使用的索引。 域是在namespace(命名空间)中创建的,例如在上一节中按照First Look: SQL Search with InterSystems Products(《技术概览:使用 InterSystems 产品进行 SQL 搜索》)的过程,创建的SAMPLES命名空间。可以在一个命名空间内创建多个域。可以将一个文本与多个域进行关联。 有多种方法可以创建、填充和构建域。以下示例使用Domain Architect界面。 在浏览器(browser)中为实例打开 Management Portal (管理门户),使用 InterSystems IRIS Basics: Connecting an IDE(《INTERSYSTEMS IRIS 基础:连接一个IDE 》)的URL described for your instance(实例适用的URL)。 导航到 Domain Architect 页面(Analytics > Text Analytics > Domain Architect)。使用Analytics选项之前,可能需要切换到启用分析功能的SAMPLES命名空间。 点击 New (新建)按钮定义域。指定以下域值(按给定的顺序): Domain name:分配给域的名称在当前命名空间必须是唯一的(不仅仅是在其package class(包类)中唯一);域名不区分大小写。本示例指定名称为 MyTest。 Definition class name:域定义 package name (包名)和 class name(类名),用句号分隔。从 Domain name字段按 Tab 键生成默认Definition class name:Samples.MyTest 。 Allow Custom Updates:此复选框允许手动将数据或字典添加到此域。本示例请勿选中此框。 点击 Finish(结束) 按钮来创建域。在屏幕中将显示 Model Elements 选项。 在域内,可以为域定义数据位置和其他模型元素。要添加或修改模型元素,请单击标题之一旁边的扩展三角形。一开始,没有扩展三角形出现。定义一些模型元素后,单击扩展三角形会显示您定义的模型元素。 点击 Data Locations 三角形以在屏幕右侧显示 Details 选项卡。Details选项卡显示五个 Add Data 选项。选择 Add data from table。 此选项允许您指定存储在 SQL 表中的数据。在本例中,我们将指定以下字段: Name:提取的数据文件集的名称。使用默认值:Table_1。 Schema:从下拉列表中选择 Aviation。 Table Name:从下拉列表中选择 Event。 ID Field:从下拉列表中选择 ID。 Data Field:从下拉列表中选择 NarrativeFull。 如果当前域定义有未保存的更改,Domain Architect 页面标题后跟一个星号 (*)。点击 Save (保存)保存更改。 按 Compile(编译) 按钮,编译 Domain。 按 Build 按钮,为源数据构建NLP索引。 分析数据 使用以下过程分析数据: 在 Domain Architect 页面上,选择屏幕右侧的 Tools 选项卡,然后单击 Domain Explorer 按钮。 Domain Explorer 最初显示源文本中最重要概念的列表: frequency选项卡按频率降序显示Top Concepts。每个列出的项目都列示其频度计数(出现次数)和分布计数(包含该概念的源数量)。 例如, pilot概念的重复出现次数为6206,分布计数为1085;student pilot概念的重复出现次数为 319,分布计数为 141。 dominance选项卡按 dominance 计算结果,降序显示Dominant Concepts。 例如,pilot概念拥有 351.6008 的dominance;student pilot概念拥有 49.3625 的dominance。 当您选择上述其中一项概念,将显示该概念的另一个Domain Explorer列表: Similar Entities 列出所选概念以及包含该概念的所有其他概念,每个概念都有其重复出现次数和分布计数。 例如,选择student pilot,Similar Entities 将显示包括student pilot, student pilot certificate, student pilot's logbook, solo student pilot在内的列表。 Related Concepts 列出与所选概念相关的其他概念,以及在上下文语境中该实例的这些概念的重复出现次数和分布技术。 例如,选择student pilot,Related Concepts 将显示包括flight instructor和airplane在内的列表。 Proximity Profile 列出所选概念相邻的其他概念,以及当发现在相同的句子中有与所选概念相同的概念,将计算这些概念的实例的相邻程度。 例如,选择student pilot,Proximity Profile 将列示 airplane的相邻程度为 2702,以及flight instructor的相邻程度为 1662 。 在上述任一列表中的选择一个概念,这些列表将根据该概念进行刷新。或者,您也可以将实体(Concept或Relation)键入到 Domain Explorer Explore 区域并单击 Explore! 按钮。 通过使用这些列表,可以确定源文档中出现哪些概念、它们的重要性以及与它们相关联的其他概念。 Domain Explorer 的下部分允许您查看所选概念在源文本中的显示方式: Sources 选项卡按来源列出包含所选概念的所有句子。该概念被高亮显示,红色文本用于表示涉及该概念的否定。 Paths 选项卡列出了包含所选概念的所有路径。路径文本被突出显示,以显示 NLP 索引:所选概念以橙色高亮显示,路径中的其他概念以蓝色高亮显示,与路径相关的概念(通常是代词)以浅蓝色高亮显示。关系显示为白色。红色文本用于表示涉及该概念的否定。 通过点击 eye 图标,可以显示源的完整文本,所选概念将被高亮显示,并使用红色文本表示否定。 Indexing 切换按钮显示源的完整文本,高亮显示 NLP 索引。因为这是源文本,所以会显示大小写、标点符号和不相关的单词;文本的这些方面没有显示在Paths列表中。 % 选项允许您显示文本摘要。指定一个百分比。文本中的句子总数减少到该百分比。NLP 包含在摘要中的句子由它们对全文的重要性计算确定 您可以添加一个 skiplist 来排除不需要的概念。通常,top concepts(上层概念)列表始于那些非常常见或在几乎没有什么有用信息的概念。这些可能是出现在所有来源中的词或短语(例如“accident report(事故报告)”或“conclusions(结论)”)、一般概念(例如“airplane(飞机)”或“pilot(飞行员)”),或与您所使用数据无关的概念(例如城市列表)。您可以使用 skiplist 避免显示这些概念。Skiplist 仅影响某些查询结果中概念的显示;它对概念的 NLP 索引没有影响。 在 Domain Architect 中单击 Open 按钮并选择 Samples >>,然后是 MyTest 打开现有域 Samples.MyTest。 点击 Skiplists 扩展三角形。将在屏幕右侧的 Details 选项卡显示 Add skiplist 按钮。点击 Add skiplist 以显示 Name 和 Entries 字段。接受 skiplist 的默认名称 (Skiplist_1)。在 Entries 框列示条目(概念),一行一个概念;条目不区分大小写。本例中列出如下概念:pilot(飞行员) student pilot(学生飞行员)、 co-pilot(副驾驶)、 passenger(乘客)、instructor(教官)、flight instructor(飞行教官)、certified flight instructor(认证飞行教官)。 Save(保存)和Compile(编译)域。(不需要使用 Build 功能去添加、修改或删除 skiplists 的域)。 在Domain Explorer中单击 sunglasses 右上角的图标。将显示您可以应用的为该域定义的skiplists的列表。选择Skiplist_1。请注意,Top Concepts 不再列出 skiplists 的概念。 了解有关 NLP 文本分析的更多信息 InterSystems 有其他相关资料可帮助您了解有关 NLP 文本分析的更多信息,包括: InterSystems IRIS Natural Language Processing (NLP) Guide(《InterSystems IRIS自然语言处理 (NLP) 指南》)
文章
Hao Ma · 十一月 2, 2021

IRIS 2021 技术文档 First Look 23 - 使用 InterSystems 分布式缓存扩展用户容量

本文档将向您介绍 InterSystems IRIS®数据平台如何通过使用应用服务器进行分布式缓存,利用企业缓存协议(Enterprise Cache Protocol,ECP)来扩展用户容量(User Volume)。本指南介绍了如何使用分布式缓存架构进行扩展,并介绍了与部署 InterSystems IRIS 分布式缓存集群相关的一些初始任务。一旦您完成了本指南,您将对分布式缓存集群的工作原理和设置方法有一个基本的了解。这些活动被设计成只使用默认的设置和功能,这样您就可以熟悉该功能的基本原理,而不必处理细节(尽管这些细节在执行实现时可能很重要)。有关使用 InterSystems IRIS 分布式缓存和 ECP 的完整文档,请参见本指南末尾 " For More Information (更多信息)" 部分中的参考资料列表。要浏览所有的技术概要(First Look),包括可以在 InterSystems IRIS 免费的评估实例上执行的那些,请参见 InterSystems First Looks(《InterSystems 技术概要》)。 1 问题:扩展用户容量(User Volume) 当用户通过应用程序连接到您的 InterSystems IRIS 数据库时,他们需要快速、有效地访问数据。无论您的企业是小型、大型,还是介于两者之间,对数据库的大量并发用户请求——用户容量(user volume)——都会在托管数据库的系统上造成性能问题。这可能会影响更多用户,使他们等待更长时间才能收到所需信息。在一个动态业务中,用户容量(User Volume)可能会迅速增长,从而进一步影响性能。特别是,如果很多用户在执行许多不同的查询,这些查询的大小会超过缓存,这意味着,它们不能再存储在内存中,而是需要从磁盘上读取数据。这种低效的过程会导致瓶颈和性能问题。您可以增加系统的内存和缓存大小(垂直扩展),但这种解决方案可能是昂贵的、不灵活的,并最终受限于硬件的最大功能。将用户的工作量分散到多个系统上(水平扩展)是一种更加灵活、高效和可扩展的解决方案。 2 解决方案:分布式缓存(Distributed Caching)为了提高用户访问数据的速度和效率,InterSystems IRIS 可以使用分布式缓存(Distributed Caching)。这种技术允许 InterSystems IRIS 在多个应用服务器(application server)上存储数据库缓存。然后,用户容量(User Volume)可以分布在这些服务器上,从而提高缓存效率。使之成为可能的节点间通信是由 ECP,即企业缓存协议(Enterprise Cache Protocol)启用的。使用分布式缓存(Distributed Caching),您可以让进行类似查询的用户共享一部分缓存,该缓存托管在应用服务器集群中,与托管数据的数据服务器一起。实际数据保留在数据服务器上,但缓存保留在应用服务器上,以加快用户访问。数据服务器负责保持企业中每台应用服务器上的缓存数据是最新的。 分布式缓存是如何工作的? 有了分布式缓存集群,您可以根据需要添加或删除应用服务器,轻松地扩展您的解决方案。所有的应用服务器都会自动维护自己与数据服务器的连接,并在连接中断时尝试恢复连接。您可以在单个集群实例上使用管理门户(Management Portal)配置应用服务器及其相关的数据服务器,或使用 InterSystems 云管理器(InterSystems Cloud Manager,ICM)部署和配置集群。有关 ICM 的更多信息 ,请参见 First Look:ICM(《技术概要:ICM》)和 InterSystems Cloud Manager Guide(《InterSystems 云管理器指南》)。 3 分布式缓存是如何工作的?当您部署一个 InterSystems IRIS 分布式缓存集群时,指定一个实例为数据服务器,指定一个或多个实例为应用服务器。这些实例不需要在相同的操作系统或硬件上运行,它们只需要符合 InterSystems IRIS 系统的要求。• 数据服务器的执行方式与标准的 InterSystems IRIS 服务器一样,在命名空间中托管数据库,并根据请求向其他系统提供数据。• 应用服务器接收来自应用程序的数据请求。当用户打开一个应用程序时,它不是连接到数据服务器,而是连接到应用服务器。用户不会注意到有什么不同。应用服务器从数据服务器获取必要的数据并提供给用户。• 应用服务器将数据存储在自己的缓存中,这样,下次任何用户请求相同的数据时,应用服务器不需要再次联系数据服务器就可以提供。• 数据服务器监控所有的应用服务器,以确保其缓存中的数据是最新的。数据服务器还处理整个系统的数据锁。• 如果应用服务器和数据服务器之间的连接丢失,应用服务器会自动尝试重新连接并恢复任何需要的数据。• 您可以设计您的应用程序,将进行类似查询的用户引导到同一个应用服务器。这样一来,用户可以共享一个包含他们最需要的数据的缓存。例如,在医疗保健设置中,您可能会让临床医生运行一组特定的查询,而前台工作人员使用相同的应用程序和相同的底层数据运行不同的查询;这些用户组可以在不同的应用服务器上分组。再比如,如果集群处理多个应用程序,每个应用程序的用户可以被引导到他们自己的应用服务器上,以获得最大的缓存效率。 4 亲自尝试分布式缓存使用 InterSystems IRIS 建立一个分布式缓存集群很容易。这个简单的程序将引导您完成在几个实例上配置 ECP 的基本步骤。注意: 为了让您体验分布式缓存,而又不至于在细节上陷入困境,我们保持了简单的探索;例如,我们让您尽可能多地使用默认设置。不过,当您把这个功能带到您的生产系统时,您可能需要以不同的方式配置一些设置(例如,安全设置)。本文档末尾提供的参考资料将为您提供更多细节。 亲自尝试分布式缓存4.1 用前须知在这个示例中,您将设置一个InterSystems IRIS 实例作为数据服务器,再设置两个实例作为应用服务器。这意味着您将总共需要三个实例。您对 InterSystems IRIS 的选择包括多种类型的已授权的实例;这些实例不需要由您正在工作的系统托管(尽管它们必须相互有网络访问权限)。关于如何部署每种类型的实例的信息(如果您还没有三个实例可以使用),请参见 InterSystems IRIS Basics: Connecting an IDE(《InterSystems IRIS 基础:连接一个 IDE》)中的 Deploying Licensed Instances(部署已授权的实例)。注意:InterSystems IRIS 数据平台(Data Platform)提供了几种自动部署分布式缓存集群的方法,这些集群在部署后可以完全运行;请参见 Scalability Guide(《可扩展性指南》)中的 Deploying a Distributed Cache Cluster Automatically(自动部署分布式缓存集群)。4.2 启用 ECP 服务器 首先,在三个实例上启用 ECP 服务器,如下所示:1. 使用 InterSystems IRIS Basics:Connecting an IDE(《InterSystems IRIS 基础:连接一个 IDE》)中URL described for your instance(为您的实例描述的 URL),在您的浏览器中打开实例的管理门户(Management Portal)。2. 进入 Services(服务器) 页面(System Administration(系统管理) > Security(安全) > Services(服务器))。3. 选择 %服务_ECP。在 Edit Service(编辑服务器)页面上,选择 Service Enabled(已启用的服务器)复选框,然后选择 Save(保存)。您现在已经在系统上启用了 ECP。只需要几个步骤就可以完成对数据服务器和两个应用服务器的设置。4.3 配置数据服务器 在将要成为您的数据服务器的系统上,只需要两个快速步骤就可以完成设置。首先,您需要将允许的应用服务器的数量从默认值增加一个。然后,您将创建一个新的数据库供应用服务器连接。当然,在生产环境中,您已经有一个正在使用的数据库。要完成数据服务器配置:1. 在管理门户(Management Portal)中,进入 ECP Settings(ECP 设置) 页面(System Administration(系统管理) > Configuration(配置) > Connectivity(连接) > ECP Settings(ECP 设置))。2. 在标有 This System as an ECP Data Server(本系统作为 ECP 数据服务器)的部分中,将 Maximum number of application servers(应用服务器的最大数量) 设置为 2。 选择 Save(保存)。3. 重新启动实例。 有关创建数据服务器和设置可用选项的更多细节,请参见 Scalability Guide(《可扩展性指南》)中 "Horizontally Scaling Systems for User Volume with InterSystems Distributed Caching(《使用 InterSystems 分布式缓存为用户容量水平扩展系统》)"一章中的 Preparing the Data Server(准备数据服务器)。要为这个练习创建一个新的数据库:1. 在管理门户(Management Portal)中,进入 Local Databases(本地数据库) 页面(System Administration(系统管理) > Configuration(配置) > System Configuration(系统配置) > Local Databases(本地数据库))。2. 选择 Create New Database(创建新的数据库)。3. 为新数据库输入一个名称。对这个练习来说,称它为 ECP。4. 选择 Next(下一步) ,然后 Finis(完成)。 您已经创建了新数据库,并且您的数据服务器也已经准备好了。 亲自尝试分布式缓存 在接下来的章节中,您将设置两个应用服务器,并配置它们使其能够与数据服务器进行通信。为此,您需要知道数据服务器的超级服务器端口号(superserver port number),如 InterSystems IRIS Basics:Connecting an IDE(《技术概要:连接一个 IDE》)中所述。 4.4 配置应用服务器 接下来,您将把另外两个实例设置为应用服务器。您将配置每个应用服务器以指向数据服务器,并在每个服务器上创建一个新的命名空间,映射到您在数据服务器上创建的数据库。请确保在每个应用服务器上执行以下两个程序。 4.4.1 设置应用服务器1. 登录管理门户(Management Portal),进入 ECP Settings(ECP 设置) 页面(System Administration(系统管理) > Configuration(配置) > Connectivity(连接) > ECP Settings(ECP 设置))。2. 选择 Data Servers(数据服务器) ,然后选择 Add Server(添加服务器)。3. 填写所需信息:• Server Name(服务器名称)——输入一个名称或标签来识别这个服务器。它不需要与实例名称或实例的主机名称相同。• Host DNS Name or IP Address(主机 DNS 名称或 IP 地址)——输入托管您在上一节配置的数据服务器实例所在系统的主机标识符。• IP Port(IP 端口)——输入数据服务器实例的超级服务器端口号(superserver port number)。 4. 选择 Save(保存)。您的数据服务器现在出现在列表中。应用服务器连接到数据服务器,验证连接可能需要一些时间。4.4.2 创建命名空间和远程数据库现在您已经将应用服务器连接到数据服务器,您需要在每个应用服务器上创建一个命名空间。这个命名空间将是应用服务器的本地命名空间,但它不是包含本地数据库,而是映射到远程数据库——也就是您在上一节创建的数据服务器上的 ECP 数据库。1. 在管理门户(Management Portal)中,进入 Namespaces(名称空间) 页面(System Administration(系统管理) > Configuration(配置) > System Configuration(系统配置)> Namespaces(命名空间))。2. 选择 Create New Namespace(创建新的命名空间)。3. 在 Name of the namespace(命名空间名称) 字段中,输入 ECPNS。4. 对于 The default database for Globals in this namespace is a(这个命名空间中的 Globals 的默认数据库是一个),选择 Remote Database(远程数据库)。然后选择 Create New Database...(创建新数据库...) 按钮。 这将打开 Create Remote Database(创建远程数据库)窗口。5. 填写所需信息:• Remote Server(远程服务器)——使用下拉菜单来选择您在前面的程序中给数据服务器的 Server Name(服务器名称)。• Remote Directory(远程目录)——在数据服务器上,选择包含 ECP 数据库的目录。• Database Name(数据库名称)——输入一个数据库的名称。这可以与它在数据服务器(本例中是 ECP)上的名称相同,也可以不同。 6. 选择 Finish(完成)。窗口关闭,您会返回到 New Namespace(新的命名空间) 页面。 您应该看到,您刚刚创建的数据库现在显示在 Select an existing database for Globals(为 Globals 选择一个现有的数据库) 字段中。 亲自尝试分布式缓存 7. 由于这个命名空间中的例程(Routines)的默认数据库是 a(The default database for Routines in this namespace is a),选择 Remote Database(远程数据库)。现在您应该能够从下拉菜单中选择您刚刚创建的新数据库。8. 清除 Enable namespace for interoperability productions(为互操作性产品启用命名空间) 复选框。9. 选择 Save(保存)。现在新的命名空间出现在列表中。 有关创建命名空间及其相关数据库的更多细节,请参见 System Administration Guide(《系统管理指南》)中 "Configuring InterSystems IRIS(《配置 InterSystems IRIS》)"一章中的 "Create/Modify a Namespace(创建/修改命名空间)"。有关背景信息,请参见 Orientation Guide for Server-Side Programming(《服务器端编程指导手册》)中的"Namespaces and Databases(命名空间和数据库)"。您已经完成了! 一旦您在每个应用服务器实例上执行了这两个程序,您就成功地创建了一个集群 ,这个集群有一个数据服务器和两个应用服务器。在下一节中,您将测试这些连接,以确保所有三个实例都能正确地相互通信。 4.5 测试设置 现在您已经启用了 ECP 服务器,并设置了两个应用服务器,其命名空间指向数据服务器上的数据库,现在是时候做一个快速测试了,以确保这三个系统相互之间的通信。为了达到这个目的,您将在一个应用服务器上设置一个简单的 global,然后在第二个应用服务器上读取并改变它。要了解有关 globals 的更多信息,请参见 Using Globals(《使用 Globals》)。1. 在一个应用服务器上,使用 InterSystems IRIS Basics:Connecting an IDE(《InterSystems IRIS 基础:连接一个 IDE》)中为您的实例描述的程序打开 InterSystems 终端(Terminal),并更改到您在上一节创建的命名空间。在这个示例中,命名空间被称为 ECPNS,因此您将执行以下操作:USER>set $namespace="ECPNS" ECPNS> 2. 创建一个 global,只需给它一个值即可: ECPNS> set ^MyGlobal = "My Value" 3. 在另一个应用服务器上,登录到终端(Terminal),并按照上面的描述更改到 ECPNS 命名空间。4. 写入 global 的值: ECPNS> write ^MyGlobal My Value 这表明两个应用服务器正在与数据服务器正常通信。您使用其中一个应用服务器来创建 global,但由于您是在包含远程数据库的命名空间中工作,global 实际上是在数据服务器上创建的。这就是为什么其他应用服务器可以读取它的原因。当然,这只是一个示例,但其机制是相同的,无论您是在终端(Terminal)上手动设置然后读取 global,还是有大量的用户通过十几台应用服务器在同一数据服务器前每秒发行数千个事务。ECP 将确保数据保持同步,并保证所有这些用户与系统交互的事务的一致性。5. 如果您愿意,可以在数据服务器实例上查看 global 作为最后检查。在管理门户(Management Portal)中,进入本地数据库(Local Databases)页面(System Administration(系统管理) > Configuration(配置) > System Configuration(系统配置) > Local Databases(本地数据库))。找到您的应用服务器所指向的数据库,并为该数据库选择 Globals。您应该会看到 MyGlobal 在列表中。 了解有关分布式缓存和 ECP 的更多信息 5 了解有关分布式缓存和 ECP 的更多信息 要了解有关使用 InterSystems IRIS 分布式缓存和 ECP 的更多信息,请参见以下参考资料:• Scalability Guide(《可扩展性指南》)的 "Horizontally Scaling Systems for User Volume with InterSystems Distributed Caching(《使用 InterSystems 分布式缓存为用户容量水平扩展系统》)"章节• Sample Mirroring Architecture and Network Configurations(《镜像架构和网络配置示例》)、Redirecting Application Connections Following Failover or Disaster Recovery(《故障转移或灾难恢复后重定向应用连接》)、Configuring Application Server Connections to a Mirror(《配置应用服务器到镜像的连接》),以及 High Availability Guide(《高可用性指南》)中"Mirroring(《镜像》)"章节中的其他分布式缓存和 ECP 相关章节
文章
Hao Ma · 十一月 2, 2021

IRIS 2021 技术文档 First Look 28 - InterSystems 公钥基础设施 (PKI)

本文档介绍了 InterSystems 公钥基础设施(PKI),它可以在开发组织的安全策略中发挥重要作用。它提供有关公钥加密、证书颁发机构和 PKI 的信息。然后介绍一些与使用 InterSystems PKI 相关的初始任务。完成本指南后,您将有能力创建一个证书颁发机构 (CA),然后向 CA 客户端请求并接收证书。 虽然 InterSystems PKI 不用于生产系统,但您可以用它来熟悉 PKI 工具和安全基础设施。作为设计和探索过程的一部分,这对于创建全面的安全方法特别有帮助。本指南使用 InterSystems IRIS®数据平台的默认设置,这使您能够熟悉 PKI 的基本原理,而不必处理其他在执行实现时很重要的细节问题。有关数据库加密的完整文档,请参见 The InterSystems Public Key Infrastructure(《 InterSystems 公钥基础设施》)。要浏览所有的技术概要(First Look),包括可以在 InterSystems IRIS 免费的评估实例上执行的那些,请参见 InterSystems First Looks(《InterSystems 技术概要》)。 1 为什么 PKI 很重要 在许多企业中,关于安全漏洞的新闻频繁出现,这表明有必要保护他们的通信安全。企业需要保护从一个站点到另一个站点的数据,或者当需要某种可验证的、具有法律约束力的数字签名时。解决这些和其他需求的强大、有效和普遍的工具是公钥加密(public-key cryptography)和公钥基础设施(PKI)。公钥加密(Public-key cryptography)能够对数据进行加密和解密。这提供了一种执行与保护数据相关的各种操作的方法。这包括保护在不安全的网络(如 Internet)上传输的数据或确定文档的来源。因此,它启用了关键技术,如传输层安全(Transport Layer Security,TLS),这是浏览器保护我们与网站连接的手段。公钥加密(Public-key cryptography)对不同实体控制的数据进行操作,这些实体可以是人、应用程序、组织等。但是,仅公钥加密(Public-key cryptography)并不能为这些实体在活动中的身份提供足够的信心,特别是在它们彼此不认识的情况下。为了达到这种信任水平,需要有一个更大的结构,同时为所涉及的实体提供值得信赖和可验证的标识信息。这样一个结构被称为 PKI(公钥基础设施)。PKI 为实体建立了一种对彼此的身份有信心的方法,即使彼此没有任何直接的个人了解或接触。这要求每个实体信任第三方——证书颁发机构(CA)——为其他实体(也称为其他对等方)的身份提供担保。通过 PKI,实体可以进行有意义的、具有法律约束力的加密操作,其中包括加密、解密、数字签名和签名验证。InterSystems 提供了一个公钥基础设施(PKI),它使用 InterSystems IRIS 的实例作为 CA,允许您创建密钥对,并允许您创建与这些密钥对有关的证书。InterSystems CA 适合在组织内部和非生产环境中使用。不建议将其作为生产或商业 CA 使用;虽然它的证书在加密上是可靠的,但商业 CA 除了技术基础设施外,还需要一定程度的组织和法律基础设施。 为什么 PKI 很重要 使用 PKI 的公钥加密支持许多的安全活动:• 对电子文档进行数字签名• 验证电子文档的签名• 加密各方之间的通信• 加密文档 1.1 公钥加密和证书颁发机构(CA)如何协同工作的基本原理在使用公钥加密时,每个实体都有一个严格保密的私钥(private key),以及一个广泛使用的公钥(public key)。如果您使用其中一个密钥执行一个操作,您可以使用另一个密钥执行互补的操作;例如,如果您用私钥加密数据,那么只有您的公钥可以解密该数据。如果别人用您的公钥对内容进行加密,只有您的私钥——因此也只有您——能够解密。这意味着公钥加密为两个实体之间的安全和私人通信提供了一种方法。为了使公钥加密在互不相识且不能轻易验证对方身份的实体之间发挥作用,需要有一个双方实体都信任的第三方。这个第三方是证书颁发机构(CA)。证书颁发机构创建证书,这些证书是将公钥绑定到公钥持有者的一组标识信息的数字文档。由于公钥和私钥不可分割地相互绑定,证书也将标识信息绑定到私钥上。一些企业有内部的 CA,它们用来支持内部活动;其他 CA 作为独立的组织运作,通常作为商业服务提供证书。商业 CA 通常在不同程度的身份验证基础上提供证书;在充分验证的情况下,证书可以在组织或个人和公私密钥对之间建立起具有法律约束力的联系。CA 的使用使处于不安全环境中的实体有足够的信心以有意义的和具有法律约束力的方式使用公钥加密。互相通信的实体不需要使用相同的 CA。相反,每一个人只需要信任对方的 CA。这种信任 CA 的关系通常是在没有任何用户干预的情况下建立的,例如让浏览器附带一组预先批准的 CA 证书。事实上,一个实体可以信任一个 CA,因为它有第二个 CA 的证书,而这个 CA 已经被信任了;在这种情况下,第一个 CA 被称为中间 CA ——而且可以有多个中间 CA。当一个实体从一个 CA 获得证书时,会发生许多事情——经常对用户不可见。首先,CA 客户端使用算法来生成密钥对;然后 CA 客户端获得必要的信息来描述使用该密钥对的实体,这与实体的位置、组织等有关。总的来说,这个标识信息包括一个专有名称(distinguished name,DN)。该实体以证书签名请求(certificate signing request,CSR)的形式向 CA 提供公钥和 DN 信息;它不提供私钥,因为这是严格保密的。CA 收到 CSR,然后根据其程序进行处理。然后,CA 签署一份文档,将公钥绑定到 DN 信息,从而创建一个证书(具体来说,就是符合 X.509 标准的证书)。最后,CA 客户端从 CA 获得证书,然后可以将它用于各种活动,如建立 TLS 连接。当两个实体需要相互认证时,它们使用它们的证书和 CA 对它们的信任关系。因此,当 Alice 和 Bob 试图通过 TLS 进行通信时,TLS 握手会对他们每个人执行如下身份验证:• Alice 最终得到了 Bob 的证书。Alice 可以信任这个证书,因为 Bob 的 CA 已经对它进行了签名,而且 Bob 的 CA 是受信任的 CA。• 持有 Alice 证书的 Bob 也是如此。 有关 InterSystems PKI 2 有关 InterSystems PKI 总的来说,CA 和公钥加密的活动是所谓的公钥基础设施(public key infrastructure ,PKI)的一部分。因此,PKI 提供了一种创建和管理密钥对和证书的方法,并可以支持加密操作,包括加密、解密、数字签名和签名验证。InterSystems IRIS 包含 PKI。使用 InterSystems PKI,您可以设置一个证书颁发机构(CA),一个 CA 客户端,并开始在用户之间发送安全数据,只需几个步骤。当 InterSystems IRIS 的一个实例充当 CA 时,它被称为 CA 服务器;当实例使用 CA 的服务时,它被称为 CA 客户端。一个实例既可以是 CA 服务器,也可以是 CA 客户端。在将自己建立为 CA 服务器时,InterSystems IRIS 的实例要么创建一个密钥对,然后将公钥嵌入到自签名的 X.509 证书中,要么使用外部 CA 签名的私钥和 X.509 证书。X.509 是一种行业标准证书结构,它将公钥与专有名称(Distinguished Name, DN)关联起来。 3 亲自尝试 InterSystems PKI设置和使用 InterSystems PKI 很容易。在这个示例中,您将使用 InterSystems IRIS 的两个实例。您将使用实例 #1 作为 CA(这里主要称为 CA 服务器)和实例 #2 作为 CA 客户端进行一系列的初始操作。这些步骤是:1. 将实例 #1 配置为 CA 服务器 2. 将实例 #2 配置为 CA 客户端 3. 在 CA 客户端上,向 CA 服务器提交证书签名请求(CSR)4. 在 CA 服务器上,处理 CSR5. 在 CA 客户端上,从 CA 服务器下载它的证书和 CA 服务器证书 重要提示: InterSystems PKI 不用于生产系统。此外,本文档中的示例以不适合使用任何 PKI 的生产系统的方式简化了设置和使用 CA 的过程。例如,它提供一个建议密码,用于加密和解密 CA 服务器的私钥。在生产系统(或除演示系统以外的任何系统)上,永远不要 使用公开的已知密码,因为这可能会危及您的 CA 的私钥的安全,从而危及您的整个 PKI;如果这个密钥被泄露或破解,那么所有 CA 的证书都变得不可信了。类似地,证书颁发机构的证书和私钥文件的目录与您在本文档练习中使用的 InterSystems IRIS 实例在同一台机器上。对于生产系统来说,这个目录应该总是在一个外部设备上(不是本地硬盘驱动器或网络服务器),最好是在一个加密的外部设备上。这是因为该目录持有 CA 的私钥。如果您创建了一个生产系统,请按照 PKI 供应商的说明操作。有关在开发或测试系统中使用 InterSystems PKI 的更多详细信息,请参见 The InterSystems Public Key Infrastructure(《InterSystems 公钥基础设施》)。 亲自尝试 InterSystems PKI3.1 用前须知要使用这个程序,您需要两个正在运行的 InterSystems IRIS 实例。这些实例可以在相同或不同的主机上,但必须相互有网络访问权限。您对 InterSystems IRIS 的选择包括多种类型的已授权的和免费的评估实例;该实例不需要由您正在工作的系统托管(尽管它们必须相互具有网络访问权限)。关于如何部署每种类型的实例的信息(如果您还没有可使用的实例),请参见 InterSystems IRIS Basics:Connecting an IDE(《InterSystems IRIS 基础:连接一个IDE》)中的 Deploying InterSystems IRIS(部署 InterSystems IRIS)。3.2 将实例 #1 配置为 CA 服务器要将实例 #1 配置为 CA 服务器:1. 使用 InterSystems IRIS Basics: Connecting an IDE(《InterSystems IRIS 基础:连接一个 IDE》)中URL described for your instance(为您的实例描述的 URL),在您的浏览器中打开实例的管理门户(Management Portal)。2. 进入 Public Key Infrastructure(公钥基础设施)页面(System Administration(系统管理) > Security(安全) > Public Key Infrastructure(公钥基础设施))。3. 在 Public Key Infrastructure(公钥基础设施)页面上,在 Certificate Authority Server(证书颁发机构服务器)下,选择 Configure Local Certificate Authority server(配置本地证书颁发机构服务器)。这将显示两个字段:• File name root for Certificate Authority’s Certificate and Private Key files(证书颁发机构的证书和私钥文件的文件名根) (没有扩展名)——输入 FLCA (技术概要证书颁发机构(First Look Certificate Authority))。此处使用 FLCA 作为私钥文件和证书文件的名称,所以私钥是在 FLCA.key 中,而证书则在 FLCA.cer 中。• Directory for Certificate Authority’s Certificate and Private Key files(证书颁发机构的证书和私钥文件的目录)——输入 flca。这将在 install-dir\mgr\ 下创建 flca 目录(install-dir 是实例的安装目录) ,并将 FLCA CA 证书和私钥文件放在那里。您也可以点击 Browse(浏览) 来选择一个不同的位置; 当你这样做时,目录选择(Directory Selection)对话框会打开到 install-dir\mgr\ 。4. 点击 Next(下一步) 继续。5. 在出现的字段中,输入以下值:• Password to Certificate Authority's Private Key file(证书颁发机构私钥文件的密码)和 Confirm Password(确认密码) — 输入密码以加密和解密 CA 的私钥文件。我们建议您使用 myflcapw,这样您在这里就有一份密码的副本。• 在 Certificate Authority Subject Distinguished Name(证书颁发机构主体专有名称)下,在 Common Name(通用名称)中 — 输入标识此 CA 的 First Look CA。 如果您使用 InterSystems PKI 进行更深入的测试和实验,当您配置 CA 服务器时,您将完成本节的字段,以包括负责签署 CA 请求的用户的电子邮件帐户。对于这个技术概要(First Look),您可以跳过它。6. 点击 Save(保存)。InterSystems IRIS 显示如下信息,表示成功: Certificate Authority server successfully configured.Created new files: C:\InterSystems\MYIRIS1\mgr\flca\FLCA.cer .key, and .srl. Certificate Authority Certificate SHA-1 fingerprint: E3:FB:30:09:53:90:9A:31:30:D3:F0:07:8F:64:65:CD:11:0A:1A:A2 这表明 InterSystems IRIS 已经执行了以下操作:• 创建一个密钥对。• 将私钥保存到您指定的文件位置,并使用您指定的根名称。• 创建一个包含公钥的自签名 CA 证书。 亲自尝试 InterSystems PKI • 将证书保存到您指定的文件位置,并使用您指定的根名称。• 创建一个颁发的证书数量的计数器,并将其存储在与证书和私钥相同目录中的 SRL(序列)文件中。(每次 CA 颁发新的证书时,InterSystems IRIS 都会根据这个计数器给证书一个唯一的序列号,然后增加 SRL 文件中的值)。 3.3 将实例 #2 配置为 CA 客户端要将实例 #2 配置为 CA 客户端:1. 使用为您的实例描述的 URL,在您的浏览器中打开实例的管理门户(Management Portal)。2. 进入 Public Key Infrastructure(公钥基础设施)页面(System Administration(系统管理) > Security(安全) > Public Key Infrastructure(公钥基础设施))。3. 在 Certificate Authority Client(证书颁发机构客户端)下,选择 Configure Local Certificate Authority Client(配置本地证书颁发机构客户端),这会在此页面上显示多个字段。4. 填写以下字段,其他字段留空或使用默认值。在上一节中,您使用了实例 #1 的主机标识符和 web 服务器端口,您必须在这里输入。在其管理门户(Management Portal) URL 中。• Certificate Authority server hostname(证书颁发机构服务器主机名)——运行 CA 服务器的主机的 IP 地址或 DNS 名称,即实例 #1 的主机。• Certificate Authority WebServer port number(证书颁发机构网络服务器端口号)——作为 CA 服务器的实例的 web 服务器端口号,也就是实例 #1。• 在 Local technical contact(本地技术联系人) 部分,Name(名称)——任何值。(这个字段是必需的,因为 CA 服务器必须有设置 CA 客户端的人的联系信息。因为您既要配置 CA 客户端,又要配置 CA 服务器,所以您是它们的本地技术联系人。) 注意: 在生产环境中,PKI 可能需要带外联系信息,如在 Local technical contact(本地技术联系人)区域。这些信息是为了身份验证,客户端需要提供联系人信息以开始这一过程。 5. 点击 Save(保存)。 InterSystems IRIS 通过诸如"成功配置证书颁发机构(Certificate Authority,CA)客户端"的信息来确认成功。3.4 在实例 #2 上,向 CA 服务器提交证书签名请求(CSR) 接下来,在实例 #2 上,向 CA 服务器提交一个证书签名请求(CSR):1. 仍然在 Public Key Infrastructure(公钥基础设施)页面(System Administration(系统管理) > Security(安全) > Public Key Infrastructure(公钥基础设施)),在 Certificate Authority Client(证书颁发机构客户端)下,选择 Submit Certificate Signing Request to Certificate Authority Server(向证书颁发机构服务器提交证书签名请求),这将显示几个新的字段。2. 按以下方式填写它们,其他字段留空或使用默认值:• File name root for local Certificate and Private Key files(本地证书和私钥文件的文件名根)(没有扩展名)——输入 FLCAclient (技术概要证书颁发机构客户端(First Look Certificate Authority client))。这使用了 FLCAclient 作为私钥文件和证书文件的名称,因此私钥在 FLCAclient.key 中,而证书将很快出现在 FLCAclient.cer 中。• 在 Subject Distinguished Name(主体专有名称)下,在 Common Name(通用名称)字段中——输入 FL CA client。 3. 按要求完成这些字段,并点击 Save(保存)。如果成功,InterSystems IRIS 将显示如下信息: 亲自尝试 InterSystems PKI Certificate Signing Request FLCAclient successfully submitted to the Certificate Authority at instance MYIRIS1 on node FLCATEST.COM.SHA-1 Fingerprint: C2:B0:D6:0D:D6:AB:43:DF:7F:B1:22:AE:14:D7:45:FF:CC:0C:20:D0 4. 此时,您已经使用 InterSystems IRIS 创建并提交了 CSR。 3.5 在实例 #1 上,处理 CSR 在实例 #1(CA 服务器)上,处理 CSR,将其转换为证书:1. 在管理门户(Management Portal)中,进入 Public Key Infrastructure(公钥基础设施)页面(System Administration(系统管理) > Security(安全) > Public Key Infrastructure(公钥基础设施))。2. 在 Public Key Infrastructure(公钥基础设施)页面上,在 Certificate Authority Server(证书颁发机构服务器)下,选择 Process pending Certificate Signing Requests(处理待处理的证书签名请求),它显示来自 CA 客户端的待处理 CSR。3. 点击 CSR 右侧的 Process(处理),显示 CSR 的内容,显示 CSR 的处理字段。有关这些字段的几个要点:• 因为您要为可以使用 InterSystems IRIS 中安全功能的 CA 客户端颁发证书,所以在 Certificate Usage(证书使用)下,您可以保留默认的 TLS/SSL,XML encryption and signature verification(TLS/SSL、XML 加密和签名验证)。• 在生产环境中,您需要验证 CA 客户端的身份。因此,本节演示如何执行这一行为;例如,在 Request Content(请求内容)下,显示 CA 客户端的电话号码和电子邮件。这将允许您通过电话或亲自联系他们并验证他们的身份。 4. 点击 Issue Certificate(颁发证书),这将导致页面显示 Password for Certificate Authority's Private Key file(证书颁发机构私钥文件的密码)字段。5. 在 Password for Certificate Authority's Private Key file(证书颁发机构私钥文件的密码)字段中,输入 myflcapw,这是您在配置 CA 服务器时创建的密码。6. 点击 Finish(完成) 来创建证书。 IRIS 显示一条信息,如 Certificate number 2 issued for Certificate Signing Request FLCAclient InterSystems IRIS 现在已经创建了证书。如果 CA 客户端列出了其技术联系人的电子邮件地址,该地址还会收到证书可供下载的通知。 3.6 在实例 #2 上,从 CA 服务器下载它的证书和 CA 服务器证书下一步也是最后一步是 CA 客户端从 CA 服务器下载 CA 服务器的证书和它自己的证书:1. 在管理门户(Management Portal)中,在实例 #2 上,进入 Public Key Infrastructure(公钥基础设施)页面 (System Administration(系统管理) > Security(安全)> Public Key Infrastructure(公钥基础设施))。2. 在 Public Key Infrastructure(公钥基础设施)页面上,在 Certificate Authority Client(证书颁发机构客户端)下,点击 Get Certificate(s) from Certificate Authority server(从证书颁发机构服务器获取证书)。3. 在显示的字段中,有一个 Get Certificate Authority Certificate(获取证书颁发机构证书) 按钮。 点击它,会下载 CA 服务器的证书,并显示一条信息,如:Certificate Authority Certificate(SHA-1 Fingerprint: 8A:38:C9:06:50:A0:4F:71:86:2B:69:4C:A2:42:E0:43:28:C8:70:EB)saved in file "c:\intersystems\MYIRIS2\mgr\FLCA.cer" 4. 再一次点击 Get Certificate(s) from Certificate Authority server(从证书颁发机构服务器获取证书)。 了解有关 InterSystems PKI 的更多信息 5. 已颁发证书表列出了 CA 客户端的证书。点击行旁边的 Get(获取)按钮。这就下载了 CA 客户端的证书,并显示一条信息,如:Certificate number 2(SHA-1 Fingerprint: 2E:82:27:73:72:38:BC:71:36:70:DC:9E:0D:EF:E6:BC:0D:A9:95:CD)saved in file "c:\intersystems\MYIRIS2\mgr\FLCAclient.cer" 3.7 总结和下一步 您现在有:1. 将 InterSystems IRIS 的一个实例配置为 CA 服务器2. 将 InterSystems IRIS 的另一个实例配置为 CA 客户端3. 从 CA 客户端向 CA 服务器提交证书签名请求(CSR)4. 在 CA 服务器上处理 CSR5. 将 CA 服务器的证书和 CA 客户端自己的 CA 证书从 CA 服务器下载到 CA 客户端 这意味着您现在有一个 InterSystems IRIS 实例是一个正常运行的 CA 服务器,另一个 InterSystems IRIS 实例是一个正常运行的 CA 客户端。如果您在另一个 InterSystems IRIS 实例上设置 CA 客户端,并为每个实例创建 TLS 配置,两个客户端可以交换加密的信息。这为各种安全活动提供了基础。注意: 最后提醒一下:这个示例系统并不能帮助建立一个安全的环境,因为 CA 的私钥已经在本文档中公开发布。妥善保护生产系统中的所有私钥是至关重要的,而保护 CA 的私钥则是最重要的。泄露在生产系统中使用的私钥,会导致安全漏洞、数据泄露、财务损失和法律漏洞。除了让您了解 InterSystems IRIS 功能之外,请不要使用此文档的 CA 服务器私钥进行其他任何操作。 4 了解有关 InterSystems PKI 的更多信息有关 InterSystems PKI 的完整文档,请参见 The InterSystems Public Key Infrastructure(《InterSystems 公钥基础设施》)。
文章
Louis Lu · 九月 26, 2021

IRIS 2021 技术文档 First Look 10 -- InterSystems .Net 网关

本技术概要( First Look)通过重点概述和一个基础的、实际操作的示例,向您介绍在 InterSystems IRIS®数据平台上使用 .NET 网关(Gateway)的基础知识。您将了解 InterSystems IRIS 如何与 .NET 程序集进行互操作,在这个示例中,您将创建一个 .NET 网关(Gateway),并从 InterSystems IRIS 中的代理类调用基础 DLL。 本文档设计简单;当您把 .NET 网关(Gateway)引入您的生产系统时,您可能需要做一些不同的事情。本文档末尾的参考资料,提供了有关在生产中使用 .NET 网关(Gateway)的详细和完整的信息。 要浏览所有的技术概要(First Look),包括其他可以在免费的云实例或 web 实例上执行的技术概要(First Look),请参见 InterSystems First Looks(InterSystems 技术概要)。 1. 为什么 .NET 网关(Gateway)很重要 InterSystems IRIS Object Gateway for .NET(也称为".NET 网关(Gateway)")为InterSystems IRIS 与 Microsoft .NET Framework 组件进行互操作提供了一种简便的方法。在使用网关(Gateway)导入 .NET DLL 后,您可以实例化一个外部 .NET 对象,InterSystems IRIS通过代理类将其作为的一个本地对象来操作。 每个代理对象(proxy object)都与相应的 .NET 对象通信,使您能够从 InterSystems IRIS 和 ObjectScript 中访问您的 .NET 类和方法。调用任何 InterSystems IRIS 代理方法都会将消息发送给 .NET 网关(Gateway) 工作线程,该线程会找到合适的方法或构造函数调用。调用的结果发送回代理对象,再将结果返回给 InterSystems IRIS 应用程序。 通常,使用 .NET 网关(Gateway)的最佳方法是在您的应用程序中为第三方 DLL 构建一个小型包装器类(a small wrapper class),然后为包装器生成代理类。包装器类只公开您想要的功能,而不是创建大量应用程序可能不需要的代理类。 2. 探索 .NET 网关(Gateway) 在这个实际操作的示例中,您将: 创建一个 DLL,其中包含要从 InterSystems IRIS 调用的示例类 定义一个 .NET 网关(Gateway),并启动服务器进程 创建一个 ObjectScript 类,从 DLL 生成代理类 创建另一个 ObjectScript 类,以连接到网关(Gateway)并通过代理对象操作 DLL 想试试 InterSystems IRIS .NET 开发和互操作性功能的在线视频演示吗?请看.NET QuickStart(.NET 快速入门)! 2.1 用前须知 要运行这个演示,您需要一个运行 Microsoft .NET Framework 4.5 版本 的 Windows 10 系统、Visual Studio,以及一个已安装的 InterSystems IRIS 实例。(有关安装 InterSystems IRIS 的说明,请参见 InterSystems IRIS Basics:Installation [《InterSystems IRIS 基础:安装》]。) 有关配置 Visual Studio 以连接到您的 InterSystems IRIS 实例的说明,请参见 InterSystems IRIS Basics:Connecting an IDE(《InterSystems IRIS 基础: 连接一个 IDE》)中的 InterSystems IRIS Connection Information(InterSystems IRIS 连接信息)和 .Net IDE。 您还将使用InterSystems 的 Studio IDE(一个在 Windows 系统上运行的客户端应用程序)来创建 ObjectScript 代码;更多信息,请参见InterSystems IRIS Basics: Connecting an IDE(《InterSystems IRIS 基础: 连接一个 IDE》)中的 Using Studio(使用 Studio) 和 Studio。 )​​​​​​ 2.2 创建 DLL 使用 Visual Studio,创建一个名为 Person 的类并复制以下 C# 代码。在本例中使用 .NET 4.5。 public class Person { public int age; public String name; //constructor public Person (int startAge, String Name) { age = startAge; name = Name; } public void setAge(int newAge) { age = newAge; } public String getName() { return name; } public int getAge() { return age; } public static void main(String []args) { Person myPerson = new Person (5, "Tom"); Console.Out.WriteLine(myPerson.getName()); Console.Out.WriteLine(myPerson.getAge()); } } 编译 Person 类,并生成一个 Person.dll 文件。注意 DLL 的位置,因为您稍后会需要它。 2.3 创建并启动 .NET 网关 使用 InterSystems IRIS Basics:Connecting an IDE(《InterSystems IRIS 基础: 连接一个 IDE》)中的 InterSystems IRIS Connection Information(InterSystems IRIS 连接信息)描述的 URL,在浏览器中打开您的实例的管理门户(Management Portal)。 导航至 System Administration(系统管理) > Configuration(配置) > Connectivity(连接) > External Language Servers(外部语言服务)。 选择 Create External Language Server(创建外部语言服务)。 输入 Server Name(网关名称)。 在 Server Type (服务类型)中选择 .Net 在 Port(端口)字段中,输入 55000。 对于 .NET Version(.NET 版本),请选择 4.5。 选择 Save(保存)。 在External Language Servers(外部语言服务)页面,找到您刚刚定义的网关(Gateway),并选择 Start(开始) 2.4 生成代理类 使用 Studio, 在实例的 USER 命名空间中创建一个名为 CreateProxyClasses.cls 的新 ObjectScript 类,并粘贴以下代码, 将您的实例的主机标识符替换为 gwyConn.%Connect 中的 server,并用双引号括起来的 Person.dll 文件的完整文件路径替换 YOUR FILEPATH HERE。 Class User.CreateProxyClasses Extends %Persistent { ClassMethod run() { // get a connection to the .NET Gateway set gwyConn = ##class(%Net.Remote.Gateway).%New() set status = gwyConn.%Connect("127.0.0.1", 55000, "USER") if $$$ISERR(status) { write !,"error: "_$system.OBJ.DisplayError(status) quit } // add the DLL to the classpath set classpath = ##class(%ListOfDataTypes).%New() do classpath.Insert("YOUR FILEPATH HERE") set status = gwyConn.%AddToCurrentClassPath(classpath) if $$$ISERR(status) { write !,"error: "_$system.OBJ.DisplayError(status) quit } // create the proxy ObjectScript classes corresponding to the .NET classes in the DLL set status = gwyConn.%Import("Person",,,,1) if $$$ISERR(status) { write !,"error: "_$system.OBJ.DisplayError(status) quit } //close the connection to the .NET Gateway set status = gwyConn.%Disconnect() if $$$ISERR(status) { write !,"error: "_$system.OBJ.DisplayError(status) quit } } } 编译并构建该类。然后使用 InterSystems IRIS Basics:Connecting an IDE(InterSystems IRIS 基础: 连接一个 IDE) 中的 instructions for your instance(对您的实例的说明),在 USER 命名空间中打开 InterSystems 终端(InterSystems Terminal), 并执行以下命令: do ##class(User.CreateProxyClasses).run() 2.5 使用ObjectScript 操作 .NET Object 在 USER 命名空间中创建另一个名为 ManipulateObjects.cls 的 ObjectScript 类,并粘贴以下代码 (注意要将您的实例的主机标识符替换 gwyConn.%Connect 中的 第一个参数): Class User.ManipulateObjects Extends %Persistent { ClassMethod run() { // get a connection to the .NET gateway set gwyConn = ##class(%Net.Remote.Gateway).%New() set status = gwyConn.%Connect("127.0.0.1", 55000, "USER") if $$$ISERR(status) { write !,"error: "_$system.OBJ.DisplayError(status) quit } // manipulate some proxy objects set person = ##class(User.Person).%New(gwyConn,5,"Tom") write !,"Name: "_person.getName() write !,"Age: "_person.getAge() do person.setAge(100) write !,"Age: "_person.getAge() // close the connection to the .NET gateway set status = gwyConn.%Disconnect() if $$$ISERR(status) { write !,"error: "_$system.OBJ.DisplayError(status) quit } } } 编译并构建该类,然后在终端(Terminal)中的 USER 命名空间中执行以下命令: do ##class(User.ManipulateObjects).run() 您应该可以看到以下输出: Name: Tom Age: 5 setting age to 100 Age: 100 现在您已经成功地完成了练习,停止您创建的 .NET 网关(Gateway)。返回到管理门户(Management Portal)中的 External Language Servers(外部语言服务)页面,找到网关(Gateway),并选择 Stop(停止)。 3. 了解更多有关 .NET 网关(Gateway)的信息 从这里,您可以继续探索 .NET 网关(Gateway)和 InterSystems IRIS。请参阅下面的文档和参考资料,了解 .NET、互操作性、应用程序开发等。 Using the Gateway for .NET(使用 .NET 网关) — 了解更多有关 InterSystems IRIS 和 Microsoft .NET Framework 组件之间互操作性的信息。 Skyrocket Your .NET Application Development(Skyrocket Your .NET 应用程序开发) — 这是 InterSystems 关于在 .NET 中作为对象建模和访问数据的演示。 .NET Documentation(.NET 文档) — Microsoft 在 .NET 上的文档,包括架构概念、教程和开发指南。
文章
Weiwei Gu · 十二月 1, 2022

InterSystems 几款主要产品的功能对比清单(Cache/Ensemble vs. IRIS For Health / Health Connect )

InterSystems 是一家已经深耕数据库平台领域达44年的公司,成立于1978年,现在已经在全球的80多个国家开展相关业务,每天有超过10亿患者的电子病历数据都跑在以我们的数据库平台构建的应用系统之上。 我们的客户遍布国内外,国内的大几百家三甲医院客户,中国复旦排行榜上超过1/3的顶级医院都在使用我们产品(包括北京协和医院,华西医院,湘雅等等),我们的技术合作伙伴,如东华医为,嘉和,和仁等也都是国内医疗信息领域的著名厂商。 而在国外,我们也有非常多的顶级客户,仅仅以美国举例,美国最顶级的排名前20的所有医院,无一例外全部都是使用的interSystems公司的数据库平台产品。 美国排名前20的所有顶级医院 2020-2021《美国新闻与世界报道》(U.S. News & World Report)最顶级医院名单(前20家医疗机构)均应用InterSystems公司的数据库平台: Mayo Clinic, Rochester, Minnesota (明尼苏达州罗彻斯特市梅奥诊所)Cleveland Clinic(克利夫兰诊所) Johns Hopkins Hospital, Baltimore(巴尔的摩约翰霍普金斯医院)(tie). New York-Presbyterian Hospital-Columbia and Cornell, New York(纽约长老会医院 ) (tie). UCLA Medical Center, Los Angeles(加州大学洛彬矶分校医学中心)Massachusetts General Hospital, Boston(波士顿麻省总医院 )Cedars-Sinai Medical Center, Los Angeles(洛杉矶Cedars-Sinai医疗中心 )UCSF Medical Center, San Francisco(旧金山加州大学旧金山分校医疗中心 )NYU Langone Hospitals, New York(纽约大学朗格尼医学中心)Northwestern Memorial Hospital, Chicago(芝加哥西北纪念医院)University of Michigan Hospitals-Michigan Medicine, Ann Arbor(安娜堡密歇根大学医学院)Brigham and Women’s Hospital, Boston(波士顿哈佛医学院教学附属医院布列根和妇女医院)Stanford Health Care-Stanford Hospital, Stanford, California(斯坦福医疗中心)Mount Sinai Hospital, New York(纽约西奈山医院)Hospitals of the University of Pennsylvania-Penn Presbyterian, Philadelphia(费城宾夕法尼亚大学-宾夕法尼亚长老会医院)Mayo Clinic-Phoenix(凤凰城梅奥诊所)Rush University Medical Center, Chicago(芝加哥拉什大学医学中心)(tie). Barnes-Jewish Hospital, St. Louis(圣路易斯巴恩斯医院)(tie). Keck Hospital of USC, Los Angeles(洛杉矶南加州大学凯克医院)Houston Methodist Hospital(休斯顿卫理公会医院) InterSystems 公司久负盛名的两款产品: Cache 与 Ensemble , 以其稳定性好,速度快著称,在国内外均有无数医院用户。 自2018年底InterSystems 公司推出其新一代的 IRIS for Health 数据库平台后,基于新产品更高的性能表现及更强大的功能与扩展能力,我们鼓励所有的Cache 及Ensemble 老用户逐渐向最新一代的IRIS 以及Health Connect 平台迁移。以获得更好的性能及用户体验,并且在未来可以支撑更多新的发展需求。 Cache 与 Ensemble 的最新版本也止于2018年,未来我们将继续对使用这两款产品的客户提供支持服务,但不会在其之上开发新的功能。 以下附件中,提供了截止目前这两款产品Cache / Ensemble 与其新的下一代的产品 IRIS for Health / Health Connect 的功能清单对比,可点击参考:
文章
Michael Lei · 六月 8, 2023

使用 InterSystems 互操作性在TeleGram中使用 Open AI ChatGPT 进行自己的聊天

嗨社区! 想与您分享我在Telegram中使用GPT创建“我自己的”聊天的练习。 这个应用需要用到 Open Exchange 上的两个组件:@Nikolay.Soloviev 的Telegram Adapter和@Francisco.López1549的IRIS Open-AI 因此,通过此示例,您可以在 Telegram 中使用 ChatGPT 设置自己的聊天。 让我们看看如何让它发挥作用! 前提条件 使用@BotFather 帐户创建一个机器人并获取机器人令牌。然后将机器人添加到电报聊天或频道中并赋予其管理员权限。在https://core.telegram.org/bots/api了解更多信息 在https://platform.openai.com/上打开(如果没有,请创建)一个帐户,并获取您的Open AI API Key和Organization id 。 确保您的 InterSystems IRIS 中安装了 IPM。如果没有,这里有一个要安装的衬垫: USER> s r = ##class ( %Net.HttpRequest ). %New (), r .Server= "pm.community.intersystems.com" , r .SSLConfiguration= "ISC.FeatureTracker.SSL.Config" d r .Get( "/packages/zpm/latest/installer" ), $system .OBJ.LoadStream( r .HttpResponse.Data, "c" ) 或者您可以像这样使用带有 IPM 的社区 docker 图像: 安装 在启用互操作性的命名空间中安装 IPM 包。 USER>zpm“安装 Telegram-gpt” 用法 打开Production 将机器人的 Telegram Token 放入 Telegram business service 和 Telegram Business operation 中: 同时使用您的聊天 GPT API 密钥和组织 ID 初始化 St.OpenAi.BO.Api.Connect 操作: 启动Production。 在Telegram聊天中提出任何问题。您将通过 Chat GPT 获得答案。尽情享受吧! 在可视化追中: 细节 本示例使用 3.5 版本的 Chat GPT Open AI。它可以在模型参数的数据转换规则中更改。
文章
姚 鑫 · 二月 2, 2023

第六十四章 使用 SNMP 监控 IRIS - 扩展 InterSystems IRIS MIB

# 第六十四章 使用 SNMP 监控 IRIS - 扩展 IRIS MIB 应用程序员可以添加托管对象定义并扩展 `IRIS` 子代理为其提供数据的 `MIB`。这不是一个完整的 `MIB` 编辑器或` SNMP` 工具包;相反,它是一种添加简单应用程序指标的方法,可以通过 `SNMP` 浏览或查询这些指标。 注意:对象必须遵循基本的 `IRIS SNMP` 结构,对 `SNMP` 表结构的支持有限(仅支持整数值索引),并且不会创建 `SNMP` 陷阱(请参阅新选项卡类中的 `%Monitor.AlertOpens`) 对管理信息的 `SNMP` 结构有一个基本的了解是很有帮助的。 要创建这些对象,请执行以下操作: 1. 在继承 `%Monitor.Adaptor` 的类中创建 `IRIS` 对象定义。 2. 执行 `SNMP` 类方法以在 `SNMP` 中启用这些被管理对象,并创建 `MIB` 定义文件供管理应用程序使用。实现此目的的方法是 `MonitorTools.SNMP.CreateMIB()`。 该方法为 `%Monitor` 数据库中定义的特定应用程序创建私有企业 `MIB` 树的一个分支。除了为应用程序创建实际的 `MIB` 文件之外,该方法还创建了 `MIB` 树的内部轮廓。 `IRIS` 子代理使用它来注册 `MIB` 子树,为 `GETNEXT` 请求遍历树,并引用特定对象方法以在 `GET` 请求中收集实例数据。 所有托管对象定义都使用与 `IRIS` 企业 `MIB` 树相同的通用组织,即:`application.objects.table.row.item.indices`。所有表格的第一个索引是 `IRIS` 应用程序 `ID`。所有应用程序都必须向 IANA 注册以获得自己的私有企业编号,这是 `CreateMIB()` 方法中的参数之一。 要禁用 `SNMP` 中的应用程序,请使用 `MonitorTools.SNMP.DeleteMIB()` 方法。这会删除应用程序 `MIB` 的内部轮廓,因此 `IRIS` 子代理不再注册或回答对该私有企业 MIB 子树的请求。 # `IRIS SNMP` 陷阱 除了通过 `SNMP` 查询提供的对象数据和指标外, `IRIS` 还可以发送异步警报或 `SNMP` 陷阱。下表描述了 `IRIS` 特定的 `SNMP` 陷阱。 ### IRIS SNMP 通知对象(陷阱) Trap Name (Number)| Description ---|--- irisStart (1) | IRIS 实例已启动。 irisStop (2)| IRIS 实例正在关闭。 irisDBExpand (3)| IRIS 数据库已成功扩展。 irisDBOutOfSpace (4)| IRIS 数据库的未来扩展可能会受到限制;文件系统上的可用空间不足,无法再扩展 10 次,或者可用空间不足 `50 MB`。 irisDBStatusChange (5)| IRIS 数据库的读/写状态已更改。 irisDBWriteFail (6) |写入 IRIS 数据库失败。它包括写入失败的 IRIS 错误代码。 irisWDStop (7)| IRIS 实例的写入守护进程已停止。 irisWDPanic (8) | IRIS 实例的写入守护进程已进入“恐慌panic”模式;也就是说,写入守护进程缓冲区不足,必须将数据库块直接写入磁盘,而无需先将它们提交到写入映像日志 (WIJ) 文件。 irisLockTableFull (9)| IRIS 实例的锁表已满,导致后续 `Locks` 失败。 irisProcessFail (10)|进程异常退出 IRIS(由于访问冲突)。 irisECPTroubleDSrv (11)| IRIS 数据库与此 `ECP` 数据服务器的连接遇到了严重的通信问题。 irisECPTroubleASrv (12)|从该 `ECP` 应用程序服务器到远程 IRIS 数据库的连接遇到了严重的通信问题。 irisAuditLost (13)| IRIS 未能记录审核事件。最可能的原因是审计数据库的空间有问题,这需要操作员的帮助。 irisLoggedError (14)|`messages.log` 文件中记录了一个“严重”错误。此陷阱包括在 `irisSysErrorMsg` 中定义的错误消息。 irisLicenseExceed (15)| 许可证请求已超出当前可用或允许的许可证数量。 irisEventLogPost (16)| 互操作性事件日志中发布的条目。 irisAppAlert (100)| 这是一个通用陷阱, IRIS 应用程序可以使用它通过 SNMP 生成警报。有关如何使用此陷阱的详细信息,请参阅 `%Monitor.Alert.External` 类方法。 下表描述了可以在上表中描述的陷阱中发送的 IRIS 特定辅助对象。 Auxiliary Object Name (Number) |Description ---|--- irisDBWriteError (1)| 数据库写入失败的 IRIS 特定错误代码。可能的值为:``、``、``、` `或 ``。 irisApp (2) |一个短文本字符串(最多 `20` 个字符),用于标识生成(或来源)`irisAppAlert` 陷阱的应用程序。 irisAppSeverity (3)|指示 `irisAppAlert` 陷阱问题严重性的代码。代码可以是 `0`(信息)、`1`(警告)、`2`(严重)或 `3`(严重)。 irisApptext (4) |导致 `irisAppAlert` 陷阱的问题、错误或事件的文本字符串描述(最多 `1024` 个字符)。
文章
姚 鑫 · 一月 22, 2023

第五十三章 使用 ^SystemPerformance 监视性能 - InterSystems IRIS Linux 平台性能数据报告

# 第五十三章 使用 ^SystemPerformance 监视性能 - InterSystems IRIS Linux 平台性能数据报告 - `%SS` - 使用 `ALL^%SS` 命令在运行过程中采集了四个样本。 - `Configuration *` - 来自服务器的 `IRIS` 实例名称和主机名、完整的 `IRIS` 版本字符串、许可客户名称和许可订单号。 - `cpf file *` - 当前活动配置文件的副本。 - `irisstat -c` - 使用命令 `irisstat cache -p-1 -c-1 -e1 -m8 -n2 -N127` 在运行过程中以均匀的间隔采集四个样本。以下是对每个参数的简要说明: - `-p-1`: 对进程表进行采样以包括进程和全局状态信息。 - `-c-1`: 对共享内存的计数器部分进行采样以显示日志、锁、磁盘和资源使用统计信息。 - `-e1`: SYSLOG 错误表。 - `-m8`: 文件表,其中包括所有 `IRIS.DAT` 文件及其属性。 - `-n2`: 网络结构表,包括本地到远程数据库的映射。 - `-N127`: 客户端和服务器连接的 `ECP` 统计信息。 - `irisstat -D` - 使用命令 `irisstat cache --f1 -D10,100` 在运行过程中以均匀的间隔采集八个样本。以下是对每个参数的简要说明: - `-fl`: 基本标志。 - `-D10,100`: 在 `10` 秒的总采样周期内,每 `100` 毫秒对块碰撞进行采样。 - `df -m *` - 有关挂载文件系统的信息,包括挂载点、逻辑卷和可用空间; `df -m` 命令的输出。 - `free -m` - 以 `MB` (`-m`) 为单位的内存使用统计信息。 - `iostat` - `CPU` 和磁盘吞吐量。 - `license *` - 使用 `Decode^%LICENSE` 和 `counts^%LICENSE` 的 `IRIS` 许可使用信息。 - `mgstat` - 使用 `^mgstat` 实用程序在运行过程中获取 `IRIS` 特定数据。请参阅 `Monitoring Guide `的 `Monitoring Performance Using ^mgstat` 部分。 - `Profile *` - 有关创建此日志的 `^SystemPerformance` 配置文件的信息。 - `ps:` - 使用命令 `ps -efly` 在运行过程中以均匀的间隔采集四个样本。 - `sar -d` - 磁盘(块)设备吞吐量和延迟统计信息。 - `sar -u` - CPU 使用率统计信息包括 `iowait` 百分比。 - `vmstat -n - CPU`、排队、分页统计。只打印一个标题 (`-n`) 。 - `CPU *` - 从 `lscpu` 和 `/proc/cpuinfo` 收集的信息 - `Linux info *` - 一般操作系统和硬件信息;包括 `uname -a`、`lsb_release -a`、`id` 和 `ulimit -a` 命令的输出以及从 `/etc/issue.net`、`/proc/partitions` 和 `/dev/mapper` 收集的信息。 - `ipcs *` - 进程间通信配置信息,包括共享内存、信号量和消息队列; `ipcs -a` 命令的输出。 - `mount *` - 有关所有文件系统及其挂载选项的信息。 - `fdisk -l *` - `/proc/partitions` 中提到的所有设备的分区表。仅当启动 `^SystemPerformance` 配置文件运行的用户具有 `root` 访问权限时才包括在内。 - `ifconfig *` - 当前活动网络接口的状态信息。 - `sysctl -a *` - 内核和系统参数设置。
文章
Claire Zheng · 九月 12, 2021

InterSystems发布InterSystems IRIS医疗版互联互通套件,加速医院互联互通平台建设

2021年9月13日,中国 北京—— 致力于帮助客户解决最关键的可扩展性、互操作性和速度问题的创新数据技术提供商InterSystems今日宣布在中国推出InterSystems IRIS医疗版互联互通套件,以满足医院信息化建设的标准化要求,促进业务协同,助力公立医院高效建设互联互通平台。 中国医院信息互联互通标准化成熟度测评工作自2012年启动以来,已成为医院信息化建设的重要抓手。2020年发布的最新版测评方案(《国家医疗健康信息医院信息互联互通标准化成熟度测评方案(2020年版)》)结合医疗健康信息化建设新需求、新技术应用情况,强化了分级管理机构职责,修订了测评流程,补充完善了测评指标,提升了测评方案的科学性和指导性。 凭借多年来深耕医疗信息化建设领域的丰富经验和强大的医疗数据平台,InterSystems结合新版测评标准,及时推出InterSystems IRIS医疗版互联互通套件,从安全管理、监控、数据管理、互联互通文档、互联互通服务、集成与交换六大方面入手,在满足测评标准化组件的基础上,提供最新版医院互联互通标准化成熟度测评规定的文档、监控、服务、Schema等组件,充分满足医院快速落地互联互通标准化成熟度测评涉及到的标准化改造需求。通过内置的模块化服务,InterSystems IRIS医疗版互联互通套件将有效缩短实施周期,加快互联互通平台建设。 InterSystems IRIS医疗版互联互通套件兼备高性能与稳定性,连续多年支持数百家大型公立医院海量数据稳定运行。 主流 PC 服务器单实例下,支持日消息吞吐量可高达27.64亿。截至2021年,InterSystems技术已助力一百余家医院通过四级及以上医院信息互联互通标准化成熟度评级。目前获评医院互联互通成熟度五级乙等评级的32家医院中,有10家均采用了InterSystems的技术和产品,某大型三甲医院日均处理数据在千万量级。 InterSystems IRIS医疗版互联互通套件包含先进的互操作技术,同时具备强大的创新功能,包括数据库管理、敏捷开发、 API 管理、FHIR资源仓库、分布式扩展、一体化机器学习、自适应分析等,全面支持医院持续开展数字化创新与应用。 InterSystems亚太区总经理卢侠亮表示:“作为一家服务中国医疗信息化市场超过20年的创新数据提供商,InterSystems致力于为中国用户提供卓越服务,此次发布的InterSystems IRIS医疗版互联互通套件专为中国用户打造,将更高效地为医疗机构标准化互联互通和信息共享提供技术保障。接下来,我们会一如既往地与本土合作伙伴和医疗机构紧密合作,将全球领先的医疗信息平台解决方案与中国市场需求相结合,为更多的医院数字化转型提供强大支持。” InterSystems将于2021年9月17日举办“InterSystems IRIS医疗版互联互通套件”线上发布会,会议详情如下,欢迎点击“此处”或扫描下方二维码报名。 目前已经可以回放,节前错过的小伙伴可以继续注册观看啦
文章
jieliang liu · 一月 7, 2021

使用 GitHub Actions 在 EKS 上部署 InterSystems IRIS 解决方案

假设你想了解 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 正常工作。 全部运行一遍。 获得工作奖励。 渐渐地你会得出结论,在我们这个[微服务](https://martinfowler.com/articles/microservices.html)时代,不使用 Docker 就太可惜了,尤其是 InterSystems 还会告诉你[怎么做](https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=ADOCK_iris)。 返回到 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 irisUSER>zpmzpm: USER>install samples-bi   将浏览器定向到 http://localhost:52773/csp/user/_DeepSee.UserPortal.Home.zen?$NAMESPACE=USER 后,再次去老板那里,因为做得好而获得一天假期。 然后你开始明白,“docker run”只是开始,至少需要使用 docker-compose。 没问题: $ cat docker-compose.ymlversion: "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](https://kompose.io/)。 我个人更喜欢简单地从手册中复制 Kubernetes 清单,然后自己编辑,但是 kompose 在完成小任务方面做得很好: $ kompose convert -f docker-compose.ymlINFO Kubernetes file "irisce-service.yaml" createdINFO Kubernetes file "irisce-deployment.yaml" created   现在你有了可以发送到某个 Kubernetes 集群的部署和服务文件。 你发现可以安装 minikube,它允许你运行一个单节点 Kubernetes 集群,这正是你现阶段所需要的。 在摆弄一两天 minikube 沙盒之后,你已经准备好在 AWS 云中的某处使用真实的 Kubernetes 部署。   设置 我们一起来进行吧。 此时,我们做以下几个假设: 首先,我们假设你有一个 AWS 帐户,你[知道其 ID](https://docs.aws.amazon.com/IAM/latest/UserGuide/console_account-alias.html),并且未使用 root 凭据。 你创建了一个具有[管理员权限](https://docs.aws.amazon.com/IAM/latest/UserGuide/getting-started_create-admin-group.html)且只能以编程方式访问的 IAM 用户(我们称之为“my-user”),并存储了其凭据。 你还创建了另一个具有相同权限的 IAM 用户,名为“terraform”: ![](/sites/default/files/inline/images/images/iam_user.png) Terraform 将以它的名义进入你的 AWS 帐户,并创建和删除必要资源。 这两个用户的广泛权限将通过演示来说明。 你在本地保存了这两个 IAM 用户的凭据: $ cat ~/.aws/credentials[terraform]aws_access_key_id = ABCDEFGHIJKLMNOPQRSTaws_secret_access_key = ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890123[my-user]aws_access_key_id = TSRQPONMLKJIHGFEDCBAaws_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 控制台中查看: ![](/sites/default/files/inline/images/images/eks.png)   觉得厌烦时就清理掉: $ terraform destroy   然后进入下一阶段,开始使用 Terraform EKS 模块,尤其它也基于同一 EKS 简介。 在 examples/ 目录中,你将看到如何使用它。 你还会在那里找到其他示例。 我们对示例进行了一定的简化。 以下是主文件,其中调用了 VPC 创建和 EKS 创建模块: $ cat /terraform/main.tfterraform {  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-1make_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   ![](/sites/default/files/inline/images/images/dynamodb.png)   注意,如果 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.tfvariable "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.tfoutput "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.ymlversion: "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.yamlapiVersion: extensions/v1beta1kind: Deploymentmetadata:  labels:    io.kompose.service: samples-bi  name: samples-bispec:  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.yamlapiVersion: v1kind: Servicemetadata:  labels:    io.kompose.service: samples-bi  name: samples-bispec:  ports:  - name: "52773"    port: 52773    targetPort: 52773  selector:    io.kompose.service: samples-bi  type: LoadBalancer   是的,我们将在“默认”命名空间中部署,该命名空间适合演示。 好了,现在我们知道了运行_位置_和_内容_。 还剩下_方式_需要了解。   GitHub Actions 工作流程 我们不需要每件事都从头开始做,而是创建一个工作流程,类似于[使用 GitHub Actions 在 GKE 上部署 InterSystems IRIS 解决方案](https://community.intersystems.com/post/deploying-intersystems-iris-solution-gke-using-github-actions)中所述的工作流程。 这次,我们不必担心构建容器。 GKE 特定的部分已替换为特定于 EKS。 粗体部分与接收提交消息和在条件步骤中使用它有关: $ cat /.github/workflows/workflow.yamlname: Provision EKS cluster and deploy Samples BI thereon:  push:    branches:    - master # Environment variables.# ${{ secrets }} are taken from GitHub -> Settings -> Secrets# ${{ github.sha }} is the commit hashenv:  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 使用它的机密: ![](/sites/default/files/inline/images/images/secrets.png)   注意工作流程的突出显示部分。 我们可以通过推送包含短语“[destroy eks]”的提交消息来销毁 EKS 集群。 请注意,我们不会使用这样的提交消息来运行“kubernetes apply”。 运行管道,但首先要创建一个 .gitignore 文件: $ cat /.gitignore.DS_Storeterraform/.terraform/terraform/*.planterraform/*.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-contextdev-cluster $ kubectl get nodesNAME                                                                               STATUS   ROLES      AGE          VERSIONip-10-42-1-125.eu-west-1.compute.internal   Ready          6m20s     v1.14.8-eks-b8860f $ kubectl get poNAME                                                       READY        STATUS      RESTARTS   AGEsamples-bi-756dddffdb-zd9nw    1/1               Running    0                      6m16s $ kubectl get svcNAME                   TYPE                        CLUSTER-IP        EXTERNAL-IP                                                                                                                                                         PORT(S)                    AGEkubernetes        ClusterIP               172.20.0.1                                                                                                                                                                                443/TCP                    11msamples-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](http://a2c6f6733557511eab3c302618b2fae2-622862917.eu-west-1.elb.amazonaws.com:52773/csp/user/_DeepSee.UserPortal.Home.zen?%24NAMESPACE=USER) _(将链接替换为你的外部 IP),然后输入“_system”、“SYS”并更改默认密码。 您应该看到一系列 BI 仪表板: ![](/sites/default/files/inline/images/images/deepsee_ui.png)   点击每个仪表板的箭头可以深入了解: ![](/sites/default/files/inline/images/images/deepsee_2.png)   记住,如果重启 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 启用。 我们将在不久的将来完成这项任务。
文章
Qiao Peng · 一月 14, 2021

InterSystems IRIS 开放授权框架 (OAuth 2.0) 实现 – 第 1 部分

本文以及后面两篇该系列文章,是为需要在其基于 InterSystems 产品的应用程序中使用 OAuth 2.0 框架(下文简称为 OAUTH)的开发人员或系统管理员提供的指南。 作者:InterSystems 高级销售工程师 Daniel Kutac # 发布后校正和更改历史记录 * 2016 年 8 月 3 日 - 修正了 Google 客户端配置屏幕截图,更新了 Google API 屏幕截图以反映新版本的页面 * 2016 年 8 月 28 日 - 更改了 JSON 相关代码,反映了对 Cache 2016.2 JSON 支持的更改 * 2017 年 5 月 3 日 - 更新了文本和屏幕,以反映 Cache 2017.1 的新 UI 和功能 * 2018 年 2 月 19 日 - 将 Caché 更改为 InterSystems IRIS 以反映最新的发展。 但是请记住,尽管产品名称发生更改,但**文章涵盖所有的 InterSystems 产品**——InterSystems IRIS 数据平台、Ensemble 和 Caché。 * 2020 年 8 月 17 日 - 大面积更改,软件方面更改更大。 要获取 Google 的更新版 Oauth2 的网址,请咨询 Micholai Mitchko。 _第 1 部分 客户端_ # **简介** 有关开放式授权框架 InterSystems 实现的相关内容,我们分 3 部分讲述,这是第 1 部分。 在第 1 部分中,我们对该主题进行了简短介绍,并提供了一个 InterSystems IRIS 应用程序担当授权服务器客户端并请求一些受保护资源的简单方案。 第 2 部分将讲述一个复杂一些的方案,在该方案中 InterSystems IRIS 本身通过 OpenID Connect 担当授权服务器和身份验证服务器。 本系列的最后一部分将描述 OAUTH 框架类的各个部分,它们由 InterSystems IRIS 实现。 ## **什么是开放授权框架 [1] ** 许多人已经听说过有关开放授权框架及其用途的信息。 因此这里只做简单介绍,以备未听说过的人参考。 开放授权框架 (OAUTH) 当前为 2.0 版,其是一种协议,允许基于 Web 的主应用程序通过在客户端(应用程序请求数据)和资源所有者(应用程序保存请求的数据)之间建立间接信任来以安全的方式交换信息。 信任本身由客户端和资源服务器都认可并信任的主体提供。 该主体称为授权服务器。 简单举例如下: 假设 Jenny(使用 OAUTH 术语,就是资源所有者)在开展 JennyCorp 公司的一个工作项目。 她为一个潜在的大型业务创建了项目计划,并邀请 JohnInc 公司的业务伙伴 John(客户端用户)审阅此文档。 不过,她并不愿意让 John 访问自己公司的 VPN,因此她将文档放在 Google 云端硬盘(资源服务器)或其他类似的云存储中。 她这样做,已经在她和 Google(授权服务器)之间建立了信任。 她标记了要与 John 共享的文档(John 已经使用 Google 云端硬盘服务,Jenny 知道他的电子邮件)。 当 John 想要阅读该文档时,他进行了 Google 帐户身份验证,然后通过移动设备(平板电脑、笔记本电脑等)启动文档编辑器(客户端服务器)并加载 Jenny 的项目文件。 这听起来很简单,但是两个人与 Google 之间有很多通信。 所有交流均遵循 OAuth 2.0 规范,因此 John 的客户端(阅读器应用程序)必须首先向 Google 进行身份验证(OAUTH 不涵盖此步骤),然后 John 申请获取 Google 对提供表格的同意,经过授权后,Google 就会发出一个访问令牌,授权阅读器应用程序访问文档。 阅读器应用程序使用该访问令牌向 Google 云端硬盘服务发出请求,以检索 Jenny 的文件。 下图说明了各方之间的通信 ![](/sites/default/files/inline/images/1_3.png) 请注意:虽然所有的 OAUTH 2.0 通信都使用 HTTP 请求,但服务器不必非得是 Web 应用程序。 让我们通过 InterSystems IRIS 来说明这一简单方案。 # **简单 Google 云端硬盘演示** 在本演示中,我们将创建一个基于 CSP 的小型应用程序,该应用程序将使用我们自己的帐户(以及作为奖励的日历列表)来请求存储在 Google 云端硬盘服务中的资源(文件列表)。 ## **基本要求** 开始应用程序编码之前,我们需要准备环境。 这包括启用 SSL 的 Web 服务器和 Google 配置文件。 ### **Web 服务器配置** 如上所述,我们需要使用 SSL 与授权服务器进行通信,因为默认情况下 OAuth 2.0 要求如此。 我们需要确保数据安全,对吧? 解释如何配置 Web 服务器来支持 SSL 的内容超出了本文讨论的范围,因此,请以您喜欢的方式参阅相应 Web 服务器的用户手册。 为了您的好奇心(我们稍后可能会显示一些屏幕截图),在此特定示例中,我们将使用 Microsoft IIS 服务器。 ### **Google 配置** 为了向 Google 注册,我们需要使用 Google API Manager-[ https://console.developers.google.com/apis/library?project=globalsummit2016demo ](https://console.developers.google.com/apis/library?project=globalsummit2016demo) 为了进行演示,我们创建了一个帐户 GlobalSummit2016Demo。 确保我们已启用 Drive API ![](/sites/default/files/inline/images/o2.png) 现在,该定义凭据了 ![](/sites/default/files/inline/images/o3.png) 请注意以下事项: _Authorized JavaScript – _我们仅允许本地生成的脚本(相对于调用页面) _Authorized redirect URIs – 从理论上讲,我们可以将客户端应用程序重定向到任何站点,但是当使用 InterSystems IRIS OAUTH 实现时,我们必须重定向到** https://localhost/csp/sys/oauth2/OAuth2.Response.cls**。您可以定义多个授权的重定向 URI,如屏幕截图所示,但是对于本演示,我们只需要两者中的第二个条目。 最后,我们需要将 InterSystems IRIS 配置为 Google 授权服务器的客户端 ### **Caché /IRIS配置** InterSystems IRIS OAUTH2 客户端配置需要两步。 首先,我们需要创建服务器配置。 在 SMP 中,导航至**系统管理 > 安全性 > OAuth 2.0 > 客户端配置**。 点击**创建服务器配置**按钮,填写表格并保存。 ![](/sites/default/files/inline/images/oauth2_1_google_server.png) 输入到表格的所有信息可以在 Google 开发者控制台网站上找到。 请注意,InterSystems IRIS 支持自动 Open ID 发现。 但是,由于我们没有使用它,因此我们手动输入所有信息 现在,点击新创建的 Issuer Endpoint 旁边的“客户端配置”链接。并点击**创建客户端配置**按钮。 ![](/sites/default/files/inline/images/2_6.png) 将“客户端信息”和“JWT 设置”选项卡保留为空(默认值),并填写客户端凭据。 ![](/sites/default/files/inline/images/3_5.png) 请注意:我们正在创建机密客户端(这比公共客户端更安全,这意味着客户端秘密永远不会离开客户端服务器应用程序(永远不会传输到浏览器) 此外,请确保选中**“使用 SSL/TLS**”,并提供主机名(本地主机,因为我们将本地重定向到客户端应用程序),最后提供端口和前缀(当同一台机器上有多个 InterSystems IRIS 实例时,这非常有用)。 根据输入的信息,会计算客户端重定向 URL 并显示在上一行中。 在上面的屏幕截图中,我们提供了一个名为 GOOGLE 的 SSL 配置。 该名称本身实际上仅用于帮助您确定此特定通信通道使用的可能是众多 SSL 配置中的哪个。 Caché 使用 SSL/TLS 配置存储所有必要的信息,以建立与服务器(在本例中,为 Google OAuth 2.0 URI)的安全流量。 有关详细信息,请参阅[文档](http://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GCAS_ssltls#GCAS_ssltls_aboutconfigs) 。 Supply Client ID 和 Client Secret 值从 Google 凭据定义表中获得(使用手动配置时)。 现在,我们完成了所有的配置步骤,可以开始编写 CSP 应用程序代码。 ## **客户端应用程序** 客户端应用程序是基于 Web 的简单 CSP 应用程序。 因此,它包含由 Web 服务器定义和执行的服务器端源代码,以及由 Web 浏览器向用户公开的用户界面。 下文提供的示例代码期望客户端应用程序在 GOOGLE 名称空间中运行。 请将路径 /csp/google/ 修改为您的命名空间。 ## **客户端服务器** 客户端服务器是一个简单的两页应用程序。 在该应用程序内,我们将: ·        将 URL 重定向到 Google 授权服务器 ·        执行向 Google Drive API 和 Google Calendar API 的请求并显示结果 ### **第 1 页** 这是应用程序的一页,我们决定在此处调用 Google 的资源。 以下是此页面上简单但功能齐全的代码。 Class Web.OAUTH2.Google1N Extends %CSP.Page { Parameter OAUTH2CLIENTREDIRECTURI = "https://localhost/csp/google/Web.OAUTH2.Google2N.cls"; Parameter OAUTH2APPNAME = "Google"; ClassMethod OnPage() As %Status { &html // we need to supply openid scope to authenticate to Google set scope="openid https://www.googleapis.com/auth/userinfo.email "_ "https://www.googleapis.com/auth/userinfo.profile "_ "https://www.googleapis.com/auth/drive.metadata.readonly "_ "https://www.googleapis.com/auth/calendar.readonly" set properties("approval_prompt")="force" set properties("include_granted_scopes")="true" set url=##class(%SYS.OAuth2.Authorization).GetAuthorizationCodeEndpoint(..#OAUTH2APPNAME,scope, ..#OAUTH2CLIENTREDIRECTURI,.properties,.isAuthorized,.sc) w !,"" &html Quit $$$OK } ClassMethod OnPreHTTP() As %Boolean [ ServerOnly = 1 ] { #dim %response as %CSP.Response set scope="openid https://www.googleapis.com/auth/userinfo.email "_ "https://www.googleapis.com/auth/userinfo.profile "_ "https://www.googleapis.com/auth/drive.metadata.readonly "_ "https://www.googleapis.com/auth/calendar.readonly" if ##class(%SYS.OAuth2.AccessToken).IsAuthorized(..#OAUTH2APPNAME,,scope,.accessToken,.idtoken,.responseProperties,.error) { set %response.ServerSideRedirect="Web.OAUTH2.Google2N.cls" } quit 1 } } 代码的简要说明如下: 1.      OnPreHTTP 方法 - 首先,我们有机会时检查一下,我们是否由于 Google 授权而获得了有效的访问令牌——这种情况可能会发生,例如当我们只是刷新页面时。 如果没有,我们需要授权。 如果我们有令牌,我们只需将页面重定向到显示结果的页面 2.       OnPage 方法 - 只有在我们没有可用的有效访问令牌时,我们才到这里,因此我们需要开始通信——向 Google 进行身份验证和授权,以便它向我们授予访问令牌。 3.       我们定义了作用域字符串和属性数组,用于修改 Google 身份验证对话框的行为(我们需要先向 Google 进行身份验证,然后它才能根据我们的身份对我们进行授权)。 4.       最后,我们收到 Google 登录页面的 URL,然后将其提供给用户,接着提供同意页面。 还有一点注意事项: 我们在 OAUTH2CLIENTREDIRECTURI 参数的 中指定真正的重定向页面。 但是,我们在 Google 凭据定义中使用了 InterSystems IRIS OAUTH 框架的系统页面! 重定向由我们的 OAUTH 处理程序类在内部处理。 ### **第 2 页** 此页面显示 Google 授权的结果,如果成功,我们将调用 Google API 调用以检索数据。 同样,此代码简单,但功能齐全。 相比读者的想象,我们以更结构化的方式来显示输入数据。 Include %occInclude Class Web.OAUTH2.Google2N Extends %CSP.Page { Parameter OAUTH2APPNAME = "Google"; Parameter OAUTH2ROOT = "https://www.googleapis.com"; ClassMethod OnPage() As %Status { &html // Check if we have an access token set scope="openid https://www.googleapis.com/auth/userinfo.email "_ "https://www.googleapis.com/auth/userinfo.profile "_ "https://www.googleapis.com/auth/drive.metadata.readonly "_ "https://www.googleapis.com/auth/calendar.readonly" set isAuthorized=##class(%SYS.OAuth2.AccessToken).IsAuthorized(..#OAUTH2APPNAME,,scope,.accessToken,.idtoken,.responseProperties,.error) if isAuthorized { // Google has no introspection endpoint - nothing to call - the introspection endpoint and display result -- see RFC 7662. w "Data from GetUserInfo API" // userinfo has special API, but could be also retrieved by just calling Get() method with appropriate url try { set tHttpRequest=##class(%Net.HttpRequest).%New() $$$THROWONERROR(sc,##class(%SYS.OAuth2.AccessToken).AddAccessToken(tHttpRequest,"query","GOOGLE",..#OAUTH2APPNAME)) $$$THROWONERROR(sc,##class(%SYS.OAuth2.AccessToken).GetUserinfo(..#OAUTH2APPNAME,accessToken,,.jsonObject)) w jsonObject.%ToJSON() } catch (e) { w "ERROR: ",$zcvt(e.DisplayString(),"O","HTML")_"" } /****************************************** * * * Retrieve info from other APIs * * * ******************************************/ w "" do ..RetrieveAPIInfo("/drive/v3/files") do ..RetrieveAPIInfo("/calendar/v3/users/me/calendarList") } else { w "Not authorized!" } &html Quit $$$OK } ClassMethod RetrieveAPIInfo(api As %String) { w "Data from "_api_"" try { set tHttpRequest=##class(%Net.HttpRequest).%New() $$$THROWONERROR(sc,##class(%SYS.OAuth2.AccessToken).AddAccessToken(tHttpRequest,"query","GOOGLE",..#OAUTH2APPNAME)) $$$THROWONERROR(sc,tHttpRequest.Get(..#OAUTH2ROOT_api)) set tHttpResponse=tHttpRequest.HttpResponse s tJSONString=tHttpResponse.Data.Read() if $e(tJSONString)'="{" { // not a JSON d tHttpResponse.OutputToDevice() } else { w tJSONString w "" /* // new JSON API &html s tJSONObject={}.%FromJSON(tJSONString) set iterator=tJSONObject.%GetIterator() while iterator.%GetNext(.key,.value) { if $isobject(value) { set iterator1=value.%GetIterator() w "",key,"" while iterator1.%GetNext(.key1,.value1) { if $isobject(value1) { set iterator2=value1.%GetIterator() w "",key1,"" while iterator2.%GetNext(.key2,.value2) { write !, "",key2, "",value2,"" } // this way we can go on and on into the embedded objects/arrays w "" } else { write !, "",key1, "",value1,"" } } w "" } else { write !, "",key, "",value,"" } } &html */ } } catch (e) { w "ERROR: ",$zcvt(e.DisplayString(),"O","HTML")_"" } } }     让我们快速看一下代码: 1.       首先,我们需要检查一下我们是否具有有效的访问令牌(即我们是否被授权) 2.       如果是,我们可以向 Google 提供且由已发布访问令牌覆盖的 API 发出请求 3.       为此,我们使用标准的 %Net.HttpRequest 类,但根据 API 规范,我们将访问令牌添加到 GET 或 POST 方法中 4.       如您所见,为了方便您,OAUTH 框架已实现 GetUserInfo()方法,但是您可以使用 Google API 规范直接检索用户信息,就像我们在 RetrieveAPIInfo()助手方法中所做的一样。 5.       由于在 OAUTH 世界中以 JSON 格式交换数据司空见惯,因此我们只读取传入的数据,然后简单地将其转储到浏览器。 应用程序开发人员可以解析和格式化接收到的数据,以便用户可以看明白。 但这超出了本演示的范围。 (尽管一些代码有注释,显示了如何完成解析。) 下图是一个输出屏幕截图,显示了原始 JSON 数据。 ![](/sites/default/files/inline/images/6_0.png) 继续阅读[第 2 部分](https://community.intersystems.com/post/cach%C3%A9-open-authorization-framework-oauth-20-implementation-part-2),该部分讲述 InterSystems IRIS 担当授权服务器和 OpenID Connect 提供程序相关的内容。   [1] https://tools.ietf.org/html/rfc6749, https://tools.ietf.org/html/rfc6750