#Mirroring

0 Seguidores · 13 Publicaciones

Mirroring es una tecnología de InterSystems para soluciones de alta disponibilidad, recuperación de desastres y respaldo de bases de datos y OLAP solutions.

Documentation.

Artículo Ricardo Paiva · sep 22, 2025 6m read

Contexto

Por una variedad de razones, los usuarios pueden desear montar un volumen persistente en dos o más pods que abarquen varias zonas de disponibilidad. Un caso de uso de este tipo es poner a disposición de ambos miembros del espejo los datos almacenados fuera de IRIS en caso de una conmutación por error.

Desafortunadamente, las clases de almacenamiento integradas en la mayoría de las implementaciones de Kubernetes (ya sea en la nube o en las instalaciones) no ofrecen esta capacidad:

0
0 22
InterSystems Official Jose-Tomas Salvador · ago 5, 2025

InterSystems se complace en anunciar la disponibilidad general (GA) de la versión 2025.2 de la plataforma de datos InterSystems IRIS®. Esta es una versión de Entrega Continua (CD). Tened en cuenta que las versiones GA de InterSystems IRIS for Health™ y HealthShare® Health Connect™ 2025.2 se han retenido temporalmente debido a limitaciones en la replicación introducidas por actualizaciones de seguridad (más detalles a continuación).

Aspectos destacados de la versión

0
0 23
Artículo Jose-Tomas Salvador · mayo 30, 2025 8m read

Si estás ejecutando IRIS en una configuración en mirror para alta disponibilidad (HA) en Azure, la cuestión de proporcionar una Mirror VIP (Virtual IP) es relevante. La Virtual IP ofrece una forma para que los sistemas interactuen con IRIS utilizando una dirección IP. Incluso cuando ocurre un failover, los otros sistemas pueden reconectarse a la misma dirección IP y continuar trabajando.

El problema principal, cuando se despliega en Azure, es que una IRIS VIP tiene el requerimiento de que IRIS sea esencialmente un admin de red, según se indica en la documentación.

Para tener HA, los miembros en mirror de IRIS deben ser desplegados en diferentes zonas de disponibilidad (availability zones o AZ) en una subred (lo que es posible en Azure ya que las subredes pueden abarcar varias zonas). Una de las soluciones puede ser utilizar balanceadores de carga pero, por supuesto, suponen un coste extra, y también necesitarás administrarlos.

En este artículo, quiero proporcionar un modo de configurar una Mirror VIP sin la utilización de balanceadores de carga que se sugiere en la mayoría de las propouestas de arquitectruas de referencia para Azure.

Arquitectura

Architecture

Tenemos una subred activa entre 2 zonas de disponibilidad (simplifico aquí - por supuesto, probablemente tendrás subredes públicas, arbitro en otra AZ, y así sucesivamente, pero esto es un ejemplo de lo mínimo imprescindible para demostrar esta propuesta). El CIDR de la subred es 10.0.0.0/24, lo que significa que las IPs que asigna van de la 10.0.0.1 a 10.0.0.255. Como Azure reserva las primeras 4 direcciones y la última dirección, podemos usar de la 10.0.0.4 a la 10.0.0.254.

Implementaremos ambos, una VIP pública y una privada al mismo tiempo. Si quieres, puedes implementar sólo la VIP privada.

Idea

Las máquinas virtuales en Azure tienen Interfaces de Red. Estos Interfaces de Red tienen Configuraciones IP. La configuración IP es una combinación de IPs Publica y Privada, y se enruta automáticamente a la máquina virtual asociada con la Interfaz de Red. Así que no hay necesidad de actualizar las rutas. Lo que haremos es, durante un evento de failover, borrar la configuración VIP IP del antiguo primario y crearla para un nuevo primario. Todas las operaciones para hacer eso llevan sólo unos 5-20 segundos por VIP Privada, y de 5 segundos a 1 minuto para una combinación de VIP IP Pública/Privada.

Implementando la VIP

  1. Asignar IP Externa para usas como una VIP pública. Salta este paso si sólo quieres una VIP Privada. Si asignas la VIP, debe residir en el mismo grupo de recursos y en la misma región y estar en todas las zonas con primario y backup. Necesitarás un nombre de IP Externa.
  2. Decide el valor de la VIP Privada. Yo utilizaré la última disponible: 10.0.0.254.
  3. En cada VM (Virtual Machine), asigna la dirección de IP de la VIP Privada al interfaz de red eth0:1.
cat << EOFVIP >> /etc/sysconfig/network-scripts/ifcfg-eth0:1
          DEVICE=eth0:1
          ONPARENT=on
          IPADDR=10.0.0.254
          PREFIX=32
          EOFVIP
sudo chmod -x /etc/sysconfig/network-scripts/ifcfg-eth0:1
sudo ifconfig eth0:1 up

Si sólo quieres probar, ejecuta: (pero no sobrevivirá a un reinicio de sistema)

sudo ifconfig eth0:1 10.0.0.254

Dependiendo del SO puede que necesites ejecutar:

ifconfig eth0:1
systemctl restart network
  1. Para cada VM, habilita Identidad asignada al Sistema o Usuario.
  2. Para cada identidad, asigna los permisos para modificar los Interfaces de Red. Para hacer eso crea un rol a medida, el permiso mínimo a establecer en ese caso sería:
{
  "roleName": "custom_nic_write",
  "description": "IRIS Role to assign VIP",
  "assignableScopes": [
    "/subscriptions/{subscriptionid}/resourceGroups/{resourcegroupid}/providers/Microsoft.Network/networkInterfaces/{nicid_primary}",
    "/subscriptions/{subscriptionid}/resourceGroups/{resourcegroupid}/providers/Microsoft.Network/networkInterfaces/{nicid_backup}"
  ],
  "permissions": [
    {
      "actions": [
        "Microsoft.Network/networkInterfaces/write",
        "Microsoft.Network/networkInterfaces/read"
      ],
      "notActions": [],
      "dataActions": [],
      "notDataActions": []
    }
  ]
}

Para entornos de no-producción podría utilizar un rol de sistema de tipo Network Contributor en el grupo de recursos, pero no está recomendado porque el Network Contributor es un rol muy amplio.

  1. Cada interfaz de red en Azure puede tener un conjunto de configuracion de IP. Cuando un miembro actual del mirror se convierte en primario, usaremos un callback de ZMIRROR para borrar una configuración de IP VIP del interfaz de red del otro miembre del miror y crear una configuración de VIP IP que le apunte a él mismo:

Aquí tienes los comandos de Azure CLI para ambos nodos, asumiendo el grupo de recursos rg, la configuración de IP vip, y mi IP Externa my_vip_ip:

az login --identity
az network nic ip-config delete --resource-group rg --name vip --nic-name mirrorb280_z2
az network nic ip-config create --resource-group rg --name vip --nic-name mirrora290_z1 --private-ip-address 10.0.0.254 --public-ip-address my_vip_ip

y:

az login --identity
az network nic ip-config delete --resource-group rg --name vip --nic-name mirrora290_z1
az network nic ip-config create --resource-group rg --name vip --nic-name mirrorb280_z2 --private-ip-address 10.0.0.254 --public-ip-address my_vip_ip

Y el mismo código en una rutina ZMIRROR:

ROUTINE ZMIRROR

NotifyBecomePrimary() PUBLIC {
    #include %occMessages
    set rg = "rg"
    set config = "vip"
    set privateVIP = "10.0.0.254"
    set publicVIP = "my_vip_ip"

    set nic = "mirrora290_z1"
    set otherNIC = "mirrorb280_z2"
    if ##class(SYS.Mirror).DefaultSystemName() [ "MIRRORB" {
        // we are on mirrorb node, swap
        set $lb(nic, otherNIC)=$lb(otherNIC, nic)
    }

    set rc1 = $zf(-100, "/SHELL", "export", "AZURE_CONFIG_DIR=/tmp", "&&", "az", "login", "--identity")
    set rc2 = $zf(-100, "/SHELL", "export", "AZURE_CONFIG_DIR=/tmp", "&&", "az", "network", "nic", "ip-config", "delete", "--resource-group", rg, "--name", config, "--nic-name", otherNIC)
    set rc3 = $zf(-100, "/SHELL", "export", "AZURE_CONFIG_DIR=/tmp", "&&", "az", "network", "nic", "ip-config", "create", "--resource-group", rg, "--name", config, "--nic-name",      nic,  "--private-ip-address", privateVIP, "--public-ip-address", publicVIP)
    quit 1
}

La rutina es la misma para ambos miembros del mirror, nosotros simplemente intercambiamos los nombre de NIC basandonos en el nombre del miembre de mirror actual. Puede que no tengas que hacer export AZURE_CONFIG_DIR=/tmp, pero a veces az intenta escribir credenciales en el directorio home de root, lo que podría fallar. En lugar de /tmp, es mejor utilizar el subdirectorio home del usuario IRIS (o puede que ni siquiera necesites ese nombre de variable, dependiendo de tu configuración).

Y, si quieres utilizar Python Embebido, aquí tienes el código de Azure Python SDK:

from azure.identity import DefaultAzureCredential
from azure.mgmt.network import NetworkManagementClient
from azure.mgmt.network.models import NetworkInterface, NetworkInterfaceIPConfiguration, PublicIPAddress

sub_id = "AZURE_SUBSCRIPTION_ID"
client = NetworkManagementClient(credential=DefaultAzureCredential(), subscription_id=sub_id)

resource_group_name = "rg"
nic_name = "mirrora290_z1"
other_nic_name = "mirrorb280_z2"
public_ip_address_name = "my_vip_ip"
private_ip_address = "10.0.0.254"
vip_configuration_name = "vip"


# remove old VIP configuration
nic: NetworkInterface = client.network_interfaces.get(resource_group_name, other_nic_name)
ip_configurations_old_length = len(nic.ip_configurations)
nic.ip_configurations[:] = [ip_configuration for ip_configuration in nic.ip_configurations if
                            ip_configuration.name != vip_configuration_name]

if ip_configurations_old_length != len(nic.ip_configurations):
    poller = client.network_interfaces.begin_create_or_update(
        resource_group_name,
        other_nic_name,
        nic
    )
    nic_info = poller.result()

# add new VIP configuration
nic: NetworkInterface = client.network_interfaces.get(resource_group_name, nic_name)
ip: PublicIPAddress = client.public_ip_addresses.get(resource_group_name, public_ip_address_name)
vip = NetworkInterfaceIPConfiguration(name=vip_configuration_name,
                                      private_ip_address=private_ip_address,
                                      private_ip_allocation_method="Static",
                                      public_ip_address=ip,
                                      subnet=nic.ip_configurations[0].subnet)
nic.ip_configurations.append(vip)

poller = client.network_interfaces.begin_create_or_update(
    resource_group_name,
    nic_name,
    nic
)
nic_info = poller.result()

Arranque inicial

NotifyBecomePrimary se llama también automáticamente cuando el sistema arranca (tras la reconexión del mirror), pero si quieres que tus entornos sin mirror adquieran una VIP del mismo modo, utiliza ZSTART routine:

SYSTEM() PUBLIC {
  if '$SYSTEM.Mirror.IsMember() {
    do NotifyBecomePrimary^ZMIRROR()
  }
  quit 1
}

Conclusión

¡Y ya estaría! Cambiamos la configuración de la IP para apuntar al mirror Primario cuando ocurre un evento NotifyBecomePrimary.

0
0 31
Artículo Luis Angel Pérez Ramos · feb 20, 2025 3m read

Es posible que hayáis notado que, para configurar un mirror en InterSystems IRIS for Health™ y HealthShare® Health Connect, hay un requisito especial. En este artículo, quiero guiaros paso a paso por el proceso.

Esto supone que ya habéis configurado el segundo miembro de conmutación por error y habéis confirmado un estado exitoso de dicho miembro en el monitor del mirror:

Paso 1: Activad el usuario HS_Services (en el servidor de respaldo y en el principal).

2
1 91
Artículo Luis Angel Pérez Ramos · abr 25, 2023 13m read

Una necesidad habitual en nuestros clientes es la configuración tanto de HealthShare HealthConnect como de IRIS en modo de alta disponibilidad.

Es común en otros motores de integración del mercado que se promocionen con configuraciones de "alta disponibilidad", pero realmente no suele ser del todo cierto. Por lo general dichas soluciones trabajan con bases de datos externas y por lo tanto, si estas no están a su vez configuradas en alta disponibilidad, al producirse una caída de la base de datos o la pérdida de conexión a la misma toda la herramienta de integración queda inutilizable.

En el caso de las soluciones de InterSystems este problema no existe, al ser la base de datos parte y nucleo de las propias herramientas. ¿Y cómo ha solucionado InterSystems el problema de la alta disponibilidad? ¿Con abstrusas configuraciones que podrían arrastrarnos a una espiral de enajenamiento y locura? ¡NO! Desde InterSystems hemos escuchado y atendido vuestras quejas (como siempre intentamos hacer ;) ) y hemos puesto a disposición de todos nuestros usuarios y desarrolladores la función de mirroring.

0
1 386
Artículo Joel Espinoza · nov 23, 2022 1m read

Hola!

Aquí les dejo un video que hice para mostrar cómo se configura la alta disponibilidad (mirroring) en IRIS en un ambiente docker, el video esta completamente en español y los archivos necesarios estarán en mi Github.

El video en YouTube en https://youtu.be/rBdiTxavWmU

https://github.com/I-am-seven/iris-mirroring-video

Espero les sea de Utilidad!

Joel

0
1 75
Artículo Luis Angel Pérez Ramos · nov 23, 2022 13m read

Antecedentes

VersiónFechaCambios
V108/02/2022Lanzamiento Inicial
V1.106/04/2022Generación de certificados con un archivo sh en vez de un pki-script
Uso de variables de entorno en los archivos de configuración

¡Hola Comunidad!

¿Ya habéis configurado un entorno en mirror? ¿Tenéis una red privada, una dirección IP virtual y una configuración SSL? Después de hacer esto un par de veces, me di cuenta de que es muy largo, y hay muchos pasos que hay que realizar manualmente para generar certificados y configurar cada instancia de IRIS. Es un dolor de cabeza para cualquiera que tenga que hacer esto a menudo.

Por ejemplo, un equipo de control de calidad podría necesitar un nuevo entorno por cada nueva versión de la aplicación que tenga que probar mientras que el equipo de soporte puede necesitar crear un entorno para reproducir un problema complejo.

Definitivamente, necesitamos herramientas para crearlos rápidamente.

En este artículo crearemos una muestra para configurar un mirror con:

  • Arbiter.
  • Primary.
  • Miembro failover del backup.
  • Miembro asíncrono de lectura-escritura de informes.
  • Configuración SSL para transferencias de journal entre nodos.
  • Red privada para el mirror.
  • Dirección IP virtual.
  • Una base de datos en mirror.

network-schema

A primera vista, parece un poco complejo y parece que hace falta una gran cantidad de código, pero no te preocupes. Hay librerías en OpenExchange para realizar fácilmente la mayoría de las operaciones.

El propósito de este artículo es ofrecer un ejemplo de cómo adaptar el proceso a vuestras necesidades, pero no es una guía de prácticas recomendadas en materia de seguridad.

Así que vamos a crear nuestra muestra.

Herramientas y librerías

  • config-api: Esta librería se utilizará para configurar IRIS. Es compatible con la configuración del mirroring desde la versión 1.1.0. No vamos a dar una descripción detallada de cómo utilizar esta librería. Ya hay varios artículos aquí. En resumen, config-api se utilizará para crear archivos de configuración de plantillas IRIS (formato JSON) y cargarlos fácilmente.

  • ZPM.

  • Docker.

  • OpenSSL.

Página de Github

Podéis encontrar todos los archivos de recursos necesarios en el repositorio iris-mirroring-samples.

Preparación del sistema

Clonad el repositorio existente:

git clone https://github.com/lscalese/iris-mirroring-samples
cd iris-mirroring-samples

Si preferís crear una muestra desde cero, en vez de clonar el repositorio, simplemente cread un nuevo directorio con subdirectorios: backup, y config-files. Descargad irissession.sh:

mkdir -p iris-mirroring-samples/backup iris-mirroring-samples/config-files
cd  iris-mirroring-samples
wget -O session.sh https://raw.githubusercontent.com/lscalese/iris-mirroring-samples/master/session.sh

Para evitar la incidencia "permiso rechazado" más tarde, tenemos que crear el grupo irisowner, el usuario irisowner, y cambiar el grupo del directorio del backup a irisowner

sudo useradd --uid 51773 --user-group irisowner
sudo groupmod --gid 51773 irisowner
sudo chgrp irisowner ./backup

Este directorio se utilizará como volumen para compartir una copia de seguridad de la base de datos después de que se configure el primer miembro mirror con los otros nodos.

Obtención de una licencia de IRIS

Mirroring no está disponible con la Edición Community de IRIS. Si aún no tenéis una licencia válida para el contenedor de IRIS, conectaos al Centro de Soporte Internacional (WRC) con vuestras credenciales. Haced clic en "Actions" --> "Online distribtion", después en el botón "Evaluations" y seleccionad "Evaluation License". Completad el formulario. Copiad vuestro archivo de licencia iris.key en este directorio.

Inicio de sesión en el Registro de Contenedores de Intersystems

Por comodidad, utilizamos Intersystems Containers Registry (ICR) para extraer imágenes de Docker. Si no sabéis vuestro nombre de usuario\contraseña de Docker, conectaos a SSO.UI.User.ApplicationTokens.cls con vuestras credenciales del Centro de Soporte Internacional (WRC), y podréis recuperar vuestro Token ICR.

docker login -u="YourWRCLogin" -p="YourICRToken" containers.intersystems.com

Creación de la base de datos myappdata y un mapeo de globales

De momento no vamos a crear la base de datos myappdata, únicamente estamos preparando la configuración para crearla al momento de crear el Docker. Para ello, simplemente creamos un archivo sencillo utilizando el formato JSON. La librería config-api se utilizará para cargarlo en las instancias de IRIS.

Cread el archivo config-files/simple-config.json

{
   "Defaults":{
       "DBDATADIR" : "${MGRDIR}myappdata/",
       "DBDATANAME" : "MYAPPDATA"

   },
   "SYS.Databases":{
       "${DBDATADIR}" : {}
   },
   "Databases":{
       "${DBDATANAME}" : {
           "Directory" : "${DBDATADIR}"
       }
   },
   "MapGlobals":{
       "USER": [{
           "Name" : "demo.*",
           "Database" : "${DBDATANAME}"
       }]
   },
   "Security.Services" : {
       "%Service_Mirror" : {                      /* Enable the mirror service on this instance */
           "Enabled" : true
       }
   }
}

Este archivo de configuración permite crear una nueva base de datos con la configuración predeterminada y hacer un mapeo del global demo.* en el namespace USER.

Para más información sobre las funciones del archivo de configuración config-api consulta el artículo, relacionado o la página de github.

El archivo Docker

El archivo Docker se basa en la plantilla existente de Docker, pero necesitamos hacer algunos cambios para crear un directorio de trabajo, instalar las herramientas para el uso de la IP virtual, instalar ZPM, etc…

Nuestra imagen IRIS es la misma para cada miembro mirror. El mirroring se establecerá en el contenedor empezando con la configuración correcta dependiendo de su función (primer miembro, backup de respaldo/failover o informe de lectura-escritura). Observa los comentarios en el Dockerfile:

ARG IMAGE=containers.intersystems.com/intersystems/iris:2021.1.0.215.0
# No es necesario descargar la imagen desde WRC, se hará automáticamente desde ICR cuando se despliegue el contenedor.

FROM $IMAGE

USER root

COPY session.sh /
COPY iris.key /usr/irissys/mgr/iris.key

# /opt/demo será nuestro directorio de trabajo y en el que almacenaremos nuestros archivos de configuración así como otros archivos de instalación.
# Instalamos iputils-arping para hacer uso del comando arping. Es necesario para configurar una IP Virtual.
# Descargamos la última versión de ZPM (o IPM, incluida en las versiones a partir de la 2023.1). 
RUN mkdir /opt/demo && \
    chown ${ISC_PACKAGE_MGRUSER}:${ISC_PACKAGE_IRISGROUP} /opt/demo && \
    chmod 666 /usr/irissys/mgr/iris.key && \
    apt-get update && apt-get install iputils-arping gettext-base && \
    wget -O /opt/demo/zpm.xml https://pm.community.intersystems.com/packages/zpm/latest/installer

USER ${ISC_PACKAGE_MGRUSER}

WORKDIR /opt/demo

# Configuramos el rol del mirror por defecto a master.
# Se sobreescribirá en el archivo docker-compose en el momento de la ejecución (master para la primera instancia, backup, y report)
ARG IRIS_MIRROR_ROLE=master

# Copiamos el contenido del directorio de archivos de configuración en /opt/demo.
# Únicamente hemos creado una configuración simple de nuestra base de datos y los mapeos de globales.
# Posteriormente en este mismo artículo incluiremos otros archivos de configuración para desplegar el mirror.
ADD config-files .

SHELL [ "/session.sh" ]

# Instalamos el ZPM (no será necesario para versiones a partir de 2023.1)
# Usamos ZPM para instalar config-api
# Cargamos el archivo de configuración simple-config.json con config-api para:
#  - crear la base de datos "myappdata",
#  - añadirmos un mapeo de globales en el namespace "USER" para los globales "demo.*" a la base de datos "myappdata".
# Basicamente, el punto de entrada para instalar tu aplicación de ObjectScript es este. 
# Para este ejemplo cargaremos simple-config.json para crear una base de datos simple y un mapeo de globals.
RUN \
Do $SYSTEM.OBJ.Load("/opt/demo/zpm.xml", "ck") \
zpm "install config-api" \
Set sc = ##class(Api.Config.Services.Loader).Load("/opt/demo/simple-config.json")

# Copiamos el script de arranque del mirror. 
COPY init_mirror.sh /

Creación de la imagen IRIS

El Dockerfile está listo, podemos crear la imagen:

docker build --no-cache --tag mirror-demo:latest .

Esta imagen se utilizará para ejecutar los nodos primarios, los de copias de seguridad y los de informes.

El archivo .env

Los archivos de configuración JSON y docker-compose utilizan variables de entorno. Sus valores se almacenan en un archivo llamado .env. Para este ejemplo, nuestro archivo env es:

APP_NET_SUBNET=172.16.238.0/24
MIRROR_NET_SUBNET=172.16.220.0/24

IRIS_HOST=172.16.238.100
IRIS_PORT=1972
IRIS_VIRTUAL_IP=172.16.238.100

ARBITER_IP=172.16.238.10

MASTER_APP_NET_IP=172.16.238.20
MASTER_MIRROR_NET_IP=172.16.220.20

BACKUP_APP_NET_IP=172.16.238.30
BACKUP_MIRROR_NET_IP=172.16.220.30

REPORT_APP_NET_IP=172.16.238.40
REPORT_MIRROR_NET_IP=172.16.220.40

Preparación del archivo de configuración del primer miembro del mirror

La librería config-api permite configurar un mirror, por lo que debemos crear un archivo de configuración específico para el primer miembro mirrorconfig-files/mirror-master.json

Para mayor comodidad, los comentarios se sitúan directamente en el JSON. Podéis descargar el mirror-master.json sin comentarios aquí.

{
    "Security.Services" : {
        "%Service_Mirror" : {
            "Enabled" : true
        }
    },
    "SYS.MirrorMaster" : {
        "Demo" : {
            "Config" : {
                "Name" : "Demo",                                /* El nombre de nuestro mirror */
                "SystemName" : "master",                        /* El nombre de esta instancia en el mirror */
                "UseSSL" : true,                
                "ArbiterNode" : "${ARBITER_IP}|2188",           /* Dirección IP y puerto para el nodo del arbiter */
                "VirtualAddress" : "${IRIS_VIRTUAL_IP}/24",     /* Dirección IP Virtual IP */
                "VirtualAddressInterface" : "eth0",             /* Interfaz de red usada para la dirección IP Virtual. */
                "MirrorAddress": "${MASTER_MIRROR_NET_IP}",     /* Dirección IP de este nodo en la red privada del mirror */
                "AgentAddress": "${MASTER_APP_NET_IP}"          /* Dirección IP de este nodo (Agent está instalado en la misma máquina) */
            },
            "Databases" : [{                                    /* Lista de bases de datos añadidas al mirror */
                "Directory" : "/usr/irissys/mgr/myappdata/",
                "MirrorDBName" : "MYAPPDATA"
            }],
            "SSLInfo" : {                                       /* Configuración SSL */
                "CAFile" : "/certificates/CA_Server.cer",
                "CertificateFile" : "/certificates/master_server.cer",
                "PrivateKeyFile" : "/certificates/master_server.key",
                "PrivateKeyPassword" : "",
                "PrivateKeyType" : "2"
            }
        }
    }
}

Preparación del archivo de configuración del miembro failover

Creamos un archivo de configuración para los miembros de backup de respaldo (failover) config-files/mirror-backup.json.

Se parece al primer miembro del mirror:

{
    "Security.Services" : {
        "%Service_Mirror" : {
            "Enabled" : true
        }
    },
    "SYS.MirrorFailOver" : {
        "Demo" : {                                          /* Datos del mirror al que se va a unir */
            "Config": {
                "Name" : "Demo",
                "SystemName" : "backup",                    /* Nombre de esta instancia en el mirror */
                "InstanceName" : "IRIS",                    /* Nombre de la instancia de IRIS del primer miembro del mirror */
                "AgentAddress" : "${MASTER_APP_NET_IP}",    /* Dirección IP del Agent del primer miembro del mirror */
                "AgentPort" : "2188",
                "AsyncMember" : false,
                "AsyncMemberType" : ""
            },  
            "Databases" : [{                                /* Base de datos en mirror */
                 "Directory" : "/usr/irissys/mgr/myappdata/"    
            }],
            "LocalInfo" : {
                "VirtualAddressInterface" : "eth0",         /* Interfaz de red usada por la dirección IP Virtual. */
                "MirrorAddress": "${BACKUP_MIRROR_NET_IP}"  /* Dirección IP de este nodo en la red privada del mirror */
            },
            "SSLInfo" : {
                "CAFile" : "/certificates/CA_Server.cer",
                "CertificateFile" : "/certificates/backup_server.cer",
                "PrivateKeyFile" : "/certificates/backup_server.key",
                "PrivateKeyPassword" : "",
                "PrivateKeyType" : "2"
            }
        }
    }
}

Preparación del archivo de configuración del miembro en modo lectura-escritura asíncrono

Es bastante similar al archivo de configuración de failover. Las diferencias son los valores de AsyncMember, AsyncMemberType, y MirrorAddress. Creamos el archivo ./config-files/mirror-report.json:

{
    "Security.Services" : {
        "%Service_Mirror" : {
            "Enabled" : true
        }
    },
    "SYS.MirrorFailOver" : {
        "Demo" : {
            "Config": {
                "Name" : "Demo",
                "SystemName" : "report",
                "InstanceName" : "IRIS",
                "AgentAddress" : "${MASTER_APP_NET_IP}",
                "AgentPort" : "2188",
                "AsyncMember" : true,
                "AsyncMemberType" : "rw"
            },
            "Databases" : [{
                 "Directory" : "/usr/irissys/mgr/myappdata/"
            }],
            "LocalInfo" : {
                "VirtualAddressInterface" : "eth0",
                "MirrorAddress": "${REPORT_MIRROR_NET_IP}"
            },
            "SSLInfo" : {
                "CAFile" : "/certificates/CA_Server.cer",
                "CertificateFile" : "/certificates/report_server.cer",
                "PrivateKeyFile" : "/certificates/report_server.key",
                "PrivateKeyPassword" : "",
                "PrivateKeyType" : "2"
            }
        }
    }
} 

Generación de certificados y configuración de los nodos IRIS y

¡Todos los archivos de configuración están listos!

Ahora tenemos que añadir un script para generar certificados para asegurar la comunicación entre cada uno de los nodos. En el repositorio gen-certificates.sh hay un script listo para ser usado

# sudo es obligatorio debido al uso de chown, chgrp chmod.
sudo ./gen-certificates.sh

Para configurar cada nodo init_mirror.sh se realizará al iniciar los contenedores. Se configurará posteriormente en docker-compose.yml en la sección de comandos command: ["-a", "/init_mirror.sh"] :

#!/bin/bash

# Base de datos usada para probar el mirror.
DATABASE=/usr/irissys/mgr/myappdata

# Directorio que contiene myappdata copiada por el master para restaurar en los otros nodos y hacer el mirror.
BACKUP_FOLDER=/opt/backup

# Archivo de configuración del mirror en json con formato de config-api para el nodo master.
MASTER_CONFIG=/opt/demo/mirror-master.json

# Archivo de configuración del mirror en json con formato de config-api para el nodo de backup.
BACKUP_CONFIG=/opt/demo/mirror-backup.json

# Archivo de configuración del mirror en json con formato de config-api para el nodo asíncrono.
REPORT_CONFIG=/opt/demo/mirror-report.json

# El nombre del mirror...
MIRROR_NAME=DEMO

# Lista de miembros del mirror.
MIRROR_MEMBERS=BACKUP,REPORT

# Ejecutado en el master.
# Carga de la configuración del mirror usando config-api con el archivo /opt/demo/simple-config.json.
# Iniciamos un Job para auto-aceptar otros miembros llamados "backup" y "report" se unan al mirror (evitando la validación manual desde el portal de gestión).
master() {
rm -rf $BACKUP_FOLDER/IRIS.DAT
envsubst < ${MASTER_CONFIG} > ${MASTER_CONFIG}.resolved
iris session $ISC_PACKAGE_INSTANCENAME -U %SYS <<- END
Set sc = ##class(Api.Config.Services.Loader).Load("${MASTER_CONFIG}.resolved")
Set ^log.mirrorconfig(\$i(^log.mirrorconfig)) = \$SYSTEM.Status.GetOneErrorText(sc)
Job ##class(Api.Config.Services.SYS.MirrorMaster).AuthorizeNewMembers("${MIRROR_MEMBERS}","${MIRROR_NAME}",600)
Hang 2
Halt
END
}

# Ejecutado por el master, hacemos un backup de /usr/irissy
make_backup() {
iris session $ISC_PACKAGE_INSTANCENAME -U %SYS "##class(SYS.Database).DismountDatabase(\"${DATABASE}\")"
md5sum ${DATABASE}/IRIS.DAT
cp ${DATABASE}/IRIS.DAT ${BACKUP_FOLDER}/IRIS.TMP
mv ${BACKUP_FOLDER}/IRIS.TMP ${BACKUP_FOLDER}/IRIS.DAT
chmod 777 ${BACKUP_FOLDER}/IRIS.DAT
iris session $ISC_PACKAGE_INSTANCENAME -U %SYS "##class(SYS.Database).MountDatabase(\"${DATABASE}\")"
}

# Restauramos la base datos en mirror "myappdata".  Esta restauración es ejecutada en los nodos "backup" y "report".
restore_backup() {
sleep 5
while [ ! -f $BACKUP_FOLDER/IRIS.DAT ]; do sleep 1; done
sleep 2
iris session $ISC_PACKAGE_INSTANCENAME -U %SYS "##class(SYS.Database).DismountDatabase(\"${DATABASE}\")"
cp $BACKUP_FOLDER/IRIS.DAT $DATABASE/IRIS.DAT
md5sum $DATABASE/IRIS.DAT
iris session $ISC_PACKAGE_INSTANCENAME -U %SYS "##class(SYS.Database).MountDatabase(\"${DATABASE}\")"
}

# Configuramos el miembro "backup"
#  - Cargamos el archivo de configuración /opt/demo/mirror-backup.json si esta instancia es la de backup o 
#    /opt/demo/mirror-report.json si esta instancia es la de report (nodo mirror con lecturas/escrituras asíncronas).
other_node() {
sleep 5
envsubst < $1 > $1.resolved
iris session $ISC_PACKAGE_INSTANCENAME -U %SYS <<- END
Set sc = ##class(Api.Config.Services.Loader).Load("$1.resolved")
Halt
END
}

if [ "$IRIS_MIRROR_ROLE" == "master" ]
then
  master
  make_backup
elif [ "$IRIS_MIRROR_ROLE" == "backup" ]
then
  restore_backup
  other_node $BACKUP_CONFIG
else
  restore_backup
  other_node $REPORT_CONFIG
fi

exit 0

Archivo Docker-compose

Tenemos cuatro contenedores para empezar. El archivo Docker-compose es perfecto para organizar nuestro ejemplo.

version: '3.7'

services:
  arbiter:
    image: containers.intersystems.com/intersystems/arbiter:2021.1.0.215.0
    init: true
    container_name: mirror-demo-arbiter
    command: 
      - /usr/local/etc/irissys/startISCAgent.sh 2188
    networks:
      app_net:
        ipv4_address: ${ARBITER_IP}
    extra_hosts:
      - "master:${MASTER_APP_NET_IP}"
      - "backup:${BACKUP_APP_NET_IP}"
      - "report:${REPORT_APP_NET_IP}"
    cap_add:
      - NET_ADMIN

  master:
    build: .
    image: mirror-demo
    container_name: mirror-demo-master
    networks:
      app_net:
        ipv4_address: ${MASTER_APP_NET_IP}
      mirror_net:
        ipv4_address: ${MASTER_MIRROR_NET_IP}
    environment: 
      - IRIS_MIRROR_ROLE=master
      - WEBGATEWAY_IP=${WEBGATEWAY_IP}
      - MASTER_APP_NET_IP=${MASTER_APP_NET_IP}
      - MASTER_MIRROR_NET_IP=${MASTER_MIRROR_NET_IP}
      - ARBITER_IP=${ARBITER_IP}
      - IRIS_VIRTUAL_IP=${IRIS_VIRTUAL_IP}
    ports:
      - 81:52773
    volumes: 
      - ./backup:/opt/backup
      - ./init_mirror.sh:/init_mirror.sh
      # Mount certificates
      - ./certificates/master_server.cer:/certificates/master_server.cer
      - ./certificates/master_server.key:/certificates/master_server.key
      - ./certificates/CA_Server.cer:/certificates/CA_Server.cer
      #- ~/iris.key:/usr/irissys/mgr/iris.key
    hostname: master
    extra_hosts:
      - "backup:${BACKUP_APP_NET_IP}"
      - "report:${REPORT_APP_NET_IP}"
    cap_add:
      - NET_ADMIN
    command: ["-a", "/init_mirror.sh"]

  backup:
    image: mirror-demo
    container_name: mirror-demo-backup
    networks:
      app_net:
        ipv4_address: ${BACKUP_APP_NET_IP}
      mirror_net:
        ipv4_address: ${BACKUP_MIRROR_NET_IP}
    ports:
      - 82:52773
    environment: 
      - IRIS_MIRROR_ROLE=backup
      - WEBGATEWAY_IP=${WEBGATEWAY_IP}
      - BACKUP_MIRROR_NET_IP=${BACKUP_MIRROR_NET_IP}
      - MASTER_APP_NET_IP=${MASTER_APP_NET_IP}
      - BACKUP_APP_NET_IP=${BACKUP_APP_NET_IP}
    volumes: 
      - ./backup:/opt/backup
      - ./init_mirror.sh:/init_mirror.sh
      # Mount certificates
      - ./certificates/backup_server.cer:/certificates/backup_server.cer
      - ./certificates/backup_server.key:/certificates/backup_server.key
      - ./certificates/CA_Server.cer:/certificates/CA_Server.cer
      #- ~/iris.key:/usr/irissys/mgr/iris.key
    hostname: backup
    extra_hosts:
      - "master:${MASTER_APP_NET_IP}"
      - "report:${REPORT_APP_NET_IP}"
    cap_add:
      - NET_ADMIN
    command: ["-a", "/init_mirror.sh"]

  report:
    image: mirror-demo
    container_name: mirror-demo-report
    networks:
      app_net:
        ipv4_address: ${REPORT_APP_NET_IP}
      mirror_net:
        ipv4_address: ${REPORT_MIRROR_NET_IP}
    ports:
      - 83:52773
    environment: 
      - IRIS_MIRROR_ROLE=report
      - WEBGATEWAY_IP=${WEBGATEWAY_IP}
      - MASTER_APP_NET_IP=${MASTER_APP_NET_IP}
      - REPORT_MIRROR_NET_IP=${REPORT_MIRROR_NET_IP}
      - REPORT_APP_NET_IP=${REPORT_APP_NET_IP}
    volumes: 
      - ./backup:/opt/backup
      - ./init_mirror.sh:/init_mirror.sh
      # Mount certificates
      - ./certificates/report_server.cer:/certificates/report_server.cer
      - ./certificates/report_server.key:/certificates/report_server.key
      - ./certificates/CA_Server.cer:/certificates/CA_Server.cer
      #- ~/iris.key:/usr/irissys/mgr/iris.key
    hostname: report
    extra_hosts:
      - "master:${MASTER_APP_NET_IP}"
      - "backup:${BACKUP_APP_NET_IP}"
    cap_add:
      - NET_ADMIN
    command: ["-a", "/init_mirror.sh"]

networks:
  app_net:
    ipam:
      driver: default
      config:
        - subnet: "${APP_NET_SUBNET}"
  mirror_net:
    ipam:
      driver: default
      config:
        - subnet: "${MIRROR_NET_SUBNET}" 

El archivo docker-compose.yml contiene una gran cantidad de variables de entorno. Observa el tipo de archivo que devuelve en el terminal:

docker-compose config

Despliegue de los contenedores

docker-compose up

Esperamos a que cada instancia tenga su estado correcto en el mirror:

  • nodo maestro (master) con estado Primary.
  • nodo de la copia de seguridad (backup) con estado Backup.
  • nodo de informes (report) con el estado Connected.

Finalmente, deberíais ver estos mensajes en los inicio de sesión de Docker:

mirror-demo-master | 01/09/22-11:02:08:227 (684) 1 [Utility.Event] Becoming primary mirror server
...
mirror-demo-backup | 01/09/22-11:03:06:398 (801) 0 [Utility.Event] Found MASTER as primary, becoming backup
...
mirror-demo-report | 01/09/22-11:03:10:745 (736) 0 [Generic.Event] MirrorClient: Connected to primary: MASTER (ver 4)

También se puede verificar el estado del mirror mediante el portal http://localhost:81/csp/sys/utilhome.csp

Mirror-Status

Acceso a los portales

En Docker-compose mapeamos los puertos 81, 82 y 83 para tener un acceso a cada portal de administración. Esta es la contraseña de acceso predeterminada para todas las instancias:

Prueba

Comprobad el monitor del mirror (portal de administración, este es el usuario y la contraseña predeterminada): http://localhost:81/csp/sys/op/%25CSP.UI.Portal.Mirror.Monitor.zenMirror-Monitor

Verifica la configuración del mirror: http://localhost:81/csp/sys/mgr/%25CSP.UI.Portal.Mirror.EditFailover.zen?$NAMESPACE=%25SYS

Mirror-Configuration

Podemos iniciar una prueba simplemente configurando un global que comience por demo. Recuerda que hemos configurado un mapeo del global demo.* en el namespace USER.

Abrid una sesión del terminal en el servidor primario:

docker exec -it mirror-demo-master irissession iris
Set ^demo.test = $zdt($h,3,1)

Comprobad si los datos están disponibles en el nodo de la copia de seguridad:

docker exec -it mirror-demo-backup irissession iris
Write ^demo.test

Comprobamos si los datos están disponibles en el nodo del informe:

docker exec -it mirror-demo-report irissession iris
Write ^demo.test

¡Bien! Tenemos un entorno de mirror listo, creado por completo programáticamente. Para rizar el rizo, deberíamos añadir un web gateway con https y encriptación entre el web gateway e IRIS, pero lo dejaremos para el próximo artículo.

Espero que este artículo os haya resultado útil si decidís crear vuestro propio script.

Fuentes

El contenido de este artículo está inspirado en:

0
1 246
Artículo Ricardo Paiva · ene 28, 2022 28m read

En este artículo, crearemos una configuración de IRIS con alta disponibilidad utilizando implementaciones en Kubernetes con almacenamiento persistente distribuido en vez del "tradicional" par de mirror de IRIS. Esta implementación sería capaz de tolerar fallos relacionados con la infraestructura, por ejemplo, fallos en los nodos, en el almacenamiento y en la Zona de Disponibilidad. El enfoque descrito reduce en gran medida la complejidad de la implementación, a costa de un Tiempo Objetivo de Recuperación (RTO, Recovery Time Objective) ligeramente mayor.

1
0 477
Artículo Laura Blázquez García · feb 11, 2022 4m read

Hasta hace no mucho, todos los entornos con los que trabajábamos eran Ensemble 2017.2. Pero recientemente hemos migrado todos los entornos a la versión 2021.1 de IRIS for Health. Ha sido un camino complicado, pero tras analizarlo detenidamente, encontramos la forma de conseguirlo.

Contamos con un servidor de desarrollo y dos servidores en producción en mirroring, en modo Failover. Tenemos más de 40 Namespaces dando servicio, unos con integraciones HL7, otros con servicios Soap, servicios Rest, procesado de archivos... un poco de todo. Necesitábamos estar seguros de que la migración a IRIS no iba a suponer un problema y sobre todo, evitar a toda costa un corte de servicio. Así que lo primero que teníamos que hacer era establecer un plan.

0
0 225
Artículo Mario Sanchez Macias · abr 27, 2021 21m read

Esta publicación es la traducción de un artículo que publicó mi compañero Murray hace un tiempo. Durante mi trabajo en soporte la he recomendado muchas veces, pues lo que aquí se explica es bastante común y los ejemplos que se dan pueden ayudar a muchos de vosotros.

0
0 375
Anuncio Esther Sanchez · jul 2, 2020

¡Hola desarrolladores!

Os traemos el quinto episodio de Data Points, el podcast de InterSystems en inglés. En esta ocasión, charlamos con Bob Binstock sobre bases de datos en mirroring para alta disponibilidad en productos InterSystems. La mayor parte de la conversación comenta este proceso en InterSystems IRIS, con alguna mención sobre las diferencias con HealthShare. ¡Dadle al play!

0
0 112
Artículo Estevan Martinez · nov 27, 2019 10m read

++ Update: August 1, 2018

El uso de la dirección IP virtual (VIP) de InterSystems incorporada en Mirroring de la base de datos de Caché tiene ciertas limitaciones. En particular, solo puede utilizarse cuando los miembros Mirror se encuentran en la misma subred. Cuando se utilizan varios centros de datos, las subredes normalmente no se “extienden” más allá del centro de datos físico debido a la complejidad añadida de la red (puede obtener más información aquí). Por las mismas razones, la IP virtual con frecuencia no puede utilizarse cuando la base de datos se aloja en la nube.

0
0 531
Anuncio Mario Sanchez Macias · oct 9, 2019

Si quieres probar mirroring de una manera simple y sencilla puedes hacerlo con estos simples scripts (ver link)

  • El fichero docker-compose.yml crea 2 contenedores con la versión que necesites
  • El script installer.sh arranca el  ISCAgent, carga la clase Installer.cls y la llama
  • Lo más interesante está en la clase Installer.cls. Esta clase contiene unos métodos muy sencillos de seguir para montar un mirror, unirse  y crear un namespace y base de datos en mirror.  Son scripts sencillos que puedes reutilizar para crear mirrors en tus propios scripts
0
0 167