在生产环境中IRIS通常以故障转移集群的形态被部署,而集群中各故障转移成员的镜像状态将决定该集群在故障发生时是否能够顺利切换保障业务不中断。因此,成员状态通常也是运维团队需要巡检或监控的目标。
尽管IRIS内部API提供了丰富的集群配置、成员状态监控等一系列接口,但除Portal上的镜像监视器外,并没有特定的接口便于从外部系统访问(如进行企业级监控集成时),也没有整合好的监控接口可用与获取镜像的健康状态。但在IRIS上开发一个REST接口暴露镜像状态数据并不困难,如下所示:
Include %syMirror
Class Monitor.MirrorMonitoring Extends %CSP.REST
{
/// Default the Content-Type for this application.
Parameter CONTENTTYPE = "application/json";
/// By default convert the input stream to Unicode
Parameter CONVERTINPUTSTREAM = 1;
/// The default response charset is utf-8
Parameter CHARSET = "utf-8";
ClassMethod GetMirrorStatus() As %Status
{
set tSC = $$$OK
//保存起始命名空间
Set nsName = ##Class(%SYSTEM.SYS).NameSpace()
set mirrorName=$lg(##class(%SYSTEM.Mirror).GetMirrorNames(),1)
if "" = mirrorName {
Quit tSC
}
#Dim mirrorStatus as %DynamicObject = {}
//进入%SYS命名空间,通过系统API获取镜像状态
zn "%SYS"
//获取仲裁状态
Set mir = ##class(Config.Mirrors).Open(mirrorName)
#Dim arbiterStatus as %DynamicObject = {}
Set arbiteraddr = $P(mir.ArbiterNode,"^",1)
Set arbiterStatus.ArbiterNode = arbiteraddr
Set vip = $P(mir.VirtualAddress,"^",1)
Set arbiterStatus.VirtualAddress = vip
Set modeString = ""
Set mode = $SYSTEM.Mirror.FailoverRule()
If mode = $$$ArbiterControlledMirrorFailover {
Set modeString = "Arbiter Controlled"
} ElseIf mode = $$$AgentControlledMirrorFailover {
Set modeString = "Agent Controlled"
} Else {
Set modeString = "User Controlled"
}
Set arbiterStatus.FailoverMode = modeString
Set stateString = ""
Set state = $SYSTEM.Mirror.ArbiterState()
Set thisConnected = $SELECT($ZB(+state,+$$$ArbiterConnected,1)'=0:1,1:0)
Set otherConnected = $SELECT($ZB(+state,+$$$ArbiterPeerConnected,1)'=0:1,1:0)
If 'thisConnected {
Set stateString = "This member is not connected to the arbiter"
} ElseIf 'otherConnected {
Set stateString = "Only this member is connected to the arbiter"
} Else {
Set stateString = "Both failover members are connected to the arbiter"
}
Set arbiterStatus.ConnectionStatus = stateString
set mirrorStatus.ArbiterStatus = arbiterStatus
//获取镜像成员状态
#Dim memberArray as %DynamicArray = []
Set result = ##class(%ResultSet).%New("SYS.Mirror:MemberStatusList")
Set tSC = result.Execute(mirrorName)
while result.Next() {
#Dim memberStatus as %DynamicObject = {}
Set colCount = result.GetColumnCount()
for i = 1:1:colCount
{
set name = result.GetColumnName(i)
set value = result.GetData(i)
d memberStatus.%Set(name,value)
}
d memberArray.%Push(memberStatus)
}
set mirrorStatus.MemberStatus = memberArray
//获取镜像数据库状态
#Dim dbArray as %DynamicArray = []
Set bdr = ##class(%ResultSet).%New("SYS.Mirror:MirroredDatabaseList")
Set tSC = bdr.Execute()
while bdr.Next() {
#Dim dbStatus as %DynamicObject = {}
Set colCount = bdr.GetColumnCount()
for i = 1:1:colCount
{
set name = bdr.GetColumnName(i)
set value = bdr.GetData(i)
d dbStatus.%Set(name,value)
}
d dbArray.%Push(dbStatus)
}
set mirrorStatus.DatabaseStatus = dbArray
//返回被执行时的命名空间
zn nsName
d mirrorStatus.%ToJSON()
Quit tSC
}
XData UrlMap [ XMLNamespace = "http://www.intersystems.com/urlmap" ]
{
<Routes>
<Route Url="/getMirrorStatus" Method="GET" Call="GetMirrorStatus"/>
</Routes>
}
}
ObjectScriptObjectScript
在该实现中,由于需要调用%SYS下的API,因此需要在执行过程中切换到%SYS命名空间,并在执行完毕后切换回原命名空间。
将该服务部署在任意命名空间,并开放对应的Web Application:
需要注意这种接口需要进行身份验证,否则恶意调用将不断消耗服务器的资源。关于如何在IRIS建立用户名密码保护REST接口,可参见之前的文章《IRIS中的权限管理》。
开放好这个接口之后,通过REST Get调用即可获取该实例的镜像状态: