Пакетная передача в концентраторы событий из приложения ASP .NET

У меня есть массив веб-сайтов, которые (асинхронно) отправляют аналитику событий на веб-сайт ASP.NET, который затем должен отправлять события в экземпляр Azure EventHubs.

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

В качестве решения я пытался пакетировать данные событий, которые отправляются в мой экземпляр EventHubs, однако у меня возникли некоторые проблемы с синхронизацией. С каждым запросом я добавляю данные о событиях в статический EventDataBatch, созданный с помощью EventHubClient.CreateBatch() с помощью eventHubData.TryAdd(), затем проверяю, находится ли количество событий в пределах предопределенного порога, и если да, я отправляю события асинхронно через EventHubClient.SendAsync(). Проблема состоит в том, что, поскольку это приложение ASP .NET, может быть много потоков, пытающихся обслуживать запросы в любом данном экземпляре - любой из которых может пытаться выполнить eventHubData.TryAdd() или EventHubClient.SendAsync() в один и тот же момент времени. плохая попытка решить эту проблему. Я попытался вызвать lock(batch) до eventHubData.TryAdd(), однако это не решает проблему, поскольку я не могу также заблокировать асинхронный метод EventHubClient.SendAsync().

Как лучше всего реализовать это решение, чтобы каждый запрос не требовал собственного запроса к концентраторам событий и мог использовать преимущества пакетной обработки, сохраняя при этом целостность самого пакета и не сталкиваясь с какими-либо проблемами взаимоблокировки?


person ppsdevelops    schedule 22.03.2019    source источник


Ответы (1)


Взгляните на исходный код SDK Application Insights, чтобы увидеть, как они решили эту проблему - вы можете повторно использовать ключевые части этого, чтобы добиться того же с концентраторами событий AMQP.

Образец,

1) Данные буфера. Определите буфер, который вы будете разделять между потоками с максимальным размером. Несколько потоков записывают данные в буфер

https://github.com/Microsoft/ApplicationInsights-dotnet/blob/develop/src/Microsoft.ApplicationInsights/Channel/TelemetryBuffer.cs

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

https://github.com/Microsoft/ApplicationInsights-dotnet/blob/develop/src/Microsoft.ApplicationInsights/Channel/InMemoryTransmitter.cs

3) Делаем трансмиссию. Отправить все элементы в виде нескольких точек данных в одном сообщении концентратора событий,

https://github.com/Microsoft/ApplicationInsights-dotnet/blob/develop/src/Microsoft.ApplicationInsights/Channel/Transmission.cs

Это 3 класса, которые объединяются для достижения этой цели с использованием HTTP для отправки в конечную точку сбора Application Insights - вы можете увидеть, как образец шаблона можно применить для сбора, объединения и передачи в концентраторы событий.

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

person Dylan Morley    schedule 25.03.2019
comment
Это хорошая отправная точка, но она намного сложнее, чем мне нужно. Есть ли другие проверенные решения, на которых я мог бы основывать свою реализацию? - person ppsdevelops; 28.03.2019
comment
Я бы сказал, что при 50 000 RPS вы находитесь в диапазоне, в котором вам нужно рассмотреть решение в этом направлении. Буфер обеспечивает синхронизированную «точку сбора», а передатчик гарантирует, что в любой момент времени отправка выполняется только одним делом, а именно двумя проблемами, с которыми вы сталкиваетесь. Если вы хотите попробовать что-то еще, например, заблокировать асинхронный SendAsync, взгляните на SemaphoreSlim blog.cdemi.io/async-waiting-inside-c-sharp-locks. Однако шаблон в ответе на самом деле недалеко от того, чем вы сейчас занимаетесь, и не потребует особых усилий. - person Dylan Morley; 29.03.2019