Как разработать высоко масштабируемые веб-сервисы на Java?


15

Я создаю несколько веб-служб, которые будут иметь 2000 одновременных пользователей. Услуги предлагаются бесплатно и, следовательно, ожидается, что они получат большую базу пользователей. В будущем может потребоваться масштабирование до 50 000 пользователей.

Уже есть несколько других вопросов, касающихся этой проблемы, например: /programming/2567254/building-highly-scalable-web-services

Однако мои требования отличаются от вопроса выше.

Например - мое приложение не имеет пользовательского интерфейса, поэтому изображения, CSS, javascript не являются проблемой. Это на Java, поэтому такие предложения, как использование HipHop для перевода PHP в нативный код, бесполезны.

Поэтому я решил задать свой вопрос отдельно.

Это мой проект настройки -

  1. Веб-сервисы, основанные на отдыхе, использующие Apache CXF
  2. Hibernate 3.0 (с соответствующими оптимизациями, такими как отложенная загрузка и настраиваемый HQL для настройки)
  3. Tomcat 6.0
  4. MySql 5.5

Каковы наилучшие практики, чтобы сделать масштабируемое приложение на Java?


Если вы предоставляете сервис REST, использование обратного прокси-сервера, такого как Varnish, очень поможет. Насколько свежими должны быть данные? Вы уверены, что вам нужна реляционная база данных? Не могли бы вы разделить данные? Учитывая описанный вами технологический стек, я бы сосредоточился на том, чтобы как можно меньше запросов действительно попадало в вашу конечную точку. Вы пытались сделать это в памяти с помощью таких решений, как Hazel cast / Gigaspaces и т. Д.?
ebaxt

@ebaxt спасибо за ваши предложения. Gigaspaces, похоже, с открытым исходным кодом. Но Hazel Cast выглядит интересно.
Кшитиз Шарма

1
@ebaxt "Вы уверены, что вам нужна реляционная база данных?" Принятие nosql приведет к радикальным изменениям в архитектуре приложения. Мы пытаемся свести сложность к минимуму. Стоимость, хотя и не является фактором для нас. Поэтому мы будем придерживаться реляционного подхода.
Кшитиз Шарма

1
Вы можете использовать Postgres, MySQL или что-либо еще. Как насчет вашей инфраструктуры? Можете ли вы использовать дисковые массивы? Расположены ли серверы в одном месте? Можете ли вы связать свой кластер с сердцебиением и т. Д.? Вы можете поместить их в одну подсеть?
edze

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

Ответы:


8

Я занимался этой проблемой в прошлом, но все же чувствую, что мне есть чему поучиться на поле. Я считаю, что это одна из самых интересных областей, которые существуют в настоящее время в разработке программного обеспечения, вот некоторые соображения по этому поводу:
MySQL является достаточно справедливой базой данных, если вы не работаете с огромным объемом данных, и в этом случае вы можете рассмотреть NoSQL базы данных, но вы должны тщательно изучить, какая база данных NoSQL лучше всего подходит для ваших нужд.

Вы должны внедрить кеширование в своей системе - попытаться кешировать как можно больше данных только для чтения или определить некоторые стратегии кеширования - например, у нас был сценарий, в котором для пользователя было бы допустимо видеть «старые данные» как пока последнее обновление имело место в последний час.
Я хотел бы рассмотреть JBoss Cache, или, возможно, Infinispan (который больше похож на распределенную структуру данных) или другую популярную инфраструктуру кэширования для этого.
Кроме того, как вы упомянули tomcat, я предполагаю, что вы работаете в каком-то модуле запроса-ответа. Попробуйте рассмотреть возможность использования кэша, который существует в области данного запроса, это может быть даже простой HashMap, связанный с локальным хранилищем потока .
Моя идея здесь очень напоминает кеш первого уровня в Hibernate .

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

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

Вы должны рассмотреть возможность использования кластеризации - вам придется иметь дело с такими проблемами, как балансировка нагрузки , зависание сеанса (что означает, что балансировщик нагрузки перенаправит запрос на тот же сервер для того же сеанса) и многое другое.

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

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

Я уже упоминал о спящем режиме - я бы порекомендовал вам тщательно рассмотреть возможность его использования - если вам нужно выполнять много записей и меньше чтений, Hibernate может не подойти вам, и вам следует подумать, возможно, работа с Spring-JDBC в качестве оболочки над JDBC.

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

Я хотел бы заявить, что в прошлом я имел дело с системой (один узел) на mysql (в основном доступ только для чтения) с jboss 4.2.1 и смог достичь 2000 одновременных пользователи
(не получая доступ сразу с точки зрения открытия 2000 сокетов на нашем сервере), но используя / просматривая нашу систему, используя JBoss Cache и предварительно загружая в кеш некоторые наиболее часто используемые данные, или данные, которые мы поняли, будут «горячими и популярными» «но наше решение было хорошо для нашей архитектуры и наших потоков,
поэтому, как я уже говорил в этих случаях, -
есть еще советы и рекомендации, но они действительно зависят от вашей архитектуры и от того, какие потоки вам нужны в вашей системе». Удачи!


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

3

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

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

Однако, как вы заметили, могут быть проблемы с соединениями с базой данных. Но у меня вопрос, как вы получаете данные? Это пользовательский или вы получаете данные от третьих лиц? Это очень важно, потому что, если вы предоставляете сервис своему пользователю с данными, агрегированными из стороннего приложения (например, FB, Twitter и т. Д.), То вы можете выполнить запись в основную базу данных и реплицировать данные в подчиненные базы данных. которые выделяются каждому экземпляру tomcat. Тогда каждый tomcat-сервер может получить из своей собственной подчиненной базы данных.

 Are there faster alternatives to Mysql?

Вы можете перейти на кластер MySQL, который имеет хранилище данных в памяти. Но остерегайтесь того факта, что приложению могут потребоваться некоторые изменения. Они sql joinsплохо поддерживаются в кластере MySQL, хотя в последней версии есть улучшения для этого. Если стоимость не является фактором, то вы можете попробовать Oracle.

Решение для кэширования определенно улучшит производительность. Но тогда все зависит от архитектуры всего приложения. Вы должны хорошо знать, когда помещать данные в кеш, когда делать их грязными (удалять из кеша).

Что касается распределения нагрузки в многосерверной среде, я бы предложил вам использовать балансировщик нагрузки, а не Apache для балансировки нагрузки.


«Я бы предложил вам использовать балансировщик нагрузки, а не Apache для балансировки нагрузки». Какой подход / программное обеспечение вы бы предложили, если бы не Apache?
Кшитиз Шарма

В основном я рекомендовал оборудование балансировки нагрузки, которое должен быть в состоянии настроить сетевой администратор. Этот курс имеет дополнительную стоимость для проекта. Этот балансировщик нагрузки будет иметь свой собственный IP-адрес (также называемый виртуальным IP-адресом), и в основном вы будете назначать этот IP-адрес своему домену. Когда приходит запрос, он направляет его на все подключенные серверы в циклическом режиме (также доступны другие алгоритмы). Вы можете использовать apache для этой цели, если аппаратное обеспечение не подходит, но я бы предпочел аппаратное обеспечение, поскольку вам не нужно настраивать apache только для этой цели.

Мы используем выделенный сервер с httpd, чтобы сделать то же самое. Аппаратное обеспечение не является проблемой.
Кшитиз Шарма

Вы можете использовать httpd и mod_cluster, если я правильно помню. Я бы тщательно обдумал, прежде чем перейти к «избыточному» решению аппаратного LB, прежде чем проверять httpd и mod_cluster

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

2

В настоящее время я настраиваю подобную систему (на профессиональном уровне), и вот дизайн, который я выбрал:

  • Два балансировщика нагрузки Nginx (оба активны, оба отказоустойчивы для другого, сбалансированы с циклическим перебором DNS)
  • Две базы данных MySQL в режиме мастер-репликации
  • Два экземпляра Tomcat как кластер Tomcat
  • Два экземпляра Memcached для кэширования и совместного использования состояния сеанса для кластера Tomcat

Это позволит создать избыточное масштабируемое решение с высокой доступностью.

Балансировщики нагрузки (на приличном оборудовании) легко загружают насыщенную линию 1 Гбит каждая. Это также отличное место для разгрузки SSL.

Вы можете сохранить информацию о сеансе в memcached. В случае сбоя экземпляра tomcat другой экземпляр tomcat может получить соответствующую информацию о сеансе, и клиенты ничего не заметят. Не забудьте сочетать это с липкими сессиями тоже. (Чтобы снизить сетевой трафик)

В кластерах Tomcat также есть возможность обмениваться информацией о сеансах между кластерами в режиме реального времени без использования memcached. Хотя я думаю, что с точки зрения производительности лучше использовать Memcached.

Если вам нужно больше энергии в любом из этих приложений:

  • Nginx: добавьте больше loadbalancers, хотя я не думаю, что это будет узким местом очень скоро.
  • Tomcat: вы можете легко увеличить размер кластера Tomcat или добавить больше кластеров
  • Mysql: добавить несколько ведомых только для чтения или увеличить размер кластера (в зависимости от вашего приложения, но поскольку вы написали приложение на основе REST, это не должно быть проблемой)
  • Memcached: добавьте больше узлов, Memcached достаточно хорошо масштабируется.

Я не знаю, как строится ваше приложение и каковы большие проблемы с ресурсами, но если вы видите высокую нагрузку на базу данных (во время ваших нагрузочных тестов!), Добавление кеша между приложением и базой данных, безусловно, может значительно повысить производительность. Но не забывайте, что не все кэшируется, если ваши запросы всегда разные, кэширование не поможет (сильно)

Мой совет - скачать VMware Workbench (или программное обеспечение для виртуализации similair) и попытаться создать простую установку. Нет балансировки нагрузки или кластеризации, только основы и работа оттуда. Один за другим добавьте больше функций (балансировка, кэширование, кластеризация и т. Д.) И обязательно проведите некоторые исследования по каждой теме, чтобы вы знали, что сделали правильный выбор.

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

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

Есть еще вопросы?

Удачи!

Wesley


фундук? hazelcast.com
NimChimpsky

Используете ли вы фреймворк для уровня кэширования или просто несколько ручных хэшей для SQL-запросов?
Джечлин
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.