Запуск сигнала OnConnected на сервере, отличном от того, к которому он фактически подключен

#signalr #web-farm

#signalr #веб-ферма

Вопрос:

Я использую SignalR и веб-ферму в IIS, в настоящее время с 3 серверами, и запросы балансируются по нагрузке через ARR.

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

Я подумал, что мог бы сделать это с помощью OnConnected и в рамках этого метода сохранить MachineName вместо connectionId в redis. Проблема в том, что OnConnected, похоже, вызывается на сервере, отличном от того, к которому подключен клиент.

При исследовании кажется, что есть три вызова: один для / negiotate, один для / connect и один для / start. Похоже, что / connect является подключением к websocket, которое поддерживается в течение всего срока действия, остальные просто временные. Эти три соединения могут происходить на разных серверах, и кажется, что соединение websocket может быть с сервером A (так что это сервер, к которому подключается SignalR клиента), но OnConnected запускается на сервере B.

Мне было интересно, не упускаю ли я из виду что-то, что позволит мне увидеть, к какому серверу на самом деле подключено SignalR connection?

Спасибо,

Приведет

Ответ №1:

Если вы собираетесь использовать веб-ферму, то вам необходимо реализовать объединительную плату для отслеживания всех сообщений.

https://learn.microsoft.com/en-us/aspnet/signalr/overview/performance/scaleout-in-signalr

Без надлежащей реализации объединительной платы невозможно сделать то, что вы хотите сделать.

Комментарии:

1. Привет, я использую объединительную плату, но как я могу определить, к какому серверу на самом деле подключен каждый клиент? Спасибо, будет

2. Вам нужно проверить базу данных, она должна быть там

Ответ №2:

Я полагаю, что это то, что вам нужно было бы сохранить. Предполагая, что вы используете базу данных для сопоставления пользователей, вы могли бы ввести дополнительное поле, такое как «LoggedInOn», и сохранить имя хоста сервера или другой идентификатор.

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

Если у вас есть внешние события, как вы говорите, как только они завершатся и сообщение будет готово к отправке обратно клиенту, объединительная плата должна отправить это на все серверы.

Если этого не происходит, я бы просмотрел документы, как заявил Келсо Шарп.

Комментарии:

1. Мой вопрос больше о том, как мне настроить это поле LoggedInOn, если OnConnected запускается на другом сервере. Причина, по которой я не просто хочу, чтобы все серверы обрабатывали сообщение, заключается в том, что может происходить некоторый доступ к базе данных и другая обработка, поэтому было бы неэффективно и недостаточно масштабируемо, если бы все серверы в ферме выполняли это для каждого клиента.

2. То, что я только что сделал, это добавил новый метод к концентратору, «OnReallyConnected», который я вызываю в .start() клиента, и оттуда я могу сообщить серверу, к которому он действительно подключен, но это кажется действительно неуклюжим, должен быть более чистый способ?

3. Все серверы обрабатывают сообщение от объединительной платы по дизайну. Сервер A может видеть клиентское соединение и отправлять его клиенту, но дополнительные серверы в ферме не будут видеть клиента (если вы отправляете только одному клиенту). Если вы отправляете сообщение от одного клиента многим клиентам, оно должно охватывать все серверы, чтобы добраться до всех. Это сделано специально, и я полагаю, вас может беспокоить неэффективность там, где ее нет. Вы всегда можете использовать crank, см. Документы, для тестирования плотности.

4. Меня беспокоит неэффективность, это правильно. У меня есть внешнее событие (не связанное с SignalR), скажем, его «уведомить пользователя A о событии X», которое включает в себя ряд вызовов базы данных для загрузки некоторых записей, а затем отправки этой информации пользователю. Я не хочу, чтобы эти вызовы базы данных повторялись на всех серверах фермы, и я не хочу, чтобы пользователь получал уведомление от каждого сервера в ферме. Если я могу определить, какой пользователь подключен к какому серверу, я могу затем заставить этот сервер обрабатывать события для пользователя, а другие серверы игнорировать эти события.

5. Если пользователь инициирует вызов, запрос будет отправлен на сервер, к которому подключен пользователь, который затем инициирует ваш запрос к БД и по завершении использует — Clients. Вызывающий.senddatatouser(yourdata);. Внешнее событие, которое запускает запрос к БД, затем вам нужно посмотреть connectionId для этого пользователя и использовать — Clients. User (Идентификатор пользователя).senddatatouser(yourdata);. Это отправит пользователю get независимо от того, к какому серверу он подключен.