Лучший способ синхронизации данных кэша между двумя серверами [закрыто]

хотите синхронизировать данные кэша между двумя серверами. Обе базы данных используют одну и ту же базу данных, но для лучшего выполнения я кэшировал данные в хэш-карту при запуске. Таким образом, требуется синхронизировать кэшированные данные без перезапуска серверов. (Оба сервера запускаются одновременно).

пожалуйста, предложите мне лучший и эффективный способ сделать.

3 ответов


вместо того, чтобы пытаться синхронизировать кэшированные данные между двумя экземплярами сервера, почему бы не централизовать кэширование вместо использования чего-то вроде memcached/couchbase или redis? Использование распределенного кэширования с чем-то вроде ehcache намного сложнее и подвержено ошибкам IMO против централизации кэшированных данных с помощью кэширующего сервера, подобного упомянутым.

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

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

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

редактировать:

A вопрос был задан в комментариях о преимуществах централизованного кэша (я предполагаю, что против чего-то вроде распределенного кэша в памяти). Я дам свое мнение по этому поводу, но сначала стандартный отказ от ответственности. Централизованное кэширование-это не лекарство. Он направлен на решение конкретных проблем, связанных с кэшированием в памяти jvm. Прежде чем оценивать, следует ли переключаться на него, вы должны сначала понять, в чем ваши проблемы, и посмотреть, соответствуют ли они преимуществам централизованного кэширования. Централизованное кэширование-это архитектурное изменение, и оно может иметь свои проблемы/предостережения. Не переключайтесь на это просто, потому что кто-то говорит, что это лучше, чем то, что вы делаете. Убедитесь, что причина соответствует проблеме.

хорошо, теперь мое мнение о том, какие проблемы централизованное кэширование может решить против кэширования в JVM-памяти (и, возможно, распределенного). Я собираюсь перечислить две вещи, хотя я уверен, что есть еще несколько. Мои два больших:Общая Память След и Проблемы Синхронизации Данных.

с Общий Объем Памяти. Предположим, вы выполняете стандартное кэширование сущностей для защиты реляционной БД от чрезмерного стресса. Предположим также, что у вас есть много данных для кэширования, чтобы действительно защитить вашу БД; скажем, в диапазоне многих GBs. Если вы делаете кэширование в JVM-памяти, и вы говорите, что у вас было 10 ящиков сервера приложений, вам нужно будет получить эту дополнительную память ( $ $ $ ) раз 10 для каждый из ящиков, которые должны были бы выполнять кэширование в памяти jvm. Кроме того, вам придется выделить большую кучу для вашей JVM, чтобы разместить кэшированные данные. Я придерживаюсь мнения, что куча JVM должна быть небольшой и обтекаемой, чтобы облегчить бремя сбора мусора. Если у вас есть большие куски старого поколения, которые не могут быть собраны, то вы собираетесь подчеркнуть свой сборщик мусора, когда он перейдет в полный GC и попытается пожать что-то из этого раздутого старого Gen space. Вы хотите избежать длительных пауз GC2, и раздувание вашего старого поколения не поможет в этом. Кроме того, если потребность в памяти превышает определенный порог, и вы случайно запускаете 32-битные машины для своего уровня приложения, вам придется обновить до 64-битных машин, и это может быть еще одна запретительная стоимость.

теперь, если вы решили централизовать кэшированные данные (используя что-то вроде Redis или Memcached), вы можете значительно уменьшить общую память footprint кэшированных данных, потому что вы можете иметь его на нескольких полях вместо всех полей сервера приложений в слое приложения. Вероятно, вы хотите использовать кластерный подход (обе технологии поддерживают его) и по крайней мере два сервера, чтобы обеспечить высокую доступность и избежать одной точки сбоя в вашем слое кэширования (подробнее об этом через секунду). Имея пару машин для поддержки необходимого объема памяти для кэширования, вы можете сэкономить значительные $$. Кроме того, вы можете настроить app коробки и коробки кэша по-разному теперь, как они служат различным целям. Коробки приложения можно настроить для высокой пропускной способности и низкой кучи, а коробки кэша-для большой памяти. И имея меньшие кучи, безусловно, поможет с общей пропускной способностью коробки слоя приложения.

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

теперь Проблемы Синхронизации Данных. При распределенном кэшировании в памяти jvm необходимо синхронизировать кэш. Изменение кэшированных данных на одном узле должно реплицироваться на другие узлы и синхронизироваться с их кэшированными данными. Такой подход немного страшно в том, что если по какой-то причине (например, сбой сети) один из узлов выпадает из синхронизации, то когда запрос идет на этот узел, данные, которые видит пользователь, не будут точными по сравнению с тем, что в настоящее время находится в БД. Хуже того, если они сделают другой запрос и попадут на другой узел, они увидят другие данные, и это будет путать пользователя. Централизация данных устраняет эту проблему. Теперь можно утверждать, что централизованный кэш нуждается в параллелизме управление обновлениями одного и того же кэшированного ключа данных. Если два параллельных обновления приходят для одного и того же ключа, как вы убедитесь, что два обновления не наступают друг на друга? Моя мысль здесь заключается в том, чтобы даже не беспокоиться об этом; когда произойдет обновление, удалите элемент из кэша (и напишите, хотя непосредственно в БД), и пусть он будет перезагружен при следующем чтении. Так безопаснее и проще. Если вы не хотите этого делать, вы можете использовать функциональность CAS (Check-And-Set) вместо оптимистичной управление параллелизмом, если вы действительно хотите обновить кэш и БД при обновлениях.

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


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

Если, однако, вам это нужно, попробуйте остановить повторное изобретение колес. Есть идеальные готовые к использованию библиотеки. Например ehCache это распределенный режим.


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