搜索​​​​

清除过滤器
文章
Lele Yang · 七月 13, 2021

FAQ 常见问题系列--系统管理篇 如何在Linux上配置InterSystems IRIS服务随机自启动?

与Windows上默认安装为服务随机自启动不同,我们在Linux上安装完InterSystems IRIS后,默认是没有配置系统服务的,需要做手动配置。本文提供使用systemd方式来配置InterSystems IRIS服务随机自启动的简单示例,供大家参考。 假设我们已经安装了InterSystems IRIS产品,安装完成后您可以通过iris list来来查看实例信息,包括安装路径,如:"/intersystems/iris" [root@RHEL8-64-001 ~]# iris list Configuration 'IRIS' (default) directory: /intersystems/iris versionid: 2021.2.0L.546.0 datadir: /intersystems/iris conf file: iris.cpf (SuperServer port = 51773, WebServer = 52773) status: running, since Mon May 31 05:03:09 2021 state: ok product: InterSystems IRIS 在安装完成后,用以下方式搜索不到iris.service, [root@RHEL8-64-001 ~]# systemctl list-unit-files --type=service|grep iris.service 如何将其配置为系统服务呢,下面是一个简单示例及操作步骤,供大家参考。注意:请使用root用户或者拥有root权限的用户来进行。 1. 创建systemd service,1) 在/usr/lib/systemd/system下创建文件,iris.service,内容如下, [root@RHEL8-64-001 system]# cat iris.service [Unit] Description=InterSystems IRIS [Service] Type=forking ExecStart=/bin/bash -c '/intersystems/iris/irisstart 2>&1 | logger -t iris_start' ExecStop=/bin/bash -c '/intersystems/iris/irisstop quietly 2>&1 | logger -t iris_stop' RemainAfterExit=yes [Install] WantedBy=multi-user.target 其中,/intersystems/iris为实例安装目录。2) 创建后,更改文件的属性, [root@RHEL8-64-001 system]# chmod 755 iris.service 更改后,文件属性如下,-rwxr-xr-x. 1 root root 225 May 31 07:32 iris.service 2. 启用该Service。1)启用,创建系统service的link, [root@RHEL8-64-001 system]# systemctl enable iris.service Created symlink /etc/systemd/system/multi-user.target.wants/iris.service → /usr/lib/systemd/system/iris.service. 2)确认状态,确保已经enabled [root@RHEL8-64-001 system]# systemctl list-unit-files --type=service|grep iris.service iris.service enabled 3. 测试该Service,1)进行到这个步骤,查看状态应为inactive(dead)。 [root@RHEL8-64-001 system]# systemctl status iris ● iris.service - InterSystems IRIS Loaded: loaded (/usr/lib/systemd/system/iris.service; enabled; vendor preset> Active: inactive (dead) lines 1-3/3 (END) 2) 下面来启动iris服务, [root@RHEL8-64-001 system]# systemctl start iris.service 3) 再次查看服务状态已经为active(running),启动成功。 [root@RHEL8-64-001 system]# systemctl status iris ● iris.service - InterSystems IRIS Loaded: loaded (/usr/lib/systemd/system/iris.service; enabled; vendor preset: disabled) Active: active (running) since Mon 2021-05-31 07:57:43 EDT; 1min 37s ago Process: 1704 ExecStart=/bin/bash -c /intersystems/iris/irisstart 2>&1 | logger -t iris_start (code=exited, status=0/SUCCE> Tasks: 52 (limit: 11442) Memory: 246.0M CGroup: /system.slice/iris.service ├─2076 /intersystems/iris/bin/irisdb -s/intersystems/iris/mgr/ -w/intersystems/iris/mgr/ -cc -B -C/intersystems/i> ├─2085 /intersystems/iris/bin/irisdb WD > ├─2086 /intersystems/iris/bin/irisdb GC > ├─2087 /intersystems/iris/bin/irisdb JD > ├─2088 /intersystems/iris/bin/irisdb AUX7 > ├─2089 /intersystems/iris/bin/irisdb AUX6 > ├─2090 /intersystems/iris/bin/irisdb AUX5 > ├─2091 /intersystems/iris/bin/irisdb AUX4 > ├─2092 /intersystems/iris/bin/irisdb AUX3 > ├─2093 /intersystems/iris/bin/irisdb AUX2 > ├─2094 /intersystems/iris/bin/irisdb AUX1 > ├─2095 /intersystems/iris/bin/irisdb DBXD > ├─2098 /intersystems/iris/bin/irisdb -s/intersystems/iris/mgr -cj -p13 START^MONITOR ├─2102 /intersystems/iris/bin/irisdb -s/intersystems/iris/mgr -cj -p13 START^CLNDMN ├─2105 /intersystems/iris/bin/irisdb -s/intersystems/iris/mgr -cj -p13 stumonitor^JRNRESTO ├─2109 /intersystems/iris/bin/irisdb -s/intersystems/iris/mgr -cj -p13 ^RECEIVE 4)最后重启操作系统,测试iris可以随机自启动。 注:以上测试在Red Hat Linux Enterprise 8版本上进行。
文章
TZ Zhuang · 六月 2, 2021

FAQ 常见问题系列--系统管理篇 如何进行数据库备份

InterSystems产品有四种备份方法:(1) 外部备份(2) 在线备份(3) 冷备份(4) 传统的并行外部备份有关这些方法的细节请参考在线文档 https://docs.intersystems.com/irisforhealthlatest/csp/docbook/DocBook.UI.Page.cls?KEY=GCDI_BACKUP 以下是对每种备份方法的简要描述: (1) 外部备份外部备份是InterSystems推荐的最佳备份方式。外部备份一般是对数据库文件所在的存储创建快照的方式来实现。创建快照可以在多个层面进行,例如存储层面,操作系统层面,等等,因此这些相关技术和工具一般由第三方来提供。在做快照前,一定要先停止对数据库文件的写入(InterSystems IRIS的IRIS.DAT,Caché/Ensemble的CACHE.DAT)。但是用户进程可以继续对内存进行更新,而不需要中断。InterSystems提供了停止对数据库文件写入的方法,用户可以把这个加入到快照工具的脚本里。外部备份一般包括以下几步:1. 使用Backup.General.ExternalFreeze()方法来停止对数据库文件的写入。2. 使用第三方快照工具来对文件系统创建快照。3. 使用Backup.General.ExternalThaw()方法来恢复对数据库文件的写入。4. 把快照拷贝到备份介质上(用于存储备份的磁盘,磁带,等等)。5. 删除快照。 (2) 在线备份在线备份是InterSystems自己特有的备份方式,可实现无宕机备份。但是,在线备份只能备份数据库文件(InterSystems IRIS的IRIS.DAT,Caché/Ensemble的CACHE.DAT),并且会把所有需要备份的数据库文件中的数据块写入到一个.cbk的备份文件。因此如果想要使用在线备份来备份整个系统环境,除了数据库文件外,还需要额外备份很多系统文件,例如InterSystems产品的安装目录,WIJ文件,主日志和备日志目录等等。在线备份包括3种类型:1. 全备份 -- 把所有使用的数据块写入到一个.cbk文件。2. 累积备份 -- 从上一次全备份起,所有变化过的数据块写入到一个.cbk文件。恢复时,需要和上一次全备份一起恢复。3. 增量备份 -- 从上一次备份起,所有变化过的数据块写入到一个.cbk文件。恢复时,需要和上一次全备份及中间所有备份一起恢复。在线备份的这些特性,并不适用于作为数据量大的生产系统的备份方案。 (3) 冷备份冷备份是在数据库系统正常停机状态下,所做的外部备份,即拷贝文件系统到存储介质。 (4) 传统的并行外部备份传统的并行外部备份是一种在特殊情况下才可行的备份方法。一般需要满足以下条件:1. 数据库在一个集群里,并且不能有宕机时间。2. 没有快照功能。3. 在线备份不能满足需求。并行外部备份结合了数据库文件(*.DAT)拷贝和在线备份里增量备份的功能。其步骤如下:1. 在数据库中设置备份启动标志。2. 拷贝数据库文件(*.DAT)。3. 对该拷贝时间内被修改的数据进行在线备份的增量备份。具体使用情况和详情也请参考在线文档 https://docs.intersystems.com/irisforhealthlatest/csp/docbook/Doc.View.cls?KEY=GCDI_backup#GCDI_backup_methods_ext_concurrent 最新版本InterSystems IRIS for Health示例:===============================================================1. 设置标志,开始备份数据库。Set ^ClearOK=$CLRINC^DBACK("QUIET")2. 拷贝操作系统上的数据库文件(*.DAT)。3. 运行下面的命令,表明你已经使用了一个外部备份工具。Set x=$$BACKUP^DBACK("","E","Dirty external backup","","","")4. 进行增量备份。Set x=$$BACKUP^DBACK("","I","incremental","test.cbk","Y","bck.log","QUIET","Y","Y")===============================================================InterSystems产品中的上述处理可以做成例程Routine或类方法,并与批处理相结合进行操作。关于传统并行外部备份中使用的^DBACK例程的更多信息,请参考以下文件https://docs.intersystems.com/irisforhealthlatest/csp/docbook/Doc.View.cls?KEY=GCDI_backup#GCDI_backup_util_DBACK_entry_backup
文章
Lele Yang · 六月 8, 2021

FAQ 常见问题系列--应用篇 升级系统后打开管理门户SMP报错5001

如果您在升级了系统之后,打开SMP时看到如下报错,ERROR #5001: 对象的服务器版本与客户端发送的版本不一致: %ZEN.Component.vgroup 一般情况下,这个报错是由浏览器缓存中残留的过期信息造成的,可以通过清除浏览器缓存来解决。 如果清除浏览器缓存之后仍然未能解决此问题,请您前往系统安装目录, 如:d:\InterSystems\IRIS\CSP\broker,查看css/js文件的时间戳在本次更新安装之后是否并没有相应地更新,如果没有,请您做以下尝试,1)在IRIS中更改数据库IRISLIB, 之前的版本是CACHELIB, 取消只读装载,方法如下,打开管理门户SMP, 系统管理->配置->本地数据库,选择要更改的数据库,取消"只读方式挂载",点击【保存】。2)重新编译%Zen组件,w ##class(%SYSTEM.OBJ).Compile("%ZEN.Component.vgroup")此时,再次前往,d:\InterSystems\IRIS\CSP\broker,会看到相关的css/js文件时间戳已经更新。3)恢复上述数据库的只读装载。 如果以上办法仍然未能解决您的问题,建议您联系WRC,寻求Support的进一步帮助。
文章
TZ Zhuang · 六月 22, 2021

FAQ 常见问题系列--系统管理篇 每个InterSystems IRIS实例可以创建多少个数据库和命名空间

一个实例中可创建的最大命名空间数量为2048个。这个上限不可修改。 一个实例中可创建的最大数据库数量(包括远程数据库)为15998个。这个上限也不可修改。 一个实例中可创建数据库的总数量还有其他因素制约: 1. 数据库路径信息总量最大为256KB,也就是所有数据库的路径字符加起来不能多于256KB。设置的路径越长,可创建的数据库数量越少。计算公式:最大数据库数量=258048/(平均数据库路径长度+3) 2. 镜像的数据库一个按两个算。也就是创建一个镜像的数据库,相当于创建了2个非镜像数据库。 更多细节请参考在线文档:https://docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls?KEY=GSA_config
文章
Lele Yang · 六月 23, 2021

FAQ 常见问题系列--互操作篇 如何在Production中通过JDBC访问外部数据库

Production是指Ensemble/HealthShare Health Connect/IRIS/IRIS for Health产品中提供的互操作功能模块,更多关于Production介绍,可参见在线文档,https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=AFL_productions#AFL_productions_quicklook Production中访问外部数据库常用的适配器Adapter有两个,一个是用于Business Service中的Enslib.SQL.InboundAdapter,另一个是用于Business Operation中的Enslib.SQL.OutboundAdapter,更多关于这两个Adapter的使用说明可以参见在线文档"Using SQL Adapters in Productions", 本文主要涵盖以下内容 1. 基本配置步骤(仅涉及与JDBC连接相关配置)2. JDBC Gateway和Java Gateway Service的区别3. 常见的问题类型4. 常用基本故障排查 基本配置步骤 前提,在配置之前请您首先确认您的环境中已经正确安装了Java。1. 创建JDBC SQL Gateway,1)打开管理门户SMP(System Management Portal),System > Configuration > SQL Gateway Connections, 创建JDBC类型连接,连接名称为"MysqlJDBC",如下图所示, 2)测试该JDBC连接,点击【TEST Connection】如果成功可以进行下一步。2. 创建Java Gateway Service, 打开Production Configuration页面,创建Business Service, 该Service名为JService,如下图所示, 需要注意的是,如果系统没有配置JavaHome,那么需要手动在组件的”其他设置“中设置"JavaHome"路径。3. 配置BS/BO的DSN和JGService。打开Production Configuration页面, 选中使用SQL Inbound Adatper的Business Service或者使用SQL Outbound Adapter的Business Operaiont组件,组件如何创建在这里不做探讨,详细说明可参见以下在线文档,https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=ESQL_inboundhttps://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=ESQL_outbound 1)设置DSN,位于"基本设置"下,值为MysqlJDBC2) 设置JGService,位于”其他设置“下,值为JService 4. 您现在可以在BS/BO中通过JDBC访问外部数据库了。 JDBC Gateway和Java Gateway Service的区别 在上面第1.步中,当您进行JDBC连接测试的时候,您可以打开SMP,System > Configuration > JDBC Gateway Server, 您可以看到”JDBC Gateway is running“, 如下图所示, 这里看到的JDBC Gateway与我们在Production中创建的Java Gateway Service是完全独立的,前者基于系统层面,后者仅作为Production中的Business Service,仅存在于互操作模块。但二者所承担的角色可以理解为是相同的,二者都会创建JVM运行时环境,来处理JDBC连接程序。 常见的问题类型有 1. JDBC连接配置有误,连接串设置或者驱动问题。2. Java Gateway Service/JDBC Gateway端口号占用3. JAVA没有正确安装。4. 数据类型不匹配。造成这种情况的原因有多种,举一个最近遇到的客户例子,在BO中通过JDBC插入SQLServer数据库,在Production中该字段类型为%String, 但是对应SQLServer中字段为int型,那么就会遇到如下的错误,Error#5023 远程网关错误,JDBC Gateway execUpdate(0) error -1: Remote JDBC error,在将varchar值 '.'转换为int型时失败。5. 字符集问题。该类型问题一般情况下都需要具体问题具体分析,因为涉及到IRIS和外部数据库的编码,以及网络传输过程中的编码。举一个最近遇到的客户例子,BO中通过JDBC查询Mysql数据库,中文乱码,最后是通过更改JDBC连接串解决的,在连接串的最后添加了如下参数,?useUnicode=true&characterEncoding=UTF8 常用故障排查工具 1. Java Gateway Service 日志。打开Producton,选择该Java Gateway Service,设置“其他设置”下日志文件,其中该日志文件包含路径和文件名,如果该文件名不存在,会自动创建。2. JDBC Gateway 日志打开SMP,System > Configuration > JDBC Gateway Server, 配置“日志文件”3. Driver Log通过在JDBC连接串最后加上 /jdbc.log,如, jdbc:IRIS://127.0.0.1:51773/User/jdbc.log 请问下 网络环境相同的情况下,使用odbc和jdbc,效率上有区别吗?感觉odbc配置会少些 没有发现过两种方式性能上有什么大的差异。
文章
Lele Yang · 七月 13, 2021

FAQ 常见问题系列--互操作篇 使用SQL Outbound Adapter调用Oracle存储过程获取CLOB的正确方式

近日遇到客户反映在Business Operation中使用SQL Outbound Adapter调用Oracle存储过程时,无法获取CLOB完整的返回内容。借此在这里介绍下该如何调用,话不多说,直接上代码。 注意,以下代码片段直接应用于Business Operation中, set pIn = 4 set pIn(1) = "aaaa" set pIn(1,"IOType") = 1 // 1:input , 4:output set pIn(1,"SqlType") = 12 // 12: varchar set pIn(2,"IOType") = 4 set pIn(2,"SqlType") = 4 // 4: integer set pIn(3,"IOType") = 4 set pIn(3,"SqlType") = 12 set pIn(4,"IOType") = 4 set pIn(4,"SqlType") = 2005 // CLOB set pIn(4,"LOB") = 1 set tQuery = "{ call test_hc(?,?,?,?) }" /// the first one parameter is input parameter, the last three are all output parameters. set tSC = ..Adapter.ExecuteProcedureParmArray(.tRS,.pOut,tQuery,"iooo",.pIn) set cnt = pOut.Count() // you will get this stream data if cnt >1 { for i=1:1:cnt { set ov = pOut.GetAt(i)) $$$TRACE("pOut("_i_")="_ov) /// the third one is the CLOB output. if (i = 3) { while 'ov.AtEnd { $$$TRACE(ov.Read()) } } } } 关于以上示例代码的几点说明,1. test_hc为Oracle存储过程, 该存储过程的第一个参数为入参,后三个为出参,第三个出参为CLOB类型。2. 使用上述方式获取到的第三个出参为%Stream.GlobalCharacter类型,拿到该数据后在程序中根据实际场景对其进行相应的处理,以上示例代码中我们只是将该%Stream类型数据读取出来。3. 关于IOType,in: 1, out:4, both:24. 关于SqlType,经常使用的几个取值,12:varchar,4:integer, 2005: CLOB, 2004: BLOB, 更多详细取值对照请查看Routine,EnsSQLTypes.INC。 如果对方的oracle只提供了表,有个字段是clob,我们使用SQL Outbound Adapter,如何写入呢
文章
Lele Yang · 七月 22, 2021

FAQ 常见问题系列--Java 从IRIS数据库中读取Stream数据性能优化-Prefetch方式介绍

提示:本文包含在Java中通过JDBC Driver对Caché/IRIS数据库进行查询的示例代码。 近期有客户反应使用Java从老版本Caché中读取数据时,如果数据中包含long varchar, Caché数据库中与之对应的属性类型为%Stream.GlobalCharacter,即使实际上该流数据长度非常小,也会成十几倍的降低性能。 大家先来看一段代码, public static void test99() { Statement stmt = null; ResultSet rs = null; int fetchSize = 100000; long before = System.currentTimeMillis(); String sql="Select Title, Notes from My.Employee Where id=1"; try { CacheDataSource ds = new CacheDataSource(); ds.setURL("jdbc:Cache://123.123.123.1:1972/Samples"); //访问Caché数据库 ds.setUser("_SYSTEM"); ds.setPassword("SYS"); Connection connection = ds.getConnection(); connection.setAutoCommit(false); stmt = connection.createStatement(); rs = stmt.executeQuery(sql); long executed = System.currentTimeMillis(); System.out.println("execute take miliseconds of:"+(executed-before)); ResultSetMetaData rsmd = rs.getMetaData(); int colnum = rsmd.getColumnCount(); String str = null; while (rs.next()) { for (int i = 1,ilen = colnum; i <= ilen; i++) { str = rs.getString(i); } } stmt.close(); rs.close(); connection.close(); long end = System.currentTimeMillis(); System.out.println("read take miliseconds of:"+(end - executed)); System.out.print("total take miliseconds of:"+(end-before)); }catch (Exception ex) { System.out.println("TinyJDBC caught exception: " + ex.getClass().getName() + ": " + ex.getMessage()); } } 以上代码中查询的sql表My.Employee,在Caché数据中对应的类如下, Class My.Employee Extends (%Persistent, %Populate) { Property Name As %String; Property Title As %String; Property Notes As %Stream.GlobalCharacter; } 那么对于Stream数据的读取慢在哪儿,为什么会慢呢?执行完sql语句数据库服务器端返回的结果集中将包括Title这个String类型数据,但是并不包括Stream数据Notes,这么设计也是合理的,因为如果把一个几个M的流数据直接包含在结果集中返回,而应用程序并不需要使用这个流数据,那么这个代价花得就有点不值了。所以真正去获取这个流数据是在getString()时向数据库服务器端发送请求然后服务器端将这个数据返回的,即使流数据的实际长度很小,网络的一来一回也无法避免。所以慢在getString, 原因是多花费了一次网络的往返。 为了应对此场景,IRIS增加了Prefetch机制,也就是预先读取一定长度的流数据放在结果集中一并返回,如果设置得恰当就能避免二次请求。以此提高读取性能。Prefetch使用方法请参考如下示例代码, public static void test98() { Statement stmt = null; ResultSet rs = null; long before = System.currentTimeMillis(); String sql="Select Title, Notes from My.Employee Where id=1"; try { IRISDataSource ds = new IRISDataSource(); ds.setURL("jdbc:IRIS://123.123.123.2:1972/USER/jdbc-prefetch2.log"); // iris数据库,此代码测试在IRIS2021.1上进行。 ds.setUser("_SYSTEM"); ds.setPassword("SYS"); IRISConnection irisconnection = (IRISConnection)ds.getConnection(); irisconnection.setStreamPrefetchSize(10000); stmt = irisconnection.createStatement(); rs = stmt.executeQuery(sql); long executed = System.currentTimeMillis(); System.out.println("execute take miliseconds of:"+(executed-before)); ResultSetMetaData rsmd = rs.getMetaData(); int colnum = rsmd.getColumnCount(); String str = null; while (rs.next()) { for (int i = 1,ilen = colnum; i <= ilen; i++) { str = rs.getString(i); } } stmt.close(); rs.close(); irisconnection.close(); long end = System.currentTimeMillis(); System.out.println("read take miliseconds of:"+(end - executed)); System.out.print("total take miliseconds of:"+(end-before)); }catch (Exception ex) { System.out.println("TinyJDBC caught exception: " + ex.getClass().getName() + ": " + ex.getMessage()); } } } 以上代码中查询的sql表My.Employee在IRIS中的定义同上。 关于如何使用Java的更多内容,请参见如下在线文档,https://docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls?KEY=BJAVA IRISDataSource API,请参见如下在线文档,https://docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls?KEY=BJAVA_refapi#BJAVA_refapi_iris-data-source 只是 IRIS才增加了Prefetch机制吗?ensemble2016呢 是的,只有IRIS上才有,ensemble2016没有。 cache里面有prefetch吗。另外,只能通过setStreamPrefetchSize添加吗,能否通过在url上添加参数达到同样的效果呢。
文章
TZ Zhuang · 八月 6, 2021

FAQ 常见问题系列--系统管理篇 如何使用命令在Journal日志文件中搜索指定的Global

可以使用%SYS.Journal.File类中的ByTimeReverseOrder查询,以及%SYS.Journal.Record类中的List查询来实现。 下面是这两个查询的具体作用: A) %SYS.Journal.File类中的ByTimeReverseOrder查询这个查询会获取journal日志文件名并按降序排列 USER>set rs=##class(%ResultSet).%New("%SYS.Journal.File:ByTimeReverseOrder") USER>do rs.Execute() USER>while rs.Next() { write rs.Name,! } c:\intersystems\cache\mgr\journal\20190620.003 c:\intersystems\cache\mgr\journal\20190620.002 c:\intersystems\cache\mgr\journal\20190620.001 c:\intersystems\cache\mgr\journal\20190610.001 B) %SYS.Journal.Record类中的List查询这个查询可以从指定journal日志文件中获取日志记录 USER>set rs2=##class(%ResultSet).%New("%SYS.Journal.Record:List") USER>do rs2.Execute("c:\intersystems\cache\mgr\journal\20190620.003") USER>while rs2.Next() { if rs2.Get("GlobalReference")["TEST" write rs2.Get("GlobalReference"),!} ^["^^c:\intersystems\cache\mgr\user\"]TEST(1) ...... ^["^^c:\intersystems\cache\mgr\user\"]TEST(9) ^["^^c:\intersystems\cache\mgr\user\"]TEST(10) 这里我们可以把从A查询获得的结果传到B查询里。如果想了解从B查询里还能获得哪些字段的内容,请参考文档里的%SYS.Journal.Record类定义 下面是一个把A和B查询合并在一起的例子: ///参数 globalname: 需要查询的Global名字(不包括^) ClassMethod SearchAllJournals(globalname As %String) { if $get(globalname)="" { write "请指定Global名字",! quit } //从当前所有journal日志文件中搜索指定的global set rs1=##class(%ResultSet).%New() set rs1.ClassName="%SYS.Journal.File" set rs1.QueryName="ByTimeReverseOrder" do rs1.%Execute() while rs1.%Next() { set jrnfile=rs1.%Get("Name") set size=rs1.%Get("Size") write "Journal file:",jrnfile,!," File size:",size/1024/1024," MB",! do ..SearchGlobal(globalname,jrnfile) } do rs1.Close() } ///第一个参数 globalname: 需要查询的Global名字(不包括^) ///第二个参数 jrnfile: 指定的journal日志文件名字(包括路径) ClassMethod SearchGlobal(globalname As %String, jrnfile As %String) { set rs1=##class(%ResultSet).%New() set rs1.ClassName="%SYS.Journal.Record" set rs1.QueryName="List" //打开journal日志文件并搜索指定的Global do rs1.%Execute(jrnfile,"GlobalReference,NewValue",,,$lb("GlobalReference","[",globalname)) while rs1.%Next() { set glo=rs1.%Get("GlobalReference") write " ",glo," = ",rs1.%Get("NewValue"),! } do rs1.Close() }
文章
Lele Yang · 八月 13, 2021

FAQ 常见问题系列--Object Script篇 字符串%String长度限制

众所周知,Object Script是一个弱类型开发语言,%String是我们非常常用的一个类型,时不时有客户在初次接触Object Script编写程序时遇到%String长度限制的问题,在这里做一个简单总结,以便于相关开发人员作为参考。 1. MAXLEN设置字符串的长度。Property Name As %String(MAXLEN = 50);a) 如果不设置MAXLEN, 默认长度限制为50b) MAXLEN = "", 没有限制长度,也就是字符串本身的长度限制。 如果超限,您将会看到如下报错,错误 #7201: 数据类型值'abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz'的长度超过50允许的MAXLEN 2. 字符串本身的长度限制。在没有开启长字符串的情况下,%String类型的长度限制是32,767个字符。 如果超限,您会遇到报错<MAXSTRING>,如果遇到这个报错,建议您改用流类型%Stream,如%Stream.FileCharacter, %Stream.GlobalCharacter等等,更多关于如何使用流类型,详见如下在线文档,http://dreamymclean.intersystems.skytapdns.com:52773/csp/docbook/DocBook.UI.Page.cls?KEY=GOBJ_propstream 3. 开启长字符串打开系统管理页面System Management Portal(SMP),系统 > 配置 > 内存和启动,选中“启用长字符串”,选中后不需要重启系统使其生效。启用长字符串之后,字符串的长度限制扩展为3,641,144个字符 那对于整个表,假设我创建一张表,里面的String 类型总长度(各个字段长度之和)是否有限制。 有的,由于单个字段长度有限制,因此总长也有限制
文章
Lele Yang · 八月 31, 2021

FAQ 常见问题系列--系统管理篇 磁盘空间不足造成系统宕机——切忌手动删除Journal文件!

1 磁盘空间不足的常见情形1)Journal所在磁盘空间不足。造成这种情况的原因有多种,比如,Mirror中备机未处于宕机状态,因此主机保留了Journal文件。2)数据库所在磁盘空间不足。比如,集成平台上Ensemble/Health Connect/IRIS for Health的消息从未清除过,导致消息数据库DAT文件不断增大,直至将磁盘空间用尽。 我们可以看到以上两种情形下,Mirror都帮不上忙,也就是说一旦问题出现,主机和备机都没有办法立即承担起业务系统的运行,第1)种,备机可能在故障出现前就已经宕机很长一段时间而没被发现,备机的数据很可能已经与主机严重不一致。实际上,主机之所以保留了大量的journal文件没有删除,就是为了让备机同步数据时使用。第2)种,虽然配置了Mirror,但是消息主库正常情况下都是镜像库,在一个健康的Mirror中,备机和主机的镜像库数据保持同步,镜像库大小应当是相同的,假设主备机的硬件配置相同(这也是我们推荐的方式)那么磁盘空间不足在备机上同样存在。 2 应急措施 切忌手动从文件系统中删除Journal文件! 以上两种情形我们都遇到过客户为了快速地腾出空间、恢复系统,第一时间手动从文件系统中将必要的Journal文件删除掉了,删除了这些Journal文件之后,尽管腾出了空间,但会造成系统无法启动,通常这个时候您会在日志文件中看到如下信息, 07/30/21-09:10:23:436 (19895) 1 1 errors during journal restore, see messages.log file for details. Startup aborted, entering single user mode. Enter with iris session HEALTHCONNECT -B and Do ^STURECOV for help recovering from the errors. 您此时可以参照日志文件中的提示进行操作。如果对于以上操作有疑问,请立即联系WRC技术支持。 假如,没有更好的办法一定要删除Journal文件来腾出磁盘空间,则可尝试以下方法安全删除Journal文件,a)使用系统工具D ^JOURNAL进行安全删除,如何使用该工具可参考如下在线文档,https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GCDI_journal#GCDI_journal_config_settingsb)可以手动运行一次清除Journal的定时任务。 3 如何预防?1)日常监控系统磁盘空间使用关于监控,在系统日志文件,IRIS版本在message.log中,其他产品版本在cconsole.log中,有关于磁盘空间使用不足的提示信息, 07/27/21-16:33:38:513 (30405) 1 [SYSTEM MONITOR] DiskPercentFull(***) Warning: DiskPercentFull = 95.00 ( Warnvalue is 95) 更多关于如何进行系统监控可参见在线文档,Caché/Ensemble参见如下链接,章节“Caché Monitoring Guide”https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=GCM IRIS参见如下链接,章节“Monitoring Guide”https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=GCM2)定期清除消息平台上消息您可以通过配置系统定时任务来达到这个目的,具体如何清理Production中的消息数据,可参见如下在线文档,https://docs.intersystems.com/latest/csp/docbook/DocBook.UI.Page.cls?KEY=EGMG_purge
文章
Lele Yang · 四月 21, 2022

FAQ 常见问题系列--Java 如何向IRIS数据库中写入Stream数据

以下示例代码可实现在Java中通过JDBC向IRIS数据库中写入Stream数据,插入的该Stream大小约为4M,对应在IRIS中字段类型为%Stream.GlobalCharacter。以下代码在IRIS2021上测试成功,供大家参考, Java代码, public static void test96() { int rt; String sql="Insert into My_Msg.Test1(MsgControlID,S1) values(?,?)"; try { IRISDataSource ds = new IRISDataSource(); //172.19.85.72/:1972/YLL IRIS Health 2021 ds.setURL("jdbc:IRIS://<ip>:1972/YLL"); ds.setUser("<username>"); ds.setPassword("<password>"); Connection connection = ds.getConnection(); PreparedStatement pstmt = connection.prepareStatement(sql); System.out.println("1"); StringBuffer txt = new StringBuffer(); for (int i = 0; i < 4000000; i++) { txt.append("a"); } pstmt.setInt(1, 1); pstmt.setObject (2, txt.toString()); rt = pstmt.executeUpdate(); System.out.println("2:"+rt); pstmt.close(); connection.close(); }catch (Exception ex) { System.out.println("JDBC caught exception: " + ex.getClass().getName() + ": " + ex.getMessage()); } } 插入的表在IRIS中对应的类定义, Class My.Msg.Test1 extends %Persistent { Property MsgControlID As %String; Property S1 As %Stream.GlobalCharacter; }
文章
Michael Lei · 一月 15, 2024

FAQ 关于当前通用内存堆(gmheap)和最大可获得锁表(locksiz)大小

作为针对数据导入处理性能和错误(锁定表已满)的衡量标准,可能需要调整常规内存堆 (gmheap) 和锁定表大小 (locksiz) 参数。 事实上,您可以使用终端和管理门户来检查当前分配了多少通用内存堆。 ★终端用 // 一般メモリヒープサマリUSER> w $system .Config.SharedMemoryHeap.GetUsageSummary() 4992226 , 6029312 , 59441152 通用内存堆摘要以使用量、分配量和配置量(字节)的形式显示返回值。 使用量是分配的锁表、进程表等实际使用的量。分配量是gmheap区域中锁表、进程表等分配的量。配置量为gmheap(KB)+IRIS系统附加区,即当前最大可用量(实际通用内存堆区值)。 如上所述,配置数量与配置参数 gmheap 的独立值不匹配。这是因为IRIS自动将内部使用的内存区域添加到配置参数gmheap中来配置通用内存堆区域。详情请参阅下面的文档。 关于gmheap 您可以使用以下命令获取锁表的使用情况:返回值显示为可用量、用户可用量和已用量(字节)。详情请参阅这篇文章。 %SYS > w ##class (SYS. Lock ).GetLockSpaceInfo() 16772624 , 16764624 , 4592 ★用于管理门户 您可以从“系统操作”>“系统使用情况”>“共享内存堆使用状态”进行检查。 对于整个通用内存堆来说,“Total SMH Pages Use”项中的“Alulated SMH/ST”表示分配量(字节)。 关于锁表“Lock Table”项中的“SMH/ST in use”表示锁表使用量(字节)。用户可用性必须通过从 locksiz 值中减去该值来计算。 更改 gmheap 涉及重新启动 IRIS 实例。要查找当前 gmheap 中可以设置的最大 locksiz 值,请执行以下操作:无需重新启动即可单独更改 Locksiz。 %SYS > write ##class (SYS. Lock ).GetMaxLockTableSize() 16777216 如果要指定的locksiz大于通过GetMaxLockTableSize()获取的值,则需要将差值添加到gmheap并设置它。 在这种情况下,新设置将在 IRIS 实例重新启动后生效。 【注意力】在版本 2023.1 及更高版本中, 共享内存堆 (gmheap)和用于锁的共享内存 (locksiz)的默认值已更改为“0”。 单击此处查看发行说明*2022.2 中,gmheap=37,568(KB),locksiz=65,536(字节)。 根据配置的Global缓冲区大小(数据库缓存大小)应用最有效的设置。如果用户未设置Global缓冲区大小,则它将从可用的系统内存中构造。与以前的版本一样,用户仍然可以使用特定值覆盖这些默认值。
文章
Lele Yang · 一月 30, 2022

FAQ 常见问题系列 -- 系统管理篇 Linux OOM Killer问题

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等,以使系统可以在内存使用方面达到最大的效用。
文章
TZ Zhuang · 一月 30, 2022

FAQ 常见问题系列--系统管理篇 如何快速查看锁表空间使用情况

如果想快速查看锁表空间的使用情况,可以通过GetLockSpaceInfo()方法来获得。 %SYS>w ##class(SYS.Lock).GetLockSpaceInfo() 4717392,4712512,1200 返回值是 "AvailableSpace,UsableSpace,UsedSpace",每个值的单位都是Byte。 AvailableSpace:锁表的总空间减去已用空间的大小(UsedSpace)。UsableSpace:预估的可用空间。AvailableSpace里有一些空间是系统内部保留的,所以UsableSpace比AvailableSpace要小。UsableSpace是用户在锁表中可用的自由空间的数量。UsedSpace:已经使用的空间。
文章
Lele Yang · 二月 18, 2022

FAQ 常见问题系列--系统管理篇 InterSystems产品的内存使用

InterSystems的产品包括Caché/Ensemble/Health Connect/IRIS/IRIS for Health,均基于进程,当它们及在它们之上开发的应用运行时,您能在操作系统上看到大量cache/irisdb进程。下面以InterSystems IRIS为例,来说明下InterSystems产品的内存使用。 InterSystems IRIS进程的内存使用主要有以下两大类, 第一类,进程私有内存。 私有内存只由该进程使用,且会为每个进程单独分配。进程初始时会被分配128KB的内存空间,随着进程运行根据需要,这个内存空间会自动扩展。InterSystems IRIS对于进程内存使用的限制是Maximum Per-Process Memory, 该参数的设置位置在系统管理门户SMP,System > Configuration > Memory and Startup,允许的取值范围是256KB到2147483647KB(2TB)。如果系统遇到<STORE>错误,那么可以尝试增加该数值,来解决进程运行时无法申请到更多内存的问题。从InterSystems IRIS开始,我们推荐将该值设置为-1, 也就是取上限2TB。 更多InterSystems IRIS进程内存使用可参见如下在线文档"Process Memory in InterSystems Products",https://docs.intersystems.com/irislatest/csp/docbook/DocBook.UI.Page.cls?KEY=AVMEM 第二类,共享内存。共享内存是一个在进程之间共享的内存区域,因此内存中只有一个实体。 InterSystems中的共享内存包括如下,1. Database Cache, 也就是我们常说的Global Buffer,设置位置在SMP,System > Configuration > Memory and Startup。 2. Routine Cache, 也就是Routine Buffer,设置位置同上。3. gmheap,设置位置在SMP,System > Configuration > Advanced Memory Settings。我们通常所说的Process Table和Lock Table占用的内存也是从这部分内存中划分出来的,如果遇到Lock Table Full的问题,需要增加locksiz大小,请注意同步调大gmheap。 InterSystems IRIS在实例启动时,会首先尝试为这部分共享内存分配Huge Page/Large Page,以获得最佳性能实践,如果分配成功,您可以在日志文件messages.log中看到如下类似内容, 11/28/21-21:00:09:081 (41752) 0 [Generic.Event] Allocated 35046MB shared memory (large pages): 31000MB global buffers, 1024MB routine buffers 另外,除以上两大类之外,还有一类特殊的内存使用, 1.长字符串内存使用InterSystems IRIS默认启用长字符串,最多支持3,641,144个字符,当进程使用长字符串时,为其分配的内存直接来自于操作系统的malloc() buffer,它不占用进程的私有内存空间,因此为字符串实际分配的内存不受限于Maximum Per-Process Memory。 综上,InterSystems IRIS所使用的内存总量是所有InterSystems IRIS进程使用的内存之和,也就等于,(进程私有内存 * 进程数) + Global Buffer + Routine Buffer + gmheap + 长字符串总体使用内存。