清除过滤器
文章
姚 鑫 · 五月 10, 2021
# 第四章 多维存储的SQL和对象使用(二)
# 索引
持久化类可以定义一个或多个索引;其他数据结构用于提高操作(如排序或条件搜索)的效率。InterSystems SQL在执行查询时使用这些索引。InterSystems IRIS对象和SQL在执行`INSERT`、`UPDATE`和`DELETE`操作时自动维护索引内的正确值。
## 标准索引的存储结构
标准索引将一个或多个属性值的有序集与包含属性的对象的对象`ID`值相关联。
例如,假设我们定义了一个简单的持久化`MyApp.Person`类,该类具有两个文本属性和一个关于其`Name`属性的索引:
```java
Class MyApp.Person Extends %Persistent
{
Index NameIdx On Name;
Property Name As %String;
Property Age As %Integer;
}
```
如果我们创建并保存此`Person`类的多个实例,则生成的数据和索引全局变量类似于:
```java
// data global
^MyApp.PersonD = 3 // counter node
^MyApp.PersonD(1) = $LB("",34,"Jones")
^MyApp.PersonD(2) = $LB("",22,"Smith")
^MyApp.PersonD(3) = $LB("",45,"Jones")
// index global
^MyApp.PersonI("NameIdx"," JONES",1) = ""
^MyApp.PersonI("NameIdx"," JONES",3) = ""
^MyApp.PersonI("NameIdx"," SMITH",2) = ""
```
请注意有关全局索引的以下事项:
1. 默认情况下,它被放在一个全局变量中,全局变量的名称是后面附加`“i”`(表示索引)的类名。
2. 默认情况下,第一个下标是索引名;这允许将多个索引存储在同一全局中,而不会发生冲突。
3. 第二个下标包含整理后的数据值。在这种情况下,使用默认的`SQLUPPER`排序函数对数据进行排序。这会将所有字符转换为大写(不考虑大小写进行排序),并在前面加上一个空格字符(强制所有数据作为字符串进行排序)。
4. 第三个下标包含包含索引数据值的对象的对象ID值。
5. 节点本身是空的;所有需要的数据都保存在下标中。请注意,如果索引定义指定数据应与索引一起存储,则将其放置在全局索引的节点中。
该索引包含足够的信息来满足许多查询,比如按姓名列出所有`Person`类。
# 位图索引
位图索引类似于标准索引,不同之处在于它使用一系列位字符串来存储与索引值对应的一组对象`ID`值。
## 位图索引的逻辑运算
位字符串是一个包含一组特殊压缩格式的位(`0`和`1`值)的字符串。
InterSystems IRIS包含一组有效创建和使用位字符串的函数。
这些都列在下表中:
位操作
函数 | 描述
---|---
`$Bit`| 在位串中设置或获取位。
`$BitCount` | 计算位串中的位数。
`$BitFind` | 查找位串中下一个出现的位。
`$BitLogic` | 对两个或多个位串执行逻辑(`AND`, `OR`)操作。
在位图索引中,位字符串中的顺序位置对应于索引表中的行(对象`ID`号)。
对于给定值,位图索引维护一个位字符串,在给定值存在的每一行中包含`1`,在没有给定值的每一行中包含`0`。
请注意,位图索引只适用于使用系统分配的默认存储结构的对象,数值型对象`ID`值。
例如,假设我们有一个类似如下的表:
ID| State| Product
---|---|---
1| MA| Hat
2| NY| Hat
3| NY| Chair
4| MA| Chair
5| MA| Hat
如果`State`和`Product`列有位图索引,则它们包含以下值:
`State`列上的位图索引包含以下位字符串值:
```
MA 1 0 0 1 1
NY 0 1 1 0 0
```
注意,对于值`“MA”`,在与`State`等于`“MA”`的表行对应的位置(1、4和5)中有一个1。
类似地,`Product`列上的位图索引包含以下位字符串值(注意,这些值在索引中被排序为大写):
```
CHAIR 0 0 1 1 0
HAT 1 1 0 0 1
```
InterSystems SQL Engine可以通过对这些索引维护的位串进行迭代、计算位内位数或执行逻辑组合(`AND, or`)来执行许多操作。
例如,要找到`State`等于`“MA”`、`Product`等于`“HAT”`的所有行,SQL引擎可以简单地将适当的位串与逻辑`and`组合在一起。
除了这些索引之外,系统还维护一个额外的索引,称为“区段索引”,对于存在的每一行包含1,对于不存在的行(如已删除的行)包含0。
这用于某些操作,如否定。
## 位图索引的存储结构
位图索引将一个或多个属性值的有序集合与一个或多个包含与属性值对应的对象`ID`值的位字符串相关联。
例如,假设我们定义了一个简单的持久`MyApp`。
`Person`类具有两个文字属性和`Age`属性上的位图索引:
```java
Class MyApp.Person Extends %Persistent
{
Index AgeIdx On Age [Type = bitmap];
Property Name As %String;
Property Age As %Integer;
}
```
如果我们创建并保存这个`Person`类的几个实例,得到的数据和索引全局变量类似于:
```java
// data global
^MyApp.PersonD = 3 // counter node
^MyApp.PersonD(1) = $LB("",34,"Jones")
^MyApp.PersonD(2) = $LB("",34,"Smith")
^MyApp.PersonD(3) = $LB("",45,"Jones")
// index global
^MyApp.PersonI("AgeIdx",34,1) = 110...
^MyApp.PersonI("AgeIdx",45,1) = 001...
// extent index global
^MyApp.PersonI("$Person",1) = 111...
^MyApp.PersonI("$Person",2) = 111...
```
关于全局索引,请注意以下几点:
1. 默认情况下,它被放置在一个全局变量中,全局变量的名称是类名,后面附加一个`“I”`(表示`Index`)。
2. 默认情况下,第一个下标是索引名;这允许多个索引存储在同一个全局中,而不会发生冲突。
3. 第二个下标包含经过整理的数据值。在这种情况下,不应用排序函数,因为这是数字数据的索引。
4. **第三个下标包含块编号;为了提高效率,位图索引被分成一系列位串,每个位串包含表中大约`64000`行的信息。这些位串中的每一个都被称为块。**
5. 节点包含位串。
另请注意:因为该表有一个位图索引,所以会自动维护一个区索引。该盘区索引存储在索引`GLOBAL`中,并使用前缀有`“$”`字符的类名作为其第一个下标。
## 位图索引的直接访问
下面的示例使用类区索引来计算存储的对象实例(行)的总数。注意,它使用`$ORDER`来迭代区索引的块(每个块包含大约64000行的信息):
```java
ClassMethod Count1() As %Integer
{
New total,chunk,data
Set total = 0
Set chunk = $Order(^Sample.PersonI("$Person",""),1,data)
While (chunk '= "") {
Set total = total + $bitcount(data,1)
Set chunk = $Order(^Sample.PersonI("$Person",chunk),1,data)
}
Quit total
}
```
```java
DHC-APP>w ##class(PHA.TEST.SQL).Count1()
208
```
文章
Louis Lu · 一月 7, 2021
**RHEL V7.2 上的 Caché 进程故障**
InterSystems WRC 处理了几个有关进程错误引发的问题,这些问题可以归因于 Red Hat Linux 最近的一次更新。
RHEL V7.2 (systemd-219-19.el7.x86_64) 中实现的一个新功能可能导致操作系统 IPC(进程间通信)信号量在 非系统用户注销时被解除分配(系统用户,即 UID 编号小于 1000 的用户除外)。
Caché 在内部利用 IPC 信号量来控制 Caché 进程的运行(例如,当尝试唤醒 Caché 进程时)。 这通过“semop”系统服务来实现,如果操作系统意外删除了 Caché 用于进行 IPC 通讯的信号量,则进程可能会出现错误。 如果发生这种情况,在 cconsole.log 中会找到以下证据:
“System error while trying to wake-up a process, code = 22”(尝试唤醒进程时系统出错,代码 = 22)
以及在 Caché SYSLOG 中也会记录相应的错误,例如以下典型示例:
Err Process Date/Time Mod Line Routine Namespace
22 39761 09/29/2016 04:41:27PM 61 359 BF0+1359^Ens.Queue.1 HSBUS
这最终可能导致 Caché 的运行实例处于挂起状态。
以下是 Redhat 提供的一篇文章的链接,文中给出了有关此功能的详细信息以及禁用该功能的方法:
[https://access.redhat.com/solutions/2062273](https://access.redhat.com/solutions/2062273 "Follow link")
此问题已在 systemd-219-19.el7_2.4(通过 RHBA-2016-0199 发布 ()中修复。
公告
Claire Zheng · 一月 25, 2022
亲爱的开发者们,
很高兴同大家分享一个好消息!我们中文社区版主、InterSystems高级销售工程师Louis(@Louis Lu)于近日顺利通过“HL7 FHIR R4 Proficiency Exam”并取得资格认证证书!
HL7 FHIR(R4)能力证书可以证明在最新和最热门的HL7标准方面达到行业公认的专业水平。考试涵盖了以下内容:FHIR原则;FHIR资源的基本概念;交换机制;一致性和实施指导;如何使用术语;如何建立安全和可靠的FHIR解决方案;FHIR维护过程;以及如何使用和处理FHIR许可和知识产权(IP)。
FHIR®(快速医疗互操作性资源)是HL7的下一代标准框架,它建立并结合了HL7第二版(V2)、第三版(V3)和临床文档架构(CDA®)产品线的最佳功能,同时利用了最新的网络标准并注重于实际实施的能力。FHIR适合在各种情况下使用,如手机应用程序、云通信、基于电子健康记录(EHR)的数据共享、大型医疗机构间服务器通信等等。FHIR还可以支持使用一个标准涵盖尽可能多的应用场景,实现医疗信息化真正意义的互操作性,是智慧医院数字化转型,实现组装式应用创新的重要基础。
一起来恭喜Louis(@Louis Lu)吧✿✿ヽ(°▽°)ノ✿✿✿ヽ(°▽°)ノ✿(*^▽^*) 恭喜🎉🎉
文章
Lele Yang · 一月 30, 2022
Linux内核机制OOM Killer,也即Out of Memory Killer, 顾名思义,该机制的主要职能就是当内存不足时,选择并杀掉一些进程,以使系统继续运行。
Caché/Ensemble/IRIS的多个客户曾经遇到过与此相关的系统宕机,宕机的直接原因是数据库核心写进程Write Daemon被OOM Killer选中并杀掉了,在我们的日志文件中可以看到如下信息,
06/15/21-10:50:31:035 (13579) 3 Daemon WRTDMN (pid 13588) died. Freezing system
06/15/21-10:52:25:940 (13601) 2 System Process 'WRTDMN' terminated abnormally (pid 13588)
与之对应,在操作系统的日志文件中可以看到如下记录,
Jun 15 10:50:34 localhost kernel: Free swap = 0kB
Jun 15 10:50:34 localhost kernel: Total swap = 20479996kB
Jun 15 10:50:34 localhost kernel: 16777102 pages RAM
Jun 15 10:50:34 localhost kernel: 0 pages HighMem/MovableOnly
Jun 15 10:50:34 localhost kernel: 324506 pages reserved
Jun 15 10:50:30 localhost kernel: cache invoked oom-killer: gfp_mask=0x42d0, order=3, oom_score_adj=0
Jun 15 10:50:35 localhost kernel: Out of memory: Kill process 13588 (cache) score 127 or sacrifice child
InterSystems在后续的IRIS版本中(从IRIS2021.1.0开始)已经对此做了优化,以使Write Daemon不那么容易被OOM Killer选中。但是要从根本上解决该问题,还是应当重新审视系统的内存分配,如Huge Page,共享内存等,检查Linux内存相关参数,如vm.swappiness,vm.dirty_background_ratio,vm.dirty_ratio等,以使系统可以在内存使用方面达到最大的效用。
文章
Michael Lei · 三月 10, 2023
InterSystems IRIS 2022.2 具有适用于 Python 的原生 SDK (https://docs.intersystems.com/iris20222/csp/docbook/Doc.View.cls?KEY=PAGE_python_native)。
我们知道如何使用 IRIS Object Script $Order 函数遍历Global数据结构。
SET key= "" FOR { SET key= $ORDER ( ^myglobal (key)) QUIT :key= "" WRITE !, ^myglobal (key) }
如何使用 IRIS Native SDK 从 Python 执行相同的操作?这里有一个代码示例:
import iris
args = { 'hostname' : '127.0.0.1' , 'port' : 51772 , 'namespace' : 'USER' , 'username' : '_SYSTEM' , 'password' : 'SYS' }
conn = iris.connect(**args)
# Create an iris object
irispy = iris.createIRIS(conn)
# Create a global array in the USER namespace on the server
irispy.set( 'A' , 'root' , 'foo' , 'SubFoo' )
irispy.set( 123 , 'root' , 'bar' , 'lowbar' , 'UnderBar' )
irispy.set( 124 , 'root' , 'bar' , 'lowbar' , 'UnderBar2' )
irispy.set( "hi" , 'root' , 'bar' , 'lowbar' )
irispy.set( "hi again" , 'root' , 'bar3' )
# Read the values from the database and print them
subfoo_value = irispy.get( 'root' , 'foo' , 'SubFoo' )
underbar_value = irispy.get( 'root' , 'bar' , 'lowbar' , 'UnderBar' )
underbar2_value = irispy.get( 'root' , 'bar' , 'lowbar' , 'UnderBar2' )
lowbar_value = irispy.get( 'root' , 'bar' , 'lowbar' )
bar3_value = irispy.get( 'root' , 'bar3' )
print( 'Created two values: ' )
print( ' root("foo","SubFoo")=' , subfoo_value)
print( ' root("bar","lowbar","UnderBar")=' , underbar_value)
print( ' root("bar","lowbar","UnderBar2")=' , underbar2_value)
print( ' root("bar","lowbar")=' , lowbar_value)
print( ' root("bar3")=' , bar3_value)
direction = 0 # direction of iteration (boolean forward/reverse)
next_sub = chr( 0 ) # start at first possible subscript
subs = []
print( "\n Iterating root \n" )
isDef = irispy.isDefined( 'root' , *subs)
while isDef:
next_sub = irispy.nextSubscript( False , 'root' , *subs, next_sub) # get first subscript
if next_sub == None : # we finished iterating nodes on this tree branch, move a level up
if len(subs) == 0 : # no more things to iterate
break
next_sub = subs.pop( -1 ) # pop last subscript in order to continue iterating this level
if irispy.isDefined( 'root' , *subs, next_sub) == 11 :
print( 'root(' ,*subs, next_sub, ')=' ,irispy.get( 'root' , *subs, next_sub))
continue
continue
isDef = irispy.isDefined( 'root' , *subs, next_sub)
if isDef in [ 10 , 11 ]: # keep building subscripts for depth first search
subs.append(next_sub)
next_sub = chr( 0 )
continue
elif isDef == 1 : # reached a leaf node, print it
print( 'root(' ,*subs, next_sub, ')=' ,irispy.get( 'root' , *subs, next_sub))
else : # def 0 is not really expected
print( "error" )
irispy.kill( 'root' )
conn.close()
exit( -1 )
# Delete the global array and terminate
irispy.kill( 'root' ) # delete global array root
conn.close()
问题
water huang · 四月 17, 2021
如图 dll放在
我调用的方式如下
期待能够在ensemble里面能便捷的调用dll,各种语言开发的dll,至少能支持c#生成的dll, 在Ensemble 2016中,使用$ZF(-4)来操作DLL是Caché的Callout网关的底层实现之一。这种方式比较通用。当然,如果这些DLL(ActiveX/COM)注册在Ensemble服务器上(Windows服务器),还有别的调用方式:使用Caché Activate 网关,用Studio来产生这些DLL的代理类,然后您就可以像使用Ensemble/Caché类一样使用这些DLL里的方法了。 使用Caché Activate 网关 这个并不好用。服务器重启后 需要重启网关,还很可能需要重新导入dll来生成代理类。因此这样的方式 我已经弃用,或者说 “可能需要重新导入dll来生成代理类” 这个是我操作不对才导致这样的结果?使用$ZF(-4)来操作DLL,这个dll具有一些特殊要求?比如? 如果dll重新编译过,那么是需要重新生成代理类的;其它情况下并不需要。另外,Ensemble 2016里有.net 网关,通过Studio来建立dll代理类。不过它依然需要在dll代码发生变化时重新生成代理类。
这也是后续版本(尤其是InterSystems IRIS)推出动态对象网关的原因:通过动态网关就不用生成代理类了,从而避免因为.net/java端发生代码变更而需要重新生成代理类。$ZF()对DLL没有特殊要求。
文章
Hao Ma · 一月 15, 2021
什么是npm-iris?
NPM是“No Project Mess(项目不乱)”的缩写。
NPM是使用Intersystems IRIS和Bootstrp 4建成的项目和任务管理应用程序。
NPM的创建初衷是通过一个简单直观的项目和任务管理软件,帮助开发者和小型商业公司降低日常问题的复杂度。
它能提供不同的任务视图,包括电子表格、看板、日历,甚至甘特图!
为什么?
在不同的团队中工作,您会发现不同的人喜欢不同的工具。
所以,有时您会在一个项目中使用甘特图,在另一个项目中使用看板,在其他项目中使用纸上的列表……
NPM专注于任务。无论您和您的团队喜欢以哪种方式查看。只需单击并更改您的视图。
功能
初始安装
项目
用户
任务 - 创建和管理任务
调度程序 - 任务的日历视图
看板 - 用看板风格管理您的任务
甘特图 - 使用甘特图查看截止日期、里程碑和进度
新特性/改进的路线图
OAuth2身份验证
项目/团队/用户的安全性
时间跟踪
自定义日历(假期)
支持附件
利用AppS.REST框架
Vue.js版本
Home面板,可以查看活动的概况
试一下这款应用程序! http://npm-iris.eastus.cloudapp.azure.com:52773/npm/home.csp
如果您喜欢这个应用程序,并认为我值得您的投票,请投票给npm-iris! https://openexchange.intersystems.com/contest/current
文章
姚 鑫 · 四月 1, 2021
# 第十四章 使用SQL Shell界面(三)
# SQL元数据、查询计划和性能指标
## 显示元数据
SQL Shell支持`M`或`Metadata`命令以显示有关当前查询的元数据信息。
对于每个结果集项目,此命令列出以下元数据:列名称(SQL字段名称),键入(ODBC数据类型整数代码),PRE(精度或最大长度),比例(最大分数数字),`NULL(BOOLEAN:1 = NULL允许,0 =不允许空值)`,标签(标题标签,请参阅列别名),表(SQL表名称),架构(架构名称),`CTYPE`(客户端数据类型,请参阅`%SQL.statementColumn ClientType`属性)。
## SHOW STATEMENT
可以执行查询,然后发出show语句或显示`st`以显示准备好的SQL语句。默认情况下,必须执行查询。可以避免通过设置`executemode =延迟`执行查询,从而发出查询,然后发出`show`语句sql shell命令。
显示声明信息包含实现类(缓存查询名称),参数(一个以逗号分隔的实际参数值,如上面条款和`WHERE`子句文字值),和语句文本(文字文本的SQL命令,包括字母大小写和参数值)。
## EXPLAIN and Show Plan
有两种方式显示SQL查询的查询计划;
如果需要,两者都可以显示备用的查询计划。
- EXPLAIN:前言用解释命令选择SELECT查询。例如:
```sql
SQL]USER>>EXPLAIN SELECT Name FROM Sample.MyTable WHERE Name='Fred Rogers'
```
- SHOW PLAN:发出查询,然后发出show plan shell命令。例如:
```sql
SQL]USER>>SELECT Name FROM Sample.MyTable WHERE Name='Fred Rogers'
SQL]USER>>SHOW PLAN
```
EXPLAIN SQL命令显示有关指定选择查询的查询计划信息而不执行查询。EXPLAIN Alt允许显示备用查询计划。EXPLAIN Stat返回性能统计信息以及查询计划。EXPLAIN只能用于返回选择查询的查询计划;它不会返回用于执行查询操作的`Insert`,`Update`或`DELETE`语句等其他命令的查询计划。
Show Plan SQL shell命令允许显示SQL Shell成功发布的上次查询的查询计划信息。显示计划可用于执行查询操作的任何SQL命令,包括选择,插入,更新和删除。默认情况下,必须执行查询。可以避免通过设置`executemode=deferred`,执行查询,发出查询,然后发出以下SQL shell命令之一:
- SHOW PLAN、SHOW PL(或简单的SHOW)显示关于当前查询的查询计划信息。
查询计划可用于调试和优化查询的性能。
它指定查询的执行方式,包括索引的使用和查询的成本值。
可以返回查询计划的语句有:`SELECT`、`DECLARE`、`non-cursor UPDATE or DELETE`、`INSERT…SELECT`。
该命令有一个`V` (VERBOSE)选项。
- 显示PLANALT显示当前查询的备用显示计划。
该命令有一个`V` (VERBOSE)选项。
可以使用`$SYSTEM.SQL.Explain()`方法从ObjectScript生成查询计划。
## SQL Shell Performance
成功执行一个SQL语句后,SQL Shell会显示四个语句准备值(`times(s)/globals/cmds/disk`)和四个语句执行值(`times(s)/globals/cmds/disk`):
- 语句准备时间是指准备动态语句所花费的时间。
这包括生成和编译语句所花费的时间。
它包括在语句缓存中查找语句所花费的时间。
因此,如果执行了一条语句,然后按编号或名称回收,回收语句的准备时间接近于零。
如果一条语句已经准备好并执行,然后通过发出GO命令重新执行,那么重新执行时的准备时间为零。
- 经过的执行时间是从调用`%execute()`到`%Display()`返回所经过的时间。
它不包括输入参数值的等待时间。
语句`globals`是全局引用的计数,`cmds`是执行的SQL命令的计数,`disk`是磁盘延迟时间,单位是毫秒。
SQL Shell为准备操作和执行操作保留单独的计数。
这些性能值只在`“DISPLAYMODE”`设置为`“currentdevice”`,`“MESSAGES”`设置为`“ON”`时显示。
这些是SQL Shell的默认设置。
# Transact-SQL支持
默认情况下,SQL Shell执行InterSystems SQL代码。
但是,SQL Shell可以用来执行`Sybase`或MSSQL代码。
## Setting DIALECT
默认情况下,SQL Shell将代码解析为InterSystems SQL。
可以使用`SET DIALECT`来配置SQL Shell以执行`Sybase`或`MSSQL`代码。
若要更改当前方言,请将`“方言”`设置为`Sybase`、`MSSQL`或IRIS。
默认值是`Dialect=IRIS`。
这些设置的方言选项不区分大小写。
下面是一个从SQL Shell中执行MSSQL程序的例子:
```java
DHC-APP>DO $SYSTEM.SQL.Shell()
SQL Command Line Shell
----------------------------------------------------
The command prefix is currently set to: .
Enter q to quit, ? for help.
DHC-APP>>SET DIALECT MSSQL
dialect = MSSQL
DHC-APP>>SELECT TOP 5 name + '-' + ssn FROM Sample.Person
1. SELECT TOP 5 name + '-' + ssn FROM Sample.Person
Expression_1
yaoxin-111-11-1117
xiaoli-111-11-1111
姚鑫-111-11-1112
姚鑫-111-11-1113
姚鑫-111-11-1114
5 Rows(s) Affected
statement prepare time(s)/globals/lines/disk: 0.1989s/46546/257369/114ms
execute time(s)/globals/lines/disk: 0.0032s/24/676/3ms
---------------------------------------------------------------------------
```
`Sybase`和`MSSQL`方言支持这些方言中有限的SQL语句子集。
它们支持`SELECT`、`INSERT`、`UPDATE`和`DELETE`语句。
它们对永久表支持`CREATE TABLE`语句,但对临时表不支持。
支持创建视图。
支持创建触发器和删除触发器。
但是,如果`CREATE TRIGGER`语句部分成功,但在类编译时失败,则此实现不支持事务回滚。
支持`CREATE PROCEDURE`和`CREATE FUNCTION`。
## Setting COMMANDPREFIX
可以使用`SET COMMANDPREFIX`指定必须追加到后续SQL Shell命令的前缀(通常是单个字符)。
在SQL Shell提示符发出的SQL语句中不使用此前缀。
这个前缀的目的是防止SQL Shell命令和SQL代码语句之间的歧义。
例如,`SET`是一个SQL Shell命令;
`SET`也是`Sybase`和`MSSQL`中的SQL代码语句。
默认情况下,没有命令前缀。
要建立命令前缀,设置`COMMANDPREFIX=prefix`,指定的前缀不带引号。
要恢复为没有命令前缀,设置`COMMANDPREFIX=""`。
以下示例显示了命令前缀/(斜杠字符)被设置、使用和恢复的示例:
```java
DHC-APP>>SET COMMANDPREFIX=/
commandprefix = /
DHC-APP>>/SET LOG=ON
log = xsql19388.log
DHC-APP>> >
1>>SELECT TOP 3 Name,Age
2>>FROM Sample.Person
3>>/GO
2. SELECT TOP 3 Name,Age
FROM Sample.Person
Name Age
yaoxin 30
xiaoli
姚鑫 7
3 Rows(s) Affected
statement prepare time(s)/globals/lines/disk: 0.0595s/46282/256257/9ms
execute time(s)/globals/lines/disk: 0.0003s/3/714/0ms
---------------------------------------------------------------------------
DHC-APP>>/SET COMMANDPREFIX
commandprefix = /
DHC-APP>>/SET COMMANDPREFIX=""
commandprefix = ""
DHC-APP>>SET COMMANDPREFIX
commandprefix =
```
当设置了命令前缀时,除了`?`、`#`和`GO`之外的所有SQL Shell命令都需要该命令前缀;
可以使用或不使用命令前缀发出这三个SQL Shell命令。
当发出`SET`或`SET COMMANDPREFIX`命令时,SQL Shell将显示当前命令前缀,作为SQL Shell初始化的一部分,并且在`?`
命令选项显示。
## 运行命令
SQL Shell `RUN`命令执行SQL脚本文件。
在发出运行命令之前必须设置方言,以指定IRIS (InterSystems SQL)、Sybase (Sybase TSQL)或MSSQL (Microsoft SQL);
默认的方言是IRIS。
可以调用`RUN scriptname`,也可以只调用`RUN`,然后提示输入脚本文件名。
`RUN`加载脚本文件,然后准备并执行文件中包含的每个语句。
脚本文件中的语句必须分隔,通常用`GO`行或分号(`;`)分隔。
`RUN`命令提示指定分隔符。
SQL脚本文件结果显示在当前设备上,也可以显示在日志文件中。
还可以生成一个包含准备失败语句的文件。
`RUN`命令返回指定这些选项的提示符,示例如下:
```java
[SQL]USER>>SET DIALECT=Sybase
dialect = Sybase
[SQL]USER>>RUN
Enter the name of the SQL script file to run: SybaseTest
Enter the file name that will contain a log of statements, results and errors (.log): SyTest.log
SyTest.log
Many script files contain statements not supported by IRIS SQL.
Would you like to log the statements not supported to a file so they
can be dealt with manually, if applicable? Y=> y
Enter the file name in which to record non-supported statements (_Unsupported.log): SyTest_Unsupported.log
Please enter the end-of-statement delimiter (Default is 'GO'): GO=>
Pause how many seconds after error? 5 => 3
Sybase Conversion Utility (v3)
Reading source from file:
Statements, results and messages will be logged to: SyTest.log
.
.
.
```
## TSQL例子
下面的SQL Shell示例创建了一个`Sybase`过程`AvgAge`。
它使用`Sybase EXEC`命令执行这个过程。
然后,它将方言更改为InterSystems IRIS,并使用InterSystems SQL `CALL`命令执行相同的过程。
```java
DHC-APP>>SET DIALECT Sybase
dialect = Sybase
DHC-APP>> >
1>>CREATE PROCEDURE AvgAge
2>>AS SELECT AVG(Age) FROM Sample.Person
3>>GO
3. CREATE PROCEDURE AvgAge
AS SELECT AVG(Age) FROM Sample.Person
statement prepare time(s)/globals/lines/disk: 0.0173s/8129/22308/4ms
execute time(s)/globals/lines/disk: 0.0436s/3844/23853/34ms
---------------------------------------------------------------------------
DHC-APP>>EXEC AvgAge
4. EXEC AvgAge
Dumping result #1
Aggregate_1
50.68137254901960784
1 Rows(s) Affected
statement prepare time(s)/globals/lines/disk: 0.0086s/8096/21623/0ms
execute time(s)/globals/lines/disk: 0.1131s/90637/458136/19ms
---------------------------------------------------------------------------
DHC-APP>>SET DIALECT=IRIS
Dialect 'iris' is not supported.
```
文章
Hao Ma · 三月 25, 2021
**关键字**:PyODBC,unixODBC,IRIS,IntegratedML,Jupyter Notebook,Python 3
## **目的**
几个月前,我简单谈到了关于“[将 Python JDBC 连接到 IRIS](https://community.intersystems.com/post/python-jdbc-connection-iris-database-quick-note)”的话题。我后来频繁提起它, 因此决定再写一篇 5 分钟的笔记,说明如何“将 Python ODBC 连接到 IRIS”。
在 Windows 客户端中通常很容易设置 ODBC 和 PyODBC,不过我每次在 Linux/Unix 风格的服务器中设置 unixODBC 和 PyODBC 客户端时,都会遇到一些麻烦。
有没有一种简单连贯的方法,可以不安装任何 IRIS,在原版 Linux 客户端中让 PyODBC/unixODBC 针对远程 IRIS 服务器运行?
## **范围**
最近,我花了点时间研究如何在 Linux Docker 环境的 Jupyter Notebook 中从头开始让一个 PyODBC 演示运行起来, 记录下这篇稍微有些繁琐的笔记,以供日后快速参考。
#### **范围内**:
这篇笔记将涉及以下组件:
PyODBC over unixODBC
安装了 TensorFlow 2.2 和 Python 3 的 Jupyter Notebook 服务器
带有 IntegratedML 的 IRIS2020.3 CE 服务器,包括示例测试数据。
在此环境中
安装了 Docker-compose over AWS Ubuntu 16.04 的 Docker Engine
Docker Desktop for MacOS 和 Docker Toolbox for Windows 10 也经过了测试
#### **范围外**:
同样,在此演示环境中不评估非功能性方面。 它们很重要,并且可以针对特定站点,如:
端到端安全和审核
性能和可扩展性
许可和可支持性等
## **环境**
任何原版 Linux Docker 镜像都可以用于以下配置和测试步骤,但有一个简单的方法可以在 5 分钟内设置这样的环境:
1. Git **克隆**此[演示模板](https://github.com/tom-dyar/integratedml-demo-template)
2. 在包含 docker-compose.yml 文件的克隆目录中运行“**docker-compose up -d**”。
这将创建一个演示环境,如下面的拓扑所示,其中包含 2 个容器。 一个用于 Jupyter Notebook 服务器作为 PyODBC 客户端,另一个用于 IRIS2020.3 CE 服务器。
在上面的环境中,tf2jupyter 仅包含“Python over JDBC”客户端配置;它尚不包含任何 ODBC 或 PyODBC 客户端配置。
因此,我们将直接在 Jupyter Notebook 内部运行以下设置步骤,以使其易于说明。
## **步骤**
以下配置和测试由我在 AWS Ubuntu 16.04 服务器中运行, 由我的同事 @Thomas.Dyar 在 MacOS 中运行。 另外在 Docker Toolbox for Windows 中也进行了简单的测试。 不过,如果您遇到任何问题,还是请告诉我们。
以下步骤可以自动化到其 Dockerfile。 我在这里特别记录一下,以防几个月后忘记。
### **1. 官方文档:**
IRIS 的 ODBC 支持
在 Unix 上定义 ODBC 数据源
IRIS 的 PyODBC 支持
### **2. 连接到 Jupyter 服务器**
我用本地 Putty 的 SSH 隧道连接到远程 AWS Ubuntu 端口 22,然后按照上述拓扑结构映射到端口 8896。
(举个例子,在本地 Docker 环境中,也可以直接直接 http 到 Docker 机器的 IP:8896。)
### **3. 从 Jupyter Notebook 中运行 ODBC 安装**
直接在 Jupyter 单元格中运行以下代码:
!apt-get update<br>!apt-get install gcc<br>!apt-get install -y tdsodbc unixodbc-dev<br>!apt install unixodbc-bin -y<br>!apt-get clean -y
它将安装 gcc(包括 g++)编译器、FreeTDS、unixODBC 和 unixodbc-dev,以在下一步重新编译 PyODBC 驱动程序。
在原生 Windows 服务器或 PC 上安装 PyODBC 不需要这一步。
### **4. 从 Jupyter 中运行 PyODBC 安装**
!pip install pyodbc
Collecting pyodbc
Downloading pyodbc-4.0.30.tar.gz (266 kB)
|████████████████████████████████| 266 kB 11.3 MB/s eta 0:00:01
Building wheels for collected packages: pyodbc
Building wheel for pyodbc (setup.py) ... done
Created wheel for pyodbc: filename=pyodbc-4.0.30-cp36-cp36m-linux_x86_64.whl size=273453 sha256=b794c35f41e440441f2e79a95fead36d3aebfa74c0832a92647bb90c934688b3
Stored in directory: /root/.cache/pip/wheels/e3/3f/16/e11367542166d4f8a252c031ac3a4163d3b901b251ec71e905
Successfully built pyodbc
Installing collected packages: pyodbc
Successfully installed pyodbc-4.0.30
以上是这个 Docker 演示的最简化 pip 安装。 在[官方文档](https://irisdocs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=BNETODBC_support#BNETODBC_support_pyodbc)中,为“MacOS X 安装”提供了更详细的 pip 安装。
### **5 在 Linux 中重新配置 ODBC INI 文件和链接:**
运行以下命令重新创建 **odbcinst.ini** 和 **odbc.ini** 链接
!rm /etc/odbcinst.ini!rm /etc/odbc.ini
!ln -s /tf/odbcinst.ini /etc/odbcinst.ini!ln -s /tf/odbc.ini /etc/odbc.ini
注:这样的原因是,**第 3 步和第 4 步通常会在 \etc\ directory 下创建 2 个空白(因此无效)的 ODBC 文件。**与 Windows 安装不同,这里的空白 ini 文件会导致问题。因此需要先将其删除,然后重新创建一个链接来指向映射的 Docker 卷中提供的真实 ini 文件:/tf/odbcinst.ini 和 /tf/odbc.ini
看一看这两个 ini 文件。在这种情况下,它们是 Linux ODBC 配置的最简形式:
!cat /tf/odbcinst.ini
[InterSystems ODBC35]
UsageCount=1
Driver=/tf/libirisodbcu35.so
Setup=/tf/libirisodbcu35.so
SQLLevel=1
FileUsage=0
DriverODBCVer=02.10
ConnectFunctions=YYN
APILevel=1
DEBUG=1
CPTimeout=<not pooled>
!cat /tf/odbc.ini
[IRIS PyODBC Demo]
Driver=InterSystems ODBC35
Protocol=TCP
Host=irisimlsvr
Port=51773
Namespace=USER
UID=SUPERUSER
Password=SYS
Description=Sample namespace
Query Timeout=0
Static Cursors=0
以上文件都已预先配置,位于映射的驱动器中。 引用的是驱动程序文件 **libirisodbcu35.so**,可以从 IRIS 服务器的容器实例中获取该文件(在其 {iris-installation}/bin 目录下)。
要使上述 ODBC 安装正常运行,**这 3 个文件**必须存在于**具有正确文件权限**的映射驱动器(或任何 Linux 驱动器)中:
libirisodbcu35.so
odbcinst.ini
odbc.ini
**6. 验证 PyODBC 安装 **
!odbcinst -j
unixODBC 2.3.4
DRIVERS............: /etc/odbcinst.ini
SYSTEM DATA SOURCES: /etc/odbc.ini
FILE DATA SOURCES..: /etc/ODBCDataSources
USER DATA SOURCES..: /root/.odbc.ini
SQLULEN Size.......: 8
SQLLEN Size........: 8
SQLSETPOSIROW Size.: 8
import pyodbcprint(pyodbc.drivers())
['InterSystems ODBC35']
以上输出将表明 ODBC 驱动程序目前具有有效链接。
我们应该能够在 Jupyter Notebook 中运行一些 Python ODBC 测试
**7. 运行将 Python ODBC 连接到 IRIS 的示例:**
import pyodbc import time
### 1. Get an ODBC connection #input("Hit any key to start")dsn = 'IRIS PyODBC Demo'server = 'irisimlsvr' # IRIS server container or the docker machine's IP port = '51773' # or 8091 if docker machine IP is useddatabase = 'USER' username = 'SUPERUSER' password = 'SYS'
#cnxn = pyodbc.connect('DSN='+dsn+';') # use the user DSN defined in odbc.ini, or use the connection string belowcnxn = pyodbc.connect('DRIVER={InterSystems ODBC35};SERVER='+server+';PORT='+port+';DATABASE='+database+';UID='+username+';PWD='+ password)
###ensure it reads strings correctly.cnxn.setdecoding(pyodbc.SQL_CHAR, encoding='utf8')cnxn.setdecoding(pyodbc.SQL_WCHAR, encoding='utf8')cnxn.setencoding(encoding='utf8')
### 2. Get a cursor; start the timercursor = cnxn.cursor()start= time.clock()
### 3. specify the training data, and give a model namedataTable = 'DataMining.IrisDataset'dataTablePredict = 'Result12'dataColumn = 'Species'dataColumnPredict = "PredictedSpecies"modelName = "Flower12" #chose a name - must be unique in server end
### 4. Train and predict#cursor.execute("CREATE MODEL %s PREDICTING (%s) FROM %s" % (modelName, dataColumn, dataTable))#cursor.execute("TRAIN MODEL %s FROM %s" % (modelName, dataTable))#cursor.execute("Create Table %s (%s VARCHAR(100), %s VARCHAR(100))" % (dataTablePredict, dataColumnPredict, dataColumn))#cursor.execute("INSERT INTO %s SELECT TOP 20 PREDICT(%s) AS %s, %s FROM %s" % (dataTablePredict, modelName, dataColumnPredict, dataColumn, dataTable)) #cnxn.commit()
### 5. show the predict resultcursor.execute("SELECT * from %s ORDER BY ID" % dataTable) #or use dataTablePredict result by IntegratedML if you run step 4 aboverow = cursor.fetchone() while row: print(row) row = cursor.fetchone()
### 6. CLose and clean cnxn.close()end= time.clock()print ("Total elapsed time: ")print (end-start)
(1, 1.4, 0.2, 5.1, 3.5, 'Iris-setosa')
(2, 1.4, 0.2, 4.9, 3.0, 'Iris-setosa')
(3, 1.3, 0.2, 4.7, 3.2, 'Iris-setosa')
(4, 1.5, 0.2, 4.6, 3.1, 'Iris-setosa')
(5, 1.4, 0.2, 5.0, 3.6, 'Iris-setosa')
... ...
... ...
... ...
(146, 5.2, 2.3, 6.7, 3.0, 'Iris-virginica')
(147, 5.0, 1.9, 6.3, 2.5, 'Iris-virginica')
(148, 5.2, 2.0, 6.5, 3.0, 'Iris-virginica')
(149, 5.4, 2.3, 6.2, 3.4, 'Iris-virginica')
(150, 5.1, 1.8, 5.9, 3.0, 'Iris-virginica')
Total elapsed time:
0.023873000000000033
这里有一些陷阱:
1. **cnxn = pyodbc.connect() **- 在 Linux 环境下,此调用中传递的连接字符串必须正确无误,不能有任何空格。
2. 正确设置连接编码,例如使用 utf8。 在这里默认值对字符串不起作用。
3. **libirisodbcu35.so** - 理想情况下,此驱动程序文件应与远程 IRIS 服务器的版本保持一致。
## **未来计划 **
这样就得到一个带有 Jupyter Notebook 的 Docker 环境,包括 Python3 和 TensorFlow 2.2(无 GPU),通过 PyODBC(以及 JDBC)连接到远程 IRIS 服务器。 所有定制的 SQL 语法应该都可以适用,比如 IRIS Integrated ML 专有的 SQL 语法。那么何不多研究一下 IntegratedML 的功能,用它驱动 ML 生命周期的 SQL 方法以进行一些创新?
另外,我希望接下来能介绍或总结出在 IRIS Native 甚至是 Python 环境中的魔法 SQL 上最简单的 IRIS 服务器挂接方法。 而且,现在有出色的 [Python Gateway](https://github.com/intersystems-community/PythonGateway),我们甚至可以直接从 IRIS 服务器内部调用外部 Python ML 应用和服务。我希望我们也能在这方面多做些尝试。
**附录**
上面的笔记本文件也将被迁入此 Github 存储库以及 Open Exchange 中。
It's also possible to simply put the driver on the driver path. Isn't this configuration of the driver too cumbersome
driver = '/usr/irisodbc/bin/libirisodbc35.so'
server = ''
database = ''
username = ''
password = ''
port = ''
cnxn = pyodbc.connect(driver=driver, server=server,port='1972', database=database, uid=username, pwd=password,charset='UTF-8')
###ensure it reads strings correctly.
cnxn.setdecoding(pyodbc.SQL_CHAR, encoding='utf8')
cnxn.setdecoding(pyodbc.SQL_WCHAR, encoding='utf8')
cnxn.setencoding(encoding='utf8')
cursor = cnxn.cursor()
cursor.execute("select top 10 * from xx.xx")
row = cursor.fetchone()
while row:
print(row)
row = cursor.fetchone()
cnxn.close()
文章
姚 鑫 · 五月 20, 2021
# 第一章 发送HTTP请求
本主题介绍如何发送`HTTP`请求(如`POST`或`GET`)和处理响应。
# HTTP请求简介
可以创建`%Net.HttpRequest`的实例来发送各种`HTTP`请求并接收响应。此对象相当于Web浏览器,可以使用它发出多个请求。它会自动发送正确的`cookie`,并根据需要设置`Referer`标头。
要创建HTTP请求,请使用以下常规流程:
1. 创建`%Net.HttpRequest`的实例。
2. 设置此实例的属性以指示要与之通信的Web服务器。基本属性如下:
- 服务器指定Web服务器的IP地址或计算机名称。默认值为`localhost`。
**注意:不要将`http://`或`https://`作为服务器值的一部分。这将导致错误`#6059:无法打开到服务器http:/的TCP/IP套接字`。**
3. 可以选择设置HTTP请求的其他属性和调用方法,如指定其他HTTP请求属性中所述。
4. 然后,通过调用`%Net.HttpRequest`实例的`get()`方法或其他方法来发送HTTP请求,如“发送HTTP请求”中所述。
可以从实例发出多个请求,它将自动处理cookie和Referer标头。
注意:如果创建此HTTP请求是为了与生产出站适配器(`EnsLib.HTTP.Outbound Adapter`)一起使用,那么请改用该适配器的方法来发送请求。
5. 如果需要,使用`%Net.HttpRequest`的同一实例发送其他HTTP请求。默认情况下,InterSystems IRIS使TCP/IP套接字保持打开状态,以便可以重复使用套接字,而无需关闭和重新打开它。
以下是一个简单的示例:
```java
/// w ##class(PHA.TEST.HTTP).Get()
ClassMethod Get()
{
set request=##class(%Net.HttpRequest).%New()
set request.Server="tools.ietf.org"
set request.Https=1
set request.SSLConfiguration="yx"
set status=request.Get("/html/rfc7158")
d $System.Status.DisplayError(status)
s response = request.HttpResponse
s stream = response.Data
q stream.Read()
}
```
# 提供身份验证
如果目标服务器需要登录凭据,则HTTP请求可以包括提供凭据的HTTP `Authorization`标头。
如果使用的是代理服务器,还可以指定代理服务器的登录凭据;为此,请设置`ProxyAuthorization`属性
## 使用HTTP 1.0时对请求进行身份验证
对于HTTP 1.0,要验证HTTP请求,请设置`%Net.HttpRequest`实例的用户名和密码属性。然后,该实例使用基本访问身份验证基于该用户名和密码创建HTTP `Authorization`标头(RFC 2617)。此`%Net.HttpRequest`发送的任何后续请求都将包括此头。
**重要提示:请确保还使用SSL。在基本身份验证中,凭据以base-64编码形式发送,因此易于读取。**
## 在使用HTTP 1.1时对请求进行身份验证
对于HTTP 1.1,要验证HTTP请求,在大多数情况下,只需设置`%Net.HttpRequest`实例的用户名和密码属性。当`%Net.HttpRequest`的实例收到`401 HTTP`状态代码和`WWW-Authenticate`标头时,它会尝试使用包含支持的身份验证方案的`Authorization`标头进行响应。使用为IRIS支持和配置的第一个方案。默认情况下,它按以下顺序考虑这些身份验证方案:
1. 协商(SPNEGO和Kerberos,根据RFC 4559和RFC 4178)
2. NTLM(NT LAN Manager身份验证协议)
3. 基本认证(RFC 2617中描述的基本接入认证)
重要:如果有可能使用基本身份验证,请确保也使用SSL(参见“使用SSL进行连接”)。
在基本身份验证中,凭据以base-64编码的形式发送,因此很容易读取。
在Windows上,如果没有指定`Username`属性,IRIS可以使用当前登录上下文。
具体来说,如果服务器使用401状态码和用于`SPNEGO`、`Kerberos`或`NTLM`的`WWW-Authenticate`头响应,那么IRIS将使用当前操作系统用户名和密码创建`Authorization`头。
具体情况与HTTP 1.0不同,如下所示:
1. 如果认证成功,IRIS更新`%Net`的`CurrentAuthenticationScheme`属性。
`HttpRequest`实例来指示它在最近的身份验证中使用的身份验证方案。
2. 如果尝试获取方案的身份验证句柄或令牌失败,IRIS会将基础错误保存到`%Net.HttpRequest`实例的`AuthenticationErrors`属性中。此属性的值为`$List`,其中每一项都具有格式`scheme ERROR: message`
仅HTTP 1.1支持协商和`NTLM`,因为这些方案需要多次往返,而HTTP 1.0要求在每个请求/响应对之后关闭连接。
### Variations
如果知道服务器允许的一个或多个身份验证方案,则可以通过包括`Authorization`标头来绕过服务器的初始往返行程,该标头包含所选方案的服务器的初始令牌。为此,请设置`%Net.HttpRequest`实例的`InitiateAuthentication`属性。对于此属性的值,请指定服务器允许的单个授权方案的名称。使用下列值之一(区分大小写):
- Negotiate
- NTLM
- Basic
如果要自定义要使用的身份验证方案(或更改其考虑顺序),请设置`%Net.HttpRequest`实例的`AuthenticationSchemes`。对于此属性的值,请指定以逗号分隔的身份验证方案名称列表(使用上一个列表中给出的准确值)。
## 直接指定授权标头
对于HTTP 1.0或HTTP 1.1(如果适用于场景),可以直接指定HTTP `Authorization`标头。具体地说,可以将`Authorization`属性设置为等于正在请求的资源的用户代理所需的身份验证信息。
如果指定`Authorization`属性,则忽略用户名和密码属性。
## 启用HTTP身份验证的日志记录
要启用HTTP身份验证的日志记录,请在终端中输入以下内容:
```java
set $namespace="%SYS"
kill ^ISCLOG
set ^%ISCLOG=2
set ^%ISCLOG("Category","HttpRequest")=5
```
日志条目将写入`^ISCLOG global`中.。要将日志写入文件(以提高可读性),请输入以下内容(仍在`%SYS`命名空间内):
```java
do ##class(%OAuth2.Utils).DisplayLog("filename")
```
其中,`filename`是要创建的文件的名称。该目录必须已存在。如果该文件已经存在,它将被覆盖。
要停止日志记录,请输入以下内容(仍在`%SYS`命名空间内):
```java
set ^%ISCLOG=0
set ^%ISCLOG("Category","HttpRequest")=0
```
# 指定其他HTTP请求属性
在发送HTTP请求之前(请参阅发送HTTP请求),可以指定其属性,如以下各节所述:
可以为`%Net.HttpRequest`的所有属性指定默认值,如最后列出的部分中所指定。
## Location属性
`Location`属性指定从Web服务器请求的资源。如果设置此属性,则在调用`Get()`, `Head()`, `Post()`, 或 `Put()`方法时,可以省略location参数。
例如,假设正在向url `http://machine_name/test/index.html`发送一个HTTP请求
在这种情况下,将使用下列值:
`%Net.HttpRequest`的示例属性
Properties |Value
---|---
Server| machine_name
Location| test/index.html
## 指定Internet媒体类型(Media Type)和字符编码(Character Encoding)
可以使用以下属性指定`%Net.HttpRequest`实例及其响应中的Internet媒体类型(也称为MIME类型)和字符编码:
- Content-Type指定`Content-Type`标头,该标头指定请求正文的Internet媒体类型。默认类型为None。
可能的值包括`application/json`、`application/pdf`、`application/postscript`、`image/jpeg`、`image/png`、`multipart/form-data`、`text/html`、`text/plan`、`text/xml`等等
- ContentCharset属性控制请求的任何内容(例如,`text/html`或`text/xml`)类型时所需的字符集。如果不指定此属性,InterSystems IRIS将使用InterSystems IRIS服务器的默认编码。
注意:如果设置此属性,则必须首先设置`ContentType`属性。
- `NoDefaultContentCharset`属性控制在未设置`ContentCharset`属性的情况下是否包括文本类型内容的显式字符集。默认情况下,此属性为False。
如果此属性为true,则如果有文本类型的内容,并且没有设置`ContentCharset`属性,则内容类型中不包括任何字符集;这意味着字符集iso-8859-1用于消息输出。
- WriteRawMode属性影响实体正文(如果包含)。它控制请求正文的写入方式。默认情况下,此属性为False,并且InterSystems IRIS以请求标头中指定的编码写入正文。如果此属性为true,则InterSystems IRIS以原始模式写入正文(不执行字符集转换)。
- `ReadRawMode`属性控制如何读取响应正文。默认情况下,此属性为False,并且InterSystems IRIS假定正文在响应标头中指定的字符集中。如果此属性为true,InterSystems IRIS将以原始模式读取正文(不执行字符集转换)。
## 使用代理服务器
可以通过代理服务器发送HTTP请求。要设置此设置,请指定HTTP请求的以下属性:
- `ProxyServer`指定要使用的代理服务器的主机名。如果此属性不为空,则将HTTP请求定向到此计算机。
- `ProxyPort`指定代理服务器上要连接到的端口。
- `ProxyAuthorization`指定`Proxy-Authorization`标头,如果用户代理必须使用代理验证其自身,则必须设置该标头。对于该值,请使用正在请求的资源的用户代理所需的身份验证信息。
- `ProxyHTTPS`控制HTTP请求是针对HTTPS页面还是针对普通HTTP页面。如果未指定代理服务器,则忽略此属性。此属性将目标系统上的默认端口更改为代理端口443。
- `ProxyTunes`指定是否通过代理建立到目标HTTP服务器的隧道。如果为true,则请求使用HTTP CONNECT命令建立隧道。代理服务器的地址取自`ProxyServer`和`ProxyPort`属性。如果`ProxyHttps`为true,则隧道建立后,系统间IRIS将协商SSL连接。在这种情况下,由于隧道与目标系统建立直接连接,因此将忽略https属性。
## 使用SSL进行连接
`%Net.HttpRequest`类支持SSL连接。要通过SSL发送请求,请执行以下操作:
1. 将`SSLConfiguration`属性设置为要使用的已激活SSL/TLS配置的名称。
2. 还要执行以下操作之一,具体取决于是否使用代理服务器:
- 如果未使用代理服务器,请将`https`属性设置为true。
- 如果使用的是代理服务器,请将`ProxyHTTPS`属性设置为true。
在这种情况下,要使用到代理服务器本身的`SSL`连接,请将https属性设置为true。
请注意,当使用到给定服务器的`SSL`连接时,该服务器上的默认端口假定为443(HTTPS端口)。例如,如果没有使用代理服务器,并且https为true,则会将Default Port属性更改为443。
### 服务器身份检查
默认情况下,当`%Net.HttpRequest`实例连接到SSL/TLS安全的Web服务器时,它会检查证书服务器名称是否与用于连接到服务器的`DNS`名称匹配。如果这些名称不匹配,则不允许连接。此默认行为可防止“中间人”攻击,在RFC 2818的3.1节中进行了描述;另请参阅RFC 2595的2.4节。
**若要禁用此检查,请将`SSLCheckServerIdentity`属性设置为0。**
## `HTTPVersion`、`Timeout`、`WriteTimeout`和`FollowRedirect`属性
`%Net.HttpRequest`还提供以下属性:
`HTTPVersion`指定请求页面时使用的HTTP版本。默认值是`"HTTP/1.1"`。你也可以使用`“HTTP/1.0”`。
`Timeout`指定等待web服务器响应的时间,以秒为单位。
缺省值是30秒。
`WriteTimeout`指定等待Web服务器完成写入的时间(以秒为单位)。默认情况下,它将无限期等待。可接受的最小值为2秒。
`FollowRedirect`指定是否自动跟踪来自Web服务器的重定向请求(由300-399范围内的HTTP状态代码发出信号)。如果使用的是GET或HEAD,则默认值为TRUE;否则为FALSE。
## 指定HTTP请求的默认值
可以为`%Net.HttpRequest`的所有属性指定默认值。
- 要指定适用于所有名称空间的默认值,请设置全局节 `^%SYS("HttpRequest","propname")`,其中`“PropName”`是属性的名称。
- 要为一个名称空间指定默认值,请转到该名称空间并设置节点`^SYS("HttpRequest","propname")`
(`^%SYS`全局设置会影响整个安装,`^SYS`全局设置会影响当前命名空间。)
例如,要为所有名称空间指定默认代理服务器,请设置全局节`^%SYS("HttpRequest","ProxyServer")`
您好,我想请教一下如下错误是什么原因造成的呢?
错误 #6085: 无法写入使用SSL/TLS配置'xxxxxx'的套接字,报告'SSL/TLS error in SSL_connect(), SSL_ERROR_SSL: protocol error, error:0A000126:SSL routines::unexpected eof while reading'错误
文章
Hao Ma · 一月 12, 2023
InterSystems公司的技术支持中心WRC(World Response Center)提供的服务包括故障报修,升级和数据迁移支持等等。当客户报告了系统故障或性能问题给WRC时, 会被要求收集以下的两份报告,以了解系统的运行情况和性能表现,它们是:***诊断报告(Diagnostic Report)和系统性能报告***。
## 诊断报告(Diagnostic Report)
有关诊断报告,您需要知道:
1. **诊断报告是当前系统的运行状况的数据收集。**
2. **是给InterSystems技术支持工程师的,维护人员基本不需要读它。**
3. **当出现紧急故障需要重启系统时,先做一次诊断报告的收集,会对WRC在故障过后分析故障原因提供极大的便利。**
#### 报告收集的步骤
进入管理门户页面,**“系统管理>诊断报告”(System Operation > Diagnostic Reports)**,点击**运行**。
- 报告收集通常**需要5-10分钟**
- 执行开始后屏幕会出现提示:诊断报告在…时间运行.报告将储存在…目录中。成功后可以在“系统管理>任务管理器>任务历史“看到记录收集成功的记录。
- 在运行前,您可以选择报告存放的位置(Diectory for archived reports).
- 如果不填写,**默认报告保存的目录是install-dir\mgr**
⚠️ :收集报告由内部用户irisuser执行,所以您选择的存放目录要有irisuser的读写权限。如果没有,点击“运行”时您并不能得到 提示错误,需要到“系统管理>任务管理器>任务历史“, 才能发现其实报告收集的任务没有执行。
- 如果有公网连接,可以配置邮件信息,报告会直接发送给WRC
- 如果开设了WRC工单,请输入WRC工单号码
- 万一您已经无法登录管理门户,还是有紧急的故障要收集诊断报告,您需要[在Terminal执行命令收集诊断报告(附录1)][1]。
#### 报告的内容细节
诊断报告是一个HTML文件,名字是license中您的机构名称+时间, 比如这样:MyCompany202301051144.html
请记住2点:
1. 收集的数据分基本信息(Basic information)和高级信息(Advanced Information)。对于维护人员,基本信息可以在操作维护的各个页面上查看,没必要去读报告。而高级信息,不要求维护人员读懂或者分析内容。
具体内容如果如下,您可以选择跳过,或者从文档中了解更多的内容:[在线文档:Caché的诊断报告内容](https://docs.intersystems.com/ens201815/csp/docbook/DocBook.UI.Page.cls?KEY=GCM_diagnostic#GCM_diagnostic_contents), [在线文档:IRIS的诊断报告内容](https://docs.intersystems.com/irisforhealth20211/csp/docbook/DocBook.UI.Page.cls?KEY=GCM_diagnostic#GCM_diagnostic_contents)。
>报告的内容是系统当前的运行状态,主要包括:
>
>- 配置信息:
>
> 主要有服务器硬件信息,操作系统信息,许可证信息,实例的配置情况(CPF文件),数据库的配置,bin目录下的文件等等
>
>- 当前系统的基本运行情况
>
> - 数据库大小,占用的百分比
> - Journal的信息
> - 许可证的使用情况
> - 安全设置,审计(Audit)日志
> - 网络的状态。比如在Linux系统,其实是执行 `netstat -an` 的输出结果
> - 进程的状态
> - 内存的状态, cstat, core dump等等
> - GloStat ..., 不一一罗列
2. **cconsole.log**,或者**messages.log** 不包含在诊断报告中。通常情况下, 您需要把这个日志文件和诊断报告一起提交WRC
#### 问题和回答
Q: 需要定期做诊断报告吗?
A: 定期做系统健康检查吧,里面包括了诊断报告
Q: 要创建定时任务做诊断报告吗?
A: 没必要。除非您要指定一个时间,比如要了解凌晨1AM的系统运行状况。
## 性能报告(SystemPerformance Report)
有关性能报告,您需要了解:
- 收集的数据包括操作系统的性能指标,Caché的设置,Caché性能指标等等。Caché性能指标大多数是每秒平均值。
- 报告收集
- Windows服务器:在Termial执行收集命令。
- Linux/Unix服务器:除了Terminal执行收集命令外,可以在管理门户设置定时任务(Task)执行。
> *为什么Windows服务器不能使用定时任务:*
>
> 性能报告的收集中会使用Windows系统的Perform.exe,也就是Windows系统性能监视程序。从用户管理门户设置Task, 或者使用当前非管理员权限的用户打开Terminal收集性能报告,会因权限不足导致内部调用Windows Perfom的失败,也就无法得倒操作系统的性能指标。
- 因为只是将系统默认收集的指标打包归档,所以它**对系统性能影响很小**。可以在任何时间执行。
- 即使没有故障要处理,定期的收集性能报告也是InterSystems推荐的。定期的报告保留了一个系统正常运行时的性能基线,便于今后的性能故障的原因分析,以及了解资源耗费情况的趋势。
如果操作中需要了解更多的内容,请参考在线文档:[Monitoring Performance Using ^SystemPerformance](https://docs.intersystems.com/irisforhealthlatest/csp/docbook/DocBook.UI.Page.cls?KEY=GCM_systemperf)(for IRIS), [Monitoring Performance Using ^pButtons](https://docs.intersystems.com/ens201815/csp/docbook/Doc.View.cls?KEY=GCM_pbuttons)(for Caché)。
### 在Terminal收集性能报告
#### Windows环境
1. 打开一个以管理员权限运行的Windows命令窗口。一般是找到CMD, 右键, “以管理员身份运行“。
2. 输入命令进入Caché或者IRIS终端。
- Caché: `
- IRIS : `iris console instanceName` 或者 `iris terminal instanceName`
3. 在%sys命名空间执行以下命令Routine:
- Caché: `do ^pButtons` (见下面的例子)
- IRIS : `do ^SystemPerfromance`
```zsh
%SYS>do ^pButtons
Current log directory: c:\intersystems\hsap\mgr\/intersystems\
Windows Perfmon data will be left in raw format.
Available profiles:
1 12hours - 12 hour run sampling every 10 seconds
2 24hours - 24 hour run sampling every 10 seconds
3 30mins - 30 minute run sampling every 1 second
4 4hours - 4 hour run sampling every 5 seconds
5 8hours - 8 hour run sampling every 10 seconds
6 test - A 5 minute TEST run sampling every 30 seconds
select profile number to run: 2
Collection of this sample data will be available in 86520 seconds.
The runid for this data is 20200123_142501_24hours.
%SYS>do Collect^pButtons
Current Performance runs:
20200123_142501_24hours ready in 24 hours 1 minute 48 seconds
nothing available to collect at the moment.
```
> `do Collect^pButtons`命令显示程序执行的状态。这是一个24小时的收集任务,显示的执行时间*“ready in 24 hours 1 minute 48 seconds”*比24小时略长,多出的2分钟用于^pButtons将整理日志并将数据转换为html格式。
#### Linux/Unix环境
进入iris terminal并执行收集命令`do ^pButtons`或者`do ^SystemPerformance` , 以下是在
```bash
$ iris session iris
Node: af34ddc4655b, Instance: IRIS
USER>zn "%sys"
%SYS>do ^SystemPerformance
Current log directory: /usr/irissys/mgr/
Available profiles:
1 12hours - 12 hour run sampling every 10 seconds
2 24hours - 24 hour run sampling every 10 seconds
3 30mins - 30 minute run sampling every 1 second
4 4hours - 4 hour run sampling every 5 seconds
5 8hours - 8 hour run sampling every 10 seconds
6 test - A 5 minute TEST run sampling every 30 seconds
Select profile number to run:
```
### 管理页面创建任务收集性能报告
对于Linux/Unix系统上安装的IRIS或者Caché, 到管理门户的“系统操作>任务管理器>新任务“,创建的新任务,

选项中,命名空间为“%SYS", 任务类型为”运行传统任务”(RunLegacyTask), 执行代码::
- Caché: `do run^pButtons(“ProfileName”)`
- IRIS: `do run^SystemPerformance(“ProfileName”)`
ProfileName也就是收集数据的时间长度, Profile定义数据采样的时间长度和频率,选项为:30mins, 4hours, 8hours, 12hours, 24hours, test。
- **24hours**: 最常用。任务执行的起始时间无所谓。如果设为零点,这样最后得到的数据图横轴是0点到24点,讨好细节控。
- **test**: 多用于24小时的收集工作前的预操作,查看5分钟的收集数据结果。
### 其他有关报告收集的注意事项
1. 多个收集任务可并行。
比如为了分析某个性能问题, 客户可以从早上9点执行两个收集任务,一个4小时的任务收集早晨业务繁忙时段的数据,一个24小时的任务收集全天的数据。
2. 默认报告保存位置是***"/mgr"***文件夹。
一个24小时报告的尺寸通常在**10MB - 100MB**。如果要保留的报告很多,可以考虑执行命令修改保存目录(注意确保Caché具有该目录的写权限)。
`%SYS>do setlogdir^pButtons("/somewhere_with_lots_of_space/perflogs/")`
3. 还可以创建另一个定时任务,清除历史报告,只保留一段时间的。
4. 在一个长的报告收集过程中,可以使用`Preview^SystemPerformance`命令在[不中断收集的情况下,读取已经收集的性能报告的数据。如果需要, 请阅读[在线文档中生成报告的部分](https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=GCM_systemperf#GCM_systemperf_produce)。
5. 如果可以要收集整个商业周期,比如一周或一个月的数据,需要[创建新性能采样profile(附录2)][2]。
6. 最后, 有一些内部的开关可以设置^pButtons采集更多的数据,比如硬盘访问的更详细的记录。通常这样的操作可能要消耗大量资源,请在WRC指导上使用。
### 性能报告的内容
性能报告是一个html文件, 默认的文件名为服务器,实例名称, 时间的组合,比如bjse01_IRIS_20220628_103554_30mins.html。
内容主要为:
- 配置, cpf文件,license等等
- 系统级别问题诊断,比如系统hang, 网络问题,性能问题等。(有兴趣可以去在线文档了解“cstat"或者“irisstat")
- Caché,IRIS性能表现的采样, 比如Global的读写速度, Rdration等指标,有兴趣可以去在线文档了解“mgstat')
- 操作系统的性能数据
- Windows Performance Monitor
- Linux Info, ps, sar, vmstat...
具体内容请阅读: [InterSystems IRIS Performance Data Report for Microsoft Windows Platforms](https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=GCM_systemperf#GCM_systemperf_reports_windows_) , [InterSystems IRIS Performance Data Report for Linux Platforms](https://docs.intersystems.com/iris20222/csp/docbook/DocBook.UI.Page.cls?KEY=GCM_systemperf#GCM_systemperf_reports_linux)
### 性能报告内容的展现
性能报告是一个html文件。内容中的简单的数据,可以直观的在html中阅读, 但表格数据,比如cpu, 内存使用,IO, Global访问等等, 展现,或者说画图工具是有必要的。
**如果维护人员或用户想阅读性能报告**,可以考虑以下工具:
[性能报告数据转csv](https://community.intersystems.com/post/extracting-pbuttons-data-csv-file-windows) : 这是一个windows PowerShell的程序, 方便使用EXCEL展现性能数据。
[YASPE](https://github.com/murrayo/yaspe) : 作者是Murrayo Oldfield,开源的工具,代码是python, 提供docker image下载。操作简单。数据可以生成图表,像下面的样子,而且可以zoom in/out。

WRC内部工具:如果您有了一个WRC工单,并且就当前问题提交了性能报告。您可以请你的技术支持提供一个报告中数据图表呈现。WRC问题有生成图表的工具,但仅供内部使用。
## 附录
[1]: 在Terminal执行命令收集诊断报告
> 万一您已经无法登录管理门户,还是有紧急的故障要收集诊断报告,您需要在Terminal操作。
>
> 这个操作命令叫**Buttons**. 据说,名字的出处是最初开发者任务收集报告应该简单的像“按一个按钮”,所以后面开发的性能报告,干脆就被称为**pButtons**, p是performance的字头。因为被使用的可能性太小,iris的文档中其实已经找不到Buttons的内容。下面的步骤只是简单的给您一个印象。如果有一天不幸您非要用它,WRC会详细的指导您。
>
> ```sh
> USER>zn "%sys"
> %SYS>do ^Buttons
> (以下步骤省略)...
> ```
>
> *执行^Buttons可以选择收集某一个命名空间的ensemble production的信息。如果有需要,请按WRC的要求操作。*
[2]: 创建新性能采样profile
> Profile定义收集数据的时长和频率, 比如24hours的profile是每10秒采样一次运行24小时。如果可以希望收集其他时间长度的数据,或者减小采样频率以减小结果文件的大小,可以考虑自己定制Profile。比如下面的my_24hours_30sec:
>
> ```sh
> //创建24小时配置文件,30秒采样间隔。30sec*2880=1440mins=24hours
> %SYS>write $$addprofile^pButtons("My_24hours_30sec","24 hours 30 sec interval",30,2880)
> %SYS>do ^pButtons
> Current log directory: /db/backup/benchout/pButtonsOut/
> Available profiles:
> 1 12hours - 12 hour run sampling every 10 seconds
> 2 24hours - 24 hour run sampling every 10 seconds
> 3 30mins - 30 minute run sampling every 1 second
> 4 4hours - 4 hour run sampling every 5 seconds
> 5 8hours - 8 hour run sampling every 10 seconds
> 6 My_24hours_30sec- 24 hours 30 sec interval
> 7 test - A 5 minute TEST run sampling every 30 seconds
>
> select profile number to run:
> ```
文章
姚 鑫 · 四月 22, 2021
# 第五章 优化查询性能(一)
InterSystems SQL自动使用查询优化器创建在大多数情况下提供最佳查询性能的查询计划。该优化器在许多方面提高了查询性能,包括确定要使用哪些索引、确定多个`AND`条件的求值顺序、在执行多个联接时确定表的顺序,以及许多其他优化操作。可以在查询的`FROM`子句中向此优化器提供“提示”。本章介绍可用于评估查询计划和修改InterSystems SQL将如何优化特定查询的工具。
InterSystems IRIS®Data Platform支持以下优化SQL查询的工具:
- `SQL Runtime Statistics`用于生成查询执行的运行时性能统计信息
- 索引分析器,用于显示当前命名空间中所有查询的各种索引分析器报告。这显示了InterSystems SQL将如何执行查询,可以全面了解索引是如何使用的。此索引分析可能表明应该添加一个或多个索引以提高性能。
- 查询执行计划:显示SQL查询(查询计划)的最佳(默认)执行计划,并可选地显示该SQL查询的备用查询计划以及统计信息。用于显示查询计划的工具包括SQL `EXPLAIN`命令、`$SYSTEM.SQL.ExPlan()`方法以及管理门户和SQL Shell中的各种`Show Plan`工具。查询计划和统计数据是在准备查询时生成的,不需要执行查询。
可以使用以下选项来指导查询优化器,方法是设置配置默认值或在查询代码中编码优化器“提示”:
- 管理所有条件的子句选项中提供的索引优化选项,或单个条件前面的`%NOINDEX`。
- SQL代码中指定的注释选项,使优化器覆盖该查询的系统范围编译选项。
- 在每个查询或系统范围的基础上可用的并行查询处理允许多处理器系统在处理器之间划分查询执行。
以下SQL查询性能工具将在本手册的其他章节中介绍:
- 缓存查询,使动态SQL查询能够重新运行,而无需在每次执行查询时准备查询的开销。
- SQL语句来保留最新编译的嵌入式SQL查询。在“SQL语句和冻结计划”一章中。
- 冻结计划以保留嵌入式SQL查询的特定编译。使用此编译,而不是使用较新的编译。在“SQL语句和冻结计划”一章中。
以下工具用于优化表数据,因此可以对针对该表运行的所有查询产生重大影响:
- 定义索引可以显著提高对特定索引字段中数据的访问速度。
- `ExtentSize`、`Selective`和`BlockCount`用于在用数据填充表之前指定表数据估计;此元数据用于优化未来的查询。
- `Tune Table`用于分析已填充的表中的代表性表数据;生成的元数据用于优化未来的查询。
本章还介绍如何将查询优化计划写入文件,以及如何生成SQL故障排除报告以提交给InterSystems WRC。
# 管理门户SQL性能工具
IRIS管理门户提供对以下SQL性能工具的访问。有两种方式可以从管理门户系统资源管理器选项访问这些工具:
- 选择工具,然后选择SQL性能工具。
- 选择SQL,然后选择工具下拉菜单。
从任一界面中您都可以选择以下SQL性能工具之一:
- SQL运行时统计信息,以生成查询执行的性能统计信息。
- 索引分析器,用于显示当前命名空间中所有查询的各种索引分析器报告。这显示了InterSystems SQL将如何执行查询,可以全面了解索引是如何使用的。此索引分析可能表明应该添加一个或多个索引以提高性能。
- 备用显示计划:显示SQL查询的可用备用查询计划以及统计信息。
- 生成报告以向InterSystems Worldwide Response Center(WRC)客户支持部门提交SQL查询性能报告。要使用此报告工具,必须首先从WRC获得WRC跟踪号。
- 导入报告允许查看SQL查询性能报告。
# SQL运行时统计信息
可以使用SQL运行时统计信息来衡量系统上运行的SQL查询的性能。SQL运行时统计信息衡量`SELECT`、`INSERT`、`UPDATE`和`DELETE`操作(统称为查询操作)的性能。SQL运行时统计信息(SQL Stat)是在准备查询操作时收集的。请参阅使用SQL运行时统计信息工具。
默认情况下,SQL运行时统计信息的收集处于关闭状态。必须激活统计信息收集。强烈建议指定超时以结束统计信息收集。激活统计信息收集后,必须重新编译(准备)现有的动态SQL查询,并重新编译包含嵌入式SQL的类和例程。
性能统计信息包括`ModuleName`、`ModuleCount`(模块被调用的次数)、`RowCount`(返回的行数)、`TimeSpent`(执行性能,单位为秒)、`GlobalRefs`(全局引用数)、`LinesOfCode`(执行的行数)和`ReadLatency`(磁盘读取访问时间,单位为毫秒)。
可以显式清除SQL Stats数据。清除缓存查询会删除所有相关的SQL统计数据。删除表或视图会删除所有相关的SQL Stats数据。
注意:系统任务在所有名称空间中每小时自动运行一次,以将特定于进程的SQL查询统计信息聚合到全局统计信息中。因此,全局统计信息可能不会反映一小时内收集的统计信息。可以使用管理门户监视此每小时一次的聚合或强制其立即发生。要查看此任务上次完成和下次调度的时间,请依次选择系统操作、任务管理器、任务调度,然后查看更新SQL查询统计信息任务。可以单击任务名称查看任务详细信息。在`Task Details`(任务详细信息)显示中,可以使用Run(运行)按钮强制立即执行任务。
# 使用SQL运行时统计信息工具
可以使用以下任一方法从管理门户显示系统范围内的SQL查询的性能统计信息:
- 选择系统资源管理器,选择工具,选择SQL性能工具,然后选择SQL运行时统计信息。

- 选择系统资源管理器,选择SQL,然后从工具下拉菜单中选择SQL运行时统计信息。
## Settings
“设置”选项卡显示当前系统范围的SQL运行时统计信息设置以及此设置的过期时间。
Change Settings(更改设置)按钮允许设置以下统计信息收集选项:
- 收集选项:可以将统计信息收集选项设置为0、1、2或3.0。0=关闭统计信息代码生成;1=为所有查询打开统计信息代码生成,但不收集统计信息;2=仅记录查询外部循环的统计信息(在主模块打开和关闭时收集统计信息);3=记录查询的所有模块级别的统计信息。
- 从0到1:更改SQL Stats选项后,需要编译包含SQL的例程和类以执行统计代码生成。对于xDBC和动态SQL,必须清除缓存查询以强制重新生成代码。
- 要从1变为2:只需更改SQL Stats选项即可开始收集统计信息。这使可以在运行的生产环境中启用SQL性能分析,并将中断降至最低。
- 从1到3(或从2到3):更改SQL Stats选项后,需要编译包含SQL的例程和类,以记录所有模块级别的统计信息。对于xDBC和动态SQL,必须清除缓存查询以强制重新生成代码。选项3通常仅用于非生产环境中已识别的性能较差的查询。
- 从1、2或3变为0:要关闭统计代码生成,不需要清除缓存的查询。
- 超时选项:如果收集选项为2或3,可以按已用时间(小时或分钟)或按完成日期和时间指定超时。可以用分钟或小时和分钟指定运行时间;该工具将指定的分钟值转换为小时和分钟(100分钟=1小时40分钟)。默认值为50分钟。日期和时间选项默认为当天午夜(23:59)之前。强烈建议指定超时选项。
- 重置选项:如果收集选项为2或3,则可以指定超时值到期时要重置为的收集选项。可用选项为0和1。
## 查询测试
查询测试选项卡允许输入SQL查询文本(或从历史记录中检索),然后显示该查询的SQL统计信息和查询计划。查询测试包括查询的所有模块级别的SQL统计信息,而与收集选项设置无关。
输入一个SQL查询文本,或使用`Show History`按钮检索一个。
可以通过单击右边的圆形“X”圆来清除查询文本字段。
使用`Show Plan With SQL Stats`按钮执行。
默认情况下,后台复选框中的“运行`Show Plan`进程”未被选中,这是大多数查询的首选设置。
仅对长时间、运行缓慢的查询选择此复选框。
当这个复选框被选中时,你会看到一个进度条显示“请等待…”的消息。
当运行一个长查询时,带有SQL Stats和`Show History`按钮的`Show Plan`消失,而显示一个`View Process`按钮。
单击`View Process`将在新选项卡中打开流程详细信息页面。
在流程详细信息页面中,可以查看该流程,并可以暂停、恢复或终止该流程。
流程的状态应该反映在显示计划页面上。
当流程完成后,显示计划会显示结果。
`View Process`按钮消失,带有SQL Stats的`Show Plan`和`Show History`按钮重新出现。
使用查询测试显示的语句文本包括注释,不执行文字替换。
## 查看统计信息
`View Stats`(查看统计信息)选项卡为提供了在此系统上收集的运行时统计信息的总体视图。
可以单击任何一个`View Stats`列标题对查询统计信息进行排序。然后,可以单击SQL语句文本以查看所选查询的详细查询统计信息和查询计划。
使用此工具显示的语句文本包括注释,不执行文字替换。`ExportStatsSQL()`和`Show Plan`显示的语句文本会去掉注释并执行文字替换。
### 清除统计信息按钮
清除统计信息按钮清除当前名称空间中所有查询的所有累积统计信息。它会在SQL运行时统计信息页上显示一条消息。如果成功,则会显示一条消息,指示已清除的统计信息数量。如果没有统计信息,则会显示无要清除的消息。如果清除不成功,则会显示一条错误消息。
## 运行时统计信息和显示计划
SQL运行时统计信息工具可用于显示包含运行时统计信息的查询的显示计划。
可以使用`Alternate Show Plans`工具将显示计划与统计数据进行比较,从而显示查询的运行时统计信息。备用显示计划工具在其显示计划选项中显示查询的估计统计信息。如果激活了收集运行时统计信息,则其`Compare Show Plans with Stats`选项将显示实际的运行时统计信息;如果运行时统计信息未处于活动状态,则此选项将显示估计统计信息。
文章
Jeff Liu · 五月 15
在本文中,我们将使用基于分布式存储的 Kubernetes 部署来构建一个 IRIS 的高可用配置,而不使用“传统的”IRIS Mirror。 这种部署将能够容忍与基础架构相关的故障,如节点、存储和可用区故障。 所描述的方法可以大大降低部署的复杂性,代价是 RTO的略微延长。 图 1 - 传统镜像与采用分布式存储的 Kubernetes
本文的所有源代码均可在 https://github.com/antonum/ha-iris-k8s 下载TL;DR
假设您有一个正在运行的 3 节点集群,并且您对 Kubernetes 有一定了解 – 请继续:
kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/master/deploy/longhorn.yaml
kubectl apply -f https://github.com/antonum/ha-iris-k8s/raw/main/tldr.yaml
如果您不确定上面两行有什么作用,或者没有可执行这些命令的系统,请跳转至“高可用性要求”部分。 我们将在后面详细介绍。
第一行安装 Longhorn - 开源分布式 Kubernetes 存储。 第二行安装 InterSystems IRIS ,将基于 Longhorn 的卷用于 Durable SYS。
等待所有 pod 进入运行状态。 kubectl get pods -A
您现在应该能通过 http://<IRIS Service Public IP>:52773/csp/sys/%25CSP.Portal.Home.zen(默认密码为“SYS”)访问 IRIS 管理门户,并通过以下命令访问 IRIS 命令行:
kubectl exec -it iris-podName-xxxx -- iris session iris
模拟故障
现在开始制造一些混乱。 但在操作之前,先尝试将一些数据添加到数据库中,并确保当 IRIS 重新上线后数据仍然存在。
kubectl exec -it iris-6d8896d584-8lzn5 -- iris session iris
USER>set ^k8stest($i(^k8stest))=$zdt($h)_" running on "_$system.INetInfo.LocalHostName()
USER>zw ^k8stest
^k8stest=1
^k8stest(1)="01/14/2021 14:13:19 running on iris-6d8896d584-8lzn5"
我们的“混乱工程”从这里开始:
# Stop IRIS - Container will be restarted automatically
kubectl exec -it iris-6d8896d584-8lzn5 -- iris stop iris quietly
# Delete the pod - Pod will be recreated
kubectl delete pod iris-6d8896d584-8lzn5
# "Force drain" the node, serving the iris pod - Pod would be recreated on another node
kubectl drain aks-agentpool-29845772-vmss000001 --delete-local-data --ignore-daemonsets --force
# Delete the node - Pod would be recreated on another node
# well... you can't really do it with kubectl. Find that instance or VM and KILL it.
# if you have access to the machine - turn off the power or disconnect the network cable. Seriously!
高可用性要求
我们正在构建可以容忍以下故障的系统:
容器/VM 内的 IRIS 实例。 IRIS – 级别故障。
pod/容器故障。
个别集群节点暂时不可用。 一个典型的例子是可用区临时下线。
个别集群节点或磁盘的永久性故障。
基本上,是我们刚才在“模拟故障”部分中尝试实现的场景。
如果发生上述任何一种故障,系统应该在没有任何人工干预的情况下保持在线,并且没有数据丢失。 从技术上说,数据持久性的保证是有限制的。 IRIS 本身可以根据应用程序内的日志循环和事务使用情况提供:https://docs.intersystems.com/irisforhealthlatest/csp/docbook/Doc.View.cls?KEY=GCDI_journal#GCDI_journal_writecycle。无论如何,我们讨论的是低于两秒的 RPO(恢复目标时间)。
系统的其他组件(Kubernetes API 服务、etcd 数据库、LoadBalancer 服务、DNS 等等)不在讨论范围内,它们通常由 Azure AKS 或 AWS EKS 等托管 Kubernetes 服务管理,因此我们假定它们已经高度可用。
换一个角度看 – 我们负责处理个别的计算和存储组件故障,并假设其余故障由基础设施/云提供商处理。
架构
在谈到 InterSystems IRIS 的高可用性时,传统的建议是使用镜像。 使用镜像时,有两个始终在线的 IRIS 实例同步复制数据。 每个节点都维护一个完整的数据库副本,如果主节点宕机,用户将重新连接到备份节点。 本质上,在镜像方法中,IRIS 负责计算和存储的冗余。
利用部署在不同可用区的Mirror,镜像方法提供了容忍计算和存储故障所需的冗余,并且实现了只有几秒的出色 RTO(目标恢复时间或系统在故障后重新上线所需的时间)。 您可以在以下网址找到在 AWS 云上部署 IRIS Mirror的模板:https://community.intersystems.com/post/intersystems-iris-deployment%C2%A0guide-aws%C2%A0using-cloudformation-template
Mirror的缺点是设置、执行备份/恢复程序比较复杂,而且缺少对安全设置和本地非数据库文件的复制。
Kubernetes 等容器编排器通过部署对象提供计算冗余,在出现故障时会自动重启有故障的 IRIS Pod/容器。 所以在 Kubernetes 架构图上只能看到一个 IRIS 节点在运行。 我们没有让另一个 IRIS 节点始终保持运行,而是将计算可用性外包给 Kubernetes。 Kubernetes 将确保当原始 pod 因任何原因发生故障时,重新创建 IRIS pod。
图 2 故障转移方案
到目前为止还不错... 如果 IRIS 节点发生故障,Kubernetes 就会创建一个新节点。 根据集群的情况,发生计算故障后,让 IRIS 重新上线需要 10 到 90 秒的时间。 相对于Mirror只需要几秒即可恢复,这确实有些退步,但如果万一发生中断时您可以容忍这一点,那么回报就是复杂度大大降低。 无需配置镜像。 无需担心安全设置和文件复制。
说实话,如果您在容器内登录,在 Kubernetes 中运行 IRIS,您甚至不会注意到您正在高可用环境中运行。 一切都像单实例 IRIS 部署一样。
等等,那存储呢? 我们还要处理数据库... 无论我们想象到什么样的故障转移方案,我们的系统都应该确保数据持久性。 Mirror依赖于 IRIS 节点本地的计算。 如果节点故障或只是暂时不可用 – 该节点的存储也会变得如此。 这就是IRIS 需要在Mirror配置内解决 IRIS 层面的数据复制的原因。
我们需要的存储不仅能在容器重启后保留数据库的状态,而且能针对节点或整个网段(可用区)宕机等事件提供冗余。 就在几年前,这个问题还没有简单的答案。 不过从上图可以猜到 – 我们现在有了这样的答案。 它称为分布式容器存储。
分布式存储将多个基础主机卷抽象成一个联合存储,供 k8s 集群的每个节点使用。 在本文中,我们使用 Longhorn https://longhorn.io;它免费、开源且相当容易安装。 但是您也可以看看其他提供相同功能的产品,例如 OpenEBS、Portworx 和 StorageOS。 Rook Ceph 是另一个可以考虑的 CNCF 孵化项目。 在高端领域 – 有企业级存储解决方案,如 NetApp、PureStorage 等。
分步指南
在 TL;DR 部分中,我们一次性安装了整套系统。 附录 B 将指导您完成逐步安装和验证过程。
Kubernetes 存储
让我们往回退一步,从总体上谈谈容器和存储,以及 IRIS 如何融入其中。
默认情况下,容器内的所有数据都是暂时的。 当容器消亡时,数据也会消失。 在 docker 中,可以使用卷的概念。 本质上,它允许将主机操作系统上的目录公开给容器。
docker run --detach
--publish 52773:52773
--volume /data/dur:/dur
--env ISC_DATA_DIRECTORY=/dur/iconfig
--name iris21 --init intersystems/iris:2020.3.0.221.0
在上面的示例中,我们启动了 IRIS 容器,并使主机本地的“/data/dur”目录可以被“/dur”挂载点上的容器访问。 所以,容器在该目录内存储的任何内容都会保留下来,并可在下次容器启动时使用。
在 IRIS 方面,我们可以通过指定 ISC_DATA_DIRECTORY 来指示 IRIS 将所有需要在容器重启后存活的数据存储在特定目录中。 Durable SYS 是您可能需要在文档 https://docs.intersystems.com/irisforhealthlatest/csp/docbook/Doc.View.cls?KEY=ADOCK#ADOCK_iris_durable_running 中查找的 IRIS 功能的名称
在 Kubernetes 中,语法有所不同,但概念是相同的。
以下是 IRIS 的基本 Kubernetes 部署。
apiVersion: apps/v1
kind: Deployment
metadata:
name: iris
spec:
selector:
matchLabels:
app: iris
strategy:
type: Recreate
replicas: 1
template:
metadata:
labels:
app: iris
spec:
containers:
- image: store/intersystems/iris-community:2020.4.0.524.0
name: iris
env:
- name: ISC_DATA_DIRECTORY
value: /external/iris
ports:
- containerPort: 52773
name: smp-http
volumeMounts:
- name: iris-external-sys
mountPath: /external
volumes:
- name: iris-external-sys
persistentVolumeClaim:
claimName: iris-pvc
在上面的部署规范中,“volumes”部分列出了存储卷。 可以在容器外部通过“iris-pvc”等 persistentVolumeClaim 访问它们。 volumeMounts 在容器内公开了此卷。 “iris-external-sys”是将卷挂载绑定到特定卷的标识符。 在现实中,我们可能有多个卷,此名称即用来区分各个卷。 如果您愿意,还可以叫它“steve”。
我们已经熟悉的环境变量 ISC_DATA_DIRECTORY 指示 IRIS 使用一个特定挂载点来存储所有需要在容器重启后存活的数据。
现在,我们来看一下持久卷声明 iris-pvc。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: iris-pvc
spec:
storageClassName: longhorn
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
相当直接。 请求 10 GB,只能在一个节点上以读/写方式挂载,使用“longhorn”存储类。
storageClassName: longhorn 在这里实际上很关键。
我们看一下我的 AKS 集群上可用的存储类:
kubectl get StorageClass
NAME PROVISIONER RECLAIMPOLICY VOLUMEBINDINGMODE ALLOWVOLUMEEXPANSION AGE
azurefile kubernetes.io/azure-file Delete Immediate true 10d
azurefile-premium kubernetes.io/azure-file Delete Immediate true 10d
default (default) kubernetes.io/azure-disk Delete Immediate true 10d
longhorn driver.longhorn.io Delete Immediate true 10d
managed-premium kubernetes.io/azure-disk Delete Immediate true 10d
默认安装了 Azure 的几个存储类,还有一个来自于 Longhorn,是我们在第一个命令中安装的:
kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/master/deploy/longhorn.yaml
如果在持久卷声明定义中注释掉 #storageClassName: longhorn,则将使用当前标记为“default”的存储类,它是一个常规 Azure 磁盘。
为了说明为什么需要分布式存储,让我们重复本文开头所述的没有 longhorn 存储的“混乱工程”实验。 前两种情况(停止 IRIS 和 删除 Pod)将成功完成,系统将恢复到运行状态。 尝试耗尽或终止节点将使系统进入故障状态。
#forcefully drain the node
kubectl drain aks-agentpool-71521505-vmss000001 --delete-local-data --ignore-daemonsets
kubectl describe pods
...
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 57s (x9 over 2m41s) default-scheduler 0/3 nodes are available: 1 node(s) were unschedulable, 2 node(s) had volume node affinity conflict.
基本上,Kubernetes 会尝试重启集群上的 IRIS pod,但最初启动该 pod 的节点不可用,另外两个节点存在“卷节点相关性冲突”。 对于这种存储类型,卷只在最初创建它的节点上可用,因为它基本上与节点主机上可用的磁盘绑定。
使用 longhorn 作为存储类时,“强制耗尽”和“节点终止”实验均会成功,并且 IRIS pod 很快会恢复运行。 为了实现这一目标,Longhorn 控制了集群的 3 个节点上的可用存储,并将数据复制到全部三个节点上。 如果其中一个节点永久不可用,Longhorn 会迅速修复集群存储。 在我们的“节点终止”场景中,系统立即使用其余的两个卷副本在其他节点上重启 IRIS pod。 然后,AKS 提供一个新节点来替换丢失的节点,一旦准备就绪,Longhorn 就会介入,并在新节点上重建所需数据。 一切都是自动的,不需要您参与。
图 3 Longhorn 在替换的节点上重建卷副本。
更多有关 k8s 部署的信息
我们看一下部署的其他几个方面:
apiVersion: apps/v1
kind: Deployment
metadata:
name: iris
spec:
selector:
matchLabels:
app: iris
strategy:
type: Recreate
replicas: 1
template:
metadata:
labels:
app: iris
spec:
containers:
- image: store/intersystems/iris-community:2020.4.0.524.0
name: iris
env:
- name: ISC_DATA_DIRECTORY
value: /external/iris
- name: ISC_CPF_MERGE_FILE
value: /external/merge/merge.cpf
ports:
- containerPort: 52773
name: smp-http
volumeMounts:
- name: iris-external-sys
mountPath: /external
- name: cpf-merge
mountPath: /external/merge
livenessProbe:
initialDelaySeconds: 25
periodSeconds: 10
exec:
command:
- /bin/sh
- -c
- "iris qlist iris | grep running"
volumes:
- name: iris-external-sys
persistentVolumeClaim:
claimName: iris-pvc
- name: cpf-merge
configMap:
name: iris-cpf-merge
策略: 重建Recreate, 副本replicas: 1 告诉 Kubernetes 在任何给定时间都应该保持一个且只能有一个 IRIS pod 实例运行。 这对应于我们的“删除 pod”场景。
livenessProbe 部分确保 IRIS 始终在容器内正常运行并应对“IRIS 下线”情况。 initialDelaySeconds 允许 IRIS 启动有一定的宽限期。 如果 IRIS 需要相当长的时间来启动部署,您可能需要增加该值。
IRIS 的 CPF MERGE配置文件合并 功能允许您在容器启动时修改配置文件 iris.cpf 的内容。 请参见 https://docs.intersystems.com/irisforhealthlatest/csp/docbook/DocBook.UI.Page.cls?KEY=RACS_cpf#RACS_cpf_edit_merge 了解相关内容。
在本示例中,我将使用 Kubernetes Config Map 管理合并文件 https://github.com/antonum/ha-iris-k8s/blob/main/iris-cpf-merge.yaml 的内容。这里我们调整了 IRIS 实例使用的全局缓冲区和 gmheap 值,但是您在 iris.cpf 文件中找到的一切都是可修改的。 您甚至可以使用 CPF Merge 文件中的“PasswordHash”字段更改默认 IRIS 密码。 更多信息请参见:https://docs.intersystems.com/irisforhealthlatest/csp/docbook/Doc.View.cls?KEY=ADOCK#ADOCK_iris_images_password_auth
除了持久卷声明 https://github.com/antonum/ha-iris-k8s/blob/main/iris-pvc.yaml 部署 https://github.com/antonum/ha-iris-k8s/blob/main/iris-deployment.yaml 和采用 CPF Merge 内容的 ConfigMap https://github.com/antonum/ha-iris-k8s/blob/main/iris-cpf-merge.yaml,我们的部署还需要一个将 IRIS 部署暴露给公网的服务:https://github.com/antonum/ha-iris-k8s/blob/main/iris-svc.yaml
kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
iris-svc LoadBalancer 10.0.18.169 40.88.123.45 52773:31589/TCP 3d1h
kubernetes ClusterIP 10.0.0.1 <none> 443/TCP 10d
iris-svc 的外部 IP 可用于通过 http://40.88.123.45:52773/csp/sys/%25CSP.Portal.Home.zen 访问 IRIS 管理门户。 默认密码为“SYS”。
备份/恢复和存储扩展
Longhorn 提供了基于 Web 的 UI 来配置和管理卷。
使用 kubectl 标识 pod、运行 longhorn-ui 组件和建立端口转发:
kubectl -n longhorn-system get pods
# note the longhorn-ui pod id.
kubectl port-forward longhorn-ui-df95bdf85-gpnjv 9000:8000 -n longhorn-system
Longhorn UI 将可通过 http://localhost:9000 访问
图 4 Longhorn UI
除了高可用性,大多数 Kubernetes 容器存储解决方案还提供了方便的备份、快照和恢复选项。 细节是特定于实现的,但通常的惯例是备份与 VolumeSnapshot 关联。 对于 Longhorn 来说就是这样。 根据您的 Kubernetes 版本和提供商,您可能还需要安装卷快照工具 https://github.com/kubernetes-csi/external-snapshotter
“iris-volume-snapshot.yaml”是此类卷快照的示例。 在使用它之前,您需要在 Longhorn 中配置备份到 S3 存储桶或 NFS 卷。 https://longhorn.io/docs/1.0.1/snapshots-and-backups/backup-and-restore/set-backup-target/
# Take crash-consistent backup of the iris volume
kubectl apply -f iris-volume-snapshot.yaml
对于 IRIS,建议在获取备份/快照之前执行外部冻结,之后再解冻。 有关详细信息,请参见:https://docs.intersystems.com/irisforhealthlatest/csp/documatic/%25CSP.Documatic.cls?LIBRARY=%25SYS&CLASSNAME=Backup.General#ExternalFreeze
要增加 IRIS 卷的大小,请调整 IRIS 使用的持久卷声明(文件“iris-pvc.yaml”)中的存储请求。
...
resources:
requests:
storage: 10Gi #change this value to required
然后,重新应用 pvc 规范。 当卷连接到正在运行的 Pod 时,Longhorn 无法实际应用此更改。 请在部署中暂时将副本数更改为零,以便增加卷大小。
高可用性 – 概述
在文章开头,我们为高可用性设置了一些标准。 下面来说明我们如何通过此架构来实现:
故障域
自动缓解方式
容器/VM 内的 IRIS 实例。 IRIS – 级别故障。
部署运行情况探测将在 IRIS 故障时重启容器
pod/容器故障。
部署重新创建 pod
个别集群节点暂时不可用。 一个典型的例子是可用区下线。
部署在其他节点上重新创建 pod。 Longhorn 使数据在其他节点上可用。
个别集群节点或磁盘的永久性故障。
同上,并且 k8s 集群自动缩放器会将受损节点替换为新节点。 Longhorn 在新节点上重建数据。
Zoombie和其他要考虑的事项
如果您熟悉在 Docker 容器中运行 IRIS,则可能已经使用了“--init”标志。
docker run --rm -p 52773:52773 --init store/intersystems/iris-community:2020.4.0.524.0
此标志的目标是防止形成“僵尸进程”。 在 Kubernetes 中,可以使用“shareProcessNamespace: true”(安全注意事项适用)或在您自己的容器中使用“tini”。 使用 tini 的 Dockerfile 示例:
FROM iris-community:2020.4.0.524.0
...
# Add Tini
USER root
ENV TINI_VERSION v0.19.0
ADD https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini /tini
RUN chmod +x /tini
USER irisowner
ENTRYPOINT ["/tini", "--", "/iris-main"]
从 2021 年开始,InterSystems 提供的所有容器映像都默认包括 tini。
您可以通过调整一些参数来进一步减少“强制耗尽节点/终止节点”场景下的故障切换时间。
Longhorn Pod 删除策略 https://longhorn.io/docs/1.1.0/references/settings/#pod-deletion-policy-when-node-is-down 和 kubernetes 基于 taint 的逐出:https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/#taint-based-evictions
免责声明
作为 InterSystems 员工,我必须在这里说明:本文使用 Longhorn 作为 Kubernetes 分布式块存储的示例。 InterSystems 不会对个别存储解决方案或产品进行验证或发布官方支持声明。 您需要测试和验证是否有任何特定存储解决方案符合您的需求。
分布式存储与节点本地存储相比,性能特征可能有很大差别。 特别是在写入操作方面,数据必须写入到多个位置才会被认为处于持久状态。 请确保测试您的工作负载,并了解您的 CSI 驱动程序具有的特定行为和选项。
基本上,InterSystems 不会验证和/或认可具体的存储解决方案(如 Longhorn),就像我们不会验证单个硬盘品牌或服务器硬件制造商一样。 我个人认为 Longhorn 很容易使用,而且开发团队在项目的 GitHub 页面上响应迅速且乐于助人。https://github.com/longhorn/longhorn
结论
Kubernetes 生态系统在过去几年有了长足的发展,通过使用分布式块存储解决方案,您现在可以构建一个高可用性配置来维持 IRIS 实例、集群节点甚至是可用区故障。
您可以将计算和存储高可用性外包给 Kubernetes 组件,这样与传统 IRIS 镜像相比,系统的配置和维护都大为简化。 同时,此配置可能无法提供与镜像配置相同的 RTO 和存储级别性能。
在本文中,我们使用 Azure AKS 作为托管的 Kubernetes 和 Longhorn 分布式存储系统,构建了一个高可用性 IRIS 配置。 你可以探索多种替代方案,如 AWS EKS、用于托管 K8s 的 Google Kubernetes Engine、StorageOS、Portworx 和 OpenEBS 作为分布式容器存储,甚至 NetApp、PureStorage、Dell EMC 等企业级存储解决方案。
附录 A. 在云中创建 Kubernetes 集群
来自公共云提供商之一的托管 Kubernetes 服务是创建此设置所需的 k8s 集群的简单方法。 Azure 的 AKS 默认配置可以直接用于本文所述的部署。
创建一个新的 3 节点 AKS 集群。 其他所有设置都保持默认。
图 5 创建 AKS 集群
在您的计算机上本地安装 kubectl:https://kubernetes.io/docs/tasks/tools/install-kubectl/
使用本地 kubectl 注册 AKS 集群
图 6 使用 kubectl 注册 AKS 集群
之后,您可以回到文章开头,并安装 longhorn 和 IRIS 部署。
在 AWS EKS 上安装更复杂一些。 您需要确保您的节点组中的每个实例都已安装 open-iscsi。
sudo yum install iscsi-initiator-utils -y
在 GKE 上安装 Longhorn 需要额外步骤,请参见此处:https://longhorn.io/docs/1.0.1/advanced-resources/os-distro-specific/csi-on-gke/
附件 B. 分步安装
第 1 步 – Kubernetes 集群和 kubectl
您需要 3 节点 k8s 集群。 附录 A 介绍了如何在 Azure 上获得一个这样的集群。
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
aks-agentpool-29845772-vmss000000 Ready agent 10d v1.18.10
aks-agentpool-29845772-vmss000001 Ready agent 10d v1.18.10
aks-agentpool-29845772-vmss000002 Ready agent 10d v1.18.10
第 2 步 – 安装 Longhorn
kubectl apply -f https://raw.githubusercontent.com/longhorn/longhorn/master/deploy/longhorn.yaml
确保“longhorn-system”命名空间中的所有 pod 都处于运行状态。 这可能需要几分钟。
$ kubectl get pods -n longhorn-system
NAME READY STATUS RESTARTS AGE
csi-attacher-74db7cf6d9-jgdxq 1/1 Running 0 10d
csi-attacher-74db7cf6d9-l99fs 1/1 Running 1 11d
...
longhorn-manager-flljf 1/1 Running 2 11d
longhorn-manager-x76n2 1/1 Running 1 11d
longhorn-ui-df95bdf85-gpnjv 1/1 Running 0 11d
有关详细信息和故障排除,请参见 Longhorn 安装指南 https://longhorn.io/docs/1.1.0/deploy/install/install-with-kubectl
第 3 步 – 克隆 GitHub 仓库
$ git clone https://github.com/antonum/ha-iris-k8s.git
$ cd ha-iris-k8s
$ ls
LICENSE iris-deployment.yaml iris-volume-snapshot.yaml
README.md iris-pvc.yaml longhorn-aws-secret.yaml
iris-cpf-merge.yaml iris-svc.yaml tldr.yaml
第 4 步 – 逐个部署和验证组件
tldr.yaml 文件将部署所需的所有组件捆绑在一起。 这里我们将逐个进行安装,并单独验证每一个组件的设置。
# If you have previously applied tldr.yaml - delete it.
$ kubectl delete -f https://github.com/antonum/ha-iris-k8s/raw/main/tldr.yaml
# Create Persistent Volume Claim
$ kubectl apply -f iris-pvc.yaml
persistentvolumeclaim/iris-pvc created
$ kubectl get pvc
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
iris-pvc Bound pvc-fbfaf5cf-7a75-4073-862e-09f8fd190e49 10Gi RWO longhorn 10s
# Create Config Map
$ kubectl apply -f iris-cpf-merge.yaml
$ kubectl describe cm iris-cpf-merge
Name: iris-cpf-merge
Namespace: default
Labels: <none>
Annotations: <none>
Data
====
merge.cpf:
----
[config]
globals=0,0,800,0,0,0
gmheap=256000
Events: <none>
# create iris deployment
$ kubectl apply -f iris-deployment.yaml
deployment.apps/iris created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
iris-65dcfd9f97-v2rwn 0/1 ContainerCreating 0 11s
# note the pod name. You’ll use it to connect to the pod in the next command
$ kubectl exec -it iris-65dcfd9f97-v2rwn -- bash
irisowner@iris-65dcfd9f97-v2rwn:~$ iris session iris
Node: iris-65dcfd9f97-v2rwn, Instance: IRIS
USER>w $zv
IRIS for UNIX (Ubuntu Server LTS for x86-64 Containers) 2020.4 (Build 524U) Thu Oct 22 2020 13:04:25 EDT
# h<enter> to exit IRIS shell
# exit<enter> to exit pod
# access the logs of the IRIS container
$ kubectl logs iris-65dcfd9f97-v2rwn
...
[INFO] ...started InterSystems IRIS instance IRIS
01/18/21-23:09:11:312 (1173) 0 [Utility.Event] Private webserver started on 52773
01/18/21-23:09:11:312 (1173) 0 [Utility.Event] Processing Shadows section (this system as shadow)
01/18/21-23:09:11:321 (1173) 0 [Utility.Event] Processing Monitor section
01/18/21-23:09:11:381 (1323) 0 [Utility.Event] Starting TASKMGR
01/18/21-23:09:11:392 (1324) 0 [Utility.Event] [SYSTEM MONITOR] System Monitor started in %SYS
01/18/21-23:09:11:399 (1173) 0 [Utility.Event] Shard license: 0
01/18/21-23:09:11:778 (1162) 0 [Database.SparseDBExpansion] Expanding capacity of sparse database /external/iris/mgr/iristemp/ by 10 MB.
# create iris service
$ kubectl apply -f iris-svc.yaml
service/iris-svc created
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
iris-svc LoadBalancer 10.0.214.236 20.62.241.89 52773:30128/TCP 15s
第 5 步 – 访问管理门户
最后使用服务的外部 IP http://20.62.241.89:52773/csp/sys/%25CSP.Portal.Home.zen 连接到 IRIS 的管理门户,用户名 _SYSTEM,密码 SYS。 您第一次登录时将被要求更改密码。
文章
姚 鑫 · 四月 3, 2021
# 第十五章 使用管理门户SQL接口(二)
# 过滤模式内容
Management Portal SQL界面的左侧允许查看模式(或匹配筛选器模式的多个模式)的内容
1. 通过单击SQL interface页面顶部的Switch选项,指定希望使用的名称空间。
这将显示可用名称空间的列表,可以从中进行选择。
2. 应用筛选器或从模式下拉列表中选择模式。
可以使用Filter字段通过输入搜索模式来筛选列表。
可以在一个模式或多个模式中筛选模式,或筛选表/视图/过程名(项)。
搜索模式由模式名、点(`.`)和项目名组成——每个名称由文字和通配符的某种组合组成。字面值不区分大小写。
通配符是:
- 星号(`*`)表示0个或多个任意类型的字符。
- 下划线(`_`)表示任意类型的单个字符。
- 撇号(`'`)倒装前缀,意为“不”(除了)。
- 反斜杠(`\`)转义字符:`\_`表示字面上的下划线字符。
例如,`S*`返回所有以`S S*`开头的模式。
`Person`返回所有以`S. *`开头的模式中的所有Person项。
`Person*`返回所有模式中以`Person开头`的所有项。
可以使用逗号分隔的搜索模式列表来选择满足所列模式(或逻辑)中的任何一种的所有项。
例如,`* .Person * *`。
`Employee*`选择所有模式中的所有Person和Employee项。
若要应用筛选器搜索模式,请单击refresh按钮或按Tab键。
过滤器搜索模式将一直有效,直到显式地更改它。
过滤器字段右侧的`“x”`按钮清除搜索模式。
3. 从schema下拉列表中选择一个模式将覆盖并重置之前的任何筛选器搜索模式,选择单个模式。
指定筛选器搜索模式将覆盖之前的任何模式。
4. 可选地,使用下拉“应用到”列表来指定要列出的项目类别:表、视图、过程、缓存查询,或以上所有。
默认为`All`。
在“应用到”下拉列表中指定的任何类别都受到筛选器或模式的限制。
在“应用到”中没有指定的类别继续在名称空间中列出该类别类型的所有项。
5. 可选地,单击System复选框以包含系统项目(名称以`%`开头的项目)。
默认情况下不包含系统项。
6. 展开类别的列表,列出指定架构或指定筛选器搜索模式的项。
展开列表时,不包含项的任何类别都不会展开。
7. 单击展开列表中的项,在SQL界面的右侧显示其目录详细信息。
如果所选项目是表或过程,则Catalog Details类名信息提供到相应类参考文档的链接。
请注意,筛选器设置是用户自定义的,并保留以供该用户将来使用。
## Browse选项卡
Browse选项卡提供了一种方便的方式,可以快速查看名称空间中的所有模式,或者名称空间中经过过滤的模式子集。
可以选择Show All Schemas或Show Schemas with Filter,这将应用在管理门户SQL界面左侧指定的过滤器。
通过单击模式名称标题,可以按字母升序或降序列出模式。
每个列出的模式都提供指向其关联表、视图、过程和查询(缓存的查询)列表的链接。
如果模式没有该类型的项,则在该模式列表列中显示一个连字符(而不是命名链接)。
这使能够快速获得关于模式内容的信息。
单击“表”、“视图”、“过程”或“查询”链接将显示有关这些项的基本信息的表。
通过单击表标题,可以按该列的值升序或降序对列表进行排序。
过程表总是包括区段过程,而不管管理门户SQL界面左侧的过程设置如何。
可以使用Catalog Details选项卡获得关于单个表、视图、过程和缓存查询的更多信息。
从Browse选项卡中选择表或视图不会激活该表的`Open Table`链接。
# 目录详情
管理门户提供每个表,视图,过程和缓存查询的目录详细信息。管理门户SQL界面的过滤架构内容(左侧)组件允许您选择单个项目以显示其目录详细信息。
## 目录表的详细信息
每个表提供以下目录详细信息选项:
- 表信息:表类型:表类型:无论是表,全局临时或系统表(仅在选择系统复选框时显示系统表),所有者名称,最后编译的时间戳,外部和读取的布尔值,类名称,范围大小,子表的名称和/或父表(如果相关)和一个或多个引用字段到其他表(如果相关),无论是使用`%storage.persistent`默认存储类,无论是支持位图指标, `ROWID`字段名称,`ROWID`基于(如果相关)的字段列表,以及表是否被分析。如果有一个显式分片键,它会显示分片键字段。
类名是在Intersystems类参考文档中的相应条目的链接。类名是通过删除标点字符,如标识符和类实体名称中所述从表名派生的唯一包。
只有当当前表中的某个字段对另一个表有一个或多个引用时,引用才会出现在表信息中。
这些对其他表的引用作为指向所引用表的表信息的链接列出。
Sharded:如果表是一个分片主表,那么表信息将显示分片本地类和表的名称,并链接到InterSystems类参考文档中相应的条目。
如果该表是一个碎片本地表,表信息将显示碎片主类和表的名称,并链接到InterSystems类参考文档中相应的条目。
只有选中“System”复选框时,才会显示“Shard-local”表。
该选项还为打开表时要加载的行数提供了一个可修改的值。
这将设置打开表中显示的最大行数。
可用范围从1到10,000;
默认值为100。
管理门户将一个超出可用范围的值修正为一个有效值:0修正为100;
一个小数四舍五入到下一个更大的整数;
大于10,000的数字更正为10,000。
- 字段:表中字段的列表,显示字段名,数据类型,列#,必需的,惟一的,排序,隐藏,MaxLen, MaxVal, MinVal,流,容器,xDBC类型,引用,版本列,选择性,离群值选择性,离群值和平均字段大小。
- 映射/索引:为表定义的索引列表,显示:索引名、SQL映射名、列、类型、块计数、映射继承和全局。
索引名称是索引属性名称,然后遵循属性命名约定;从SQL索引名称生成时,将删除SQL索引名称中的标点符号(例如下划线)。 SQL映射名称是索引的SQL名称。生成的SQL映射名称与约束名称相同,并遵循相同的命名约定(下面描述)。列指定为索引指定的字段或逗号分隔的字段列表;它可以指定index collation类型和full schinea.table.field参考,如下例所示:`$$sqlupper({sample.people.name})`。类型可以是以下之一:位图范围,数据/主,索引(标准索引),位图或`bitslice`索引以及唯一的约束。块计数包含计数和该计数的确定:由Class Author(定义)明确地设置,由可调组织(测量)计算,或由类编译器(估计)估计。如果映射继承?是的,map是从超类继承的。全局是包含索引数据的下标全局的名称。索引全局的命名约定在索引全局名称中描述。您可以向ZWRITE提供此全局名称以显示索引数据。
此选项还为每个索引提供重建索引的链接。
- 触发:为表显示的触发器列表显示:触发名称,时间事件,订单,代码。
- 约束:表格的字段列表,显示:约束名称,约束类型和约束数据(括号中列出的字段名称)。约束包括主键,外键和唯一约束。主键是定义,唯一;它仅列出一次。此选项列出约束名称的约束;使用显示组件字段的逗号分隔列表的约束数据列出了一次涉及多个字段的约束。约束类型可以是唯一的主键,隐式主键,外键或隐式外键。
还可以通过调用`Information_schema.constraint_column_usage`来列出约束。此列表按字段名称约束。以下示例返回字段的名称和所有唯一,主键,外键和`Check Constraints`的约束的名称:
```sql
SELECT Column_Name,Constraint_Name FROM INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE WHERE TABLE_SCHEMA='Sample' AND TABLE_NAME='Person'
```

如果该表定义为`%PublicraWID`,并且没有定义显式主键,则`RowID`字段列出了具有约束名称`RowidField_As_PKey`的`Contriced`主键的约束类型。
对于显式约束,约束名称是如下生成的:
- 字段定义中指定的约束:例如,`fullname varchar(48)`唯一或`fullname varchar(48)`主键。字段的约束名称值是具有语法`tableName_ctype#`的生成值,其中ctype是唯一的,`pkey`或`fkey`,`#`是在表定义中指定的顺序分配给未命名约束的顺序整数。例如,如果`FullName`具有`MyTest`表中的第二个未命名的唯一约束(不包括ID字段),则`FullName`的生成约束名称将是`mytest_unique2`;如果`fullname`是`MyTest`表中指定的主键和第3个未命名约束(不包括ID字段),则`FullName`的生成约束名称将是`MyTest_pKey3`。
- 约束关键字命名约束子句:例如,约束`UFULLNAME`唯一(名字,`LastName`)或约束`Pkname`主键(`FullName`)),约束名称是指定的唯一约束名称。例如,`MyTest`表中的名字和`LastName`每个都将每个约束名称`UfullName`; `fullname`将具有约束名称`pkname`。
- 未命名约束子句:例如,唯一(名字,姓氏)或主键(`FullName`)。约束名称值是具有语法`tableNamectype#`的生成值,其中`ctype`是唯一的,`pkey`或`fkey`,`##`是在表定义中指定的顺序分配给未命名约束的顺序整数。例如,如果`FirstName`和`LastName`具有`MyTest`表中的第2个未命名的唯一约束(不包括ID字段),则`FirstName`和`LastName`的生成约束名称将是`MyTestunique2`;如果`FullName`是`MyTest`表中指定的主要键和第3个未命名的约束(不包括ID字段),则`FullName`的生成约束名称将是`MyTestPKEY3`。 (注意混合大写/小写,没有下划线。)
如果一个字段涉及多个唯一约束,则为每个约束名称单独列出。
- 缓存查询:表的缓存查询列表显示:例程名称,查询文本,创建时间,源,查询类型。
- 表的SQL语句:为此表生成的SQL语句列表。与命名空间的SQL语句相同的信息。
## 目录的视图详细信息
Management Portal SQL接口还提供视图,过程和缓存查询的目录详细信息:
为每个视图提供以下目录详细信息选项:
- 查看信息:所有者名称,最后编译的时间戳。使用“编辑视图”链接并保存更改时,此时间戳更新。
定义为只读,视图是可更新的布尔值:如果仅读取的视图定义,则它们分别设置为1和0。否则,如果查看视图是从单个表定义的,它们被设置为0和1;如果视图由已加入的表定义,则它们设置为0和0。可以使用编辑视图链接更改此选项。
类名是唯一的包。通过删除标点字符,如标识符和类实体名称中所述,从视图名称派生的名称。
如果查看定义包含“使用”选项“子句,则仅列出选项。它可以是本地的或级联。您可以使用编辑视图链接更改此选项。
类类型是视图。它提供了编辑视图链接以编辑视图定义。
查看文本是用于定义视图的`SELECT`语句。可以使用编辑视图链接更改视图定义。
字段列表包括字段名称,数据类型,maxlen参数,maxval参数,minval参数,blob(`%stream.globalcharacter`或`%stream.globalbinary`字段),长度,精度和比例。
- 查看的SQL语句:为此视图生成的SQL语句列表。与命名空间的SQL语句相同的信息。
## 存储过程的目录详细信息
为每个过程提供以下目录详细信息:
- 存储过程信息:
类名是一个唯一的包。通过将类型标识符( `‘func’, ‘meth’, ‘proc’, or ‘query’`)预定到类名(例如,SQL函数`MyProc`变为`FuncMyProc`)并删除标点符号字符,如标识符和类实体名称中所述。类文档是Intersystems类参考中相应条目的链接。过程类型(例如,函数)。方法或查询名称生成的类方法或类查询的名称;此名称在标识符和类实体名称中描述。运行过程链接提供交互方式的选项。
- 存储过程SQL语句:为此存储过程生成的SQL语句列表。与命名空间的SQL语句相同的信息。
## 缓存查询的目录详细信息
缓存查询提供查询的全文,一个选项来显示查询执行计划,以及交互式执行缓存查询的选项。
# 向导
- 数据导入向导 - 运行向导将数据从文本文件导入Intersystems Iris类。
- 数据导出向导 - 运行向导将数据从Intersystems Iris类导出到文本文件中。
- 数据迁移向导 - 运行向导以从外部源迁移数据,并创建一个Intersystems Iris类定义来存储它。
- 链接表向导 - 运行向导,以链接到外部源中的表或视图,就像它是本机Intersystems Iris数据一样。
- 链接过程向导 - 运行向导,以链接到外部源中的过程。
# 操作
- 创建视图 - 显示一个页面以创建视图。使用此选项的说明提供了本书的“定义和使用视图”章节。
- 打印目录 - 允许打印有关表定义的完整信息。单击打印目录显示打印预览。通过单击此打印预览上的指数,触发器和/或约束,可以从目录打印输出中包含或排除此信息。
- Purege缓存查询 - 提供三种用于清除缓存查询的选项:清除当前命名空间的所有缓存查询,清除指定表的所有缓存查询,或者仅清除所选缓存的查询。
- 调谐表信息 - 对选定的表运行调谐表工具。这计算了每个表列对当前数据的选择性。选择性值1表示定义为唯一(因此具有所有唯一数据值)的列。选择性值为`1.0000%`表示未定义所有当前数据值是唯一值的唯一列。 `1.0000%`的百分比值更大,指示当前数据中该列的重复值的相对数量。通过使用这些选择性值,可以确定要定义的索引以及如何使用这些索引来优化性能。
- 调整架构中的所有表 - 运行调谐表工具,针对所属于当前命名空间中指定架构的所有表。
- 重建表索引 - 重建指定表的所有索引。
- 删除此项目 - 删除(删除)指定的表定义,查看定义,过程或缓存查询。必须具有适当的权限来执行此操作。除非表类定义包括[`DDLOWALLED`],否则否则不能在通过定义持久性类创建的表上使用删除。否则,操作失败了,使用`SQLCode -300`错误,其中包含类`“Schema.TableName”`的`%MSG DDL`。如果相应的持久性类具有子类(派生类),则不能在表格上使用删除;使用`%msg`类`'schema.tableName'`具有派生类`SQLCode -300`错误失败,因此无法通过DDL删除。
如果一个类被定义为链接表,则下降操作也会将链接表放在本地系统上,即使链接的表类未被定义为ddlowed。下降不会删除实际表此链接引用服务器上的引用。
- 导出所有语句 - 将所有SQL语句导出在当前命名空间中。 SQL语句以XML格式导出。可以选择导出到文件,或导出到浏览器显示页面。
- 导入语句 - 将SQL语句从XML文件导入当前命名空间。
# 打开表
如果在管理门户SQL接口的左侧选择表或视图,则会显示该表或视图的目录详细信息。页面顶部的打开表链接也变为活动状态。打开表显示表中的实际数据(或通过视图访问)。数据以显示格式显示。
默认情况下,将显示前100行数据;通过在“目录详细信息”选项卡信息中将表打开时,通过设置要加载的行数来修改此默认值。如果表格中的行数多于此行到加载值,则在数据显示的底部显示越多的数据...指示器。如果表格中的行较少,则要加载值的行数,则在数据显示的底部显示完整的指示符。
一列数据类型`%Stream.globalcharacter`将实际数据(最多100个字符)显示为字符串。超出前100个字符的附加数据由省略号(`...`)表示。
一列数据类型`%Stream.Globalbinary`显示为。
# 工具
System Explorer,SQL,Tools下拉列表提供对以下工具的访问。这些是系统资源管理器,工具,SQL性能工具的相同工具:
- SQL运行时统计信息:用户界面生成指定查询的SQL运行时统计信息。
- 索引分析仪:用于收集指定架构的各种类型索引分析的用户界面。
- 替代表演计划:用户界面生成指定查询的备用显示计划。
- 生成报告以将SQL查询性能报告提交给Intersystems WRC(全球响应中心客户支持)。要使用此报告工具,必须先从WRC获取WRC跟踪号码。
- 导入报告以通过文件名导入现有WRC报告。仅用于Intersystems使用。

文章
Frank Ma · 六月 27, 2022
比较不同的商业智能技术是非常有趣的。我很好奇它们在功能、开发工具、速度和可用性方面有什么不同。
在这个应用程序中,我选择了一个有欧洲各国水状况的数据集。这是一个开源的数据集,包含1991年到2017年的观测数据。
团队和我决定使用IRIS BI、Tableau、PowerBI和InterSystems Reports(由Logi Reports驱动)在这个BI数据集的基础上制作一个模型
对于前端,我们通过Embedded Python在PythonFlask中制作了一个网页界面。
顺便说一下,其结果可以在这个网页上看到:http://atscale.teccod.com:8080/ 你可以看看demo stand (演示台),因为从资源库部署一个容器可能需要多至20分钟的时间。大量的python包,后面会有更多的原因。
主页面
数据
事实上,数据似乎很小,期间只有17年 :)
因此,在现有的基础上,我想延续数据集,为此使用了一个神经网络。使用同样的嵌入式Python,使用了Tensorflow,这个包下载后占据了511MB,不要惊讶
实际上,这也是容器部署时间长的原因--为神经网络下载了很多包,相当多的相关包,安装时间很长。不过会有一篇关于神经网络和Integrated ML(一体化机器学习)的单独文章,我很快会发表。
我还要说的是,预测的结果被输入到同一个数据库,所以你可以通过BI工具看到数据集。但是预测只针对法国的一条河,请仔细看一下。因为我们只有足够的力量计算一件事。完整的预测会花很长的时间。
数据立方体
数据立方体是在IRIS中制作的,同时立方体也是在Adaptive Analytics(由AtScale驱动)中制作的。因此,IRIS的BI仪表盘是在IRIS上建立的,其余的工具(Logi、PowerBI、Tableau)从AtScale上获取数据。
仪表板
实际上商业智能系统是以多种形式呈现的。
这是在python中的Dash。
我们喜欢的IRIS BI
InterSystems报告(由Logi报告提供)。
PowerBI
Tableau 样例
完成
对于所介绍的所有BI系统,源文件都可以在资源库中找到。你可以看到报告和仪表盘是如何工作的,并在你未来的项目中使用它们。
通过它们,你可以直观地看到一个特定的系统是如何工作的,也可以了解一个特定的系统有哪些开发工具。
我们没时间来制作一个页面,让你可以输入各种参数和条件,使用神经网络的可能值进行计算。这里有一些先决条件,有一个实施神经网络的例子,以及在其帮助下所做的预测,这些都是在嵌入式Python中实现的。神经网络已被训练,启动脚本也是可用的,位于 https://github.com/teccod/water-conditions-Europe/blob/main/iris/src/PythonFlask/pages/ml/ml_run.py文件夹中。
谢谢你阅读这篇文章,我在等待评论和反馈。很快就会有一篇关于在嵌入式Python和IntegratedML(一体化机器学习)中比较神经网络的文章,我将把它附在这篇文章中。