Mantener la afinidad entre un grupo de suscripciones y el servidor del buzón de Exchange

Obtenga información sobre cómo mantener la afinidad entre un grupo de suscripciones y el servidor de buzones de correo.

La afinidad es la asociación de una secuencia de mensajes de solicitud y respuesta con un servidor de buzón determinado. Para la mayoría de las funciones de Exchange, el servidor controla la afinidad. Las notificaciones, sin embargo, son una excepción. El cliente es responsable de mantener la afinidad con el servidor de buzones de correo para las suscripciones de notificación. Esta afinidad permite al equilibrador de carga y a los servidores de acceso de cliente entre el cliente y el servidor enrutar las suscripciones de notificación y las solicitudes relacionadas al servidor de buzones de correo que mantiene la suscripción. Sin afinidad, es posible que la solicitud se enrute a otro servidor de buzón de correo que no incluya las suscripciones del cliente, lo que puede hacer que se devuelva un error ErrorSubscriptionNotFound .

¿Cómo se mantiene la afinidad?

La afinidad en Exchange se basa en cookies. El cliente desencadena la creación de la cookie mediante la inclusión de encabezados específicos en la solicitud de suscripción y, a continuación, la respuesta de la suscripción contiene la cookie. A continuación, el cliente envía esa cookie en solicitudes posteriores para asegurarse de que la solicitud se enruta al servidor de buzones adecuado.

Más concretamente, la afinidad en Exchange se controla mediante lo siguiente:

  • X-AnchorMailbox: encabezado HTTP que se incluye en la solicitud de suscripción inicial. Identifica el primer buzón de un grupo de buzones que comparten afinidad con el mismo servidor de buzones.

  • X-PreferServerAffinity: encabezado HTTP que se incluye en la solicitud de suscripción inicial con el encabezado X-AnchorMailbox y se establece en true para indicar que el cliente solicita que se mantenga la afinidad con el servidor de buzones.

  • X-BackEndOverrideCookie: cookie que se incluye en la respuesta de suscripción inicial y contiene una cookie que el equilibrador de carga y el servidor de acceso de cliente usan para enrutar las solicitudes posteriores al mismo servidor de buzones.

Cómo mantener la afinidad mediante la API administrada de EWS o EWS?

Puede usar los mismos pasos para mantener la afinidad entre varias suscripciones de buzón de correo y sus servidores de buzones, independientemente de si usa notificaciones de streaming, extracción o inserción, e independientemente de si tiene como destino un servidor local de Exchange o Exchange Online.

  1. Para cada buzón de correo, llame a Detección automática y obtenga la configuración de usuario GroupingInformation y ExternalEwsUrl. Para la detección automática de SOAP, se usa el elemento Setting y, para la detección automática de POX, se usa el elemento GroupingInformation .

  2. Con la configuración GroupingInformation y ExternalEwsUrl de las respuestas de detección automática, coloque los buzones con el mismo valor concatenado ExternalEwsUrl y GroupingInformation en el mismo grupo. Si algún grupo tiene más de 200 buzones, desglosa los grupos más abajo para que cada grupo no tenga más de 200 buzones.

  3. Cree y use un objeto ExchangeService para el resto del procedimiento. Cuando se usa el mismo objeto ExchangeService , las cookies y los encabezados (cuando se establecen) se mantienen automáticamente. Tenga en cuenta que si no tiene previsto agrupar suscripciones de streaming en una sola conexión, puede crear un objeto ExchangeService diferente para cada usuario suplantado.

  4. Envíe una solicitud de suscripción para el usuario cuyo nombre de usuario aparece primero cuando todos los usuarios del grupo están ordenados alfabéticamente (se hará referencia a este usuario como el usuario del buzón de anclaje). Haga lo siguiente:

  • Incluya el encabezado X-AnchorMailbox con un valor establecido en la dirección SMTP del usuario del buzón de anclaje.

  • Incluya el encabezado X-PreferServerAffinity con un valor establecido en true.

  • Use el rol ApplicationImpersonation (el tipo ExchangeImpersonation ).

  1. En la respuesta de la suscripción, obtenga el valor X-BackEndOverrideCookie. Incluya este valor en cada una de las solicitudes de suscripción posteriores para los usuarios de este grupo.

  2. Para cada usuario adicional del grupo, envíe una solicitud de suscripción y haga lo siguiente:

  • Incluya el encabezado X-AnchorMailbox con un valor establecido en la dirección SMTP del usuario del buzón de anclaje para el grupo.

  • Incluya el encabezado X-PreferServerAffinity con un valor establecido en true.

  • Incluya la X-BackEndOverrideCookie que se devolvió en la respuesta de suscripción del usuario del buzón de anclaje.

  • Use el rol ApplicationImpersonation (el tipo ExchangeImpersonation ).

    Tenga en cuenta que el servidor usa los valores X-PreferServerAffinity y X-BackendOverrideCookie juntos para realizar el enrutamiento al servidor de buzón de correo. El encabezado X-AnchorMailbox también es necesario, pero el servidor omite si los otros dos valores son válidos. Si X-AnchorMailbox y X-PreferServerAffinity están en una solicitud y no se incluye X-BackendOverrideCookie, el valor X-AnchorMailbox se usa para enrutar las solicitudes.

    Dado que los valores X-PreferServerAffinity y X-BackendOverrideCookie realizan el enrutamiento, si el buzón de anclaje alguna vez se mueve a otro grupo o servidor, la lógica no cambia porque X-BackendOverrideCookie enrutará la solicitud al servidor correcto para el grupo.

  1. Envíe una única solicitud GetStreamingEvents o GetEvents para el grupo y haga lo siguiente:
  • Incluya los valores de SubscriptionId devueltos en cada una de las respuestas de suscripción individuales para los buzones del grupo.

  • Si existen más de 200 suscripciones para el grupo, cree varias solicitudes. El número máximo de valores SubscriptionId que se van a incluir en una solicitud es 200.

  • Si necesita más conexiones de las que están disponibles para el buzón de destino, use la cuenta de servicio para suplantar el buzón de anclaje para el grupo; De lo contrario, no use la suplantación. Lo ideal es suplantar un buzón único por solicitud GetStreamingEvents o GetEvents para que nunca encuentre límites de limitación.

  • Use ApplicationImpersonation si necesita más conexiones de las disponibles para el buzón de destino; De lo contrario, no use ApplicationImpersonation.

  • Incluya el encabezado X-PreferServerAffinity y establézcalo en true. Este valor se incluye automáticamente si usa el objeto ExchangeService que creó en el paso 2.

  • Incluya el X-BackEndOverrideCookie para el grupo (el X-BackEndOverrideCookie que se devolvió en la respuesta de suscripción del usuario del buzón de anclaje). Este valor se incluye automáticamente si usa el objeto ExchangeService que creó en el paso 2.

  1. Pase los eventos devueltos a un subproceso independiente para su procesamiento.

¿Qué valores de limitación debo tener en cuenta?

A medida que planee la implementación de la notificación, querrá tener en cuenta dos valores: el número de conexiones y el número de suscripciones. En la tabla siguiente se enumeran los valores predeterminados para cada configuración de limitación y cómo se usa la configuración. Para cada valor, el presupuesto se asigna al buzón de correo de destino. Por este motivo, el uso de la suplantación para obtener conexiones adicionales es un paso necesario en muchos escenarios.

Tabla 1. Valores de limitación predeterminados

Área de consideración Configuración de limitación Valor predeterminado Descripción
Conexiones de streaming
Límite de conexión colgante predeterminado
10 para Exchange Online
3 para Exchange 2013
Número máximo de conexiones de streaming simultáneas que una cuenta puede tener abiertas en el servidor a la vez. Para trabajar dentro de este límite, use una cuenta de servicio con el rol ApplicationImpersonation asignado para los buzones de destino y suplantar al primer usuario de cada grupo de identificadores de suscripción al obtener eventos transmitidos.
Extracción o inserción de conexiones
EWSMaxConcurrency
27
Número máximo de conexiones de extracción o inserción simultáneas (solicitudes que se han recibido pero a las que todavía no se ha respondido) que una cuenta puede tener abierta en el servidor a la vez.
Suscripciones
EWSMaxSubscriptions
20 para Exchange Online
5000 para Exchange 2013
Número máximo de suscripciones no asociadas que una cuenta puede tener a la vez. Este valor se reduce cuando se crea la suscripción en el servidor.

En el ejemplo siguiente se muestra cómo se controlan los presupuestos entre cualquier buzón de destino y la cuenta de servicio que tiene asignado el rol ApplicationImpersonation para los buzones de destino.

  • ServiceAccount1 (sa1) suplanta a muchos usuarios (m1, m2, m3, etc.) y crea suscripciones para cada buzón. Tenga en cuenta que cuando se crean las suscripciones, el propietario de la suscripción es sa1, por lo que cuando sa1 abre una conexión con las suscripciones, EWS exige que las suscripciones sean propiedad de sa1.

  • Sa1 puede abrir la conexión de las siguientes maneras:

  1. Sin suplantación, por lo que la conexión se cobra por sa1.

  2. Suplantando a cualquiera de los usuarios (por ejemplo, m1) para que la conexión se cargue con una copia del presupuesto de m1. (M1 puede abrir diez conexiones mediante Exchange Online y todas las cuentas de servicio que suplantan m1 pueden abrir diez conexiones mediante el presupuesto copiado).

  • Si se alcanza el límite de conexión, están disponibles las siguientes soluciones alternativas:

    • Si se usa la opción 1, el administrador puede crear varias cuentas de servicio para suplantar a usuarios adicionales.

    • Si se usa la opción 2, el código puede suplantar a otro usuario, por ejemplo, m2.

Ejemplo: Mantener la afinidad entre un grupo de suscripciones y el servidor de buzones

De acuerdo, vamos a verlo en acción. En el ejemplo de código siguiente se muestra cómo agrupar usuarios y usar los encabezados X-AnchorMailbox y X-PreferServerAffinity y la cookie X-BackendOverrideCookie para mantener la afinidad con el servidor de buzones. Dado que los encabezados y la cookie son de importancia principal en el caso de afinidad, este ejemplo se centra en las solicitudes y respuestas XML de EWS. Para usar la API administrada de EWS para crear el cuerpo de las solicitudes y respuestas de suscripción, vea Stream notifications about mailbox events by using EWS in Exchange and Pull notifications about mailbox events by using EWS in Exchange (Transmitir notificaciones sobre eventos de buzón de correo mediante EWS en Exchange). En esta sección se incluyen pasos adicionales específicos para mantener la afinidad y agregar los encabezados a las solicitudes.

Este ejemplo tiene cuatro usuarios: alfred@contoso.com, alisa@contoso.com, ronnie@contoso.comy sadie@contoso.com. En la ilustración siguiente se muestra la configuración de Detección automática de GroupingInformation y ExternalEwsUrl para los usuarios.

Figura 1. Configuración de detección automática usada para agrupar buzones

Tabla que muestra los valores de GroupingInformation y ExternalEwsUrl para cada uno de los usuarios.

Con la configuración de las respuestas de detección automática, los buzones se agrupan por el valor concatenado de la configuración GroupingInformation y ExternalEwsUrl. En este ejemplo, Alfred y Sadie tienen los mismos valores, por lo que están en un grupo, y Alisa y Ronnie comparten los mismos valores, por lo que están en otro grupo.

Figura 2. Creación de grupos de buzones

Tabla que muestra cómo se crean los grupos de buzones usando la configuración de Detección automática.

Para este ejemplo, nos centraremos en el grupo A. Usaremos los mismos pasos para el grupo B, pero usaremos un valor X-AnchorMailbox diferente para ese grupo.

Con ApplicationImpersonation, cree la solicitud de suscripción para el buzón de anclaje (alfred@contoso.com), con el encabezado X-AnchorMailbox establecido en su dirección de correo electrónico y un valor de encabezado X-PreferServerAffinity de true. Al establecer estos dos valores de encabezado, el servidor creará un X-BackEndOverrideCookie para la respuesta.

Si usa la API administrada de EWS, use el método HttpHeadersAdd para agregar los dos encabezados a la solicitud de suscripción, como se muestra.

service.HttpHeaders.Add("X-AnchorMailbox", Mailbox.SMTPAddress);
service.HttpHeaders.Add("X-PreferServerAffinity", "true");

Así que la solicitud de suscripción de Alfred tiene este aspecto.

POST https://outlook.office365.com/EWS/Exchange.asmx HTTP/1.1
Content-Type: text/xml; charset=utf-8
Accept: text/xml
User-Agent: ExchangeServicesClient/15.00.0516.014
X-AnchorMailbox: alfred@contoso.com
X-PreferServerAffinity: true
Host: outlook.office365.com
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:m="https://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types" xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <t:RequestServerVersion Version="Exchange2013" />
    <t:ExchangeImpersonation>
      <t:ConnectingSID>
        <t:SmtpAddress>alfred@contoso.com</t:SmtpAddress>
      </t:ConnectingSID>
    </t:ExchangeImpersonation>
  </soap:Header>
  <soap:Body>
    <m:Subscribe>
      <m:StreamingSubscriptionRequest>
        <t:FolderIds>
          <t:DistinguishedFolderId Id="inbox" />
        </t:FolderIds>
        <t:EventTypes>
          <t:EventType>NewMailEvent</t:EventType>
        </t:EventTypes>
      </m:StreamingSubscriptionRequest>
    </m:Subscribe>
  </soap:Body>
</soap:Envelope>

El siguiente mensaje XML es la respuesta a la solicitud de suscripción de Alfred e incluye X-BackEndOverrideCookie. Vuelva a enviar esta cookie para todas las solicitudes posteriores de los usuarios de este grupo. Tenga en cuenta que la respuesta también contiene cookies adicionales, como la cookie exchangecookie usada por Exchange 2010. Exchange Online, Exchange Online como parte de Office 365 y versiones de Exchange a partir de Exchange 2013, omita exchangecookie si se incluye en solicitudes de suscripción posteriores.

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Set-Cookie: exchangecookie=ddb8c383aef34c7694132aa679744feb; expires=Thu, 25-Sep-2014 18:42:45 GMT; path=/;
    HttpOnly
Set-Cookie: X-BackEndOverrideCookie=CO1PR06MB222.namprd06.prod.outlook.com~1941996295; path=/; secure; HttpOnly
Set-Cookie: X-BackEndCookie=alfred@contoso.com=Ox8XKzcXLxg==; 
    expires=Wed, 25-Sep-2013 18:52:49 GMT; path=/EWS; secure; HttpOnly
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="https://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <h:ServerVersionInfo MajorVersion="15"
                         MinorVersion="0"
                         MajorBuildNumber="775"
                         MinorBuildNumber="7"
                         Version="V2_4"
                         xmlns:h="https://schemas.microsoft.com/exchange/services/2006/types"
                         xmlns="https://schemas.microsoft.com/exchange/services/2006/types"
                         xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
  </s:Header>
  <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <m:SubscribeResponse xmlns:m="https://schemas.microsoft.com/exchange/services/2006/messages"
                         xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types">
      <m:ResponseMessages>
        <m:SubscribeResponseMessage ResponseClass="Success">
          <m:ResponseCode>NoError</m:ResponseCode>
          <m:SubscriptionId>JgBjbzFwcjA2bWIyMjIubmFtcHJkMDYucHJvZC5vdXRsb29rLmNvbRAAAAAUeGk+7JFdSaFM8/NI/gQQpVdgZX6H0Ag=</m:SubscriptionId>
        </m:SubscribeResponseMessage>
      </m:ResponseMessages>
    </m:SubscribeResponse>
  </s:Body>
</s:Envelope>

Con el X-BackEndOverrideCookie de la respuesta de Alfred y el encabezado X-AnchorMailbox, la solicitud de suscripción se crea para Sadie, el otro miembro del grupo A. La solicitud de suscripción de Sadie tiene este aspecto.

POST https://outlook.office365.com/EWS/Exchange.asmx HTTP/1.1
Content-Type: text/xml; charset=utf-8
Accept: text/xml
User-Agent: ExchangeServicesClient/15.00.0516.014
X-AnchorMailbox: alfred@contoso.com
X-PreferServerAffinity: true
Host: outlook.office365.com
Cookie: X-BackEndOverrideCookie=CO1PR06MB222.namprd06.prod.outlook.com~1941996295
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:m="https://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types" xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <t:RequestServerVersion Version="Exchange2013" />
    <t:ExchangeImpersonation>
      <t:ConnectingSID>
        <t:SmtpAddress>sadie@contoso.com </t:SmtpAddress>
      </t:ConnectingSID>
    </t:ExchangeImpersonation>
  </soap:Header>
  <soap:Body>
    <m:Subscribe>
      <m:StreamingSubscriptionRequest>
        <t:FolderIds>
          <t:DistinguishedFolderId Id="inbox" />
        </t:FolderIds>
        <t:EventTypes>
          <t:EventType>NewMailEvent</t:EventType>
        </t:EventTypes>
      </m:StreamingSubscriptionRequest>
    </m:Subscribe>
  </soap:Body>
</soap:Envelope>

La respuesta de la suscripción de Sadie es similar a esta. Tenga en cuenta que no incluye el X-BackEndOverrideCookie. El cliente es responsable de almacenar en caché ese valor para futuras solicitudes.

HTTP/1.1 200 OK
Content-Type: text/xml; charset=utf-8
Set-Cookie: exchangecookie=640ea858f69d47ff8cce8b44c337f6d9; path=/
Set-Cookie: X-BackEndCookie=alfred@contoso.com=Ox8XKzcXLxg==; 
   expires= Wed, 25-Sep-2013 18:53:06 GMT; path=/EWS; secure; HttpOnly
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="https://schemas.xmlsoap.org/soap/envelope/">
  <s:Header>
    <h:ServerVersionInfo MajorVersion="15"
                         MinorVersion="0"
                         MajorBuildNumber="775"
                         MinorBuildNumber="7"
                         Version="V2_4"
                         xmlns:h="https://schemas.microsoft.com/exchange/services/2006/types"
                         xmlns="https://schemas.microsoft.com/exchange/services/2006/types"
                         xmlns:xsd="http://www.w3.org/2001/XMLSchema"
                         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/>
  </s:Header>
  <s:Body xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <m:SubscribeResponse xmlns:m="https://schemas.microsoft.com/exchange/services/2006/messages"
                         xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types">
      <m:ResponseMessages>
        <m:SubscribeResponseMessage ResponseClass="Success">
          <m:ResponseCode>NoError</m:ResponseCode>
          <m:SubscriptionId>JgBjbzFwcjA2bWIyMjIubmFtcHJkMDYucHJvZC5vdXRsb29rLmNvbRAAAAB4EQOy2pfrQJfM3hzs/nZJIZssan6H0Ag=</m:SubscriptionId>
        </m:SubscribeResponseMessage>
      </m:ResponseMessages>
    </m:SubscribeResponse>
  </s:Body>
</s:Envelope>

Con los valores SubscriptionId de las respuestas de suscripción, se creó una solicitud de operación GetStreamingEvents para todas las suscripciones del grupo. Dado que hay menos de 200 suscripciones en este grupo, todas se envían en una solicitud. El encabezado X-PreferServerAffinity se establece en true y el X-BackEndOverrideCookie está incluido.

POST https://outlook.office365.com/EWS/Exchange.asmx HTTP/1.1
Content-Type: text/xml; charset=utf-8
Accept: text/xml
User-Agent: ExchangeServicesClient/15.00.0516.014
X-AnchorMailbox: alfred@contoso.com
X-PreferServerAffinity: true
Host: outlook.office365.com
Cookie: X-BackEndOverrideCookie=CO1PR06MB222.namprd06.prod.outlook.com~1941996295
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:m="https://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="https://schemas.microsoft.com/exchange/services/2006/types" xmlns:soap="https://schemas.xmlsoap.org/soap/envelope/">
  <soap:Header>
    <t:RequestServerVersion Version="Exchange2013" />
    <t:ExchangeImpersonation>
      <t:ConnectingSID>
        <t:SmtpAddress>sadie@contoso.com</t:SmtpAddress>
      </t:ConnectingSID>
    </t:ExchangeImpersonation>
  </soap:Header>
  <soap:Body>
    <m:GetStreamingEvents>
      <m:SubscriptionIds>
        <t:SubscriptionId>JgBjbzFwcjA2bWIyMjIubmFtcHJkMDYucHJvZC5vdXRsb29rLmNvbRAAAAB4EQOy2pfrQJfM3hzs/nZJIZssan6H0Ag=</t:SubscriptionId>
        <t:SubscriptionId>JgBjbzFwcjA2bWIyMjIubmFtcHJkMDYucHJvZC5vdXRsb29rLmNvbRAAAAAUeGk+7JFdSaFM8/NI/gQQpVdgZX6H0Ag=</t:SubscriptionId>
      </m:SubscriptionIds>
      <m:ConnectionTimeout>10</m:ConnectionTimeout>
    </m:GetStreamingEvents>
  </soap:Body>
</soap:Envelope>

A continuación, los eventos devueltos se pasan a un subproceso independiente para su procesamiento.

¿Cómo ha cambiado la afinidad?

En Exchange 2010, las suscripciones se mantienen en el servidor de acceso de cliente, como se muestra en la figura 3. En las versiones de Exchange posteriores a Exchange 2010, las suscripciones se mantienen en el servidor de buzones, como se muestra en la figura 4.

Figura 3. Proceso para mantener la afinidad en Exchange 2010

Ilustración que muestra cómo se mantiene la tabla de suscripciones activas en el servidor de acceso de cliente en Exchange 2010.

Figura 4. Proceso para mantener la afinidad en Exchange Online y Exchange 2013

Ilustración que muestra cómo el equilibrador de carga y el servidor de acceso de cliente enrutan las solicitudes al servidor de buzones que mantiene la tabla de suscripciones activas en Exchange Server y Exchange Online.

En Exchange 2010, el cliente solo conoce la dirección del equilibrador de carga y el exchangecookie devuelto por el servidor garantiza que la solicitud se enrute al servidor de acceso de cliente correcto. Sin embargo, en versiones posteriores, el equilibrador de carga y los roles de servidor de acceso de cliente tienen que enrutar las solicitudes correctamente antes de que lleguen al servidor de buzón de correo. Para ello, se requiere información adicional, por lo que se introdujeron los nuevos encabezados y cookies. En el artículo Suscripciones de notificación, eventos de buzón de correo y EWS en Exchange se explica cómo se mantienen las suscripciones en Exchange 2013.

Es posible que observe que el exchangecookie que Exchange 2010 usa sigue siendo devuelto por versiones posteriores. No hay ningún daño al incluir esta cookie en las solicitudes, pero las versiones posteriores de Exchange la ignoran.

Vea también