Альтернативные причины для индекса были вне границ массива в словаре .Net
Я понимаю, что одной из главных причин индекса за пределами ошибки границ объекта Dictionary является столкновение потоков. (Чтение и запись в один и тот же словарь одновременно). Однако я столкнулся с недоумением, когда столкновение потоков не является достаточным объяснением.
Здесь ситуация:
Я написал код, который реализует словарь небезопасным способом для многопоточной обработки.
Код реализован как веб-служба на двух серверах, сервере A и сервере B. Доступ к разлочкам осуществляется через балансировщик нагрузки, который будет отправлять запросы серверам A и B циклическим способом.
Теперь вот сложная часть. Ошибка ТОЛЬКО появляется на сервере A и никогда на сервере B. Согласно нашей аппаратной команде, оба сервера идентичны. Хотя столкновение потоков по сути является случайным процессом, оно должно по-прежнему влиять на оба моих сервера одинаково. Я вижу 50+ экземпляров ошибки на одном сервере и 0 на другой. Статистически маловероятно, что конфликты потоков происходят только на одном из моих серверов, в то время как другой работает без ошибок.
Я уже изменяю приложение, чтобы сделать его потоком более безопасным, но какие другие причины могут существовать для этой ошибки, возникающей во время операции Вставки объекта Dictionary?
Ответы
Ответ 1
Хотя столкновение потоков по сути является случайным процессом
Совсем нет. Это критически зависит от времени. И время может быть повторяемо, системы, как правило, согласуются с конкретными шаблонами. Диагностический инструмент для расчёта нитей, такой как Microsoft Research CHESS, работает путем ввода случайных задержек в выполнение потока. Чтобы система выпала из такого шаблона. Как это иногда делает сам по себе, но только раз в неделю или около того. Это случайное, просто не случайное, чтобы когда-либо дать вам шанс отладить проблему.
Таким образом, если один сервер терпит неудачу, а другой ничего не значит. Вероятно, это связано с балансировкой нагрузки. Вы просто не сможете точно определить причину, потому что вы не можете узнать, что произошло в 50 раз. Этого недостаточно.
Ответ 2
Это, вероятно, надуманно, но знаете ли вы, знаете ли, что ваши соединения с двумя серверами через балансировщик нагрузки равны? (Я действительно ничего не знаю о том, как работает балансировка нагрузки, так что это может быть глупой мыслью от get-go.)
Я просто думаю, скажу, что у вас немного больше латентности сети в вашем соединении с сервером B, чем с сервером A. Это может обеспечить достаточное расстояние между клиентскими запросами на этом сервере, что приведет к доступу к словарю, позволяя вам уйти с вашим многопоточным код, который не является безопасным.
Если запросы доходят до сервера А немного быстрее, это может сделать разницу, которая дает вам ошибки вне диапазона.
Как я уже сказал, вероятно, надуманный - просто идея. Я подумал, что это не помешает выбросить его там.
Ответ 3
Я не могу объяснить, почему он не работает на одном сервере, но не на другом. Однако ваши проблемы являются многопоточными.
Как вы могли заметить, это не будет работать в многопоточной среде:
if (!dict.ContainsKey("myKey"))
dict.Add("myKey", value);
То же самое для:
if (dict.ContainsKey("myKey"))
return dict["myKey"];
Что может вас удивить, так это то, что TryGetValue также не является потокобезопасным:
MyObject obj;
return dict.TryGetValue("myKey", out obj) ? obj : null;
Ссылка: http://www.grumpydev.com/2010/02/25/thread-safe-dictionarytkeytvalue/