Руководство прикладного разработчика#

Шлюз ActiveMQ Artemis, ASGT далее (Шлюз) продукта Platform V Synapse Enterprise Integration (SEI) поставляется в виде собранного Docker-образа, размещаемого в целевом Docker-репозитории, и предназначается для использования в составе прикладных интеграционных решений, разрабатываемых продуктовыми командами.

Термины и определения#

Термин/Аббревиатура

Определение

XML

eXtensible Markup Language

JSON

JavaScript Object Notation, текстовый формат обмена данными, основанный на JavaScript

API

Application Programming Interface

HTTP

HyperText Transfer Protocol, протокол передачи гипертекста

HTTP/2

Вторая версия протокола Hypertext Transfer Protocol

SSL

Security Socket Layer

JMS

Java Message System

MQ

Message Queue

gRPC

Google Remote Procedure Call

REST

Representational State Transfer, архитектурный стиль взаимодействия компонентов распределенного приложения в сети

URI

Uniform Resource Identifier, унифицированный идентификатор ресурса

URL

Система унифицированных адресов электронных ресурсов

RPC

Remote Procedure Call, система удаленного вызова процедур

Service Mesh

Конфигурируемый инфраструктурный уровень с низкой задержкой. Используется для обработки большого объема сетевых межпроцессных коммуникаций между API

Spring

Сокращение от Spring Framework, универсальный фреймворк с открытым исходным кодом для Java-платформы

Spring Boot

Проект, который позволяет упростить создание приложений на основе Spring

Artemis

Программный продукт Apache ActiveMQ Artemis

ВХС

Внешнее хранилище секретов на основе hashicorp vault

Системные требования#

Требования к системному программному обеспечению приведены в разделе Системные требования документа «Руководство по установке»

Подключение и конфигурирование#

Перечень артефактов Kubernetes, требующихся для запуска тестового экземпляра Шлюза.

Артефакт

Содержание

Описание

Deployment

Параметры запуска контейнера приложения в Kubernetes

Наименование экземпляра приложения, ссылка на образ контейнера приложения, запрашиваемые ресурсы, публикуемые порты, параметры liveness и readiness проб, необходимость и параметры подключения sidecar-контейнеров, точки монтирования конфигурационных артефактов в файловую систему контейнера

Config Map

application.yml

Файл, содержащий параметры конфигурации приложения

Secret

Ключи и сертификаты

Файлы, содержащие ключи и сертификаты для подключения к брокерам Artemis по SSL. Содержит конфиденциальные данные, поэтому загружается в виде секрета

Service

Артефакт для регистрации приложения в service discovery Kubernetes

Селекторы и порты для подключения приложения к механизмам распределения трафика Kubernetes

Virtual Service

Артефакт для настройки политик Istio

Параметры маршрутизации трафика между сервисами в Kubernetes

Destination Rule

Артефакт для настройки политик Istio

Параметры балансировки трафика между pods приложения

Service Entry

Артефакт для регистрации внешнего сервиса в Kubernetes

Содержит адреса хостов и номера портов для подключения к брокерам Artemis. Если для нужных брокеров Service Entry уже установлен в проекте, загружать его повторно не требуется

Service

Артефакт регистрирующий фиктивный сервис (empty-service)

empty-service — фиктивный сервис Kubernetes, требуется в каждом проекте для правильной работы механизмов маршрутизации Istio. В отличие от реального сервиса, в empty-service НЕ должно быть задано значение параметра selector

Порядок подключения#

  1. На брокерах Artemis Dev-стенда создать 2 тестовые очереди для входящих и исходящих сообщений (например, TEST.GW.IN и TEST.GW.OUT);

  2. Проверить и при необходимости загрузить артефакт ServiceEntry, задающий точку подключения;

    В артефакте должны быть указаны параметры:

    • spec.hosts[].<hostname>

    • spec.ports[].protocol: tcp

    • spec.ports[].name: tcp

    • spec.ports[].number:<port>

    нужного брокера Artemis

    ServiceEntry

    apiVersion: networking.istio.io/v1alpha3
    kind: ServiceEntry
    metadata:
      name: amq-brocker-se
    spec:
      exportTo:
        - .
      hosts:
        - <hostname брокера MQ>
      location: MESH_EXTERNAL
      ports:
        - name: tcp
          number: <port брокера MQ>
          protocol: tcp
      resolution: DNS
    
  3. Подготовить и загрузить артефакт Config Map c файлом application.yml, задающий настройки Шлюза.

    В артефакте должны быть указаны параметры:

    • режима работы Шлюза:

      • mq.typeMQ: ARTEMIS_MQ (значение по умолчанию - ARTEMIS_MQ может быть опущено)

      • mq.workMode: all

      • mq.systemType: sp

    • очередей MQ:

      • mq.connection.receiveQueue[]: [TEST.GW.IN]

      • mq.connection.sendQueue: TEST.GW.OUT

    • подключения к MQ:

      • mq.connection.connections[].url: <протокол>://<имя хоста>:<номер порта>

      • mq.connection.connections[].username: <логин для подключения к брокеру>

      • mq.connection.connections[].password: <пароль для подключения к брокеру>

    • порта Healthcheck:

      • server.port: 8787

    • сервера и клиента gRPC:

      • grpc.server.serverPort: 5454

      • grpc.client.settings.default.port: 5454

    • трейсинга

      • tracing.tracingHeaders[].x-synapse-rquid:<заполнить из примера ниже>

    • и маршрутизации:

      • routing.routeList[].destinationExpression: ServiceName

      • routing.routeList[].variables[]:<заполнить из примера ниже>

    ConfigMap

    kind: ConfigMap
    apiVersion: v1
    metadata:
      name: test-gw-config
    data:
      application.yml: |-
        mq:
          typeMQ:ARTEMIS_MQ
          workMode: async
          systemName: test
          systemType: sp
          connection:
            receiveQueue: [TEST.GW.IN]
            sendQueue: TEST.GW.OUT
            connections:
              - url: <протокол>://<имя хоста>:<номер порта> # <протокол>='amqp' для подключения без ssl
                username: <логин к брокеру MQ>   
                password: <пароль к брокеру MQ>
        server:
          port: 8787
        grpc:
          server:
            serverPort: 5454
          client:
            settings:
              default:
                hostname: empty-service
                port: 5454
        tracing:
          generateXB3Headers: 'true'
          generate128bitTraceId: 'true'
          tracingHeaders:
            x-synapse-rquid:
              - type: fromBody
                value: //RqUID
        routing:
          routeList:
            - routeName: default
              destinationExpression: ServiceName
              variables:
                - name: ServiceName
                  valueFrom:
                    - type: fromConst
                      value: <имя клиентского приложения>
    
  4. Подготовить и загрузить артефакт Deployment, задающий параметры запуска контейнера Шлюза;

    В артефакте должны быть заданы параметры:

    • spec.template.metadata.labels[].app: <имя сервиса Шлюза> #в приведенном здесь примере test-gw

    • spec.template.spec.volumes[0].configMap.name: <Имя артефакта Config Name>

    • spec.template.spec.containers[].ports[].containerPort: 5454

    • spec.template.spec.containers[].ports[].containerPort: 8787

    • spec.template.spec.containers[].image: <ссылка на Docker-образ Шлюза в целевом репозитории>

    В подсекции resources задаются limits и requests ЦПУ и памяти, необходимые для нормальной работы приложения. Эти параметры зависят от нагрузки на экземпляр Шлюза и должны быть определены при выполнении нагрузочного тестирования конкретной интеграционной цепочки.

    Выделение ресурсов для приложения должно удовлетворять следующим ограничениям:

    • memory - не более 8 Гб на Pod;

    • CPU не более 4 ядер;

    • размер контейнера не более 1024 Мб;

    • размер временное хранилища (ephemeral volume) для Pod не должен превышать 2.5 ГБ.

    Deployment

    kind: Deployment
    apiVersion: apps/v1
    metadata:
      name: test-gw
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: test-gw
      template:
        metadata:
          labels:
            app: test-gw
          annotations:
            sidecar.istio.io/inject: 'true'
        spec:
          volumes:
            - name: application-config
              configMap:
                name: test-gw-config
                items:
                  - key: application.yml
                    path: application.yml
                defaultMode: 256
            - name: synapselogs
              emptyDir: {}
          containers:
            - resources:
                limits:
                  cpu: 200m
                  memory: 400Mi
                requests:
                  cpu: 100m
                  memory: 330Mi
              readinessProbe:
                httpGet:
                  path: /actuator/health/readiness
                  port: 8787
                  scheme: HTTP
                initialDelaySeconds: 30
                timeoutSeconds: 5
                periodSeconds: 2
                successThreshold: 1
                failureThreshold: 2
              terminationMessagePath: /dev/termination-log
              name: test-gw
              livenessProbe:
                httpGet:
                  path: /actuator/health/liveness
                  port: 8787
                  scheme: HTTP
                initialDelaySeconds: 180
                timeoutSeconds: 5
                periodSeconds: 60
                successThreshold: 1
                failureThreshold: 10
              env:
                - name: PROJECT_NAME
                  valueFrom:
                    fieldRef:
                      apiVersion: v1
                      fieldPath: metadata.namespace
                - name: NODE_NAME
                  valueFrom:
                    fieldRef:
                      apiVersion: v1
                      fieldPath: spec.nodeName
                - name: NODE_IP
                  valueFrom:
                    fieldRef:
                      apiVersion: v1
                      fieldPath: status.hostIP
              ports:
                - containerPort: 5454
                  protocol: TCP
                - containerPort: 8787
                  protocol: TCP
              imagePullPolicy: Always
              securityContext:
                privileged: false
                runAsNonRoot: true
                readOnlyRootFilesystem: true
                capabilities:
                  drop: ["ALL"]
                allowPrivilegeEscalation: false
                runAsUser: 1001  # DropApp/Kubernetes
                runAsGroup: 1001  # DropApp/Kubernetes
                seccompProfile:   # DropApp/Kubernetes
                  type: RuntimeDefault
              volumeMounts:
                - name: application-config
                  readOnly: true
                  mountPath: /deployments/config
                - name: synapselogs
                  mountPath: /opt/synapse/logs
              terminationMessagePolicy: File
              image: >-
                <ссылка на докер-образ в целевом репозитории>
          terminationGracePeriodSeconds: 60
          securityContext:
            runAsUser: 1002 # DropApp/Kubernetes
            runAsGroup: 1002 # DropApp/Kubernetes
            runAsNonRoot: true
            fsGroup: 1001 # DropApp/Kubernetes
            seccompProfile: # DropApp/Kubernetes
              type: RuntimeDefault
      strategy:
        type: RollingUpdate
        rollingUpdate:
          maxUnavailable: 25%
          maxSurge: 25%
    
  5. Подготовить и загрузить артефакт Service, регистрирующий сервис в Kubernetes.

    В артефакте должны быть заданы параметры:

    spec.ports[].name: grpc spec.ports[].protocol: TCP spec.ports[].port: 5454 spec.ports[].targetPort: 5454

    Service

    kind: Service
    apiVersion: v1
    metadata:
      name: test-gw
    spec:
      ports:
        - name: grpc
          protocol: TCP
          port: 5454
          targetPort: 5454
      selector:
        app: test-gw
    
  6. Проверить, что Шлюз запущен и готов к работе.

    В консоли Kubernetes войти в меню Workloads/pods, найти pod Шлюза и, перейдя по ссылке в наименовании pod, проверить, что он имеет статус Running.

    Зайти в терминал pod и выполнить команду:

    sh-4.2$ curl localhost:8799/actuator/health/ping
    {"status":"UP"}
    

    Отклик {"status":"UP"} показывает, что Шлюз запущен и готов к работе.

Миграция на текущую версию#

Для миграции на текущую версию требуется:

  1. Уточнить в разделе Примечания к релизу необходимость внесения изменений в конфигурацию Шлюза при переходе на текущую версию;

  2. При необходимости подготовить Config map с новой конфигурацией;

  3. Подготовить артефакт Deployment, в котором заменить ссылку на docker-образ Шлюза в репозитории ссылкой на Docker-образ с текущей версией;

  4. Если это указано в разделе «Примечания к релизу», изменить значения выделяемых ресурсов;

  5. Остановить Шлюз;

  6. Загрузить новую конфигурацию Шлюза;

  7. Загрузить новый deployment;

  8. Запустить Шлюз (если в deployment указано количество реплик >0, Шлюз запустится автоматически).

Дополнительно:

Порядок действий при обновлении описан в разделе Обновление документа Руководство по установке.

Порядок действий для остановки и запуска Шлюза описано в разделе Сценарии администрирования документа Руководство по системному администрированию.

Быстрый старт#

Разработка первого приложения с использованием программного компонента#

  1. Подготовить proto-файлы с описанием универсального API Шлюза:

    Message.proto

    syntax = "proto3";
    
    import "google/protobuf/any.proto";
    
    package com.sbt.synapse.gateway;
    
    message ProtoMessage {
        string messageId = 1;
        string correlationId = 2;
        string body = 14;
        map<string, string> systemHeaders = 3;
        map<string, string> userHeaders = 4;
        google.protobuf.Any extension = 15;
    }
    

    Heartbeat.proto

    syntax = "proto3";
    
    package com.sbt.synapse.gateway;
    
    message Heartbeat {
        int64 timestamp = 1;
        string messageId = 2;
    }
    

    MessageService.proto

    syntax = "proto3";
    
    import "Message.proto";
    import "Heartbeat.proto";
    
    package com.sbt.synapse.gateway;
    
    option java_multiple_files = true;
    option java_package = "com.sbt.synapse.gateway.protobuf";
    option java_outer_classname = "MessageService";
    option objc_class_prefix = "HLW";
    
    service MessageAsyncChannel {
        rpc processMessage (ProtoMessage) returns (Heartbeat);
    }
    
    service MessageSyncChannel {
        rpc processMessage (ProtoMessage) returns (ProtoMessage);
    }
    

    MqMessageInformation.proto

    syntax = "proto3";
    
    package com.sbt.synapse.gateway.mq;
    
    message MqMessageInformation {
        enum DeliveryMode {
            UNKNOWN_MODE = 0;
            NON_PERSISTENT = 1;
            PERSISTENT = 2;
        }
        enum MessageType {
            UNKNOWN_TYPE = 0;
            REQUEST = 1;
            REPLY = 2;
            REPORT = 4;
            DATAGRAM = 8;
        }
        MessageType messageType = 1;
        int32 priority = 2;
        DeliveryMode deliveryMode = 3;
        int64 expiry = 4;
        string destinationQueue = 5;
        string destinationManager = 6;
        string sourceQueue = 7;
        string sourceManager = 8;
        string jmsType = 9;
    }
    
  2. Создать проект простого Springboot приложения;

  3. По proto-описанию сгенерировать Java-классы, используя proto-компилятор (protoc) или плагин для используемой системы сборки (gradle, maven);

  4. Добавить полученные файлы к проекту.

    Package

    Classes

    com.sbt.synapse.gateway

    Message
    HeartbeatOuterClass

    com.sbt.synapse.gateway.protobuf

    MessageAsyncChannelGrpc MessageSyncChannelGrpc

    com.sbt.synapse.gateway.mq

    MqMessageInformationOuterClass

  5. Дополнительно прописать зависимости:

    Зависимости

    <dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-protobuf</artifactId>
    <version>1.20.0</version>
    </dependency>
    <dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-stub</artifactId>
    <version>1.20.0</version>
    </dependency>
    <dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-core</artifactId>
    <version>1.20.0</version>
    </dependency>
    <dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-netty</artifactId>
    <version>1.20.0</version>
    </dependency>
    <dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-services</artifactId>
    <version>1.20.0</version>
    </dependency>
    
  6. Добавить импорт полученных классов, а также классов поддержки protobuf и grpc в свое приложение

    Импорт классов

    import com.google.protobuf.Any;
    import com.sbt.synapse.gateway.HeartbeatOuterClass.Heartbeat;
    import com.sbt.synapse.gateway.protobuf.MessageAsyncChannelGrpc;
    import com.sbt.synapse.gateway.Message.ProtoMessage;
    import com.sbt.synapse.gateway.mq.MqMessageInformationOuterClass.MqMessageInformation;
    import io.grpc.ManagedChannel;
    import io.grpc.ManagedChannelBuilder;
    import io.grpc.stub.StreamObserver;
    
  7. Добавить в приложение сервис для приема и асинхронных входящих вызовов и отправки подтверждений

    Пример сервиса

    @GRpcService
    public class GrpcService extends MessageAsyncChannelGrpc.MessageAsyncChannelImplBase {
    
    @Override
    public void processMessage(ProtoMessage message, StreamObserver<Heartbeat> responseObserver) {
    Logger logger = LoggerFactory.getLogger(GrpcService.class);
    logger.info("Request: " + message.getBody());
    
    responseObserver.onNext(Heartbeat.newBuilder().setMessageId(message.getMessageId()).setTimestamp(System.currentTimeMillis()).build());
    
    responseObserver.onCompleted();
    }
    }
    
  8. Добавить в приложение клиента, формирующего простой запрос в XML-формате с установкой messageId и Expiry

    Пример клиента

    @Component
    public class GrpcClientSender {
    
        @Value("${service.host}")
        private String serviceHost;
    
        @Value("${service.port}")
        private int servicePort;
    
        public void makeRequest() {
            Logger log = LoggerFactory.getLogger(GrpcClientSender.class);
    
            ManagedChannel channel = ManagedChannelBuilder.forAddress(serviceHost, servicePort).usePlaintext().build();
            MqMessageInformation mqMessageInformation = MqMessageInformation.newBuilder().setExpiry(30000).build();
            ProtoMessage message = ProtoMessage.newBuilder()
                    .setBody("<Rq><RqUID>12345678901234567890123456789012</RqUID></Rq>").setExtension(Any.pack(mqMessageInformation)).setMessageId("123456789012345678901234567890").build();
            MessageAsyncChannelGrpc.MessageAsyncChannelBlockingStub messageAsyncChannelBlockingStub = MessageAsyncChannelGrpc.newBlockingStub(channel);
    
            try {
                Heartbeat pongMessage = messageAsyncChannelBlockingStub.processMessage(message);
                log.info("Response: " + pongMessage.getMessageId());
            } catch (Exception e) {
                System.out.println("catch error " + e.getMessage());
            } finally {
                channel.shutdown();
            }
        }
    }
    
  9. В application.properties задать параметры:

    фрагмент application.properties

    service.host=localhost
    service.port=5454
    server.port=8787
    grpc.port=5454
    
  10. Для публикации образа приложения в docker-registry создать Dockerfile:

    В нем указать, на основе какого базового образа собирать контейнер с приложением, имя JAR-файла приложения для установки в контейнер и команду для его запуска.

    Dockerfile

    #Ссылка на базовый Docker-образ, нужно указать свой
    FROM <базовый образ для сборки>
    
    ADD <jarName>.jar /app/<jarName>.jar
    CMD touch /app/<jarName>.jar
    ENTRYPOINT ["java","-Dfile.encoding=UTF-8","-Dspring.config.location=file:/deployments/config/application.properties","-Djava.security.egd=file:/dev/./urandom","-jar","/app/<jarName>.jar"]
    
  11. Собрать Docker-образ и опубликовать его в Dev-репозиторий

  12. Настроить артефакты для приложения:

    Config Map

    kind: ConfigMap
    apiVersion: v1
    metadata:
      name: test-app-config
    data:
      application.properties: |-
        server.port=8787
        grpc.port=5454
        service.host=<имя сервиса Шлюза>
        service.port=5454
    

    Deployment

    kind: Deployment
    apiVersion: apps/v1
    metadata:
      name: test-app
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: test-app
      template:
        metadata:
          labels:
            app: test-app
          annotations:
            sidecar.istio.io/inject: 'true'
        spec:
          volumes:
            - name: application-config
              configMap:
                name: test-app-config
                items:
                  - key: application.properties
                    path: application.properties
                defaultMode: 400
          containers:
            - resources:
                limits:
                  cpu: 200m
                  memory: 400Mi
                requests:
                  cpu: 100m
                  memory: 330Mi
              name: test-app
              env:
                - name: PROJECT_NAME
                  valueFrom:
                    fieldRef:
                      apiVersion: v1
                      fieldPath: metadata.namespace
              ports:
                - containerPort: 5454
                  protocol: TCP
                - containerPort: 8787
                  protocol: TCP
              imagePullPolicy: Always
              volumeMounts:
                - name: application-config
                  readOnly: true
                  mountPath: /deployments/config
              terminationMessagePolicy: File
              image: >-
                <ссылка на Docker-образ приложения в dev-репозитории>
          terminationGracePeriodSeconds: 80
    

    Service

    apiVersion: v1
    kind: Service
    metadata:
      name: test-app
    spec:
      selector:
        app: test-app
      ports:
        - name: grpc
          port: 5454
          targetPort: 5454
      type: LoadBalancer
    
  13. Загрузить артефакты в Kubernetes.

  14. Зайти в терминал pod приложения и проверить, что в логах отражаются записи об успешной отправке сообщений.

    Пример лога клиента

    2021-02-07 10:54:27.740  INFO 14592 --- [           main] c.s.s.workshop.grpc.GrpcClientSender     : Response: 123456789012345678901234567890
    2021-02-07 10:54:27.743  INFO 14592 --- [           main] c.s.s.workshop.grpc.GrpcClientSender     : Response: 123456789012345678901234567890
    2021-02-07 10:54:27.746  INFO 14592 --- [           main] c.s.s.workshop.grpc.GrpcClientSender     : Response: 123456789012345678901234567890
    
  15. Чтобы проверить прием входящих сообщений в асинхронном режиме, нужно разместить сообщение в тестовой очереди входящих сообщений.

  16. В логе приложения должна появиться запись о приеме сообщения.

    Пример лога сервера

    2021-02-07 10:54:27.743  INFO 3876 --- [ault-executor-0] c.sbt.synapse.workshop.grpc.GrpcService  : Request: <Rq><RqUID>12345678901234567890123456789012</RqUID></Rq>
    2021-02-07 10:54:27.746  INFO 3876 --- [ault-executor-0] c.sbt.synapse.workshop.grpc.GrpcService  : Request: <Rq><RqUID>12345678901234567890123456789012</RqUID></Rq>
    2021-02-07 10:54:27.748  INFO 3876 --- [ault-executor-0] c.sbt.synapse.workshop.grpc.GrpcService  : Request: <Rq><RqUID>12345678901234567890123456789012</RqUID></Rq>
    

Использование программного компонента#

Асинхронный режим работы#

В этом режиме Шлюз может принимать асинхронные запросы по gRPC и передавать их в очередь Artemis, считывать сообщения из очереди Artemis и асинхронно отправлять их по gRPC.

Конфигурация Шлюза#

Для запуска Шлюза в этом режиме необходимо в конфигурационном файле application.yml установить параметры:

mq:
  workMode: all                 # Шлюз работает только в совмещенном (синхронно/асинхронном режиме)
  systemName: <имя системы>       # аббревиатура внешней системы
  systemType: <sc/sp>             # sc - если инициатор взаимодействия - внешняя система, sp - если микросервис
  connection:
    receiveQueue: [<имя входящей очереди>] # Список очередей, из которых Шлюз читает сообщения, которые будут обработаны асинхронно
    sendQueue: <имя исходящей очереди>   # очередь, в которую Шлюз кладет сообщения
    connections:
      - url: <hostname брокера Artemis>           # при подключении без SSL
        username: <логин к брокеру Artemis>
        password: <пароль к брокеру Artemis>
      - url: <hostname брокера Artemis>           # при подключении по SSL
        sslConfigName: <имя профиля SSL>               # имя профиля SSL из секции sslConfigs 
sslConfigs:
  - sslConfigName: <имя профиля SSL> 
    verifyHost: false # принудительно отключает проверку CN сертификата брокера на соответствие имени хоста
    allowedDNs: # список DN брокеров к которым разрешено подключение
      - <DN брокера>           
    sslCipherSuite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
    sslSocketFactory:
      protocol: TLSv1.2
      keyPem: <путь к файлу с личным ключом Шлюза>
      certPem: <путь к файлу с сертификатом Шлюза>
      rootPem: <путь к файлу с сертификатами УЦ>            
server:
  port: <порт HTTP>     # порт HTTP, на котором выставляется эндпойнт actuator/health для liveness и readiness проб
grpc:
  server:
    serverPort: <порт gRPC>    # порт, на котором поднимается gRPC-сервер для приема входящих запросов
  client:
    settings:
      default:
        hostname: empty-service
        port: <порт>          # порт по которому Шлюз будет выполнять исходящие gRPC-вызовы
tracing:                       # задает заголовки для исходящего gRPC вызова и правила их заполнения
  generateXB3Headers: 'true'
  generate128bitTraceId: 'true'
  tracingHeaders:
    x-synapse-rquid:         # правило определения заголовка x-synapse-rquid по входящему сообщению
      - type: fromBody
        value: //RqUID
    x-synapse-operationname:   # правило определения заголовка x-synapse-operationname по входящему сообщению
      - type: fromBody
        value: local-name(/*)
routing:                         # задает правила маршрутизации исходящего gRPC вызова (определение имени сервиса назначения)
  routeName:                     # определение имени маршрута
    valueFrom:
      - type: fromBody
        value: local-name(/*)
    expr:
  routeList:
    - routeName: default         # имя маршрута. Правила описанные в default применяются по-умолчанию
      destinationExpression: toLower(ServiceName)
      variables:
        - name: ServiceName
          valueFrom:
            - type: fromBody,
              value: '//ServiceName'
            exp: coalesce(value?"<имя вызываемого сервиса по-умолчанию>":value)

Отправка сообщения в MQ#

Для отправки сообщения в очередь Artemis нужно сделать вызов асинхронного API Шлюза:

Heartbeat MessageAsyncChannel.ProcessMessages(ProtoMessage)

Обязательные поля ProtoMessage:

Поле

Тип

Описание

body

string

информационное сообщение в формате XML для отправки в MQ

Дополнительные поля ProtoMessage

Поле

Тип

Описание

messageId

string

Задать при необходимости установить определенное значение при отправке. Если отсутствует – будет сгенерировано в момент отправки в MQ

correlationId

string

Задать при необходимости установить определенное значение при отправке. Если отсутствует – не будет установлено

extension.expiry

int64

Задать при необходимости установить время жизни сообщения в очереди

Обязательные заголовки gRPC

Заголовок

Описание

x-synapse-rquid

Уникальный идентификатор сообщения

x-synapse-operationname

Имя операции

x-synapse-from-pod-name

Имя pod сервиса — инициатора вызова

Поля возвращаемого Heartbeat

Поле

Тип

Описание

timestamp

int64

время получения сообщения

messageId

string

messageId отправленного в MQ сообщения

Чтение сообщений из MQ#

Шлюз постоянно опрашивает очередь входящих сообщений.

При появлении сообщения в очереди Шлюз считывает сообщение и выполняет вызов асинхронного API:

Heartbeat MessageAsyncChannel.ProcessMessages(ProtoMessage)

Имя сервиса назначения определяется по правилам, прописанным в секции routing конфигурации Шлюза.

Обязательные поля ProtoMessage:

Поле

Тип

Описание

messageId

string

MessageId входящего сообщения

correlationId

string

CorrelationId входящего сообщения

body

string

Информационное сообщение в формате XML

extension.sourceQueue

string

Очередь, из которой было считано входящее сообщение

Дополнительные поля ProtoMessage

Поле

Тип

Описание

systemHeaders

map<string, string>

Заполняется при наличии во входящем сообщении свойств с ключами, имеющими префикс JMS

userHeaders

map<string, string>

Заполняется при наличии во входящем сообщении свойств с ключами, не имеющими префикс JMS

Обязательные заголовки gRPC

Заголовок

Описание

x-synapse-rquid

Уникальный идентификатор сообщения

x-synapse-operationname

Имя операции

x-synapse-from

Имя внешней системы из конфигурации Шлюза

x-synapse-from-pod-name

Имя pod Шлюза, принявшего сообщение

Поля возвращаемого Heartbeat

Поле

Тип

Описание

timestamp

int64

время получения сообщения

messageId

string

messageId из ProtoMessage (не меняется)

Синхронный режим, отправка сообщений в MQ#

В этом режиме Шлюз может принимать синхронные запросы по gRPC и передавать их в очередь Artemis, возвращая в ответе считанное из MQ ответное сообщение. Режим неблокирующий, во время ожидания прихода ответных сообщений Шлюз продолжает принимать новые вызовы по gRPC.

Конфигурация Шлюза#

Для запуска Шлюза в этом режиме необходимо в конфигурационном файле application.yml установить параметры:

mq:
  systemName: <имя системы>       # аббревиатура внешней системы
  systemType: sp                  # sp - инициатор взаимодействия микросервис
  workMode: sync                  # режим работы - синхронный
  connection:
    sendQueue: <имя исходящей очереди>   # очередь, в которую Шлюз кладет сообщения
    connections:
      - url: <hostname брокера Artemis>           # при подключении без SSL
        username: <логин к брокеру Artemis>
        password: <пароль к брокеру Artemis>
      - url: <hostname брокера Artemis>           # при подключении по SSL
        sslConfigName: <имя профиля SSL>               # имя профиля SSL из секции sslConfigs 
sslConfigs:
  - sslConfigName: <имя профиля SSL> 
    verifyHost: false # принудительно отключает проверку CN сертификата брокера на соответствие имени хоста
    allowedDNs: # список DN брокеров к которым разрешено подключение
      - <DN брокера>           
    sslCipherSuite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
    sslSocketFactory:
      protocol: TLSv1.2
      keyPem: <путь к файлу с личным ключом Шлюза>
      certPem: <путь к файлу с сертификатом Шлюза>
      rootPem: <путь к файлу с сертификатами УЦ>            
  sync-receiver:
    poolSize: 20                                 # число потоков выполняющих чтение - разбор очереди
    startDelay: 1                                # отложить время чтения ответа на ms
    maxDelay: 10                                 # максимальная задержка переповтора.
    maxProcessingTime: 100000                    # таймаут ожидания ответного сообщения
    maxStopTime: 100000                          # время ожидания получения ответов при остановке Шлюза
    receiveTimeout: 50                           # таймаут на операцию чтения
    defaultReceiveQueue: <имя входящей очереди>  # дефолтная очередь используется если в сообщении не задан ReplyToQ
server:
  port: <порт HTTP>     # порт HTTP, на котором выставляется эндпойнт actuator/health для liveness и readiness проб
grpc:
  server:
    serverPort: <порт gRPC>    # порт, на котором поднимается gRPC-сервер для приема входящих запросов
  client:
    settings:
      default:
        hostname: empty-service
        port: <порт>           # порт по которому Шлюз будет выполнять исходящие gRPC-вызовы
tracing:                       # задает заголовки для исходящего gRPC вызова и правила их заполнения
  generateXB3Headers: 'true'
  generate128bitTraceId: 'true'
  tracingHeaders:
    x-synapse-rquid:         # правило определения заголовка x-synapse-rquid по входящему сообщению
      - type: fromBody
        value: //RqUID
    x-synapse-operationname:   # правило определения заголовка x-synapse-rquid по входящему сообщению
      - type: fromBody
        value: local-name(/*)

Отправка сообщения в MQ#

Для отправки сообщения в очередь Artemis нужно сделать вызов синхронного API Шлюза:

ProtoMessage MessageSyncChannel.ProcessMessages(ProtoMessage)

Обязательные поля ProtoMessage:

Поле

Тип

Описание

body

string

информационное сообщение в формате XML для отправки в MQ

Дополнительные поля ProtoMessage

Поле

Тип

Описание

messageId

string

Задать при необходимости установить определенное значение при отправке. Если отсутствует — будет сгенерировано в момент отправки в MQ

correlationId

string

Задать при необходимости установить определенное значение при отправке. Если отсутствует — не будет установлено.

extension.expiry

int64

Задать при необходимости установить время жизни сообщения в очереди.

systemHeaders

map<string, string>

Если содержит пару "ReplyToQ":"<имя очереди>" Шлюз ждет ответное сообщение в этой очереди. Внешняя система должна уметь отвечать по этому заголовку.
Если пара отсутствует, Шлюз ожидает ответы в очереди по умолчанию из настроек

Обязательные заголовки gRPC

Заголовок

Описание

x-synapse-rquid

Уникальный идентификатор сообщения

x-synapse-operationname

Имя операции

x-synapse-from-pod-name

Имя pod сервиса — инициатора вызова

Прием ответного сообщения из MQ#

Шлюз постоянно опрашивает очередь ответных сообщений. При появлении ответного сообщения считывает его и возвращает ProtoMessage в ответе на gRPC вызов. Если в полученном ответе отсутствует (пустое) тело сообщения, то Шлюз записывает в системный лог предупреждение: "Отсутствует тело в ответе на сообщение <ID сообщения>".

Считывание производится по CorrelationId.

Обязательные поля возвращаемого ProtoMessage:

Поле

Тип

Описание

messageId

string

MessageId входящего сообщения

correlationId

string

CorrelationId должен содержать MessageId исходного сообщения

body

string

Информационное сообщение (ответ) в формате XML

extension.sourceQueue

string

Очередь, из которой было считано входящее сообщение

Дополнительные поля возвращаемого ProtoMessage

Поле

Тип

Описание

systemHeaders

map<string, string>

Заполняется при наличии во входящем сообщении свойств с ключами, имеющими префикс JMS

userHeaders

map<string, string>

Заполняется при наличии во входящем сообщении свойств с ключами, не имеющими префикс JMS

Обязательные заголовки gRPC

Заголовок

Описание

x-synapse-rquid

Уникальный идентификатор сообщения

x-synapse-operationname

Имя операции

x-synapse-from

Имя внешней системы из конфигурации Шлюза

x-synapse-from-pod-name

Имя pod Шлюза, принявшего сообщение

Тайм-аут#

Если ответное сообщение не вычитано за время, установленное настройкой mq.sync-receiver.maxProcessingTime, то в ответ на синхронный вызов возвращается исключение deadline-exceeded

Дополнительно в Шлюзе реализованы режимы синхронного чтения ответов со всех подключенных менеджеров. Подробнее описано в разделе Особенности режима синхронного поставщика в кластере Artemis данного документа.

Синхронный режим, чтение сообщений из MQ#

В этом режиме Шлюз читает сообщения из Artemis и синхронно отправляет их по gRPC. Режим неблокирующий, во время ожидания ответа Шлюз продолжает считывать сообщения.

Конфигурация Шлюза#

Для запуска Шлюза в этом режиме необходимо в конфигурационном файле application.yml установить параметры:

mq:
  systemName:  <имя системы>     # аббревиатура внешней системы
  systemType:                   # sс - инициатор взаимодействия внешняя система
  workMode: sync                  # режим работы - синхронный
  connection:
    receiveQueue: [<имя входящей очереди>] # Список очередей, из которых Шлюз читает сообщения
    sendQueue: <имя исходящей очереди>   # очередь, в которую Шлюз кладет сообщения
    connections:
      - url: <hostname брокера Artemis>           # при подключении без SSL
        username: <логин к брокеру Artemis>
        password: <пароль к брокеру Artemis>
      - url: <hostname брокера Artemis>           # при подключении по SSL
        sslConfigName: <имя профиля SSL>               # имя профиля SSL из секции sslConfigs 
sslConfigs:
  - sslConfigName: <имя профиля SSL> 
    verifyHost: false # принудительно отключает проверку CN сертификата брокера на соответствие имени хоста
    allowedDNs: # список DN брокеров к которым разрешено подключение
      - <DN брокера>           
    sslCipherSuite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
    sslSocketFactory:
      protocol: TLSv1.2
      keyPem: <путь к файлу с личным ключом Шлюза>
      certPem: <путь к файлу с сертификатом Шлюза>
      rootPem: <путь к файлу с сертификатами УЦ>            
server:
  port: <порт HTTP>            # порт HTTP, на котором выставляется эндпойнт actuator/health для liveness и readiness проб
grpc:
  server:
    serverPort: <порт gRPC>    # порт, на котором поднимается gRPC-сервер для приема входящих запросов
  client:
    settings:
      default:
        hostname: empty-service
        port: <порт>           # порт по которому Шлюз будет выполнять исходящие gRPC-вызовы
        timeout: <время в мс>  # таймаут ожидания ответа для исходящего gRPC-вызова
tracing:                       # задает заголовки для исходящего gRPC вызова и правила их заполнения
  generateXB3Headers: 'true'
  generate128bitTraceId: 'true'
  tracingHeaders:
    x-synapse-rquid:           # правило определения заголовка x-synapse-rquid по входящему сообщению
      - type: fromBody
        value: //RqUID
    x-synapse-operationname:   # правило определения заголовка x-synapse-rquid по входящему сообщению
      - type: fromBody
        value: local-name(/*)
routing:                         # задает правила маршрутизации исходящего gRPC вызова (определение имени сервиса назначения)
  routeName:                     # определение имени маршрута
    valueFrom:
      - type: fromBody
        value: local-name(/*)
    expr:
  routeList:
    - routeName: default         # имя маршрута. Правила описанные в default применяются по-умолчанию
      destinationExpression: toLower(ServiceName)
      variables:
        - name: ServiceName
          valueFrom:
            - type: fromBody,
              value: '//ServiceName'
            exp: coalesce(value?"<имя вызываемого сервиса по-умолчанию>":value)

Чтение сообщений из MQ#

Шлюз постоянно опрашивает очередь входящих сообщений.

При появлении сообщения в очереди Шлюз считывает сообщение и выполняет вызов синхронного API:

ProtoMessage MessageSyncChannel.ProcessMessages(ProtoMessage)

Имя сервиса назначения определяется по правилам, прописанным в секции routing конфигурации Шлюза.

Обязательные поля ProtoMessage:

Поле

Тип

Описание

messageId

string

MessageId входящего сообщения

correlationId

string

CorrelationId входящего сообщения

body

string

Информационное сообщение в формате XML

extension.sourceQueue

string

Очередь, из которой было считано входящее сообщение

Дополнительные поля ProtoMessage

Поле

Тип

Описание

systemHeaders

map<string, string>

Заполняется при наличии во входящем сообщении свойств с ключами, имеющими префикс JMS

userHeaders

map<string, string>

Заполняется при наличии во входящем сообщении свойств с ключами, не имеющими префикс JMS

Обязательные заголовки gRPC

Заголовок

Описание

x-synapse-rquid

Уникальный идентификатор сообщения

x-synapse-operationname

Имя операции

x-synapse-from

Имя внешней системы из конфигурации Шлюза

x-synapse-from-pod-name

Имя pod Шлюза, принявшего сообщение

Отправка ответного сообщения в MQ#

Шлюз ожидает возврата ответного ProtoMessage, получив его, отправляет ответ в MQ

Обязательные поля ответного ProtoMessage:

Поле

Тип

Описание

messageId

string

MessageId исходного сообщения

correlationId

string

CorrelationId должно содержать MessageId исходного сообщения

body

string

Информационное сообщение (ответ) в формате XML

Дополнительные поля ответного ProtoMessage

Поле

Тип

Описание

extension.expire

int64

Задать при необходимости установить время жизни сообщения в очереди.

Обязательные заголовки gRPC

Заголовок

Описание

x-synapse-rquid

Уникальный идентификатор сообщения

x-synapse-operationname

Имя операции

x-synapse-from-pod-name

Имя pod сервиса — инициатора вызова

Тайм-аут#

Если ответ не будет получен до истечения времени указанного в параметре grpc.client.settings.default.timeout, то Шлюз логирует ошибку и завершает обработку сообщения.

Подключение по SSL#

Для подключения к брокерам Artemis по протоколу SSL должна быть задана конфигурация подключения. Конфигурация задается в секции mq.sslConfigs[] и содержит список профилей с настройками SSL/TLS. Имя профиля задается в параметре sslConfigName и используется для связывания по одноименному параметру с настройками соединения (mq.connection.connections[].sslConfigName). Если в профиле не задано имя, то ему присваивается имя default.

Профиль default используется как для соединений, у которых sslConfigName = default, так и для соединений, у которых sslConfigName явно не задано.

mq:
  connection:
    connections:
      - url: <hostname брокера Artemis>           # при подключении без SSL
        username: <логин к брокеру Artemis>
        password: <пароль к брокеру Artemis>
      - url: <hostname брокера Artemis>           # при подключении по SSL
        sslConfigName: <имя профиля SSL>               # имя профиля SSL из секции sslConfigs 
sslConfigs:
  - sslConfigName: <имя профиля SSL> 
    verifyHost: false # принудительно отключает проверку CN сертификата брокера на соответствие имени хоста
    allowedDNs: # список DN брокеров к которым разрешено подключение
      - <DN брокера>           
    sslCipherSuite: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
    sslSocketFactory:
      protocol: TLSv1.2
      keyPem: <путь к файлу с личным ключом Шлюза>
      certPem: <путь к файлу с сертификатом Шлюза>
      rootPem: <путь к файлу с сертификатами УЦ>            

Файлы ключей и сертификатов должны быть загружены в Kubernetes в виде отдельного артефакта Secret и подключены в контейнер Шлюза по путям, указанным в конфигурации SSL.

Мониторинг и очистка очереди ответов#

Возможна ситуация, когда при синхронном вызове в MQ, внешняя система в ответе не проставляет Expiration. Если при этом на ее стороне возникают задержки с ответом, превышающие тайм-аут, установленный в настройках Шлюза, то эти сообщения не вычитываются и начинают накапливаться в очереди ответов.

Для предотвращения накоплений на очередях ответов от синхронных поставщиков необходимо настроить политики очистки очереди.

Политики настраиваются на брокере Artemis в файле broker.xml, для конкретного адреса или шаблона адресов. Если для адреса задан параметр expiry-delay, то всем сообщениям, помещаемым в очередь, у которых expiration = 0 (не задано), будет установлено expiration = timestamp + expiry-delay. Если сообщение, помещаемое в очередь имеет expiration, не равное 0, значение изменено не будет.

<address-setting match="exampleQueue">
   <expiry-address>expiryQueue</expiry-address>
   <expiry-delay>10</expiry-delay>
</address-setting>

Важно! Для очередей ответов синхронных сервисов необходимо устанавливать значение expiry-delay > величины таймаута сервиса.

Логирование#

В процессе работы Шлюз фиксирует события в логах.

Системное логирование#

В системном логе фиксируются события, возникающие в приложении в процессе его работы. По умолчанию системный лог выводится в консоль контейнера приложения.

Доступ к системному логу можно получить через Web-интерфейс Kubernetes (Workloads->Pods->Имя pod->вкладка Logs).

Системный лог может быть выгружен через консоль клиента Kubernetes командой:

kubectl logs -c <имя контейнера> <имя pod> > <имя файла>.txt

Также уровень системного логирования можно изменить, задав его в конфигурации Шлюза:

    logging:
      level: debug

Прикладное логирование#

В прикладном логе фиксируются следующие шаги прохождения интеграционной цепочки:

  • Шлюз вычитал сообщение JMS/MQ из очереди внешней системы;

  • Шлюз вызвал микросервис по gRPC и отправил ему сообщение;

  • Шлюз получил сообщение по gRPC от микросервиса;

  • Шлюз отправил JMS/MQ сообщение в очередь внешней системы;

  • Ошибка на Шлюзе.

Для корректного отражения в прикладном логе в Шлюзе должен быть заданы:

  • Заголовок x-synapse-rquid. Правило определения значения задается в секции трейсинг;

  • Переменная ServiceName. Правило определения задается в секции Routing. Значение фиксируется в прикладном логе в поле operationName. Если переменная не задана, то будет использовано значение имени маршрута (routeName).

Прикладной лог пишется на смонтированный в контейнер приложения ресурс. По умолчанию прикладной лог пишется в файлы:

/opt/synapse/logs/messages*.log

Прикладные логи могут быть извлечены из контейнера приложения и отправлены в подсистему журналирования платформы. Для этого в deployment Шлюза должен быть сконфигурирован sidecar-контейнер с компонентом платформы Synapse — Агентом журналирования.

Порядок подключения и использования Агента журналирования приведены в разделе Подключение и конфигурирование документа Руководство прикладного разработчика на компонент Сервис Журналирование (LOGA) Platform V Monitor.

Интеграционное журналирование (трассировка)#

Интеграционное журналирование выполняется средствами Service Mesh.

Sidecar-контейнер istio-proxy обеспечивает передачу трассировочной информации из транспортных заголовков каждого исходящего gRPC-вызова в систему интеграционного журналирования.

Шлюз заполняет заголовки трассировки в соответствии с заданными настройками.

Правила заполнения заголовков трассировки устанавливаются в секции настроек tracing.

Горизонтальное масштабирование#

Горизонтальное масштабирование Шлюза реализуется и регулируется системными механизмами Kubernetes/Istio. В любой момент при необходимости могут работать одновременно произвольное количество экземпляров Шлюза с общей конфигурацией (произвольное количество pods одного Deployment). Количество запущенных экземпляров определяется настройкой в Deployment и ограничивается только лимитами ресурсов проекта в Kubernetes.

Количество запускаемых экземпляров (pods) Шлюза задается в артефакте Deployment параметром spec.replicas.

Метрики#

Для дополнительного мониторинга параметров Шлюза в нем реализован механизм сбора метрик его работы. Метрики публикуются на HTTP-интерфейсе Шлюза и доступны по URI /actuator/prometheus (метод GET).

Порт, на котором поднимается HTTP-сервис, устанавливается настройкой:

server.port 

Получить текущий актуальный список метрик можно, выполнив в терминале контейнера Шлюза команду:

curl localhost:<номер HTTP порта Шлюза>/actuator/prometheus

Мониторинг сертификатов#

Шлюз в процессе работы проверяет срок действия используемых сертификатов SSL и публикует метрику certs, выводящую эту информацию, вид метрики приведен ниже. Значения параметров указаны для примера и в действующей системе будут отличаться.

certs{certLabel="{Alias='gateway', Subject='CN=GATEWAY', Expiration date='01.03.2122', Issuer='CN=SYNAPSEDEV_ROOT_CA'}",} 364.0
certs{certLabel="{Alias='root-ca', Subject='CN=SYNAPSEDEV_ROOT_CA', Expiration date='26.07.3021', Issuer='CN=SYNAPSEDEV_ROOT_CA'}",} 3649.0

Мониторинг используемых ресурсов#

Для расчета производных показателей используются платформенные метрики, публикуемые Kubernetes:

Метрика

Комментарий

container_memory_working_set_bytes

рабочий набор контейнера = RSS+Cache, кеш — уровня ОС и не регулируется приложением

container_spec_memory_limit_byte

лимит памяти контейнера

container_memory_rss

RSS контейнера

Метрики Kubernetes публикуются для всех контейнеров в pod, поэтому при расчете показателей их нужно фильтровать по контейнеру приложения, а не только по pod.

Для мониторинга ресурсов в системе визуализации (Grafana) можно настроить следующие показатели:

Container working set %

 =max(container_memory_working_set_bytes{pod="$instance", container=~".*gate.*"})/max(container_spec_memory_limit_bytes{pod="$instance", container=~".*gate.*"})*100

Это процент использования памяти контейнера: то, что отображается в стандартном мониторинге.

Container working set

 =max(container_memory_working_set_bytes{pod="$instance", container=~".*gate.*"})

Это рабочий набор контейнера

Container rss %

 =max(container_memory_rss{pod="$instance", container=~".*gate.*"})/max(container_spec_memory_limit_bytes{pod="$instance", container=~".*gate.*"})*100

Это % RSS от лимита памяти контейнера

Container rss

 =max(container_memory_rss{pod="$instance", container=~".*gate.*"})

Это RSS контейнера

В примерах выше переменные содержащие $app - имя Deployment, а $instance - имя pod Шлюза.

Многоточечное подключение#

При многоточечном подключении один экземпляр Шлюза может быть подключен к нескольким брокерам Artemis. При отправке сообщений в исходящие очереди выполняется балансировка по точкам подключения (hostname:port).

Это внутренняя функция Шлюза, которая никак не связана с настройкой брокеров Artemis.

В Шлюзе реализована периодическая проверка доступности брокеров, если проверка завершается неудачей, брокеры исключаются из балансировки до следующей успешной проверки. Из балансировки также исключаются брокеры отключенные настройкой disabledManagerIds, причем по брокерам отключенным настройкой, проверка доступности не выполняется. Если доступные брокеры отсутствуют, то Шлюз опускает readiness-пробу, и трафик на этот экземпляр (pod) Шлюза блокируется механизмами Kubernetes/Istio.

Если брокер доступен, но при отправке сообщения в MQ возникает ошибка, то Шлюз выполняет попытку отправки через другой брокер из числа доступных. Если сообщение не удается отправить ни через один из брокеров, то Шлюз возвращает ошибку вызывавшему микросервису и опускает readiness-пробу.

Шлюз читает запросы/асинхронные ответы из входящих очередей всех доступных брокеров.

В синхронном режиме работы Шлюз читает ответ из того же брокера, через который был отправлен запрос.

Настройки проверки доступности брокеров устанавливается в секции mq.connection.health конфигурации Шлюза.

В секции mq.connection.health можно задать период опроса, задержку, и, отдельно, количество попыток перед вводом брокера в балансировку, и выводом из балансировки. Подробнее см. раздел «Полное описание настроек».

Для корректной работы механизма проверки, необходимо, чтобы таймаут блокирующих вызовов к брокеру mq.connection.callTimeout имел величину меньшую или равную mq.connection.health.timeoutSeconds.

HTTP-интерфейс#

HTTP-интерфейс в Шлюзе предназначен для организации взаимодействия между внешними АС с разными протоколами взаимодействия — MQ и HTTP.

Использование Шлюза с HTTP-интерфейсом позволяет осуществлять вызов MQ/HTTP с возможностью трансформации транспортных заголовков HTTP→MQ/MQ→HTTP (без преобразования тела сообщения).

Не реализована возможность вызова HTTP→gRPC и gRPC→HTTP.

Определение параметров маршрутизации по телу сообщения работает только с форматами тела сообщения XML и JSON. Возможность работы с другими форматами не поддерживается.

Тип Шлюза: Шлюз потребителя (MQ→HTTP)#

При появлении в очереди запросов входящего сообщения Шлюз считывает сообщение из очереди.

Из полученного сообщения Шлюз извлекает значения параметров, определяющих дальнейшую маршрутизацию вызова. Эти параметры могут содержаться как в заголовках, так и в теле сообщения, либо задаваться константой. Правила определения параметров маршрутизации устанавливаются в секции настроек routing.

Для вызова по HTTP в параметрах маршрута должен быть задан тип транспорта HTTP. Тип транспорта устанавливается настройкой routing.routeList[].transportType.

Шлюз преобразует полученный запрос в httpMessage и вызывает по HTTP-сервис, заданный в параметрах секции HTTP-конфигурации Шлюза, передавая ему сформированное сообщение. Параметры по умолчанию вызываемого сервиса устанавливаются в блоке настроек http.

Параметры вызываемого сервиса для конкретного маршрута устанавливаются в секции настроек routing.routeList[].http.

Важно ! В секцию http входят настройки SSL для HTTP-вызова. Эти настройки должны храниться и монтироваться в артефакте типа secret. В отдельный конфигурационный файл можно вынести только настройки SSL по умолчанию из блока http.

Правила преобразования MQ-заголовков в заголовки HTTP-сообщения устанавливаются в настройке transform.mq-http.headers.

Порядок формирования сообщения подробно описан в разделе Преобразование интерфейсов.

В асинхронном режиме Шлюз, отправив сообщение, завершает вызов.

В синхронном режиме Шлюз ожидает ответ в течение времени тайм-аута, заданного в конфигурации в секции http. Если в течении этого времени ответ не получен, Шлюз прерывает вызов и записывает в журнал тайм-аут. В случае успешного завершения вызова, Шлюз получает ответ от поставщика сервиса. В противном случае в журнал записывается ошибка.

Шлюз преобразует полученное сообщение в MQ-сообщение. Правила преобразования заголовков HTTP-сообщения в заголовки MQ-сообщения устанавливаются в настройке transform.http-mq.

Порядок формирования сообщения подробно описан в разделе Преобразование интерфейсов.

Шлюз отправляет сообщение в очередь, определяемую из настроек Шлюза и информации, содержащейся в ответе.

Если отправка завершилась неудачей, Шлюз записывает ошибку в журнал.

Тип Шлюза: Шлюз поставщика (HTTP→MQ)#

Шлюз при запуске поднимает сервис согласно параметрам, указанным в настройках в секции server конфигурации Шлюза. Параметры HTTP-сервиса устанавливаются в блоке настроек server. Когда сервис получает HTTP-запрос, Шлюз преобразует его в MQ-сообщение. Правила преобразования заголовков HTTP-сообщения в заголовки MQ-сообщения устанавливаются в секции настроек transform.http-mq.

Порядок формирования сообщения подробно описан в разделе Преобразование интерфейсов.

В зависимости от значения параметра sendToCustomDestination в разделе mq конфигурации Шлюза и информации, полученной во входящем сообщении, Шлюз может отправить сообщение:

  • в очередь, указанную в настройках Шлюза;

  • в очередь, указанную в блоке Destination Proto-сообщения;

  • в очередь, указанную в gRPC-заголовках входящего вызова.

В асинхронном режиме Шлюз после отправки сообщения в очередь возвращает HTTP-код 200 (успешное завершение).

Для синхронного ответа АС-поставщик должен установить значение MsgId запроса в CorrelId ответа. Кроме того, ответ должен быть считан тем же экземпляром Шлюза, который отправил запрос.

В синхронном режиме Шлюз отправляет преобразованное сообщение и синхронно ожидает ответ с CorrelId, равным MsgId запроса. Тайм-аут устанавливается настройкой mq.sync-receiver.maxProcessingTime.

АС-поставщик считывает сообщение из очереди запросов, выполняет бизнес-функцию и помещает ответ в очередь ответов по ReplyToQ.

Шлюз считывает ответ и преобразует его в HttpMessage. Правила преобразования MQ-заголовков в заголовки HTTP-сообщения задаются в настройке transform.mq-http.headers.

Порядок формирования сообщения подробно описан в разделе Преобразование интерфейсов.

Шлюз возвращает преобразованное сообщение инициатору запроса.

Работа с кластером Artemis#

Для асинхронных режимов работа в кластере не отличается от работы с множеством брокеров, не связанных в кластер, т. к. в этом случае запросы и ответы балансируются по Pods независимо друг от друга.

Особенности режима синхронного поставщика в кластере Артемис#

Шлюз реализует три варианта работы с кластером Артемис в синхронном режиме:

1. Режим динамического создания очередей для ответов для каждого Pod.

В этом режиме Шлюз при старте каждого Pod создает на общем адресе отдельная очередь с именем Pod (<адрес>::<имя Pod1>, <адрес>::<имя Pod2> и т. д.).

При отправке запроса АС-поставщику конкретный Pod Шлюза в заголовке ReplyToQ передает FQQN "своей" очереди для ответа.

АС поставщик адресует ответ в указанную очередь.

Ответ считывается тем же Pod Шлюза, который отправлял запрос.

В этом варианте Pod Шлюза должен проверять ответы на каждом брокере, к которому он подключен, но поскольку он работает только со своими очередями, чтение по селектору не требуется.

Динамические очереди именуются на основе имени Pod: {ADDRESS}::{PODNAME}, где ADDRESS - имя адреса из настройки mq.sync-receiver.defaultReceiveQueue или из заголовка ReplyToQ, если он есть, PODNAME - имя Pod. В этом режиме заголовок ReplyToQ входящего по gRPC сообщения не должен содержать FQQN очереди. То же касается и параметра mq.sync-receiver.defaultReceiveQueue конфигурации Шлюза.

Для использования этого функционала необходимы следующие настройки в брокере Artemis:

<address-setting match="<адрес>#">
    <auto-create-queues>true</auto-create-queues>   
    <auto-delete-queues>true</auto-delete-queues>  
    <auto-delete-queues-delay>30000</auto-delete-queues-delay>
    <auto-delete-queues-message-count>0</auto-delete-queues-message-count>
</address-setting>
  • автоматическое создание очередей auto-create-queues - по умолчанию включено, убедиться что не выключено явно;

  • автоматическое удаление созданных автоматически очередей auto-delete-queues - по умолчанию включено, убедиться что не выключено явно;

  • таймаут, после которого очередь будет удалена при отсутствии потребителей и сообщений - auto-delete-queues-delay. Рекомендуется ставить достаточный интервал на случай перезапуска Envoy, либо других сайдкаров, во избежание пересоздания одной и той же очереди. Так же на таймаут влияет глобальный параметр брокера address-queue-scan-period интервал сканирования очередей на удаление. Например, при настройке auto-delete-queues-delay=0 и address-queue-scan-period = 30000 пустая очередь может удалиться в промежутке от 0 до 30 секунд.

  • Количество сообщений в очереди должно быть меньше или равно указанному в auto-delete-queues-message-count чтобы очередь могла быть удалена. Если в настройке задано значение -1, то проверка на наличие сообщений не производится.

    Если выставить таймаут на удаление очереди равным общему таймауту на Шлюзе, то в этом случае потерь сообщений не будет (так как оставшиеся в очереди сообщения все равно не будут обработаны из-за истечения таймаута).

    Разрешения на работу с такими очередями устанавливаются в настройках безопасности для адреса (можно применять wildcard-синтаксис):

    <security-settings>
        <security-setting match="TEST.QUEUE.RESPONSE">
    
            <!-- Очередь для ответов  -->
            <permission type="createNonDurableQueue" roles="amq, gwsp"/>
            <permission type="createDurableQueue" roles="amq, gwsp"/>
            <permission type="consume" roles="amq, gwsp"/>
            <permission type="browse" roles="amq, gwsp"/>
            <permission type="send" roles="amq, assp"/>
            <!-- we need this otherwise ./artemis data imp wouldn't work -->
             <permission type="manage" roles="amq"/>
        </security-setting>
    
        <security-setting match="TEST.QUEUE.REQUEST">
            <!-- Очередь для запросов -->
            <permission type="consume" roles="amq, assp"/>
            <permission type="browse" roles="amq, assp"/>
            <permission type="send" roles="amq, gwsp"/>
            <!-- we need this otherwise ./artemis data imp wouldn't work -->
             <permission type="manage" roles="amq"/>
        </security-setting>
    </security-settings>
    

    В текущем примере gwsp - роль, созданная в брокере для Шлюза, может создавать очереди и читать из них на адресе TEST.QUEUE.RESPONSE, но не может в них писать. Для очередей на адресе TEST.QUEUE.REQUEST наоборот, есть права на запись, но нет на чтение. assp - роль для АС, обладает противоположными правами — только читать из очередей на TEST.QUEUE.REQUEST и только писать в очереди на адресе TEST.QUEUE.RESPONSE. Создавать очереди сама не может.

    Шлюз и АС должны подключаться к брокеру под отдельными пользователями, каждому из которых назначена соответствующая роль. Права на удаление и обслуживание очередей таким пользователям не требуются. Созданные ими очереди будут автоматически удалены брокером при выполнении условий для удаления.

2. Режим синхронного чтения ответов из всех подключенных брокеров по корреляционному идентификатору

В этом случае используется схема адресации с одной очередью на адрес. Сценарий:

  • при отправке запроса АС-поставщику конкретный Pod Шлюза в заголовке ReplyToQ передает имя общей очереди для ответа;

  • АС поставщик отвечает в эту очередь, не уточняя имя брокера или имя Pod Шлюза;

  • Конкретный Pod Шлюза читает очереди ответов на всех подключенных брокерах, но считывает только "свои" сообщения, используя селектор по корреляционному идентификатору (CorrelationID).

3. Режим синхронного чтения ответов из всех подключенных брокеров по селектору

Это смешанный режим — вычитка происходит со всех менеджеров по селектору, но селектор не по CorrelId, а по фиксированному, заранее созданному селектору, индивидуальному для каждого Pod (соответствует имени Pod).

В этом случае используется схема адресации с одной очередью на адрес. Сценарий:

  • при отправке запроса АС-поставщику конкретный Pod Шлюза передаёт:

    • в заголовке ReplyToQ имя общей очереди для ответа.

    • в заголовке GWResponseSelector значение для селектора, по которому текущий Pod читает сообщения из очереди для ответа

  • АС поставщик отвечает в эту очередь, не уточняя имя брокера или имя Pod Шлюза, но обязательно сохраняет и передаёт в сообщении заголовок GWResponseSelector и его значение

  • Конкретный Pod Шлюза читает очереди ответов на всех подключенных брокерах, но считывает только "свои" сообщения, используя селектор по GWResponseSelector.

    В качестве значения селектора используется только имя Pod в заголовке GWResponseSelector

    Используемый заголовок можно поменять через настройку mq.sync-receiver.selectorName.

Выбор режима работы:

Выбор осуществляется настройкой:

mq:
  sync-receiver:
   replyToMode: UNIQUE #SHARED # SHARED_SINGLE # SHARED_SELECTOR
   #selectorName: GWResponseSelector # для режима SHARED_SELECTOR

где UNIQUE - вычитка из динамической очереди (п.1), SHARED и SHARED_SINGLE - вычитка по CorrelId (п.2) из всех или одного менеджера (в который был отправлен запрос), SHARED_SELECTOR - вычитка из всех менеджеров по селектору (п.3)

Для сохранения обратной совместимости по умолчанию используется режим SHARED_SINGLE.

Режим workMode: ALL — совмещенный синхронный и асинхронный режим#

Шлюз может работать в совмещенном (синхронном и асинхронном) режиме. Для этого предусмотрен режим работы ALL.

Для включения режима нужно в конфигурации Шлюза задать настройку:

mq:
  workMode = all

Для входящих из MQ сообщений режим обработки определяется входящей очередью:

Входящая очередь

Режим

из настройки mq.connection.receiveQueue[]

async

из настройки mq.connection.receiveQueueSync[]

sync

Для исходящих в MQ сообщений режим обработки определяется API, через который был вызван Шлюз:

АПИ

Режим

Асинхронное

async

Синхронное

sync

Режим systemType: ALL — объединенный режим поставщика и потребителя#

Объединенный режим работы Шлюза устанавливается настройкой mq.systemType: all.

mq:
  systemName: <Аббревиатура системы>
  systemType: all
  workMode: all # если systemType: all, то workMode всегда тоже all

Идентификация режимов при обработке сообщений.

Шлюз в объединенном режиме поднимает два API, синхронный и асинхронный, а также прослушивает заданный в настройках набор очередей.

Для каждой входящей очереди в настройках указывается, в каком режиме обрабатывать пришедшие в нее сообщения.

  1. Вызов синхронного API Шлюза будет обработан в режиме «Синхронный поставщик»;

  2. Для вызовов асинхронного API устанавливается асинхронный режим обработки, но определить, делается запрос в сторону поставщика или ответ в сторону потребителя, невозможно. Это надо учитывать при реализации интеграций через объединенный Шлюз;

  3. Сообщение положенное в очередь, помеченную в настройках Шлюза параметрами workMode: async, systemType: sc будет обработано как асинхронный запрос от потребителя;

  4. Сообщение положенное в очередь, помеченную в настройках Шлюза параметрами workMode: async, systemType: sp будет обработано как асинхронный ответ от поставщика;

  5. Сообщение положенное в очередь, помеченную в настройках Шлюза параметрами workMode: sync, systemType: sc будет обработано как синхронный запрос от потребителя.

Важно! В настройках очередей нельзя указывать workMode: all либо systemType: all. Чтение из таких очередей выполняться не будет.

Настройки очередей:

Входящие очереди для всех используемых режимов должны быть заданы в списке listReceiveQueue (кроме режима синхронного поставщика):

mq:
  connection:
    listReceiveQueue:
      - queue: <очередь1>
        workMode: sync
        systemType: sc
        systemName: <АС1>
      - queue: <очередь2>
        workMode: async
        systemType: sc
        systemName: <АС1>
      - queue: <очередь3>
        workMode: async
        systemType: sp
        systemName: <АС1>

Исходящие очереди для асинхронных режимов не задаются, отправка производится по customDestination. Для синхронных режимов также используется отправка по customDestination, но можно задать дефолтные очереди в разрезе потребитель/поставщик:

    mq:
      connection:
        defaultSendQueues:
          syncProvider:
            queue: <очередь синхронного поставщика>
            systemName: <АС1>
          syncConsumer:
            queue: <очередь синхронного потребителя>
            systemName: <АС1>

В настройки коррекции заголовков для исходящих сообщений mq.outbound для возможности разделения настроек между режимами добавлен селектор. Между асинхронными Шлюзами async sc и async sp дефолтные настройки разнести невозможно, так как нет параметра во входящем gRPC вызове, по которому можно было бы надежно определить, направлено оно поставщику или потребителю. Для именованных сервисов можно разнести настройки, например, по наличию «rq» или «rs» в корневом теге сообщения

    mq:
      outbound:
        serviceName:
          valueFrom:
            - type: fromBody
              value: local-name(/*)
          expr:
        serviceList:
          - serviceName: default
            selector: SYNC_SP                 # <-----------------Для режима синхронного поставщика. Могут быть (SYNC_SC, SYNC_SP, ASYNC)

В блок routing для исключения случаев пересечения дефолтных схем маршрутизации можно задать селектор, определяющий на какой поток применить схему — синхронный или асинхронный, потребителя или поставщика.

    routing:
      routeName:
        valueFrom:
          - type: fromBody
            value: local-name(/*)
        expr:
      routeList:
        - routeName: default
          selector: ASYNC_SC # <-----------------Для режима асинхронного потребителя. Могут быть (SYNC, ASYNC_SP, ASYNC_SC)
          . . .
        - routeName: default
          selector: ASYNC_SP # <-----------------Для режима асинхронного поставщика. Могут быть (SYNC, ASYNC_SP, ASYNC_SC)
          . . .

В блоке tracing можно задавать списки настроек в разрезе режимов. Добавлен селектор для разделения списков настроек.

    #признак генерации заголовков трассировки x-b3-*
    tracing:
      generateXB3Headers: true
      generate128bitTraceId: true
      listTracingHeaders:
        - selector: ASYNC_SC # <-----------------Для режима асинхронного потребителя. Могут быть (SYNC, ASYNC_SP, ASYNC_SC)
          tracingHeaders:
            x-synapse-rquid:
              - type: fromBody
                value: //*[local-name()='RqUID']

Валидация сообщений на Шлюзе#

Валидация сообщений на Шлюзе выполняется внешним компонентом (Валидатор запросов IGEG (REQV)).

Возможна валидация как входящих (из MQ), так и исходящих (в MQ) сообщений в форматах XML и JSON.

Для синхронных вызовов можно настроить отправку информационных ответов об ошибках валидации, если форматы (схемы) ответных сообщений это позволяют.

Получив сообщение по одному из своих основных интерфейсов, Шлюз в соответствии со своими настройками вызывает по HTTP-контейнер с валидатором и отправляет тело сообщения на валидацию. Валидатор по своим настройкам определяет нужную схему сообщения и проводит валидацию, после чего возвращает Шлюзу результат. В случае положительного результата валидации Шлюз отправляет сообщение дальше в точку назначения. В случае отрицательного результата валидации Шлюз фиксирует ошибку, сообщение дальше не отправляется.

Если сообщение пришло в синхронном вызове и в настройках валидатора для этого сообщения задан шаблон ответа об ошибке, то, в случае отрицательного результата валидации, валидатор формирует и передает Шлюзу ответ об ошибке, а Шлюз возвращает его инициатору.

Чтобы Валидатор мог определить схему сообщения для валидации, ему в заголовках HTTP-вызова должны быть переданы два параметра: metod и path. Значение заголовка path на Шлюзе определяется динамически, на основании параметров сообщения, по правилам заданным в настройках Шлюза. Соответствие значений path схемам сообщений задается в конфигурации валидатора.

Важно!

При работе валидатора совместно со Шлюзом:

Заголовок metod всегда имеет значение POST.

Валидатор, при ошибке валидации должен всегда возвращать код 403 (используется по-умолчанию).

Возвращаемые валидатором заголовки error-headers Шлюзом не обрабатываются.

Шлюз при вызове валидатора самостоятельно заполняет заголовок x-request-id значением RqUID определенным для целей логирования.

Подключение валидатора#

Для подключения валидатора необходимо в Deployment Шлюза добавить контейнер валидатора, а также тома с его конфигурацией (артефакт ConfigMap или Secret содержащий файл appl.yml) и схемами сообщений (артефакт ConfigMap или Secret содержащий схемы сообщений) и их точки монтирования.

Пример подключения валидатора в Deployment Шлюза:

Deployment: spec.template.spec.containers

      containers
        - name: validator
          resources:
            limits:
              cpu: 200m
              memory: 160Mi
            requests:
              cpu: 100m
              memory: 150Mi
          terminationMessagePath: /dev/termination-log
          env:
            - name: PROJECT_NAME
              valueFrom:
                fieldRef:
                  apiVersion: v1
                  fieldPath: metadata.namespace
          ports:
            - containerPort: 50051
              protocol: TCP
          imagePullPolicy: IfNotPresent
          volumeMounts:
            - name: validator-schemas
              readOnly: true
              mountPath: /schemas
            - name: validator-config
              mountPath: /config
            - name: synapselogs
              mountPath: /opt/synapse/logs
          terminationMessagePolicy: File
          image: >-
            registry.example.com/ci01994970/ci03302438_synapse-igeg/rhel7-java-synapse-sidecar-validator-ci03302438:0.1.0.26

Deployment: spec.template.spec

       volumes:
        - name: validator-config
          configMap:
            name: validator-config
            defaultMode: 416
        - name: validator-schemas
          configMap:
            name: validator-schemas
            defaultMode: 416

В настройках Валидатора нужно задать порт, на котором Валидатор будет принимать запросы. Порт валидатора по номеру не должен совпадать с портом, который использует Шлюз. Также в настройках задается соответствие параметров вызова валидатора конкретной схеме валидации.

Пример настройки Валидатора: validator-config

  app.yaml: |
    port: 8787
    log_level: info
    schemas:
      - name: 'foo'
        method: POST
        path: '/ping'
        schema: /schemas/foo.json
        type: 'json'
        error_response: '{"error-message":{"x-request-id": "{{get .Header "x-request-id"}}", "error": "{{get .Error "error_message"}}"}}'
        error_headers:
          - key: content-type
            value: application/json
          - key: foo
            value: '{{get .Header "foo"}}'
        headers:
          - key: x-foo-first
            value: foo1
        error_code: 200
      - name: bar
        method: POST
        path: '/'
        schema: /schemas/bar.xsd
        type: 'xml'
        error_code: 403
        error_response: '<error_rs>{{get .Error "error_message"}}</error_rs>'

Дополнительно к валидатору в точку монтирования /schemas должен быть смонтирован артефакт типа ConfigMap или Secret, содержащий схемы для валидации сообщений.

Пример артефакта со схемами: validator-schemas

  bar.xsd: |
    <?xml version="1.0" encoding="UTF-8" ?>
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
        <xs:element name="address">
            <xs:complexType>
                <xs:sequence>
                    <xs:element name="RqUID" type="xs:string"/>
                    <xs:element name="street" type="xs:string"/>
                    <xs:element name="street-number" type="xs:string"/>
                    <xs:element name="city" type="xs:string"/>
                    <xs:element name="zip" type="xs:string"/>
                    <xs:element name="country" type="xs:string"/>
                </xs:sequence>
            </xs:complexType>
        </xs:element>
    </xs:schema>
  barn.xsd: |
    <?xml version="1.0" encoding="UTF-8" ?>
    <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
        <xs:element name="address">
            <xs:complexType>
                <xs:sequence>
                    <xs:element name="RqUID" type="xs:string"/>
                    <xs:element name="street" type="xs:string"/>
                    <xs:element name="street-number" type="xs:string"/>
                    <xs:element name="city" type="xs:string"/>
                    <xs:element name="zip" type="xs:string"/>
                    <xs:element name="country-n" type="xs:string"/>
                </xs:sequence>
            </xs:complexType>
        </xs:element>
    </xs:schema>
  foo.json: |
    {
      "$id": "http://json-schema.org/draft/2019-09/json-schema-core.html",
      "$schema": "https://json-schema.org/draft/2019-09/schema",
      "$comment": "sample comment",
      "title": "Config dump",
      "type": "object",
      "properties": {
        "configs": {
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "@type": {
                "type": "string"
              },
              "last_updated": {
                "type": "string"
              },
              "bootstrap": {
                "type": "object",
                "properties": {
                  "admin": {
                    "type": "object"
                  },
                  "dynamic_resources": {
                    "type": "object"
                  },
                  "node": {
                    "type": "object"
                  },
                  "static_resources": {
                    "type": "object"
                  },
                  "stats_config": {
                    "type": "object"
                  }
                },
                "required": ["admin", "dynamic_resources", "node", "static_resources", "stats_config"]
              }
            },
            "required": ["@type", "last_updated", "bootstrap"]
          }
        }
      },
      "required": [
        "configs"
      ]
    }

Более подробная информация содержится в разделе Использование программного продукта документа Руководство прикладного разработчика на компонент Валидатор запросов (REQV) Platform V Synapse Service Mesh.

Настройка Шлюза для выполнения валидации#

Включить валидацию#

Добавить в конфигурацию Шлюза блок параметров верхнего уровня validator. Параметры могут быть добавлены в существующий файл конфигурации application.yml, но, учитывая их критичность, можно выделить их в отдельный файл validator-secret.yml, и поместить его в артефакт типа Secret.

Отдельный артефакт необходимо подключить к контейнеру Шлюза в Deployment: Пример подключения секрета с настройками валидации

      volumes:
        - name: test-gw-validator
          secret:
            secretName: test-gw-validator
            defaultMode: 288
      . . .
      containers
        - name: test-gw
          volumeMounts:
            - name: test-gw-validator
              mountPath: /deployments/config/validator

Установить настройку validator.enabled в true.

Установить параметры вызова валидатора#

Установить настройки validator.http.client.url и validator.http.client.timeout

URL нужно задать в формате http://localhost/:<port>/check, где port соответствует номеру порта заданному в настройках валидатора.

Установить правила выбора профиля настроек#

Заполнить секцию validator.serviceName. Секция задает правило выбора профиля настроек валидации по параметрам сообщения. Принцип заполнения такой же, как для секции routing, но дефолтный профиль не предусмотрен.

Обычно (но не обязательно) профиль соответствует наименованию сервиса и может быть получен, например, из пользовательского заголовка ServiceName (если он используется) либо из тега ServiceName в теле сообщения.

Пример заполнения секции validator.serviceName

       serviceName: # правила определения схем для сообщений
        valueFrom:
          - type: fromRfh2Header
            value: ServiceName
          - type: fromBody
            value: //ServiceName
            valueJson: $..ServiceName
        expr:
Установить правила выбора пути для поиска схемы#

Заполнить секцию validator.serviceList. Секция задает список профилей, и для каждого профиля — правила вычисления значения заголовка path для вызова валидатора. Принцип заполнения такой же, как для секции routing. Значение pathопределяется как результат вычисления выражения заданного в pathExpression над списком переменных. Значения переменных определяются из параметров конкретного сообщения по заданным в профиле правилам.

В большинстве случаев (но не всегда) достаточно привязать path к корневому тегу сообщения:

Пример заполнения секции serviceList

       serviceList:
        - serviceName: testServiceName
          pathExpression: ServiceNameRootTag
          variables:
            - name: ServiceNameRootTag
              valueFrom:
                - type: fromBody
                  value: local-name(/*)
              expr:
предопределенные переменные#

Для более точной идентификации схемы можно использовать встроенные переменные, которые Шлюз заполняет самостоятельно.

  • direction - направление движения сообщения, варианты:

    • outbound - в MQ

    • inbound - из MQ

  • workMode - режим вызова, варианты:

    • sync - сообщение получено в синхронном вызове

    • async - сообщение получено в асинхронном вызове

  • msgType - тип сообщения (определяется только для синхронных вызовов), варианты:

    • rq - синхронный запрос

    • rs - ответ на синхронный запрос

    • "_" - сообщение в асинхронном вызове

Пример использования предопределенных переменных

       serviceList:
        - serviceName: testServiceName
          pathExpression: ("/"+variables['direction']+"/"+variables['workMode']+"/"+variables['msgType']+"/"+ServiceNameRootTag)
          variables:
            - name: ServiceNameRootTag
              valueFrom:
                - type: fromBody
                  value: local-name(/*)
              expr:
Заголовки#

В вызов валидатора могут быть добавлены дополнительные заголовки. Они используются для уточненного поиска схемы, а также для параметризации ответа об ошибке валидации (подробности см. в документации на Валидатор запросов (REQV) Platform V Synapse Service Mesh).

Для добавления заголовка в вызов нужно для конкретного профиля настроек заполнить параметр headers:

Пример настройки заполнения заголовков

       serviceList:
        - serviceName: testServiceName
          headers: # Заполняется, если требуется передать дополнительные заголовки для вставки в ответ.
            RqUID:
              - type: fromBody
                value: //RqUID
                # Matching values
                valueJson: $..RQID
          pathExpression: ("/"+variables['direction']+"/"+variables['workMode']+"/"+variables['msgType']+"/"+ServiceNameRootTag)
          variables:
            - name: ServiceNameRootTag
              valueFrom:
                - type: fromBody
                  value: local-name(/*)
              expr:

Выполнение валидации на Шлюзе#

Если на Шлюзе включена валидация, то к каждому проходящему через Шлюз сообщению применяются правила определения профиля валидации.

Если профиль найден, то вычисляется параметр path по правилам, заданным в профиле настроек, и тело сообщения отправляется на валидацию.

Если профиль для сообщения не задан, то по умолчанию сообщение будет признано валидным и отправлено дальше по маршруту. Это поведение можно изменить установкой параметра настройки invalidateByDefault в true.

При положительном результате валидации сообщение будет оправлено дальше по маршруту.

При отрицательном результате валидации будет вызвано исключение. Если вызов был синхронным и валидатор вернул информационный ответ об ошибке, этот ответ будет возвращен инициатору. В остальных случаях:

  • для входящего сообщения из MQ обработка прекращается;

  • для входящих по gRPC/HTTP — возвращается исключение и статус/код завершения соответственно.

Возврат ответа#

Если Шлюз при обработке синхронного вызова получил от валидатора ошибку валидации с информационным ответом, то:

  • Для синхронного запроса из MQ ответ отправляется в очередь и менеджер указанные в заголовках MQMD.ReplyToQ и MQMD.ReplyToQMgr входящего запроса. По умолчанию заголовок MQMD.CorrelId ответа заполняется значением заголовка MQMD.MsgId запроса (стандартное поведение, может быть изменено установкой параметра replyByCorrelId в true);

  • Для ответа на синхронный запрос из MQ тело ответа заменяется полученным от валидатора сообщением, заголовки не модифицируются;

  • Для вызовов по gRPC/HTTP ответ возвращается в вызове.

Вызов завершается штатно, исключение не вызывается.

Логирование и мониторинг#

Шлюз фиксирует в прикладном логе заголовок PATH и результат вызова валидатора. Тело сообщения по умолчанию не логируется (поведение можно изменить установкой параметра настройки loggingBody в true).

Шлюз отображает в метрике errors_gateways количество ошибок валидации и количество ошибок вызова валидатора раздельно по кодам 604 и 605 соответственно.

Ошибки валидации на Шлюзе:

ошибка

Описание

код

HTTP статус

gRPC статус

ошибка валидации сообщения

Сюда относятся только ошибки несоответствия сообщения его схеме, в случаях, когда информационный ответ об ошибке инициатору не возвращается

604

403 Forbidden

aborted

ошибка вызова валидатора (синхронные запросы и асинхронные вызовы)

Сюда относятся все ошибки вызова валидатора, при которых результат проверки остается неизвестным (транспортные ошибки включая тайм-ауты, внутренние ошибки валидатора)

605

502 Bad gateway Есть возможность повтора вызова через другой экземпляр Шлюза (если настроены повторы)

unavailable Есть возможность повтора вызова через другой экземпляр Шлюза (если настроены повторы)

ошибки вызова валидатора (ответы на синхронные запросы)

Сюда относятся все ошибки вызова валидатора, при которых результат проверки остается неизвестным (транспортные ошибки включая таймауты, внутренние ошибки валидатора)

605

400 Bad request Не выполняется повтор вызова, чтобы избежать дублирования запроса

internal Не выполняется повтор вызова, чтобы избежать дублирования запроса

Хранение секретов во внешнем хранилище#

При использовании внешнего хранилища (ВХС) для хранения секретов с конфиденциальными данными требуется синхронизация запуска приложения Шлюза и момента готовности файлов секретов к чтению со стороны приложения, так как подготовка и монтирование секретов начинается уже после запуска pod.

Для этого в Шлюзе реализован механизм ожидания готовности файлов конфигурации перед запуском приложения.

Для настройки механизма нужно добавить в проект configMap со списком секретов, которые нужно ждать.

kind: ConfigMap
apiVersion: v1
metadata:
  name: gateway-all-sp-secman
data:
  secman.txt: |-
    /mnt/secrets/cert.pem  #путь к файлу личного сертификата для SSL-подключения.
    /mnt/secrets/key.pem  #путь к файлу личного ключа для SSL-подключения.
    /mnt/secrets/root.pem  #путь к файлу доверенных сертификатов для SSL-подключения.
    # далее - стандартные пути секретов конфигураций, неизменяемые
    /deployments/config/masking/masking-secret.yml
    /deployments/config/validator/validator-secret.yml

и смонтировать в контейнер с приложением по пути /tmp/secman/config.

    spec:
      volumes:
        # подключение файла со списком путей к файлам, создание которых ожидается
        - name: secman-config
          configMap:
            name: gateway-all-sp-secman
            items:
              - key: secman.txt
                path: secman.txt
            defaultMode: 256
      containers:
          volumeMounts:
            - name: secman-config
              readOnly: true
              mountPath: /tmp/secman/config

Путь /tmp/secman/config, по которому должен быть смонтирован файл с конфигурацией, зафиксирован в образе Шлюза и не может быть изменен.

Добавить SE для ВХС. Также необходимо исправить параметр host в SE, в зависимости от стенда согласно таблице в инструкции

SE-secman.yaml

apiVersion: networking.istio.io/v1beta1
kind: ServiceEntry
metadata:
  name: se-secman
spec:
  exportTo:
    - .
  hosts:
    - t.secrets.domainname.ru
  location: MESH_EXTERNAL
  ports:
    - name: https-443
      number: 443
      protocol: HTTPS
  resolution: DNS

В deployment Шлюза добавляются аннотации и метки, обеспечивающие подключение vault-агента и монтирование секретов из него. Пример файла с необходимыми аннотациями и монтированиями:

Пример deployment

kind: Deployment
apiVersion: apps/v1
spec:
  template:
    metadata:
      labels:
        secman-injector: enabled #обеспечивает подключение vault-агента к подам
      annotations:
        # базовые аннотации
        sidecar.istio.io/inject: 'true'     #подключение Sidecar istio
        vault.hashicorp.com/agent-init-first: "false" # ОТКЛЮЧИТЬ (смонтировать секреты до запуска основного контейнера)
        vault.hashicorp.com/agent-inject: "true" # обеспечивает инъекцию init-контейнера и Sidecar Vault-Agent в поды Шлюза MQ
        vault.hashicorp.com/namespace: CIxxxxxxxx_CIxxxxxxxx #имя пространства в хранилище секретов формата CIxxxxxxxx_CIxxxxxxxx
        vault.hashicorp.com/agent-pre-populate: "false" #ОТКЛЮЧИТЬ (обеспечить наличие секретов до запуска основного контейнера_
        vault.hashicorp.com/role: ciNNNNNNNN_xxx # роль в SecMan, получаемая при подключении к хранилищу (по тикету в Jira)
        vault.hashicorp.com/agent-volumes-default-mode: "0400" # задание прав на созданные файлы с секретами в примонтированном EmptyDir
        vault.hashicorp.com/agent-inject-perms-<имя ресурса>: 0400 # задает права на примонтированный ресурс <имя ресурса>
        vault.hashicorp.com/agent-inject-containers: <имя контейнера приложения Шлюза> # ограничивает монтирование ресурсов только контейнером (контейнерами) из списка.
        vault.hashicorp.com/agent-run-as-same-user: "true" # запуск контейнера Vault-агента от имени того же пользователя, что и приложение в containers[0] 

        # подключение секрета настроек маскирования сообщений
        vault.hashicorp.com/secret-volume-path-masking-secret.yml: /deployments/config/masking # путь монтирования файла конфигурации маскирования из секрета
        vault.hashicorp.com/agent-inject-secret-masking-secret.yml: 'true' # признак монтирования секрета -vault.hashicorp.com/agent-inject-secret - статичная часть, masking-secret.yml - имя секрета
        vault.hashicorp.com/agent-inject-file-masking-secret.yml: masking-secret.yml # имя файла конфигурации маскирования из секрета, будет создан по пути выше
        vault.hashicorp.com/agent-inject-template-masking-secret.yml: |    # шаблон извлечения секрета конфигурации маскирования
        {{- with secret "CIxxxxxxxx_CIxxxxxxxx/x/xxxx/xxx/x/KV/secret_name" -}}   #полный путь к секрету в хранилище
          {{ .Data.masking }}                                                     #имя свойства секрета, в котором хранится значение секрета
        {{- end -}}

        # подключение секрета настроек валидатора
        vault.hashicorp.com/secret-volume-path-validator-secret.yml: /deployments/config/validator # путь монтирования файла конфигурации валидатора из секрета
        vault.hashicorp.com/agent-inject-secret-validator-secret.yml: 'true' # признак монтирования секрета -vault.hashicorp.com/agent-inject-secret - статичная часть, masking-secret.yml - имя секрета
        vault.hashicorp.com/agent-inject-file-validator-secret.yml: validator-secret.yml # имя файла конфигурации валидатора из секрета, будет создан по пути выше
        vault.hashicorp.com/agent-inject-template-validator-secret.yml: |    # шаблон извлечения секрета конфигурации валидатора
        {{- with secret "CIxxxxxxxx_CIxxxxxxxx/x/xxxx/xxx/x/KV/secret_name" -}}
          {{ .Data.validator }}
        {{- end -}}

        # подключение секрета файла доверенных сертификатов для ssl-соединения
        vault.hashicorp.com/secret-volume-path-root.pem: /mnt/secrets # путь монтирования файла из секрета
        vault.hashicorp.com/agent-inject-secret-root.pem: 'true' # признак монтирования секрета -vault.hashicorp.com/agent-inject-secret - статичная часть, root.pem - имя секрета
        vault.hashicorp.com/agent-inject-file-root.pem: root.pem # имя файла из секрета, будет создан по пути выше
        vault.hashicorp.com/agent-inject-template-root.pem: |   # шаблон извлечения секрета с декодированием из Base64
        {{- with secret "CIxxxxxxxx_CIxxxxxxxx/x/xxxx/xxx/x/KV/secret_name" -}}
          {{ base64Decode .Data.rootPem }}    #декодирование Base64 значения секрета
        {{- end -}}

        # подключение секрета файла личного сертификата для ssl-соединения
        vault.hashicorp.com/secret-volume-path-cert.pem: /mnt/secrets # путь монтирования файла из секрета
        vault.hashicorp.com/agent-inject-secret-cert.pem: 'true' # признак монтирования секрета -vault.hashicorp.com/agent-inject-secret - статичная часть, cert.pem - имя секрета
        vault.hashicorp.com/agent-inject-file-cert.pem: cert.pem # имя файла из секрета, будет создан по пути выше
        vault.hashicorp.com/agent-inject-template-cert.pem: |   # шаблон извлечения секрета с декодированием из Base64
        {{- with secret "CIxxxxxxxx_CIxxxxxxxx/x/xxxx/xxx/x/KV/secret_name" -}}
          {{ base64Decode .Data.certPem }}    #декодирование Base64 значения секрета
        {{- end -}}

        # подключение секрета файла личного ключа для ssl-соединения
        vault.hashicorp.com/secret-volume-path-key.pem: /mnt/secrets # путь монтирования файла из секрета
        vault.hashicorp.com/agent-inject-secret-key.pem: 'true' # признак монтирования секрета -vault.hashicorp.com/agent-inject-secret - статичная часть, key.pem - имя секрета
        vault.hashicorp.com/agent-inject-file-key.pem: key.pem # имя файла из секрета, будет создан по пути выше
        vault.hashicorp.com/agent-inject-template-key.pem: |   # шаблон извлечения секрета с декодированием из Base64
        {{- with secret "CIxxxxxxxx_CIxxxxxxxx/x/xxxx/xxx/x/KV/secret_name" -}}
          {{ base64Decode .Data.keyPem }}    #декодирование Base64 значения секрета
        {{- end -}}

Важно! Аннотация vault.hashicorp.com/agent-run-as-same-user: "true" требуется для корректного назначения прав на смонтированные Vault-агентом ресурсы.

После старта pod в логах образа Шлюза можно наблюдать счётчик времени ожидания, там же видно какие файлы ожидаются и какие из них найдены.

В Deployment Шлюза, должен быть задан минимальный уровень полномочий на монтируемые ресурсы.

Динамическая загрузка TLS сертификатов#

При изменении файлов секретов с хранилищами ключей внешней системой хранения сертификатов, Шлюз должен перечитать новые значения и использовать их для создания подключений.

Последовательность действий при обновлении сертификатов:

  1. Шлюз мониторит изменения (обновление, удаление, создание) файлов ключей и сертификатов (расположение файлов указывается в конфигурации).

  2. При наступлении события изменения файлов, Шлюз:

    • выдерживает паузу определяемую алгоритмом временного смещения для снижения коллизий (перекрытия по времени недоступности двух или более pods общего Deployment (см. ниже мониторинг каскадных перезапусков));

    • останавливает обработку сообщений;

    • останавливает все коннекты к брокерам MQ;

    • перечитывает файлы ключей и сертификатов;

    • восстанавливает коннекты с использованием новых ключей и сертификатов;

    • возобновляет обработку сообщений.

  3. Сообщения принятые по каналам HTTP и gRPC во время обновления сертификатов (с момента остановки обработки до ее возобновления) накапливаются в пуле потоков обработки, и обрабатываются после восстановления коннектов.

  4. Если пул потоков обработки исчерпан, а процедура обновления еще не завершена, новые входящие вызовы по каналам HTTP и gRPC будут отклоняться шлюзом, и средствами istio будет выполняться повтор вызова на другие pod-ы шлюза.

  5. Предусмотрена настройка, позволяющая задать состояние Readiness пробы на время проведения процедуры обновления. По умолчанию Readiness - проба не опускается. Снятие Readiness-пробы выводит шлюз из балансировки на время приостановки обработки. Это позволяет предотвратить повторы вызовов на уровне сервис меша и связанное с этим увеличение латентности в прикладных интеграциях.

Чтобы исключить существенное негативное влияние на поток, предусмотрен механизм, снижающий вероятность одновременного обновления ключей на нескольких экземплярах одного deployment приложения.

С этой целью Шлюз сдвигает начало применения новых сертификатов от момента изменения файлов хранилищ. Время сдвига определяется для каждого экземпляра независимо, по вероятностному алгоритму, который позволяет минимизировать количество коллизий перезапуска коннектов, но не исключает их полностью.

Описание алгоритма#

Алгоритм использует хэш от имени пода, распределенный по заданному количеству сегментов, для получения временного смещения начала перезапуска коннектов, относительно момента изменения файлов ключей и сертификатов.

Временное смещение определяется исходя из номера сегмента для конкретного пода и размера интервала обновления.

Интервал обновления — это время необходимое одному поду шлюза, для выполнения процедуры применения сертификатов

Произведение интервала обновления и количества сегментов дает общее время выполнения процедуры обновления сертификатов на deployment шлюза.

При уменьшении фактора репликации вероятность коллизий будет снижаться, при этом величина коллизий (количество подов одновременно начавших процедуру применения сертификатов) и общее время выполнения процедуры на deployment сохраняются.

Шлюз вносит дополнительную фиксированную временную задержку, задаваемую параметром mq.sslCertUpdate.certificateReloadDelay для того, чтобы при несинхронном изменении файлов ключей и сертификатов со стороны внешней системы хранения сертификатов исключить излишние повторы процедуры обновления.

Конфигурирование#

Для настройки алгоритма используются следующие параметры (mq.sslCertUpdate):

enable - включение(true)/выключение(false) механизма обновления сертификатов. Если установлено значение false, контроль за изменением файлов хранилища сертификатов отключается.

checkInterval - устанавливает периодичность проверки изменения файлов хранилища сертификатов.

downReadinessProbe - задает нужно (true), или не нужно (false) опускать Readiness-пробу на время выполнения обновления сертификатов. Если значение true, то Readiness-проба на каждом конкретном экземпляре шлюза будет переводиться в состояние down с момента остановки обработки сообщений до момента ее возобновления этим конкретным экземпляром.

intervalsNumber - количество интервалов (сегментов распределения). С его уменьшением вероятность коллизий будет увеличиваться. Можно уменьшить, если у deployment малый фактор репликации (количество запущенных подов < 5), чтобы уменьшить обще время выполнения процедуры замены сертификатов.

updateTimeInSeconds - Интервал обновления — время применения сертификатов для одного пода Шлюза. Нужно увеличивать, если у шлюза задано большое количество коннектов (очередей и брокеров), так как в этом случае отключение и подключение всех коннектов потребует больше времени. Пропорционально увеличивает общее время выполнения для deployment.

roundTimeInMinutes - интервал на который округляется (в большую сторону) момент изменения файлов хранилищ ключей. Это позволяет нивелировать временную разницу распространения обновленных файлов по нодам, и обеспечить независимые поды общей точкой отсчета для начала процедуры. Нужно увеличивать, если в проекте наблюдается значительный разброс времени распространения файлов по нодам. Приводит к сдвигу общего времени выполнения процедуры для deployment на величину roundTimeInMinutes.

certificateReloadDelay - Дополнительная фиксированная временная задержка, для того, чтобы при несинхронном изменении файлов ключей и сертификатов со стороны внешней системы хранения сертификатов исключить излишние повторы процедуры обновления.

Пример настройки (приведены значения по умолчанию):

mq:
  sslCertUpdate:
    enable: false
    checkInterval: 30000ms
    downReadinessProbe: false
    intervalsNumber: 20
    updateTimeInSeconds: 2
    roundTimeInMinutes: 10
    certificateReloadDelay: 30s
Обработка внештатных ситуаций#

В процессе обновления сертификатов возможно возникновение исключительных ситуаций:

  1. Файл хранилища был удален, но новый файл не был доставлен. В действующей реализации попытка прочитать реквизиты удаленного файла завершиться неудачей, шлюз продолжит работу со старыми сертификатами, и продолжит попытки проверить реквизиты файла. Когда будет смонтирован файл хранилища, то шлюз выполнит проверку реквизитов, и в случае их изменения обновит сертификаты.

  2. Новый файл хранилища поврежден (файл есть, но "битый"). При попытке загрузить новые сертификаты возникнет ошибка инициализации библиотек криптографии. Будет снята Readiness - проба, шлюз будет пытаться инициализировать библиотеку. После устранения ошибки будут загружены сертификаты, и восстановлена Readiness-проба.

  3. Сертификаты в новом файле хранилища не валидные. После обновления сертификатов возникнет ошибка установки соединения с менеджерами MQ. Readiness-проба будет снята. Шлюз будет пытаться установить соединение с менеджерами. После устранения ошибки подключения будут восстановлены, и Readiness-проба поднята.

Настройка регистрации событий аудита#

Шлюз позволяет фиксировать события аудита в локальном буфере аудита.

Перечень фиксируемых событий Аудита, которые возникают в процессе функционирования Шлюза:

Код

Событие

Комментарий

MQ_success

Успешное подключение к брокеру MQ

Фиксируется при каждом успешном подключении Шлюза к брокеру MQ. Для многоточечного подключения (один Шлюз к нескольким брокерам) фиксируется отдельное событие подключения к каждому брокеру MQ.

MQ_error

Ошибка подключения к брокеру MQ

Фиксируется при ошибке подключения Шлюза к брокеру MQ. Для многоточечного подключения события фиксируются для каждого подключенного брокера отдельно.

Параметры события#

Общие:

Код

Параметр

Комментарий

Время события

Время фиксируется по моменту возникновения события в конкретном экземпляре шлюза

Проект

Наименование проекта в Kubernetes с запущенным Pod шлюза, на котором произошло событие

Источник события

Имя Pod шлюза, на котором произошло событие

Имя Node

Имя Node, на которой запущен Pod шлюза

IP адрес Node

IP Node, на которой запущен Pod шлюза

Имя менеджера

не используется

Канал

не используется

Имя хоста

Имя хоста брокера, к которому выполнялось подключение

Номер порта

номер порта брокера, по которому выполнялось подключение

Схема шифрования

Схема шифрования указанная в настройках Pod шлюза

DN шлюза

DN сертификата шлюза из настроек

DN менеджера MQ

DN брокеров MQ из настройки allowedDNs конфигурации шлюза.

Описание ошибки

Для успешного подключения: пусто;
Для ошибки подключения: Текст ошибки вызванной при подключении.

Чтобы отправить событие аудита в ТС Аудит (AUDT) Platform V Audit SE, в нем предварительно должна быть зарегистрирована метамодель события.

Шлюз формирует метамодель в формате JSON:

{
    "metamodelVersion": "1",
    "module": "mq-gateway",
    "events": [
        {
            "name": "MQ_success",
            "description": "Успешное подключение к менеджеру MQ",
            "success": "true",
            "mode": "reliability",
            "params": [
                {
                    "name": "time",
                    "description": "Время события (timestamp)"
                },
                {
                    "name": "os_project",
                    "description": "Проект OpenShift"
                },
                {
                    "name": "event_source",
                    "description": "Имя Pod источника события"
                },
                {
                    "name": "node_name",
                    "description": "Имя Node для Pod источника события"
                },
                {
                    "name": "node_ip",
                    "description": "IP Node для Pod источника события"
                },
                {
                    "name": "mqm_name",
                    "description": "Имя менеджера к которому выполнялось подключение"
                },
                {
                    "name": "mqm_channel",
                    "description": "Имя канала по которому выполнялось подключение"
                },
                {
                    "name": "mqm_host",
                    "description": "Имя хоста менеджера к которому выполнялось подключение"
                },
                {
                    "name": "mqm_port",
                    "description": "Номер порта менеджера к которому выполнялось подключение"
                },
                {
                    "name": "cipher",
                    "description": "Используемая схема шифрования"
                },
                {
                    "name": "dn_mqgateway",
                    "description": "DN сертификата шлюза из настроек"
                },
                {
                    "name": "dn_mqm",
                    "description": "Ожидаемый DN менеджера MQ из настроек"
                },
                {
                    "name": "error_desc",
                    "description": "Описание ошибки"
                }
            ]
        },
        {
            "name": "MQ_error",
            "description": "Ошибка подключения к менеджеру MQ",
            "success": "false",
            "mode": "reliability",
            "params": [
                {
                    "name": "time",
                    "description": "Время события (timestamp)"
                },
                {
                    "name": "os_project",
                    "description": "Проект OpenShift"
                },
                {
                    "name": "event_source",
                    "description": "Имя Pod источника события"
                },
                {
                    "name": "node_name",
                    "description": "Имя Node для Pod источника события"
                },
                {
                    "name": "node_ip",
                    "description": "IP Node для Pod источника события"
                },
                {
                    "name": "mqm_name",
                    "description": "Имя менеджера к которому выполнялось подключение"
                },
                {
                    "name": "mqm_channel",
                    "description": "Имя канала по которому выполнялось подключение"
                },
                {
                    "name": "mqm_host",
                    "description": "Имя хоста менеджера к которому выполнялось подключение"
                },
                {
                    "name": "mqm_port",
                    "description": "Номер порта менеджера к которому выполнялось подключение"
                },
                {
                    "name": "cipher",
                    "description": "Используемая схема шифрования"
                },
                {
                    "name": "dn_mqgateway",
                    "description": "DN сертификата шлюза из настроек"
                },
                {
                    "name": "dn_mqm",
                    "description": "Ожидаемый DN менеджера MQ из настроек"
                },
                {
                    "name": "error_desc",
                    "description": "Описание ошибки"
                }
            ]
        }
    ]
}

Метамодель отправляется один раз при старте приложения.

Примеры событий в JSON - формате:

Успешное

{
    "module": "mq-gateway",
    "metamodelVersion": "1",
    "name": "MQ_success",
    "userNode": "NO-USERNODE",
    "userLogin": "NO-USER",
    "createdAt": "1234567890000",
    "session": "NO-SESSION",
    "userName": "",
    "tags": [
        "<project_name>",
        "<deployment_name>"
    ],
    "params": [
        {
            "name": "time",
            "value": "1234567890"
        },
        {
            "name": "os_project",
            "value": "ci01994970-idevgen2-synapse-esbub-dev"
        },
        {
            "name": "event_source",
            "value": "test-gw-56558d77b6-hcl9v"
        },
        {
            "name": "node_name",
            "value": "nodename.domainname.ru"
        },
        {
            "name": "node_ip",
            "value": "10.125.82.208"
        },
        {
            "name": "mqm_name",
            "value": "не используется"
        },
        {
            "name": "mqm_channel",
            "value": "не используется"
        },
        {
            "name": "mqm_host",
            "value": "amqps://hostname.domainname.ru"
        },
        {
            "name": "mqm_port",
            "value": "61617"
        },
        {
            "name": "cipher",
            "value": "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
        },
        {
            "name": "dn_mqgateway",
            "value": "CN=TEST-GW"
        },
        {
            "name": "dn_mqm",
            "value": "CN=SYNAPSE"
        },
        {
            "name": "error_desc",
            "value": ""
        }
    ]
}

Ошибка

{
    "module": "mq-gateway",
    "metamodelVersion": "1",
    "name": "MQ_error",
    "userNode": "NO-USERNODE",
    "userLogin": "NO-USER",
    "createdAt": "1234567890000",
    "session": "NO-SESSION",
    "userName": "",
    "tags": [
        "<project_name>",
        "<deployment_name>"
    ],
    "params": [
        {
            "name": "time",
            "value": "1234567890"
        },
        {
            "name": "os_project",
            "value": "ci01994970-idevgen2-synapse-esbub-dev"
        },
        {
            "name": "event_source",
            "value": "test-gw-56558d77b6-hcl9v"
        },
        {
            "name": "node_name",
            "value": "nodename.domainname.ru"
        },
        {
            "name": "node_ip",
            "value": "10.125.82.208"
        },

        {
            "name": "mqm_name",
            "value": "не используется"
        },
        {
            "name": "mqm_channel",
            "value": "не используется"
        },
        {
            "name": "mqm_host",
            "value": "amqps://hostname.domainname.ru"
        },
        {
            "name": "mqm_port",
            "value": "61617"
        },
        {
            "name": "cipher",
            "value": "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
        },
        {
            "name": "dn_mqgateway",
            "value": "CN=TEST-GW"
        },
        {
            "name": "dn_mqm",
            "value": "CN=SYNAPSE"
        },
        {
            "name": "error_desc",
            "value": "{errorCode=, reason=dial tcp 10.25.8.7:61619: connect: connection refused, linkedErr=dial tcp 10.25.8.7:61619: connect: connection refused}"
        }
    ]
}

Получение данных об имени проекта, имени Node и ее IP-адреса.

Чтобы приложение Шлюза получило доступ к этим данным, в deployment Шлюза должны быть добавлены следующие настройки:

env:
  - name: PROJECT_NAME
    valueFrom:
      fieldRef:
        apiVersion: v1
        fieldPath: metadata.namespace
  - name: NODE_NAME
    valueFrom:
      fieldRef:
        apiVersion: v1
        fieldPath: spec.nodeName
  - name: NODE_IP
    valueFrom:
      fieldRef:
        apiVersion: v1
        fieldPath: status.hostIP

Шлюз при заполнении данных о событиях должен передать в параметре os_project значение переменной окружения PROJECT_NAME, в параметре node_name значение переменной окружения NODE_NAME, в параметре node_ip значение переменной окружения NODE_IP.

Для включения регистрации событий, аудита нужно в конфигурацию Шлюза добавить секцию:

audit:
  enable: true
  transportType: file
  directory: /opt/synapse/logs

В этом случае Шлюз MQ при старте создает в каталоге, указанном в параметре directory два файла:

event.aud

metamodel.amm

В файл metamodel.amm однократно выгружается метамодель событий. В файл event.aud начинают выгружаться события аудита по мере их возникновения на Шлюзе.

Эту схему можно использовать, если при регистрации событий аудита не предполагается использовать ТС Аудит, либо передача событий в ТС Аудит должна выполняться сторонними компонентами, выбранными архитектором и разработчиком конечной системы.

Для прямой отправки событий в ТС Аудит, секцию audit нужно настроить следующим образом.

audit:
  enable: true
  transportType: http
  http:
    client:
      httpMethod: POST
      url: http://хост:порт
    eventPath: /event_endpoint
    metamodelPath: /metamodel_endpoint
    responseTimeout: 10000
    maxBufferSize: 3000
    retry:
      attempts: 10

При старте Шлюз подключится к endpoint ТС Аудит зарегистрирует метамодель и начнет отправку событий.

Одна и та же версия метамодели может регистрироваться произвольное количество раз, но при этом описатель метамодели не должен меняться. Поэтому версия метамодели вместе с самой метамоделью прошита в коде Шлюза и меняется только при перепоставке.

Это гарантирует, что Шлюзы одной и той же версии установленные в разных проектах всегда будут оправлять консистентную модель.

При возникновении ошибок отправки, Шлюз сохраняет событие в локальном буфере в памяти приложения и пытается отправить его повторно. Количество попыток настраивается в параметре audit.http.retry.attempt. Количество событий, которое может быть сохранено в буфере настраивается в параметре audit.http.maxBufferSize.

Если возникает ошибка при регистрации модели, то Шлюз повторяет попытки, пока модель не будет зарегистрирована, при этом readiness проба не поднимается, и перевод трафика на этот экземпляр Шлюза не происходит.

Маршрутизация gRPC вызовов в Шлюзе#

Маршрутизация в Шлюзе — это определение имени сервиса-получателя (точки назначения), которому необходимо направить gRPC-вызов с преобразованным в формат ProtoMessage входящим сообщением.

В Шлюзе реализована динамическая маршрутизация по гибким правилам на основании параметров входящего MQ-сообщения.

Механизм маршрутизации работает следующим образом:

В настройках Шлюза в блоке gRPC прописывается наименование сервиса-заглушки empty-service.

grpc:
  client:
    settings:
      default:
        hostname: empty-service
        port: 5454

При выполнении gRPC-вызова он перенаправляется механизмами Kubernetes в сервис, имя которого задано в параметре вызова Authority.

Шлюз позволяет динамически задать значение этого параметра при вызове, применяя правила, заданные в конфигурации Шлюза к параметрам (элементам тела и транспортным заголовкам) входящего сообщения.

Правила определения Authority задаются в конфигурации Шлюза в блоке routing.

Процесс маршрутизации сообщения состоит из нескольких шагов:

Шаг 1. Определение имени маршрута#

Правила определения имени маршрута задаются в секции routeName блока routing.

Секция определения имени маршрута (routeName):

routing:
  routeName:
    valueFrom:
      - type: fromRfh2Header
        value: OperationName
      - type: fromBody
        value: local-name(/*)
      - type: fromConst
        value: SomeServiceRq
    expr: value[0:len(value)-2]
  routeList:
...

В этой секции задается список правил, каждое правило состоит из пары type и value.

type - определяет источник, из которого будет извлечено значение. value - определяет правило извлечения значения. Для различных type возможные варианты значений value различны.

Для type= fromBody есть дополнительный тег valueJson, в котором можно задать выражение JsonPath для работы с сообщениями в формате JSON.

Возможные варианты:

type

описание

Значения value

fromHeader

значение извлекается из блока системных заголовков.

value должно содержать название системного заголовка, из которого будет взято значение

fromRfh2Header

значение извлекается из блока пользовательских заголовков.

value должно содержать название пользовательского заголовка, из которого будет взято значение

fromBody

значение будет извлечено из тела сообщения.

value должно содержать XPath * запрос, которым из тела сообщения будет получено значение. Работает только с сообщениями в формате XML
valueJson должно содержать JsonPath запрос, которым из тела сообщения будет получено значение. Работает только с сообщениями в формате JSON

fromConst

значение задается константой непосредственно в конфигурации.

value должно содержать непосредственно нужное значение

* При вычислении значений на основе содержимого тела XML-сообщения, Шлюз MQ может работать в одном из двух режимов: DOM или SAX. Режим может быть задан в параметре mq.typeParser конфигурации Шлюза MQ. По умолчанию используется значение DOM. Режим SAX более экономный в отношении использования ОЗУ, но ограничивает возможность задания value тремя типами выражений:

  • local-name(/*) — получение имени корневого тега XML-сообщения

  • //tagName — получение значения элемента с именем tagName, если он встречается на любом уровне вложенности в сообщении. Возвращается значение первого найденного с таким именем элемента.

  • //tagName/@attributeName — получение значения атрибута attributeName элемента tagName, если они встречаются на любом уровне вложенности сообщения. Возвращается значение для первого найденного с таким сочетанием имен аттрибута.

Для повышения гибкости определения маршрута в секции routeName есть параметр expr:, в нем можно задать выражение для дополнительной коррекции полученного значения. Обращение к найденному значению выполняется через предопределенную переменную value.

Например, выражение value[0:len(value)-2] позволяет обрезать два последних символа в полученном значении.

Шлюз применяет правила к входящему сообщению по порядку их следования в конфигурации, до тех пор, пока не будет получено ненулевое значение. Поэтому правило c типом fromConst следует ставить в конце списка.

К найденному значению Шлюз применяет выражение заданное в expr:

Полученное в результате этих действий значение и будет являться именем маршрута routeName.

Пример:

Настройки Шлюза заданы как указано выше.

Если сообщение содержит Property с ключом OperationName и значением "OneServiceNameRq", а тело сообщения содержит блок:

    <Message>
      <RqUID>4382730B7D4111ebB66EFA163E29F519</RqUID>
      <RqTm>2021-03-05T08:44:09.000+00:00</RqTm>
      <Mode>Async</Mode>
...

В routeName будет получено значение: OneService.

Шаг 2. Поиск блока настроек в списке маршрутов routeList#

Полученное на предыдущем шаге имя маршрута сопоставляется со списком элементов следующей секции блока routing - routeList.

Секция правил определения Authority (routeList)

  routeList:
    - routeName: AnotherService
      destinationExpression: 'system1-anotherservice-system2-rs'
    - routeName: default
      destinationExpression:  variables['SCName'] + '-' + variables['ServiceName'] + '-' + variables['SPName']
      variables:
        - name: ServiceName
          valueFrom:
            - type: fromBody
              value: local-name(/*)
          expr: value[0:len(value)-2]
        - name: SCName
          valueFrom:
            - type: fromRfh2Header
              value: SCName
            - type: fromConst
              value: 'System1'
          expr: toLower(value)
        - name: SPName
          valueFrom:
            - type: fromRfh2Header
              value: SPName
            - type: fromBody
              value: //SystemID
          expr: value+'-rs'
      destinations:
        'system1-someservice-system2-rs': 'system1-someservice-system2-async-rs'

Каждый элемент этой секции содержит именованный набор правил вычисления Authority сервиса назначения и состоит из параметров:

параметр

описание

routeName

Имя маршрута, сопоставляется с полученным значением routeName

destinationExpression

Задает выражение, для непосредственного вычисления Authority из элементов variables

variables

задает список именованных переменных, используемых в destinationExpression, и правил определения их значений.
Правила аналогичны используемым для определения routeName

destinations

список соответствия вычисленных значений зафиксированным в этом списке. Позволяет при необходимости полученное значение другим

Если в списке routeList найден блок с именем, соответствующим полученному routeName, то он используется для определения Authority.

Если нужный routeName не найден, но задан блок с routeName: default, то для определения Authority будет использован блок default. Если и блок default не задан, то будет сгенерировано исключение.

Шаг 3. Определение значений переменных#

Шлюз вычисляет значения всех переменных, описанных в списке variables. Каждый элемент списка variables содержит имя (name), список правил вычисления (type, value) и дополнительное выражение (expr).

      variables:
        - name: ServiceName
          valueFrom:
            - type: fromBody
              value: local-name(/*)
          expr: value[0:len(value)-2]
        - name: SCName
          valueFrom:
            - type: fromRfh2Header
              value: SCName
            - type: fromConst
              value: 'System1'
          expr: toLower(value)

Принцип применения type, value и expr был детально рассмотрен выше, при описании вычисления routeName. Например, для приведенного примера значение параметра variables['ServiceName'] будет взято из корневого тега сообщения с обрезанием двух последних символов.

Шаг 4. Определение destinationExpression#

Полученные на шаге 3 значения параметров Шлюз подставляет в выражение заданное в destinationExpression и вычислив его получает Authority вызываемого сервиса.

В частном случае destinationExpression может быть задано константой.

Шаг 5. Подстановка#

В блоке правил может быть задан список destinations.

      destinations:
        'system1-someservice-system2-rs': 'system1-someservice-system2-async-rs'

Если он задан, Шлюз производит в нем поиск по наименованию значения, полученного на шаге 4. Если поиск успешен, то Шлюз производит замену Authority на значение из найденного элемента. Если список destinations не задан или поиск в нем неудачен, используется значение, полученное на шаге 4.

Шаг 6. Выполнение вызова#

Шлюз выполняет вызов сервиса по найденному Authority.

Примечание#

Прочие секции настроек блока routing кроме приведенных здесь на маршрутизацию сообщений не влияют.

Синтаксис Expression#

Поскольку строка в goel - это массив символов, а не объект, для обработки нужно использовать функции и/или операторы, а не методы.

функции

Комментарий

toLower(value)

Преобразовать к нижнему регистру

toUpper(value)

Преобразовать к верхнему регистру

'<строка>'==value

Сравнение строк

len(ServiceName)

Получение длины строки

ServiceName[0:len(ServiceName)-2]

Выделение подстроки

value contains '<строка>'

проверка, что переменная содержит строку

indexOf(value,'<строка>')

определение позиции подстроки в строке

replace(value,'-','',<количество>)

Замена одной подстроки другой

split(value,'-')[1]

поделить строку на подстроки с использованием разделителя

'TB'+intToStr(strToInt(variables['Id1'])+1)

конкатенация строки строкового представления целого значения с инкрементом

strToInt(variables['Id1'])

преобразование строки в целое число

inc(strToInt(variables['Id1']),1)

инкремент

dec(strToInt(variables['Id1']),1)

декремент

coalesce(variables['Id1'],variables['Id2'],'0');

проверка на пустое значение

Реализация на Go поддерживает тернарный оператор.

Выражения:

SCName+'-'+ServiceName[0:len(ServiceName)-2]+'-'+SPName

"variables['SCName'] + '-' + 'srv' + variables['ServiceName'][0:len(ServiceName)-2] + '-' + variables['SPName']"

destinationExpression: '"ufsfl-srvgetcarddeliverystatus-oddo-rq"'

destinationExpression: "'ufsfl-srvgetcarddeliverystatus-oddo-rq'"

destinationExpression: ('ufsfl-srvgetcarddeliverystatus-oddo-rq')

"'<строка>' == toLower(value) ? '<строка 1>':value"

будут работать в реализации на Golang.

Спецификация интерфейсов#

Интерфейс транспортной библиотеки (Artemis - AMQP)#

Структура native-сообщения Artemis имеет ограниченный набор предопределенных заголовков, и список пользовательских свойств произвольного размера. Детально использование брокеров Artemis описано в документации Apache ActiveMQ Artemis.

Кодировка сообщений#

Artemis не обеспечивает механизма перекодирования сообщений и не имеет зарезервированного заголовка для передачи кодовой страницы.

Шлюз при работе с брокером Artemis обеспечивает передачу сообщений только в кодировке UTF-8.

Протокол обмена#

Шлюз, подключается к брокерам Artemis с использованием протокола AMQP. Спецификация протокола приведена в стандарте Advanced Message Queueing Protocol (AMQP) v1.0

Заголовки AMQP - Artemis#

Заголовок (Header)/Свойство (property) Artemis

Комментарий

header userID

UserID, который в Artemis выполняет функцию уникального идентификатора сообщения имеет формат UUID. При попытке отправить в очередь сообщение с несовместимым идентификатором, клиентская библиотека вызовет исключение.

property CorrelationID

Корреляционный идентификатор сообщения, формат - String

header priority

Приоритет обработки сообщения

header durable

Персистентность сообщения, durable = false - неперсистентное сообщение, durable = true - персистентное.

header expiration

Момент времени, после которого сообщение считается просроченным

header type

тип сообщения (text, byte, map, stream, object)

header timestamp

Время помещения сообщения в очередь

header redelivered

Признак повторной доставки сообщения.

header deliveryCount

Количество повторов доставки. Присутствует в свойствах сообщения после переноса в DeadLetterQueue

property groupID (_AMQ_GROUP_ID)

ID группы сообщений

property groupSequence (_AMQ_GROUP_SEQUENCE)

Номер сообщения в группе

Properties

Прочие пользовательские свойства сообщения Artemis доступны через JMS интерфейс как пользовательские свойства JMS

Annotations

Сообщения в Artemis могут аннотироваться. Например, при перемещении в ExpiryQueue в сообщении проставляются аннотации с исходным именем очереди и исходным expiry.

Интерфейс gRPC#

Для выполнения вызовов внутри кластера используется протокол gRPC поверх HTTP/2.

Для определения интерфейса и генерации API использован Protobuf:

syntax = "proto3";

import "google/protobuf/any.proto";

package com.sbt.synapse.gateway;

option java_package = "com.sbt.synapse.gateway.protobuf";
option java_outer_classname = "MessageService";

service MessageAsyncChannel {
    rpc processMessage (ProtoMessage) returns (Heartbeat);
}

service MessageSyncChannel {
    rpc processMessage (ProtoMessage) returns (ProtoMessage);
}

message ProtoMessage {
    string messageId = 1;
    string correlationId = 2;
    string body = 14;
    map<string, string> systemHeaders = 3;
    map<string, string> userHeaders = 4;
    google.protobuf.Any extension = 15;
}

message Heartbeat {
    int64 timestamp = 1;
    string messageId = 2;
}

package com.sbt.synapse.gateway.mq;

message MqMessageInformation {
    enum DeliveryMode {
        UNKNOWN_MODE = 0;
        NON_PERSISTENT = 1;
        PERSISTENT = 2;
    }
    enum MessageType {
        UNKNOWN_TYPE = 0;
        REQUEST = 1;
        REPLY = 2;
        REPORT = 4;
        DATAGRAM = 8;
    }
    MessageType messageType = 1;
    int32 priority = 2;
    DeliveryMode deliveryMode = 3;
    int64 expiry = 4;
    string destinationQueue = 5;
    string destinationManager = 6;
    string sourceQueue = 7;
    string sourceManager = 8;
    string jmsType = 9;
}

Параметры gRPC вызова:

Запрос

Параметр

Описание

:method

POST

:scheme

"http"/"https"

:path

Имя сервиса/имя метода описанное в схеме

:authority

Виртуальное имя вызываемого хоста

grpc-timeout

Тайм-аут вызова

content-type

"application/grpc"

grpc-message-type

Название типа схемы сообщения

Ответ

Параметр

Описание

:status

HTTP-статус вызова

grpc-status

gRPC-статус вызова

grpc-message

Описание к статусу

Метаданные gRPC вызова:

Заголовок

Описание

Обязательны для трассировки сообщений. Если не заполнены — генерируются внутренним прокси

x_request_id

Уникальный идентификатор сообщения.
Формат: GUID.
Генерируется Envoy'ем, если запрос еще не имеет такого заголовка.

x_b3_traceid

Уникальный идентификатор Trace'а.
Формат: строка с Hex-представлением 64- или 128-битного целого числа.
Генерируется Envoy'ем, если запрос еще не имеет такого заголовка.

x_b3_spanid

Уникальный идентификатор Span'а.
Формат: строка с Hex-представлением 64-битного целого числа.

x_b3_parentspanid

Уникальный идентификатор родительского Span'а.
Формат: строка с Hex-представлением 64-битного целого числа.

x_b3_sampled

Признак семплирования запроса – если <<1>>, то трассировка этого запроса должна быть отправлена в систему сбора информации.

x_b3_flags

Дополнительные флаги

Используются на прикладном уровне.

x-synapse-status-code

Возвращаемый статус код. Включается в трассировку

x-synapse-status-desc-bin

Описание статуса. Включается в трассировку

x-synapse-messageid

Идентификатор сообщения. Включается в трассировку

x-synapse-corellationid

Корреляционный идентификатор. Включается в трассировку

x-synapse-rquid

RqUID. Включается в трассировку

x-synapse-rquid-bin

RqUID. Используется, если RqUID содержит символы не из ASCII набора (например кириллицу). При заполнении значение упаковывается в BASE64. Включается в трассировку.

x-synapse-rqtm

RqTm. Включается в трассировку

x-synapse-spname

Идентификатор поставщика сервиса. Включается в трассировку

x-synapse-scname

Идентификатор потребителя сервиса. Включается в трассировку

x-synapse-servicename

Наименование сервиса. Включается в трассировку

x-synapse-operationname

Наименование операции

x-synapse-from

Источник сообщения

x-synapse-type-message

Тип сообщения Запрос/Ответ (Rq/Rs) для асинхронных интеграционных взаимодействий

x-synapse-monitoring-notification

Признак нотификации

x-synapse-serviceversion

Версия сервиса. Включается в трассировку

x-synapse-from-pod-name

Имя pod источника сообщения

x-synapse-propagate

Признак необходимости отправки нотификации

x-synapse-logging-system-name

Необязательные. Используются для корректировки параметров исходящего сообщения

x-synapse-override-clear-correlationid

Исключает CorrelationID из сообщения (true/false)

x-synapse-override-destination-queue

Заменяет очередь назначения

x-synapse-override-expiry

Заменяет JMSExpiration. Указывается в миллисекундах

x-synapse-override-jmstype

Заменяет JMSType в Jms сообщении

x-synapse-override-persistence

Заменяет персистентность (Режим доставки) сообщения (0 = UNKNOWN_MODE; 1 = NON_PERSISTENT; 2 = PERSISTENT)

x-synapse-override-priority

Заменяет приоритет сообщения

x-synapse-override-replytoq

Заменяет очередь для ответа

x-synapse-override-replytoqmgr

Заменяет менеджер для ответа

Интерфейс HTTP#

Для выполнения вызовов используется протокол HTTP/1.1. Тип вызова — синхронный.

Параметры вызова (используется только метод POST):

Запрос

Параметр

Описание

Метод

POST

URI

Адрес вызываемого ресурса

Протокол

HTTP/1.1

Host

Имя хоста

Content-Type

Тип тела запроса

Content-Length

Длина тела запроса

Ответ

Параметр

Описание

Протокол

HTTP/1.1

HTTP-status

Статус вызова

Status

Описание статуса

Content-Type

Тип тела ответа

Content-Length

Длина тела ответа

Тело сообщения:

Текстовое, в формате XML.

Пользовательские заголовки вызова:

Специальных требований к наличию дополнительных заголовков не предъявляется.

Состав используемых заголовков определяется индивидуально для каждого прикладного интеграционного взаимодействия и задается в конфигурации.

Преобразование интерфейсов#

Преобразование интерфейса AMQP-Artemis в gRPC (чтение сообщения из MQ)#

При трансляции JMS-сообщения в gRPC вызов поля структуры ProtoMessage заполняются по следующим правилам:

| Структура | Поле | Тип | Источник значения | Комментарий | |----------------------|------------------------------------------------------|------------------------------|--------------------------------------------------------------| |ProtoMessage|messageId | | userID | Уникальный идентификатор полученного сообщения | |ProtoMessage|correlationId | | CorrelationID | Корреляционный идентификатор полученного сообщения | |ProtoMessage|body | | body | Тело текстового сообщения копируется без преобразования.
Сообщение типа массив байтов преобразуется в строку | |ProtoMessage|systemHeaders
| <string, string>
… | properties … | В цикле добавляются свойства (Property) сообщения имеющие префикс "JMS" в названии.
key заполняется названием свойства. | |ProtoMessage|userHeaders | <string, string>
… | properties … | В цикле добавляются свойства (Property) сообщения не имеющие префикса "JMS" в названии.
key заполняется названием свойства. | |ProtoMessage|extension (<MqMessageInformation> extension)|messageType | property "JMS_IBM_MsgType", если не задано, то 0 | Тип сообщения. Не используется в Artemis | |ProtoMessage|extension (<MqMessageInformation> extension)|priority | priority | Приоритет сообщения. | |ProtoMessage|extension (<MqMessageInformation> extension)|deliveryMode | durable | Признак персистентности сообщения | |ProtoMessage|extension (<MqMessageInformation> extension)|expiry | expiration - timestamp | Время жизни сообщения в миллисекундах. Пересчитывается из TTL | |ProtoMessage|extension (<MqMessageInformation> extension)|destinationQueue | - | Наименование MQ-очереди в которую выходной Шлюз должен отправить сообщение. При чтении сообщения из очереди не заполняется | |ProtoMessage|extension (<MqMessageInformation> extension)|sourceQueue | sourceQueue | Очередь из которой вычитано входящее сообщение. Задается Шлюзом | |ProtoMessage|extension (<MqMessageInformation> extension)|jmsType | type | Тип сообщения. |

Заголовки gRPC-вызова заполняются по следующим правилам:

Параметр

Источник значения

Комментарий

:method

POST

Используемый метод HTTP протокола

:scheme

"http"

Всегда используется HTTP, при необходимости использовать HTTPS для внутренних вызовов настраивается средствами Kubernetes ServiceMesh

:path

/com.sbt.synapse.gateway.MessageSyncChannel/processMessage для синхронного вызова
/com.sbt.synapse.gateway.MessageAsyncChannel/processMessage для асинхронного вызова

Имя сервиса/имя метода описанное в схеме

:authority

Задается по правилам маршрутизации

Виртуальное имя вызываемого хоста, вычисляется по правилам заданным в настройках destinationExpression, variables и destinations секции routing.routeList конфигурации Шлюза

grpc-timeout

Из настройки timeout секции grpc.client.settings конфигурации.

Таймаут вызова по gRPC

content-type

"application/grpc"

Тип контента

grpc-message-type

ProtoMessage

Название типа схемы сообщения

При синхронном вызове, когда ответ возвращается в той же сессии gRPC, в которой был получен запрос:

Заголовки gRPC-ответа заполняются по следующим правилам:

Параметр

Источник

Комментарий

:status

Заполняется Шлюзом

HTTP-статус вызова

grpc-status

Заполняется Шлюзом

gRPC - статус вызова

grpc-message

Заполняется Шлюзом

Описание к статусу

Метаданные gRPC-вызова заполняются по следующим правилам:

Заголовок

Источник значения

Комментарий

Обязательны для трассировки сообщений. Если не заполнены — генерируются внутренним прокси

x_request_id

Генерируется

Уникальный идентификатор сообщения. Формат: GUID. Генерируется Envoy'ем (внутренним прокси), если запрос еще не имеет такого заголовка.

x_b3_traceid

Генерируется

Уникальный идентификатор Trace. Формат: строка с Hex-представлением 64- или 128-битного целого числа. Генерируется Шлюзом, если установлена настройка generateXB3Headersв секции traсing конфигурации Шлюза, если установлена настройка generate128bitTraceId генерируется в 128-битном формате. Если генерация в Шлюзе отключена, то генерируется через Envoy.

x_b3_spanid

Генерируется

Уникальный идентификатор Span. Формат: строка с Hex-представлением 64-битного целого числа. Генерируется Шлюзом, если установлена настройка generateXB3Headers в секции traсing конфигурации Шлюза

x_b3_parentspanid

Генерируется

Уникальный идентификатор родительского Span. Формат: строка с Hex-представлением 64-битного целого числа. Генерируется Шлюзом, если установлена настройка generateXB3Headers в секции traсing конфигурации Шлюза

x_b3_sampled

1

Признак семплирования запроса — если <<1>>, то трассировка этого запроса должна быть отправлена в систему сбора информации. Устанавливается в 1, если установлена настройка generateXB3Headers в секции traсing конфигурации Шлюза

x_b3_flags

не заполняется на Шлюзе

Дополнительные флаги

Используются на прикладном уровне

x-synapse-status-code

Не заполняется в запросе

Возвращаемый статус код. Включается в трассировку

x-synapse-status-desc-bin

Не заполняется в запросе

Описание статуса. Включается в трассировку

x-synapse-messageid

protoMessage.getMessageId()

Идентификатор сообщения. Заполняется значением из ProtoMessage (см. блок заполнения ProtoMessage). Включается в трассировку

x-synapse-corellationid

protoMessage.getCorrelationId()

Корреляционный идентификатор. Заполняется значением из ProtoMessage (см. блок заполнения ProtoMessage). Включается в трассировку

x-synapse-rquid

Реквизит входящего сообщения

RqUID - уникальный ID запроса. Должен поставляться внешней АС. Порядок извлечения определяется настройкой tracingHeaders.x-synapse-rquid секции tracing конфигурации Шлюза. Включается в трассировку.

x-synapse-rquid-bin

Реквизит входящего сообщения

Аналогичен x-synapse-rquid но значение упаковывается в BASE64. Включается системой в трассировку.

x-synapse-rqtm

Реквизит входящего сообщения

RqTm - время запроса. Может поставляться внешней АС. Порядок извлечения определяется настройкой tracingHeaders.x-synapse-rqtm секции tracing конфигурации Шлюза. Включается в трассировку

x-synapse-spname

getSpName()

Идентификатор поставщика сервиса. Определяется настройкой variables секции routing.routeList конфигурации Шлюза. Включается в трассировку

x-synapse-scname

getSсName()

Идентификатор потребителя сервиса. Определяется настройкой variables секции routing.routeList конфигурации Шлюза. Включается в трассировку

x-synapse-servicename

Не заполняется на Шлюзе

Наименование сервиса. Включается в трассировку

x-synapse-operationname

getServiceName()

Наименование операции. Определяется настройкой variables секции routing.routeList конфигурации Шлюза. Включается в трассировку

x-synapse-from

getSystemName()

Источник сообщения. Заполняется значением настройки systemName секции mq конфигурации Шлюза

x-synapse-type-message

"RQ"

Тип сообщения Запрос/Ответ (Rq/Rs) для асинхронных интеграционных взаимодействий. Для Шлюза потребителя проставляется "RQ"

x-synapse-serviceversion

getServiceVersion()

Версия сервиса. Определяется настройкой variables секции routing.routeList конфигурации Шлюза. Включается в трассировку

x-synapse-from-pod-name

getCurrentPodName()

Имя Pod источника сообщения. Заполняется на Шлюзе именем собственного pod.

x-synapse-propagate

не заполняется на Шлюзе

Признак необходимости отправки нотификации

x-synapse-logging-system-name

Не заполняется на Шлюзе

Имя системы для записи в лог

Необязательные. Используются для корректировки параметров исходящего сообщения

x-synapse-override-clear-correlationid

Не заполняется на Шлюзе

Исключает CorrelationID из сообщения (true/false)

x-synapse-override-destination-manager

Не заполняется на Шлюзе

Заменяет менеджер назначения

x-synapse-override-destination-queue

Не заполняется на Шлюзе

Заменяет очередь назначения

x-synapse-override-expiry

Не заполняется на Шлюзе

Заменяет expiration Указывается в миллисекундах!!!

x-synapse-override-jmstype

Не заполняется на Шлюзе

Заменяет JMSType в сообщении

x-synapse-override-persistence

Не заполняется на Шлюзе

Заменяет персистентность (Режим доставки) сообщения (0 = UNKNOWN_MODE; 1 = NON_PERSISTENT; 2 = PERSISTENT)

x-synapse-override-priority

Не заполняется на Шлюзе

Заменяет приоритет сообщения

x-synapse-override-replytoq

Не заполняется на Шлюзе

Заменяет очередь для ответа

В конфигурации Шлюза можно дополнительно задать значение персистентности отправляемых сообщений по умолчанию:

  • mq.outbound.defaultPersistence (значения PERSISTENT/NON_PERSISTENT) для Шлюза в целом,

  • mq.outbound.serviceList[].overridePersistense (значения PERSISTENT/NON_PERSISTENT) для конкретного сервиса.

    Признак персистентности в отправляемом сообщении (deliveryMode) будет выставлен:

  • в соответствии с параметром overridePersistense на сервисе при его наличии;

  • иначе в соответствии с параметром defaultPersistence на Шлюзе, при его наличии;

  • иначе в соответствии с заголовком x-synapse-override-persistence при его наличии;

  • иначе в соответствии с заголовком ProtoMessage.extension.messageType.

Преобразование интерфейса gRPC в AMQP-Artemis (отправка сообщения в MQ)#

Параметры отправляемого сообщения

Источник

комментарий

body

ProtoMessage.body

Тело сообщения копируется в исходящее сообщение без преобразования

CorrelationID

ProtoMessage.correlationId

Корреляционный идентификатор сообщения. Если во входящем сообщении отсутствует или заполнен нулями, то не передается в исходящее сообщение

durable

ProtoMessage.extension.deliveryMode

Режим доставки. Если значение = 0, то не заполняется (определяется настройкой на целевой очереди)

destination

Настройка sendQueue
или ProtoMessage.extension.destinationQueue
или ProtoMessage.systemHeaders.get("ReplyToQ")

Назначение (Очередь, в которую должно быть помещено сообщение).
Если настройка sendToCustomDestination = false (по умолчанию, секция mq.connection конфигурации Шлюза), то задается из настройки sendQueue той же секции. В противном случае заполняется (в порядке приоритета):
Значением поля ProtoMessage.extension.destinationQueue;
если оно не задано, то значением системного заголовка ReplyToQ
если они не заданы, то задается из настройки sendQueue.

expiration

ProtoMessage.extension.expiry

Время жизни сообщения. Преобразуется из expiry в TTL

userID

ProtoMessage.messageId

Идентификатор сообщения

priority

ProtoMessage.extension.priority

Приоритет сообщения

ReplyTo

ProtoMessage. systemHeaders.get("ReplyToQ")

Назначение для ответа (Очередь, в которую должен быть помещен ответ на это сообщение)

timestamp

Проставляется MQ менеджером

Метка времени сообщения

type

-

Тип сообщения. Определяется классом отправляемого сообщения

systemKey

ProtoMessage. systemHeaders.get(systemKey)

В цикле добавляются все свойства из ProtoMessage.systemHeaders

В цикле добавляются все свойства из ProtoMessage.systemHeaders

userKey

ProtoMessage.userHeaders.get(userKey)

В цикле добавляются все свойства из ProtoMessage.userHeaders

В цикле добавляются все свойства из ProtoMessage.userHeaders

Подмена значений свойств сообщения с помощью заголовков gRPC-вызова.

Если во входящем вызове заданы определенные gRPC-заголовки, их значение переопределяет значение свойств отправляемого в MQ сообщения до его отправки, в порядке указанном в таблице:

Параметр сообщения

gRPC заголовок

Действие

priority

x-synapse-override-priority

Заменяет

durable

x-synapse-override-persistence

Заменяет

expiration

x-synapse-override-expiry

Заменяет

JMSType

x-synapse-override-jmstype

Заменяет

ReplyTo

x-synapse-override-replytoq

Заменяет

CorrelationID

x-synapse-override-clear-correlationid

Очищает

Формирование квитанции (HeartBeat) при получении асинхронного вызова#

При получении асинхронного вызова по gRPC Шлюз в ответ отправляет квитанцию (HeartBeat), содержащую информацию о статусе вызова.

Заголовки gRPC-ответа в этом случае заполняются по следующим правилам:

Параметр

Источник

Комментарий

:status

Заполняется Шлюзом

HTTP-статус вызова

grpc-status

Заполняется Шлюзом

gRPC-статус вызова

grpc-message

Заполняется Шлюзом

Описание к статусу

Поля сообщения HeartBeat заполняются по следующим правилам:

Поле структуры

Источник

Комментарий

Heartbeat

timestamp

int64

Системное время Шлюза

Метка времени ответа при вызове через MessageAsyncChannel. Проставляется на Шлюзе по системному времени

Heartbeat

messageId

string

userID

ID сообщения в ответе при вызове через MessageAsyncChannel. Проставляется на Шлюзе по userID отправленного сообщения.

Преобразование интерфейса AMQP-Artemis в HTTP при запросе со стороны внешней АС#

Параметры сообщения передаются в HTTP-вызов по следующим правилам:

Запрос:

Параметр

Описание

Комментарий

Метод

Настройка httpMethod

Вызываемый метод HTTP-протокола. Заполняется из настройки httpMethod секции http.client конфигурации Шлюза.

URI

Настройка url

Адрес вызываемого ресурса. Заполняется из настройки url секции http.client конфигурации Шлюза.

Протокол

HTTP/1.1

Сигнатура протокола.

Host

Настройка url

Имя хоста. Заполняется из настройки url секции http.client конфигурации Шлюза.

Content-Type

application/xml application/json

Тип тела запроса.

Content-Length

Задается Шлюзом

Длина тела запроса.

Система копирует тело запроса из входящего JMS-сообщения без преобразования на Шлюзе. Дополнительные заголовки HTTP добавляются системой в исходящий вызов, если установлена настройка mqHttpRequired в секции transform.mq-http конфигурации Шлюза, либо если по правилам роутинга определен тип транспорта - http, и для него заданы правила трансформации. В этом случае все заголовки, описанные в секции transform.mq-http.headers (либо по правилам трансформации, заданным в секции routing), будут добавлены к исходящему HTTP-вызову.

Важно! Все заголовки сообщения, которые необходимо передать в HTTP-вызов, должны быть явно заданы в правилах трансформации.

Существует ограничение для заголовков, для которых указано правило извлечения fromHeaders. Для них определен фиксированный набор ключей и правила сопоставления с JMS-заголовками.

Ключ

Источник

Комментарий

MQMD.MsgId

userID

Идентификатор сообщения.

MQMD.CorrelId

CorrelationID

Корреляционный идентификатор сообщения.

MQMD.ReplyToQ

ReplyToQ

Очередь для ответа.

MQMD.GroupId

groupID

Идентификатор группы сообщения.

MQMD.Priority

priority

Приоритет сообщения.

MQMD.Persistence

durable

Режим отправки.

MQMD.Expiry

expiration - timestamp

Время жизни сообщения.

MQMD.DestinationQueue

destination

Очередь назначения.

Преобразование интерфейса AMQP-Artemis в HTTP при ответе со стороны внешней АС#

Ответ:

Параметр

Описание

Комментарий

Протокол

HTTP/1.1

Сигнатура протокола

HTTP-status

Заполняется Шлюзом

Статус вызова

Status

Заполняется Шлюзом

Описание статуса

Content-Type

application/xml application/json

Тип тела ответа

Content-Length

Заполняется Шлюзом

Длина тела ответа

Тело запроса:

Система копирует тело запроса из входящего JMS-сообщения без преобразования на Шлюзе. Дополнительные заголовки HTTP добавляются системой в ответ по тем же правилам, что и при обработке запроса.

Преобразование интерфейса HTTP в AMQP-Artemis при запросе со стороны HTTP клиента и ответе со стороны HTTP сервиса#

Тело сообщения (Body):

Параметры сообщения

Источник

Комментарий

body

http.payload

Тело сообщения копируется в исходящее JMS-сообщение без преобразования

Система заполняет заголовки (Headers) из HTTP сообщения, если включена настройка httpMqRequired в секции transform.http-mq. Правила прописаны в секциях http-mq.mqmd и http-mq.usr. При этом используются ключи:

Параметры отправляемого сообщения

ключ настройки

Комментарий

CorrelationID

CorrelId

Корреляционный идентификатор сообщения.

durable

Persistence

Режим доставки.

destination

DestinationQueue

Назначение — очередь, в которую должно быть помещено сообщение. Заполняется значением, полученным по ключу DestinationQueue

expiration

Expiry

Время жизни сообщения.

userID

MsgId

Идентификатор сообщения.

ReplyToQ

ReplyToQ

Назначение для ответа — очередь, в которую помещается ответ на это сообщение. Заполняется значением, полученным по ключу ReplyToQ

timestamp

Заполняется брокером

Метка времени сообщения.

type

Не определено

Тип сообщения.

groupID

GroupId

Номер группы.

groupSeq

1

Номер сообщения в группе.

userKey

userkey

В цикл добавляются все значения, определенные по ключам. Ключи задаются в transform.http-mq.usr конфигурации Шлюза.

Важно! Все заголовки сообщения, которые необходимо передать из HTTP-вызова, должны быть явно заданы в правилах трансформации.

Полное описание настроек#

Важно! Строковые значения представляющие числовые величины рекомендуется заключать в кавычки, во избежание неявных преобразований типов при загрузке и чтении конфигурации.

Верхнеуровневые блоки настроек#

Название

Описание

Обязательность

grpc

Настройки gRPC-клиента/сервера

-

server

Настройки сервера

-

http

Настройки HTTP-транспорта

-

logger

Настройки прикладного журнала

-

transform

Описание преобразования HTTP-заголовков в формат MQ и обратно

-

mq

Настройки подключения к MQ

+

routing

Правила маршрутизации

+ Необязателен для синхронного Шлюза провайдера

tracing

Настройки трассировки

+

logging

Настройки журналирования

-

validator

Настройки подключения внешнего валидатора REQV

-

audit

Настройки отправки событий в аудит

cleanFDC

Настройки настройки механизма очистки .FDC файлов
(Не работает для Artemis так как не создаются .FDC файлы)

-

parser

Настройка разбора тела сообщения

-

refresh

Настройка параметров проверки файлов конфигурации на изменение

Блок grpc#

Настройки gRPC-клиента/сервера:

Поле

Тип

Описание

Обязательность

По умолчанию

client

GRpcClientProperties

Настройки клиента для gRPC API

+

server

GRpcServerProperties

Настройки сервера gRPC API

-

Тип grpc.GRpcClientProperties#

Настройки клиента gRPC API:

Поле

Тип

Описание

Обязательность

По умолчанию

settings

Map<String, ClientSettings>

Имя канала и соответствующие ему настройки. Предопределен канал: - default — для запросов без повторов (на уровне gRPC)

+

Тип grpc.ClientSettings#

Настройки gRPC-канала:

Поле

Тип

Описание

Обязательность

По умолчанию

hostname

String

Хост, к которому будет осуществляться запрос

-

empty-service

port

int

Порт подключения

+

5454

timeout

int

Тайм-аут запроса, мс
Если установить 0 - запрос будет выполнен без таймаута

-

300 000

Пример настройки секции client

 grpc:
  client:
    settings:
      default:
        hostname: localhost
        port: 5455
        timeout: 1000

Тип grpc.GRpcServerProperties#

Настройки сервера gRPC API:

Поле

Тип

Описание

Обязательность

По умолчанию

serverPort

int

Порт сервера gRPC API

-

6565

threadPool

ThreadPoolConfiguration

Настройки пула обработчиков запросов

-

maxMessageSizeInMb

int

Настройка максимального размера сообщения, передаваемого через gRPC, Мбайт

4

Тип grpc.ThreadPoolConfiguration#

Параметры pool потоков сервера gRPC. Предназначен для тонкой настройки.

Поле

Тип

Описание

Обязательность

По умолчанию

concurrentConsumers

int

Минимальное количество потоков, обрабатывающих запросы

-

1

maxConcurrentConsumers

int

Максимальное количество потоков, обрабатывающих запросы

-

5

threadKeepAliveSeconds

int

Время жизни потока после обработки последнего сообщения, с

-

60

rejectCapacity

int

Ограничение на число запросов в обработке. По умолчанию отключено. (Deprecated, рекомендуется использовать параметр concurrentLimiter) Используется для защиты от перегрузок. Если установлено значение больше нуля, то при его превышении будет генерироваться ошибка со статусом UNAVAILABLE. При таком коде ошибки Envoy по умолчанию повторяет вызовы – запрос уйдет на менее нагруженный pod

-

0

Пример настроек блока grpc

grpc:
  maxMessageSizeInMb: 4 - максимальный размер gRPC-сообщения
  server:
    serverPort: 5455
    threadPool:
      #ограничение запросов в обработке
      rejectCapacity: 500
      concurrentConsumers: 30
      maxConcurrentConsumers: 30
  client:
    settings:
      default:
        hostname: localhost
        port: 5454

Блок server#

Настройки сервера:

Поле

Тип

Описание

Обязательность

По умолчанию

systemName

String

Псевдоним системы-инициатора, используемый при фиксации HTTP-вызова в прикладном журнале. Используется для ведения журнала в HTTP-вызовах

-

REST

port

int

Порт, на котором запустится приложение

-

8080

uri

string

URI HTTP-сервиса, поднимаемого Шлюзом

-

convertRequired

boolean

Признак конвертации запросов из формата XML в JSON и обратно

-

true

maxHeaderLength

int

Только для реализации на Golang.
Максимальный размер буфера для заголовков HTTP-вызова.Задается в формате: <значение><единицы> (без пробела. Единицы: B, KB, MB)Если суммарный размер заголовков будет превышать заданное значение, будет вызвано исключение.

16KB

MaxRequestBodySize

int

Максимальный размер тела сообщения

-

concurrentLimiter

ConcurrentLimiter

Параметры ограничения одновременной обработки сообщений по http

Тип server.ConcurrentLimiter#

настройки ограничителя одновременной обработки сообщений по http

Поле

Тип

Описание

Обязательность

По умолчанию

enable

boolean

включен ли ограничитель

false

fixedLimit

int

кол-во одновременно выполняемых запросов

-

100

Блок http#

Настройки HTTP-транспорта:

Поле

Тип

Описание

Обязательность

По умолчанию

client

httpClientConfiguration

Настройки клиента HTTP

+

Тип httpClientConfiguration#

Настройки клиента HTTP:

Поле

Тип

Описание

Обязательность

По умолчанию

url

String

URL, по которому будет вызываться сервер

+

timeout

Long

Тайм-аут, мс

-

Без тайм-аута

httpMethod

enum

Тип метода, который будет использоваться при HTTP-вызове

-

POST

Блок logger#

Настройки ведения прикладного журнала:

Поле

Тип

Описание

Обязательность

headers

<String, List<ExtractionRule>>

Правила определения заголовков для ведения журнала. Доступны RqUID и OperationName. Будут записаны в соответствующие поля в прикладном журнале. Только для HTTP-вызовов

-

mask

LoggerMaskConfigurationProperties

Настройка правил маскирования элементов тела сообщения в прикладном журнале. Обычно настройка выносится в отдельный файл конфигурации masking-secret.yml, который загружается в секрет.

-

Тип LoggerMaskConfigurationProperties#

Настройки маскирования элементов тела сообщения при записи в прикладной журнал.

Поле

Тип

Описание

Обязательность

enabled

boolean

Включение/выключение маскирования

-

cardNumAttributes

Set<String>

Список наименований XML-атрибутов, в которых нужно замаскировать номер карты

-

cardNumElements

Set<String>

Список наименований XML и JSON-элементов, в которых нужно замаскировать номер карты

-

phoneNumAttributes

Set<String>

Список наименований XML-атрибутов, в которых нужно замаскировать номер телефона

-

phoneNumElements

Set<String>

Список наименований XML и JSON-элементов, в которых нужно замаскировать номер телефона

-

docNumAttributes

Set<String>

Список наименований XML-атрибутов, в которых нужно замаскировать номер паспорта

-

docNumElements

Set<String>

Список наименований XML и JSON-элементов, в которых нужно замаскировать номер паспорта.

-

fioAttributes

Set<String>

Список наименований XML-атрибутов, в которых нужно замаскировать ФИО

-

fioElements

Set<String>

Список наименований XML и JSON-элементов, в которых нужно замаскировать ФИО.

-

innAttributes

Set<String>

Список наименований XML-атрибутов, в которых нужно замаскировать ИНН.

-

innElements

Set<String>

Список наименований XML и JSON-элементов, в которых нужно замаскировать ИНН.

-

attributes

Set<String>

Список наименований XML-атрибутов, значение которых нужно полностью замаскировать.

-

elements

Set<String>

Список наименований XML и JSON-элементов, значение которых нужно полностью замаскировать.

-

elementsWithAttribute

HashMap<String, Set<String>>

Список карт наименований XML-элементов и их атрибутов, значения которых нужно полностью замаскировать. Используется, когда есть повторяющиеся наименования XML-атрибутов. Важно! Тег не может быть пустым. Добавление данного тега, не содержащего элементов и аттрибутов для маскирования, приведет к ошибке загрузки Шлюза.

-

elementByAttribute

HashMap<String, Set<String>>

Список карт наименований XML-атрибутов и их значений, значения элементов которых необходимо полностью замаскировать. Используется, когда есть повторяющиеся наименования XML-элементов и XML-атрибутов. Важно! Тег не может быть пустым. Добавление данного тега, не содержащего аттрибутов и их значений для маскирования, приведет к ошибке загрузки Шлюза.

-

Пример настроек маскирования

 logger:
  mask:
    enabled: true
    cardNumElements:
      - CardNum # Будет замаскировано значение элемента CardNum: <CardNum>44****9695</CardNum>
    elements:
      - Phone # # Будет замаскировано значение элемента Phone: <Phone>***********</Phone>
    elementsWithAttribute:
      ID:
        - Value
        - Name
      AccountNumber:
        - Value # Будет замаскировано значение аттрибута Value в элементе <AccountNumber Value=\"*******************\"></AccountNumber>
      TaxId:
        - Value
    elementByAttribute:
      type:
        - CardNum
        - DocNum
      item:
        - FIO # Будет замаскировано значение элементов, у которых аттрибут item имеет значение "FIO" <Value item="FIO">********** ******* ********</Value>

Шлюз позволяет осуществлять маскирование в экранированном XML. Пример маскирования экранированного XML

 Настройка:
    logger:
      mask:
        enabled: true
        phoneNumElements:
          - phone
        docNumElements:
          - doc
        fioElements:
          - Fio

Сообщение:

        <Root xmlns:hdr="http://example.com/ESB/mq/headers">
        &lt;hdr:ElementTest&gt;
        &lt;Contacts&gt;
        &lt;phone&gt;+7 (123) 456-78-90&lt;/phone&gt;
        &lt;/Contacts&gt;
        &lt;Passport&gt;
        &lt;doc&gt;9911 123456&lt;/doc&gt;
        &lt;/Passport&gt;
        &lt;/hdr:ElementTest&gt;
        </Root>

Отражение в прикладном журнале:
 <Root xmlns:hdr="http://example.com/ESB/mq/headers">        &lt;hdr:ElementTest&gt;        &lt;Contacts&gt;        &lt;phone&gt;+* (***) ***-78-90&lt;/phone&gt;        &lt;/Contacts&gt;       &lt;Passport&gt;        &lt;doc&gt;**** ****56&lt;/doc&gt;        &lt;/Passport&gt;        &lt;/hdr:ElementTest&gt;        </Root>

Блок transform#

Тип TransformConfig#

Описание преобразования HTTP-заголовков в формат MQ и обратно:

Поле

Тип

Описание

Обязательность

Динамические настройки

mq-http

MqHttpTransformConfig

Правила преобразования MQ-заголовков в HTTP-заголовки

+

+

http-mq

HttpMqTransformConfig

Правила преобразования HTTP-заголовков в MQ-заголовки

+

+

Тип MqHttpTransformConfig#

Правила преобразования MQ-заголовков в HTTP-заголовки:

Поле

Тип

Описание

Обязательность

По умолчанию

headers

Map<String, List<ExtractionRule>>

Список заголовков с правилами преобразования

+

Пример настроек MQ-HTTP

 mq-http:
  headers:
    MsgType:
      type: fromConst
      value: '8' #DATAGRAM(8)
    MsgId:
      type: fromHeader
      value: 'MQMD.MsgId' #Из входящего ProtoMessage будет взят messageId и помещен в HttpMessage в заголовок MsgId

Тип HttpMqTransformConfig#

Правила преобразования MQ-заголовков в HTTP-заголовки:

Поле

Тип

Описание

Обязательность

По умолчанию

mqmd

Map<String, List<ExtractionRule>>

Список mqmd-заголовков с правилами преобразования

-

usr

Map<String, List<ExtractionRule>>

Список usr-заголовков с правилами преобразования

-

Пример настроек HTTP-MQ

 http-mq:
  mqmd:
    MsgId:
      type: fromHeader
      value: 'MsgId'
    MsgType:
      type: fromConst
        value: '8'
    Persistence:
      type: fromConst
      value: '1'
    ReplyToQ:
      - type: fromHeader
        value: ReplyToQ  # можно задать очередь для ответа
    DestinationQueue: # так можно задать очередь, в которую нужно отправить сообщение (если sendToCustomDestination: true)
      - type: fromHeader
        value: DestinationQueue
  usr:
    ServiceName:
      type: fromConst
      value: 'TestServiceName'

Блок mq#

Блок настроек в части MQ.

Поле

Тип

Описание

Обязательность

По умолчанию

Версия Шлюза, в которой появилось поле

Динамические настройки

typeMQ

String

Используемый провайдер MQ (поддерживается только ActiveMQ Artemis)

+

ARTEMIS_MQ

systemName

String

Имя системы, с которой осуществляется взаимодействие

+

typeParser

Enum

DOM/SAX Задает тип парсера для обработки XML. Используется для вычисления значений через Xpath. Менее требовательный к памяти SAX. При использовании SAX-парсера есть ограничения на использование Xpath-выражений. Допускаются:
local-name(/*)
//tagName
//tagName/@attributeName

DOM

3.11.0

systemType

Enum

Тип Шлюза: Шлюз потребителя или Шлюз поставщика. Значения: sp, sc, all

+

workMode

String

Режим работы Шлюза: поддерживается только совмещенный синхронный и асинхронный (all) режим работы

+

connection

GlobalConnectionConfiguration

Настройки подключения к MQ

+

sslConfigs

List<SslConfig>

Список настроек SSL для соединений из настройки connections

-

consumerParams

ConsumerConfiguration

Параметры считывания сообщений из MQ. Не используется при systemType=sp и синхронных запросах, см. следующий блок syncReceiver

-

syncReceiver

SyncReceiveTaskConfig

Параметры настройки сервиса получения ответов из MQ. Используется только при systemType=sp и синхронных запросах

-

rollbackIfError

boolean

Включает режим отката сообщения при ошибке. Шлюз вызывает синхронно Async и Sync интерфейс gRPC и, в случае ошибки, делает возврат считанного сообщения в очередь

-

false

outbound

OutboundMqConfiguration

Параметры для исходящих в MQ сообщений

-

+

concurrentLimiter

ConcurrentLimiterConfig

Параметры ограничения одновременной обработки считанных сообщений

-

+

rateLimiter

RateLimiterConfig

Параметры ограничения скорости обработки считанных сообщений

-

+

MaxMsgLength

Int

Ограничение размера обрабатываемых сообщений, получаемых из MQ.

-

100

MaxMsgHeaderLength

String

Задает размер памяти пользовательских заголовков, которые может вычитать шлюз (реализовано только в Go). Формат задаваемых значений: 1KB / 1MB / 1GB

-

1KB

concurrentLimiterSyncCall

LimiterSyncCall

Параметры ограничения одновременной обработки синхронных вызовов

-

concurrentLimiterSend

ConcurrentLimiterSendConfig

Параметры ограничения отправки в MQ

-

sslCertUpdate

SslCertUpdate

Параметры обновления SSL сертификатов

-

Тип mq.GlobalConnectionConfiguration#

Настройки MQ:

Поле

Тип

Описание

Обязательность

По умолчанию

Версия Шлюза, в которой появилось поле

Динамические настройки

connections

List<ConnectionConfiguration>

Список соединений

receiveQueue

List<String>

Список имен очередей для чтения в режимах (workMode): sync, async, all. В режиме all сообщения из этих очередей будут обрабатываться асинхронно. Для синхронных запросов очереди для считывания ответов будут определяться в приоритете через заголовок с именем ReplyToQ. workMode == all. Для синхронного поставщика очередь по умолчанию задается параметром mq.sync-receiver.defaultReceiveQueue. Если параметры receiveQueue и receiveQueueSync не заданы, то Шлюз работает только на отправку сообщений в MQ (Нотификация). Тем не менее чтение синхронных ответов продолжает работать

-

receiveQueueSync

List<String>

Список очередей для чтения сообщений для потребителя в режиме all. Вызов по gRPC выполняется синхронно!

-

sendQueue

String

Очередь для отправки сообщений. Может быть переопределено: - через заголовок x-synapse-override-destination-queue (см. Проставление MQ-заголовков для сервисов без трансформации); - через destinationQueue из ProtoMessage (см. sendToCustomDestination)

-

+

listReceiveQueue

List<ParamQueue>

Очереди для чтения в режиме ALL (поставщик+потребитель)

-

defaultSendQueues

SendQueues

Очереди по умолчанию для отправки в режиме ALL (поставщик+потребитель)

-

sendToCustomDestination

boolean

Если true, сообщение будет отправлено в очередь, указанную в поле destinationQueue ProtoMessage. Если false — в очередь, указанную в настройке sendQueue Шлюза

-

false

+

restoreGroupIdFromUsr

boolean

Установка параметров групповых сообщений в отправляемом сообщении, из UserHeaders ProtoMessage. Устанавливаются заголовки с именами: JMSXGroupID, JMSXGroupSeq, JMS_IBM_Last_Msg_In_Group (при наличии)

-

false

shareConvAllowed

boolean

Включение использования одного сокета для нескольких MQ-сессий.
При подключении к нескольким брокерам отключать разделение сессий не рекомендуется (особенно для синхронного режима), так как это приводит к существенному увеличению потребления ресурсов — создаются дополнительные сетевые потоки, увеличивается (существенно) потребление памяти и CPU.

true

health

HealthConfiguration

Настройки проверки доступности брокеров MQ
Не выполняется по брокерам, отключенным настройкой disabledManagerIds

-

senderCacheSize

int

Размер кэша Sender влияет на ТПС и скорость восстановления соединения. Должен соответствовать настройке grpc.ThreadPoolConfiguration.maxConcurrentConsumers ± 10%

-

10

Тип ConnectionConfiguration#

Поле

Тип

Описание

Обязательность

По умолчанию

url

String

url подключения в формате <протокол>://<имя хоста>:<порт>,
где <протокол> — amqp для подключений без SSL, amqps для подключений с SSL

+

username

String

username брокера

-

password

String

password брокера

-

sslConfigName

String

Название профиля конфигурации SSL, который будет применен к этому соединению. Сопоставляется с именем из SslConfig

-

default

Тип SslConfig#

Поле

Тип

Описание

Обязательность

По умолчанию

sslConfigName

String

Имя профиля конфигурации SSL сопоставляется с sslConfigName из ConnectionConfiguration

-

default

sslCipherSuite

String

Имя шифровального набора (формат соответствует формату, используемому на брокере).

-

allowedDNs

List<String>

Задает список DN сертификатов для проверки. Если не задан, будет использована проверка по имени хоста

-

verifyHost

boolean

Задает необходимость проверки сертификата брокера на соответствие имени хоста. Если задан список DN, то проверка на имя хоста не проводится

-

true

sslSocketFactory

SSLSocketFactoryConfiguration

Параметры фабрики для создания SSL-сокетов

-

Тип mq.SSLSocketFactoryConfiguration#

Параметры фабрики для создания SSL-сокетов:

Поле

Тип

Описание

Обязательность

protocol

enum

Протоколы, которые поддерживаются провайдером SunJSSE. Протоколы SSL_TLS, SSLv2, SSL_TLSv2 исключены из списка, т. к. не поддерживаются SunJSSE. Значения: SSL, SSLv3, TLS, TLSv1, TLSv1.1, TLSv1.2

+

keyPem

String

путь к файлу с личным ключом шлюза

+

certPem

String

путь к файлу с сертификатом шлюза

+

rootPem

String

путь к файлу с сертификатами УЦ

+

Тип HealthConfiguration#

Поле

Тип

Описание

Обязательность

По умолчанию

successThreshold

int

Количество успешных проверок, после которого брокер возвращается в балансировку

-

1

failureThreshold

int

Количество неуспешных проверок, после которого брокер исключается из балансировки

-

1

timeoutSeconds

int

Таймаут проверки

-

5

periodSeconds

int

Период опроса.

-

initialDelaySeconds

int

Задержка перед началом опроса

-

Тип mq.ConsumerConfiguration#

Параметры считывания сообщений из MQ. Данный блок предназначен для тонкой настройки.

Поле

Тип

Описание

Обязательность

По умолчанию

Появилось в версии Шлюза

Динамические настройки

readEnabled

boolean

Признак включения или выключения MQ-listeners. При старте Шлюза настройка со значением false не запустит listeners и после старта Шлюз не начнет читать сообщения. Можно менять во время выполнения, редактируя значение в конфигурационном файле. Listeners будут отключаться и включаться при перемонтировании файла к pod в Kubernetes. Файл перемонтируется не мгновенно и не всегда за одинаковое время. При этом из каждого экземпляра Шлюза в журнал будет вноситься запись со статусом LISTENERS_ON и LISTENERS_OFF. По адресу <URL приложения>:<порт>/actuator/prometheus доступна метрика mqgate_mq_listeners_enabled (1 - включены, 0 - выключены). После отключения листенеров Шлюз продолжает читать сообщения из gRPC и отправлять их в MQ. Настройка никак не влияет на sync sp Шлюз, т. к. листенеры в нем не создаются

-

true

+

transactionTimeout

String

Максимальное время выполнения транзакции в секундах. "-1" - время выполнения транзакции не ограничено. Требуется обязательное указание размерности (300s), если не указать, при загрузке ШЛюза настройка будет сброшена в значение по умолчанию, в системный лог будет выведено предупреждение.
Важно в предыдущих версиях параметр задавался как целое, но значение интерпретировалось как мс, а не секунды.

-

300

sessionCacheSize

int

Максимальное количество кешированных сессий JMS

-

10

receiveTimeout

int

Максимальное время выполнения считывания сообщения из MQ в миллисекундах

-

100

idleTaskExecutionLimit

int

Минимально количество потоков, одновременно выполняющих чтение из MQ

-

1

idleConsumerLimit

int

Минимальное количество открытых очередей на чтение из MQ

-

1

copyReplyToIntoUsr

boolean

Признак копирования заголовка ReplyToQ в поле UserHeaders Proto-сообщения при трансформации

-

false

copyGroupIdIntoUsr

boolean

Признак копирования заголовка GroupId в поле UserHeaders Proto-сообщения при трансформации

-

false

threadPool

ThreadPoolConfiguration

Параметры пула потоков считывания сообщений из MQ

-

disabledManagerIds

List<string>

Отключение чтения и отправки в указанный брокер. Список отключаемых брокеров в формате: <хост>:<порт>
Важно При отключении всех брокеров Шлюз опускает Readiness-пробу. Если Liveness проба использует общий endpoint (actuator/health), то она тоже будет опущена, что при длительном отключении приведет к перезапуску Шлюза.

-

пусто

+

Тип mq.ThreadPoolConfiguration#

Параметры pool потоков считывания сообщений из MQ. Предназначен для тонкой настройки:

Поле

Тип

Описание

Обязательность

По умолчанию

concurrentConsumers

int

Минимальное количество потоков, обрабатывающих входящие сообщения из MQ

-

1

maxConcurrentConsumers

int

Максимальное количество потоков, обрабатывающих входящие сообщения из MQ

-

5

threadKeepAliveSeconds

int

Время жизни потока в секундах после обработки последнего сообщения

-

60

Тип mq.SyncReceiveTaskConfig#

Параметры настройки сервиса получения ответов из MQ. Используется только при systemType=sp и workMode=sync.

Поле

Тип

Описание

Обязательность

По умолчанию

replyToMode

enum

Устанавливает режим чтения ответов от синхронного поставщика. Возможные значения: SHARED_SINGLE, // вычитка по селектору из общей очереди по CorelId с одного менеджера SHARED, // вычитка по селектору из общей очереди по CorelId (все менеджеры)UNIQUE, // вычитка из выделенной очереди для Pod/инстанса SHARED_SELECTOR // вычитка из общей очереди с фиксированным селектором по имени Pod

-

SHARED_SINGLE

selectorName

String

Пользовательское имя заголовка — селектора для режима чтения ответов SHARED_SELECTOR

-

GWResponseSelector

poolSize

int

Количество потоков в пуле обработчиков — потоков, считывающих ответы из MQ

-

20

startDelay

int

Время ожидания перед первым считыванием ответа, в мс

-

200

maxDelay

int

Максимальное время между повторами считывания ответа, в мс

-

2000

maxProcessingTime

int

Максимальное время получения ответа, в мс. По истечении этого времени ответ не будет получен и клиенту будет отправлена отмена вызова. Должен быть больше любого тайм-аута на сервисе

-

30000

maxStopTime

int

Максимальное время ожидания ответов при остановке приложения, в мс

-

100000

receiveTimeout

int

Тайм-аут на MQ GET, в мс. В течение данного времени MQ при выполнении GET ожидает ответ. По истечении данного периода поток возьмет следующее сообщение в очереди запросов и будет проверять наличие ответа для него. Значение = 0 приведет к бесконечному ожиданию ответа, устанавливать не рекомендуется, так как может привести к остановке считывания ответов, если ответы не будут приходить длительное время. Остальные тайм-ауты при этом не сработают. Отрицательное значение приведет к считыванию (GET) без ожидания

-

100

defaultReceiveQueue

String

Задает очередь для считывания ответов в случае если не задано через ReplyToQ

-

ignoreReplyToQ

Boolean

при включение флага игнорирует то, что задано в запросе в заголовке ReplyToQ, и очередь для вычитки ответа будет определяться по параметру defaultReceiveQueue. В основном используется для тестирования

-

false

ReceiveByRequestCorrelId

Boolean

При включенном флаге производит вычитку ответа по CorrelId равному CorrelId запроса, а не MsgId запроса.

-

false

Пример настроек sync-receiver

 mq:
  sync-receiver:
    replyToMode: SHARED_SINGLE #SHARED #SHARED_SELECTOR #UNIQUE 
    selectorName: GWResponseSelector # для режима SHARED_SELECTOR    
    poolSize: 10
    startDelay: 100
    maxDelay: 300
    maxProcessingTime: 35000
    maxStopTime: 100000
    receiveTimeout: 100

Тип mq.ConcurrentLimiterConfig#

Параметры ограничения одновременной обработки считанных сообщений:

Пол

Тип

Описание

Обязательность

По умолчанию

enable

boolean

Включает режим ограничения

-

false

limitConcurrent

int

Кол-во одновременно обрабатываемых сообщений после считывания

-

10

Пример настроек concurrent-limiter

 mq:
  concurrentLimiter:
    enable: true
    limitConcurrent: 10

Тип mq.RateLimiterConfig#

Параметры ограничения скорости обработки считанных сообщений:

Поле

Тип

Описание

Обязательность

По умолчанию

enable

boolean

Включает режим ограничения

-

false

settings

Map<String, RateLimiterSetting>

Map профилей настроек ограничений по скорости в срезе очередей

-

-

Пример настроек rate-limiter

 mq:
  #настройка ограничения скорости считывания из входящих очередей
  rate-limiter:
    enable: true
    settings:
      default:
        limitRefreshPeriod: 1000
        limitForPeriod: 100
      "[UB.TEST.QUEUE]":
        limitRefreshPeriod: 1000
        limitForPeriod: 10
      "[UB.TEST.QUEUE.SYNC]":
        limitRefreshPeriod: 1000
        limitForPeriod: 50

Тип RateLimiterSettings#

Параметры настройки ограничения по скорости обработки сообщений после считывания:

Поле

Тип

Описание

Обязательность

По умолчанию

limitRefreshPeriod

long

Период обновления ограничения, мс

-

1000

limitForPeriod

int

Ограничение для вызова метода обработки сообщения за limitRefreshPeriod

-

100

Тип СoncurrentLimiterSendConfig#

Параметры ограничения одновременной обработки синхронных вызовов:

Пол

Тип

Описание

Обязательность

По умолчанию

enable

boolean

Включает режим ограничения

-

false

limitConcurrent

int

Кол-во одновременно обрабатываемых синхронных вызовов

-

30

Пример настроек concurrentLimiterSend

 mq:
  concurrentLimiterSend:
    enable: true
    limitConcurrent: 30

Тип LimiterSyncCall#

Поле

Тип

Описание

Обязательность

По умолчанию

enable

boolean

включение ограничителя

-

false

size

int

Ограничение для синхронных вызовов

-

5000

Тип SslCertUpdate#

Поле

Тип

Описание

Обязательность

По умолчанию

enable

boolean

включение механизма обновления сертификатов

-

false

checkInterval

String

периодичность проверки изменения файлов хранилища сертификатов

-

30000ms

downReadinessProbe

int

опускать Readiness-пробу на время выполнения обновления сертификатов

-

false

intervalsNumber

int

количество интервалов (сегментов распределения)

-

20

updateTimeInSeconds

int

Интервал обновления — время применения сертификатов для одного Pod Шлюза

-

2

roundTimeInMinutes

int

интервал на который округляется (в большую сторону) момент изменения файлов хранилищ ключей

-

10

certificateReloadDelay

String

Дополнительная фиксированная временная задержка, чтобы при несинхронном изменении файлов ключей и сертификатов со стороны внешней системы хранения сертификатов исключить излишние повторы процедуры обновления.

-

30s

Тип mq.OutboundMqConfiguration#

Параметры для исходящих в MQ сообщений:

Поле

Тип

Описание

Обязательность

По умолчанию

serviceName

VariableService

Правило выбора имени сервиса

+

serviceList

List<ServiceConfig>

Список именованных маршрутов

+

enableCopyHeadersFromRequest

boolean

Признак необходимости копировать заголовки из запроса (который пришел по gRPC) в ответ (который пришел из MQ). Работает только для sync-sp Шлюза. Применятся для всех сообщений

-

false

copyHeadersFromRequestSettings

CopyHeadersFromRequestSettings

Настройки копирования заголовков из запроса в ответ. Применятся для всех сообщений

-

defaultPersistence

enum

Значение по-умолчанию для признака персистентности отправляемых в MQ сообщений. Может иметь значения PERSISTENT, NON_PERSISTENT. Если задан — Шлюз будет принудительно проставлять его в каждом отправляемом в MQ сообщении. Если не задан — персистентность будет определяться заголовками в сообщении. Может быть переопределено для конкретного сервиса в секции serviceList

-

Пример настройки секции outbound

 mq:
  outbound: # параметры для исходящих в MQ сообщений
    defaultPersistence: NON_PERSISTENT     # Значение персистентности по умолчанию
    serviceName: # определение названия сервиса
      valueFrom:
        - type: fromBody
          value: local-name(/*)
      expr:
    serviceList:  # список сервисов с их правилами
      - serviceName: default # поведение по умолчанию
        usrHeaders: #заполняет usr-заголовки перед отправкой в MQ
          ReplyToQueueHeader:
            - type: fromDestination # из назначения MQ-сообщения
              value: 'queue' # очередь назначения
          AnotherHeader2: # ключ заголовка
            - type: fromBody
              value: //RqUID
          AnotherHeader3:
            - type: fromConst
              value: 'someValue'
      - serviceName: Service1
        overridePersistence: PERSISTENT    # переопределение персистентности по умолчанию для конкретного сервиса
        parent: default # родительский профиль (его правила тоже применятся)
        usrHeadersExt:  # Расширенное заполнение пользовательских заголовков в исходящем MQ сообщении
          - name: custom1
            valueFrom:
              - type: fromExpression 
                value: "variables['cust1']"
                variables:
                  cust1:
                    type: fromConst
                    value: thereiscust1
            expr: "'const1' + value + 'const2'" 
          - name: ExtLogRqTm
            valueFrom:
              - type: fromConst
                value: yyyy-MM-dd'T'HH:mm:ss.SSSx':00'
            expr: "dateNow(value)"  
          - name: ExtLogPersistence
            valueFrom:
              - type: fromHeader
                value: Persistence
            expr: "value == '2' ? '1' : '0'" # получить значение Persistence в формате MQ (в ProtoMessage в формате JMS)

Тип mq.outbound.VariableService#

Поле

Тип

Описание

Обязательность

valueFrom

List<ExtractionRule>

Список правил вычисления, применяются по порядку указания в списке до получения ненулевого значения

+

expr

String

Дополнительное SpEL-преобразование для вычисленного значения

-

Тип mq.outbound.ServiceConfig#

Поле

Тип

Описание

Обязательность

Значение по умолчанию

serviceName

String

Имя сервиса. Используется при поиске сервиса по вычисленному в mq.outbound.serviceName значению. Предопределенное значение default используется, если другие сервисы не попадают под правило выбора

+

selector

enum

Фильтр режима, для которого задан профиль. Значения: SYNC_SP, ASYNC, SYNC_SC. Используется в объединенных Шлюзах для исключения конфликтов по настройкам

-

usrHeaders

Map<String, List<ExtractionRule>>

Правила определения usr-заголовков, которые нужно проставить при отправке сообщения в MQ для этого маршрута. Полученные заголовки помещаются в поле mqrfh2.usr у MQ-сообщения

-

copyHeadersFromRequestSettings

CopyHeadersFromRequestSettings

Настройки копирования заголовков из запроса в ответ

-

overridePersistence

enum

Переопределение значения по-умолчанию для признака персистентности отправляемых в MQ сообщений, для конкретного сервиса. Может иметь значения PERSISTENT, NON_PERSISTENT. Если задан — Шлюз будет для данного сервиса принудительно проставлять его в каждом отправляемом в MQ сообщении. Если не задан — персистентность будет определяться общим дефолтным значением, а если оно не задано, то заголовками в сообщении.

-

Тип SendQueues#

Поле

Тип

Описание

Обязательность

syncProvider

ConfigSendQueue

Очередь по умолчанию для отправки синхронному поставщику

-

syncConsumer

ConfigSendQueue

Очередь по умолчанию для отправки синхронному потребителю

-

async

ConfigSendQueue

Очередь по умолчанию для асинхронной отправки (при асинхроне нельзя разделить поставщика и потребителя), можно использовать, если асинхронная отправка предполагается только в адрес поставщика или только в адрес потребителя. Иначе использовать sendToCustomDestination

-

Тип ParamQueue#

Поле

Тип

Описание

Обязательность

queue

String

Название очереди

+

workMode

String

режим (sync/async)

-

systemType

String

режим (sc/sp)

-

systemName

String

Имя внешней системы (для логирования)

-

Тип ConfigSendQueue#

Поле

Тип

Описание

Обязательность

queue

String

Имя очереди

-

systemName

String

Имя системы

-

Блок routing#

Параметры маршрутизации входящих сообщений. Обязательный блок.

Поле

Тип

Описание

Обязательность

По умолчанию

Динамические настройки

routeName

VariableRoute

Правило выбора имени маршрута

+

+

routeList

List<RouteConfig>

Список именованных маршрутов

+

+

Тип routing.VariableRoute#

Поле

Тип

Описание

Обязательность

name

String

Имя переменной

+ кроме секции routing.routeName (см. пример настройки блока routing в данном документе)

valueFrom

List<ExtractionRule>

Список правил вычисления

+

expr

String

Дополнительное SpEL-преобразование для вычисленного значения

-

Тип routing.RouteConfig#

Описание маршрута:

Поле

Тип

Описание

Обязательность

По умолчанию

Доступно в версии Шлюза

routeName

String

Имя маршрута. Используется при поиске маршрута по вычисленному в routing.routeName значению. Предопределенное значение default используется, если другие маршруты не попадают под правило выбора

+

selector

enum

Фильтр режима, для которого задан профиль. Значения: ASYNC_SP, SYNC_SC, ASYNC_SC. Используется в объединенных Шлюзах для исключения конфликтов по настройкам.

-

transportType

String

Тип транспорта, который будет вызван после получения сообщения из MQ (GRPC/HTTP)

-

GRPC

http

HttpConfig

Настройки HTTP-транспорта для текущего маршрута (если задан общий корневой блок настроек http, то будут применены настройки из него)

-

copyHeadersFromRequestSettings

CopyHeadersFromRequestSettings

Настройки копирования заголовков MQ из запроса в ответ (работает для HTTP-транспорта)

-

transform

TransformConfig

Настройки преобразования сообщения для HTTP-транспорта (если задан общий корневой блок http, будут применены настройки из общего корневого блока transform)

grpcHeaders

Map<String,List<ExtractionRule>>

Правила определения gRPC-заголовков, которые нужно проставить при вызове для этого маршрута

-

systemHeaders

Map<String,List<ExtractionRule>>

Правила определения system-заголовков, которые нужно проставить при вызове для этого маршрута. Полученные заголовки помещаются в поле systemHeaders у Proto-сообщения

-

userHeaders

Map<String,List<ExtractionRule>>

Правила определения user-заголовков, которые нужно проставить при вызове для этого маршрута. Полученные заголовки помещаются в поле userHeaders у Proto-сообщения

-

destinationExpression

String

SpEL-выражение для определения имени вызываемого хоста. Может быть заполнено константой. Пример: variables['ServiceName']. Если ServiceName не задано, то значение данной переменной будет соответствовать значению routeName. ("urn:systems:99-ufs".equals(ScName.toLowerCase())?"ufsuko":ScName)+'-srv'+ServiceName.substring(0,ServiceName.length()-2)+'-'+SpName+'-rs' ScName+'-'+ServiceName+'-'+SpName+'-rq' 'some-constant-destination'

+

variables

List<VariableRoute>

Переменные для вычисления маршрута

-

destinations

Map<String,String>

Дополнительный блок для определения маршрута. Если блок не задан, маршрутизировать будет сразу по значению, вычисленному из destinationExpression. Если блок задан по вычисленному значению destinationExpression, то будет выполняться поиск на соответствие в ассоциативном массиве для дальнейшей маршрутизации.
Важно Поиск регистрозависимый.
Пример: 'UFS-srvGetServiceApplicationDetail-ASBS-rs': 127.0.0.1

-

Тип CopyHeadersFromRequestSettings#

Настройки копирования заголовков из запроса в ответ:

Поле

Тип

Описание

Обязательность

По умолчанию

copyAllMqmdHeaders

boolean

Копировать все mqmd-заголовки из запроса в ответ

-

false

copyAllUsrHeaders

boolean

Копировать все usr-заголовки из запроса в ответ

-

false

usr

Map<String,List<ExtractionRule>>

Правила определения usr-заголовков, которые нужно скопировать из запроса в ответ

-

mqmd

Map<String,List<ExtractionRule>>

Правила определения mqmd-заголовков, которые нужно скопировать из запроса в ответ

-

Пример настройки блока routing

 routing:
  routeName:
    valueFrom: # 1) сначала из тела сообщения xPath'ом(local-name(/*)) получаем RouteName (в данном случае — корневой тег). Можно получать не fromBody, а из usr-заголовков fromRfh2Header(в value название заголовка) или fromConst(в value строковую константу)
      - type: fromBody
        value: local-name(/*)
  routeList: # 2) далее по полученному на шаге 1 routeName ищется маршрут в списке routeList с таким именем. Если не найден, то берется маршрут с именем default, как в этом примере
    - routeName: default
      destinationExpression: variables['SCName'] + '-' + variables['ServiceName'] + '-' + variables['SPName'] # 4) после вычисления всех переменных, вычисляется название вызываемого сервиса через SpEL-выражение. variables здесь - Map с переменными, полученными на шаге 3
      variables: # 3) Далее Шлюз получает переменные для вычисления названия сервиса, в который отправится сообщение
        - name: ServiceName
          valueFrom: # 3.1.1) переменная ServiceName получается из тела (fromBody) xPath'ом local-name(/*)
            - type: fromBody
              value: local-name(/*)
          expr: value[0:len(value)-2]  # 3.1.2) потом к тому, что вычислено на шаге 3.1.1, применяется SpEL-выражение. value здесь - то, что было получено на шаге 3.1.1. Параметр expr необязательный. Можно оставить value без изменений
        - name: SCName # 3.2.1) переменная SCName получается сначала из usr-заголовка SCName. Если его нет или он пустой, то берется константа UFS
          valueFrom:
            - type: fromRfh2Header
              value: SCName
            - type: fromConst
              value: UFS
          expr: ("urn:systems:99-ufs"==toLower(value))?"ufsuko":value) # 3.2.2) Далее к тому, что вычислено на шаге 3.2.1 применяется SpEL-выражение. Здесь значение urn:systems:99-ufs заменяется на ufsuko
        - name: SPName # 3.3.1) переменная SPName получается сначала из usr-заголовка SPName. Если его нет или он пустой, то получается из тела xPath'ом //SystemID
          valueFrom:
            - type: fromRfh2Header
              value: SPName
            - type: fromBody
              value: //SystemID
          expr: value+'-rs' # 3.3.3) Далее к тому, что вычислено на шаге 3.3.1, применяется SpEL-выражение. Здесь добавляется суффикс rs
      destinations:
        'UFS-srvGetServiceApplicationDetail-ASBS-rs': 127.0.0.1

Вариант без маршрутизации

 routing:
  routeList:
    - routeName: default
      destinationExpression: '"ufs-srvgetcard-ucs"'

Название сервиса, который в итоге был вызван Шлюзом, можно найти в системном журнале по ключевому слову authority.

Пример конфигурации с grpcHeaders, systemHeaders, userHeaders

 routing:
  routeName:
    valueFrom:
      - type: fromBody
        value: local-name(/*)
    expr:
  routeList:
    - routeName: default
      grpcHeaders:
        x-synapse-mgr:
          - type: fromRfh2Header
            value: 'Mgr'
      userHeaders:
        RqUID:
          - type: fromBody
            value: //RqUID
      systemHeaders:
        Expiry:
          - type: fromConst
            value: 100000

Блок tracing#

Настройки трассировки:

Поле

Тип

Описание

Обязательность

По умолчанию

Динамические настройки

tracingHeaders

Map<String,ExtractionRule>

Список имен полей заголовков трассировки и правил их вычисления

-

+

listTracingHeaders

List<ParamTracingHeaders>

Списки правил заполнения заголовков трассировки в разрезе режимов. Используется в объединенных Шлюзах.

-

+

generateXB3Headers

boolean

Признак необходимости генерации заголовков трассировки x-b3-*

-

false

+

generate128bitTraceId

boolean

Признак генерации заголовка x-b3-traceid 128-битного формата. Необходимо установить в случае, если Шлюз является первым компонентом в цепочке gRPC-вызовов для корректной работы механизма трассировки Istio

-

true

+

Тип ParamTracingHeaders#

Поле

Тип

Описание

Обязательность

selector

enum

Фильтр режима, для которого задан профиль. Значения: ASYNC_SP, SYNC_SC, ASYNC_SC. Используется в объединенных Шлюзах для исключения конфликтов по настройкам.

+

tracingHeaders

Map<String, <ExtractionRule>

Список имен полей заголовков трассировки и правил их вычисления

+

Пример настройки блока tracing

 tracing:
  generateXB3Headers: true
  generate128bitTraceId: true
  tracingHeaders:
    x-b3-traceid: #перезапишет сгенерированный. обрежется до 16 символов при выставленном generate128bitTraceId
      - type: fromBody
        value: '//RqUID'
    x-synapse-bussinesserrorcode-bin:
      - type: fromBody
        value: './/*[local-name()=''RoutingSet'']/errorCode/text()'
    x-synapse-rquid:
      - {type: fromBody, value: //RqUID}
    x-synapse-rqtm:
      - {type: fromBody, value: //RqTm}
    x-synapse-custom1:
      - type: fromInnerXML #                                 
        value: "/*[local-name()='QueueMessage']/system"
        innerPath: "/*[local-name()='SYSTEM']/*[local-name()='Operation']/*[local-name()='Type']"
    x-synapse-custom2:
      - type: fromExpression #                                 
        value: "variables['SCName'] + '-' + toLower(variables['ServiceName'][0:len(variables['ServiceName'])-2]) + '-' + variables['SPName'] + '-rq'"
        variables:
          SCName:
            type: fromConst
            value: consumer
          SPName:
            type: fromConst
            value: provider
          ServiceName:
            type: fromExpression
            value: "variables['OperName'] + 'RecursiveRq'"
            variables:
              OperName:
                type: fromConst
                value: SomeService

Блок logging#

Настройки журналирования:

Поле

Тип

Описание

Обязательность

По умолчанию

Динамические настройки

level

String

позволяет изменить уровень логирования

Блок validator#

Блок настроек validator задает настройки подключения внешнего валидатора. Блок может быть размещен в отдельном файле validator-secret.yml в артефакте типа Secret.

Поле

Тип

Описание

Обязательность

Default

Динамические настройки

enabled

boolean

Включает (true) валидацию сообщений.

-

false

+

invalidateByDefault

boolean

При включенной валидации (enabled: true), если данная настройка имеет значение false, то сообщения, для которых не задан профиль валидации будут считаться валидными. если данная настройка имеет значение true - то невалидными.

-

false

+

replyByCorrelId

boolean

Определяет, как для ответов об ошибке валидации отправляемых в MQ будет задаваться заголовок MQMD.CorrelId. Если параметр имеет значение false, то в CorrelID будет записываться MsgId запроса (стандартный вариант). Если параметр имеет значение true, то в CorrelId ответа будет записываться CorrelId запроса.

-

false

+

loggingBody

boolean

Определяет, нужно ли логировать тело сообщения при вызове валидатора.

-

false

+

http.client

HttpConfig

Настройки клиента HTTP для вызова валидатора

+

+

serviceName

VariableService

Правила определения профиля валидации

+

+

serviceList

List< ServiceConfig >

Правила определения параметра path вызова валидатора для профилей настроек

-

+

Тип validator.VariableService#

Поле

Тип

Описание

Обязательность

Default

valueFrom

List< ExtractionRule >

Список правил вычисления, которые применяются по порядку указания в списке до получения ненулевого значения.

+

expr

String

Дополнительное преобразование для вычисленного значения

-

Тип validator.ServiceConfig#

Поле

Тип

Описание

Обязательность

Default

serviceName

String

Наименование профиля настроек

+

pathExpression

String

Выражение для вычисления значения path. Кроме переменных описанных в списке variables в pathExpression можно использовать три встроенных переменных: direction (принимает значения inbound для сообщений считанных из MQ, и outbound для сообщений отправляемых в MQ), workMode (принимает значение sync в синхронных вызовах, и async в асинхронных), msgType (принимает значение rq при обработке синхронных запросов, rs при обработке синхронных ответов и "_" (подчерк) при асинхронных вызовах)

+

headers

Map<String, List<ExtractionRule>>

Список правил определения заголовков для добавления к вызову валидатора

-

variables

List<VariableRoute>

Список правил определения переменных для вычисления и подстановки в pathExpression.

-

Пример настройки блока validator

     validator:
      enabled: true
      invalidateByDefault: false
      replyByCorrelId: false
      loggingBody: false
      http:
        client:
          url: http://127.0.0.1:8787/check
          timeout: 3000
      serviceName: # правила определения схем для сообщений
        valueFrom:
          - type: fromRfh2Header
            value: ServiceName
        expr:
      serviceList:
        - serviceName: address
          pathExpression: ServiceName
          headers: # Заполняется, если требуется передать дополнительные заголовки для вставки в ответ.
            RqUID:
              - type: fromBody
                value: //RqUID
                # Matching values
                valueJson: $..RQID
          variables:
            - name: ServiceName
              valueFrom:
                - type: fromConst
                  value: "/"
              expr:
        - serviceName: address1
          pathExpression: ServiceName
          headers: # Заполняется, если требуется передать дополнительные заголовки для вставки в ответ.
            x-foo-first:
              - type: fromConst
                value: foo1
          variables:
            - name: ServiceName
              valueFrom:
                - type: fromConst
                  value: "/ping"
              expr:
        - serviceName: address2
          pathExpression: ("/bar2")
        - servicename: address3
          pathExpression: ("/bar")
        - servicename: address4
          pathExpression: ("/"+ServiceName)
          variables:
            - name: ServiceName
              valueFrom:
                - type: fromConst
                  value: "bar"
              expr:
        - servicename: address5
          pathExpression: ("/"+variables['direction']+"/"+variables['workMode']+"/"+variables['msgType']+"/"+ServiceName)
          variables:
            - name: ServiceName
              valueFrom:
                - type: fromConst
                  value: "bar"
              expr:
        - servicename: address6
          headers: # Заполняется, если требуется передать дополнительные заголовки для вставки в ответ.
            Content-Type:
              - type: fromConst
                value: 'application/json'
          pathExpression: ("/"+variables['direction']+"/"+variables['workMode']+"/"+variables['msgType']+"/"+ServiceName)
          variables:
            - name: ServiceName
              valueFrom:
                - type: fromConst
                  value: "foo"

Блок audit#

Блок настроек audit задает настройки регистрации событий аудита. Доступно с версии 2.9

Поле

Тип

Описание

Обязательность

Default

Динамические настройки

enable

boolean

Включает (true) отправку сообщений в аудит

false

transportType

enum

Тип транспорта для отправки событий в ТС Аудит
Значения: HTTP, FILE

HTTP

directory

String

Путь для записи метамодели для транспорта = FILE

+ (для transportType==FILE)

http

AuditHttp

Настройки HTTP-транспорта

+ (для transportType==HTTP)

Тип AuditHttp#

Настройки HTTP-транспорта для ТС Аудит

Поле

Тип

Описание

Обязательность

Default

Динамические настройки

client

httpClientConfiguration

Настройки веб-клиента для вызова ТС Аудит

+

eventsPath

String

Путь к endpoint для отправки событий

/event

metamodelPath

String

Путь к endpoint для отправки метамодели

/metamodel

responseTimeout

int

Таймаут вызова ТС Аудит для отправки событий, миллисекунд

5000

maxBufferSize

int

Размер буфера событий для Retry отправки

3000

retry

RetryConfig

Настройки повторной отправки событий в случае неуспешной попытки

Тип RetryConfig#

Поле

Тип

Описание

Обязательность

Default

Динамические настройки

attempts

int

Количество попыток повторной отправки события в случае ошибки

10

audit:
  enable: true
  transportType: http
  http:
    client:
      httpMethod: POST
      url: http://хост:порт
    eventPath: /event_endpoint
    metamodelPath: /metamodel_endpoint
    responseTimeout: 10000
    maxBufferSize: 3000
    retry:
      attempts: 10

Блок cleanFDC#

Только для реализации Шлюза MQ на Golang

Поле

Тип

Описание

Обязательность

Default

enable

Boolean

включение механизма очистки

-

false

path

String

Путь по которому искать .FDC файлы. Настройка не влияет на то где файлы формируются.

-

Если задана MQ_OVERRIDE_DATA_PATH то равно
"<значение MQ_OVERRIDE_DATA_PATH>/errors",
иначе "/IBM/MQ/data/errors"

maxFilesSize

String

Суммарный размер .FDC файлов, при превышении которого включается очистка.

-

50MB

freePercent

Int

Сколько процентов от суммарного размера должно быть освобождено при очистке

-

80

period

String

Период сканирования

-

60s

outdatedScanTime

String

Время запуска удаления устаревших файлов

-

01:00

maxAgeInDays

Int

возраст в днях при достижении которого файлы считаются устаревшими

-

7

retry:

RetryClean

Настройка количества повторных попыток, если при попытке удаления файл был заблокирован.

Тип RetryClean#

Поле

Тип

Описание

Обязательность

Default

attempts

Int

количество попыток

-

3

waitDuration

String

интервал между попытками

-

500ms

Блок parser#

Только для реализации Шлюза MQ на Golang

Поле

Тип

Описание

Обязательность

Default

xml

XmlParserConfig

Настройка разбора XML-сообщений

Тип XmlParserConfig#

Поле

Тип

Описание

Обязательность

Default

skipDeclaration

Boolean

Пропуск XML- декларации

-

false

Блок refresh#

Поле

Тип

Описание

Обязательность

Default

settingsPeriodCheckUpdateFile

String

Величина интервала через который Шлюз проверяет файлы конфигурации, и если они изменились, выполняет обновление параметров, которые допускают динамическое изменение

30s

Общие типы#

Тип extractor.ExtractionRule#

Правила получения значений из сообщения. Представляет собой именованный список, в котором для каждого имени заголовка определяются:

Поле

Тип

Описание

Обязательность

type

ExtractionType

Место, откуда необходимо получить значение параметра

+

value

String

Имя заголовка, константа или xPath-выражение для получения значения из тела. Для типа fromInnerXML определяет элемент в сообщении, в котором находится вложенный XML

+ (для всех типов кроме fromBody)

valueJson

String

Для типа fromBody. JsonPath-выражение для получения значения из тела. Только для типа fromBody. Используется при обработке сообщений формата JSON

-

innerPath

String

только для типа fromInnerXML — XPath для получения значения из вложенного XML

-

variables

Map<String, List< ExtractionRule>>

Для типа fromExpression — набор правил определения переменных, составляющих выражение

-

Настройки value и valueJson типа fromBody применяются только к сообщениям своего формата. Для сообщений другого формата настройка игнорируется. Если настройка задана для одного формата, но не задана для другого, то при обработке сообщения формата, для которого настройка не задана, будет возвращаться пустое значение. Например, настройка прописана для XML, но не прописана для JSON, тогда, при обработке сообщения формата JSON, будет получено пустое значение.

Правило value корректно извлекает значения из тела сообщения даже если тело сообщения представляет собой строку полностью экранированного XML.

Например сообщения:

<Root>
  <RqUID>d6e3fd28ab2f4f51968c9c7423f99113</RqUID>
  <Message>Какое-то сообщение</Message>
</Root>

и

&lt;Root&gt;&lt;RqUID&gt;d6e3fd28ab2f4f51968c9c7423f99113&lt;/RqUID&gt;&lt;Message&gt;Какое-то сообщение&lt;/Message&gt;&lt;/Root&gt;

дадут одинаковый результат.

Пример:

 - type: fromBody
  value: local-name(/*)
- type: fromRfh2Header
  value: SCName
- type: fromConst
  value: UFS
- type: fromRfh2Header
  value: SPName
- type: fromBody
  value: //SystemID
  valueJson: $.SystemID
- type: fromInnerXML
  value: "/*[local-name()='QueueMessage']/system"
  innerPath: "/*[local-name()='SYSTEM']/*[local-name()='Operation']/*[local-name()='Type']"
- type: fromExpression
  value: "variables['SCName'] + '-' + toLower(variables['ServiceName'][0:len(variables['ServiceName'])-2]) + '-' + variables['SPName'] + '-rq'"
  variables:
    SCName:
      type: fromConst
      value: consumer
    SPName:
      type: fromConst
      value: provider
    ServiceName:
      type: fromExpression
      value: "variables['OperName'] + 'RecursiveRq'"
      variables:
        OperName:
          type: fromConst
          value: SomeService

Тип extractor.ExtractionType#

Способ получения значения из сообщения:

Значение

Описание

fromHeader

Заголовки

fromRfh2Header

rfh-заголовки

fromBody

Тело сообщения (XML или JSON)

fromConst

Константа

fromExpression

Из SPEL выражения

fromInnerXML

Из вложенного (экранированного) XML

fromDestination

Из назначения MQ-сообщения. Используется только в секции mq.outbound.serviceList. Доступные значения: queue

Часто встречающиеся проблемы и пути их устранения#

Информация о часто встречающихся проблемах и путях их решения — в разделе «Часто встречающиеся проблемы и пути их устранения» документа «Руководство по системному администрированию».