Источник: блог YanDBlogs, 15.12.2013,
http://yandblogs.wordpress.com/2013/12/15/%D0%BA%D0%BB%D0%B0%D1%81%D1%82%D0%B5%D1%80%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F-oracle-identity-management/
О кластеризации IDM было уже сказано не раз, подборку материалов по этой теме можно найти в конце статьи. Я же хочу далее сосредоточиться на практической стороне вопроса. Да, во всех встречавшихся мне документах достаточно подробно и широко рассмотрены многочисленные вопросы обеспечения HA для продуктов всего семейства Fusion Middleware, в общем, и Identity management, в частности. Однако же им не хватает деталей конкретной реализации: как заставить все перечисленные отдельные HA компоненты работать совместно?
Ниже описано, как все это работает в нашей картине мира на кластере из нескольких серверов commodity hardware в разных ДЦ.
Нет смысла описывать, как конкретно кластеризуется каждый из компонентов: для этого есть документация. Проблема обеспечения отказоустойчивости состоит в том, что необходимо каким-то образом связать разнородные компоненты (ldap сервера, java приложения, web-сервера на apache) так, чтобы автоматически о выходе из строя одного из них узнавали все элементы мозаики и больше к нему не обращались. Ключевое архитектурное решение здесь – использовать для общения с любым компонентом, даже внутри системы, балансеры. В документации также есть явное упоминание этого: “All components in the Oracle Identity Management software stack require a hardware load balancer when deployed in a high availability configuration”. Единственное, что не так в этой цитате – использование hardware балансировщиков. В действительности нет необходимости приобретать какое-то дополнительное оборудование, со всем задачами справляются software решения. У нас это были OHS, haproxy и nginx. Каждый для своего компонента и со своим набором фич. С одной стороны, это решило проблему связей между компонентами: ходи в балансер и не думай о том, что там с риал-серверами за ним. С другой стороны, позволило выбирать способы определения живости сервера в зависимости от его свойств. Например, web-сервер может быть вполне себе живой формально, но при этом отдавать на любой запрос HTTP 500-ю ошибку.
Для начала стандартная картинка, какие компоненты участвуют в процессе аутентификации пользователя в OeBS:
Рис. Потоки запросов процесса аутентификации пользователя OeBS
На этой картинке каждый компонент должен быть задублирован, а каждая стрелка потока данных должна идти через балансер. Часть компонентов инфраструктуры уже были кластеризованы и исходная диспозицция была такова:
AccessGate - приложение java в контейнере weblogic, Webgate - модуль для Apache совместно с модулем OHS. Так что здесь делаем все по стандартной схеме:
<Location /ebsauth_OEBS> SetHandler weblogic-handler WebLogicCluster server1:7043,server2:7043 RequestHeader set IS_SSL ssl WLProxySSL on </Location>
OAM, как и AccessGate - приложение java в контейнере weblogic, так что, подобно accessgate, приложение устанавливается в кластер weblogic. И, как у любого сервера weblogic, для него можно задать номера HTTP/HTTPS портов. Однако же эти порты предназначеня для общения с внешним миром. Номера портов для общения с webgate другие и прописываются в конфиге OAM. Очевидно, OHS для доступа использоваться не может, и все адреса машин кластера OAM прописываются в настройках webgate - файле ObAccessClient.xml, а за работу в кластерной конфигурации отвечает сам webgate. Проблем с этим нет и все работает "из коробки". Пример конфига ObAccessClient.xml
<ValNameList
xmlns="http://www.oblix.com"
ListName="primaryServer1">
<NameValPair
ParamName="host"
Value="server1">
</NameValPair>
<NameValPair
ParamName="port"
Value="5576">
</NameValPair>
<NameValPair
ParamName="numOfConnections"
Value="1">
</NameValPair>
</ValNameList>
<ValNameList
xmlns="http://www.oblix.com"
ListName="primaryServer2">
<NameValPair
ParamName="host"
Value="server2">
</NameValPair>
<NameValPair
ParamName="port"
Value="5576">
</NameValPair>
<NameValPair
ParamName="numOfConnections"
Value="8">
</NameValPair>
</ValNameList>
Для всех внешних систем компонены кластера IDM представляют собой комплект web-серверов. Общение с ними может осуществляться как через OHS (о настройке accessgate было выше, о дополнительных шагах для OAM можно почитать в пункте 9.2.3.12 Configure Access Manager to Work with Oracle HTTP Server), так и через внешние балансеры. Мы использовали внешний балансер nginx, в основном по причинам:
Требований к балансеру достаточно много (3.4.1 Load Balancer Requirements), но ключевое его свойство - обеспечение Sticky routing capability. На старте проекта мы потратили достаточно много времени, пытаясь понять причину множества невразумительных ошибок и падений процесса аутентификации в самых неожиданных местах. Оказалось, что OHS, а вместе с ними webgate и OAM, весьма чувствителен к процессу аутентификации. Т.е. ничего страшного не произойдет, если через некоторое время клиент придет на другой сервер. Однако же первые несколько GET запросов HTTP в процессе аутентификации сессии должны придти на один и тот же сервер. Т.е. честный round robin get запросов не работает. Описание оказалось длинее, чем реальный конфиг nginx, который в действительности тривиален, пример для webgate:
upstream webgate {
ip_hash;
server server1:2004 max_fails=10 fail_timeout=120;
server server2:2004 max_fails=10 fail_timeout=120;
}
server {
listen *:2003;
server_name webgate;
set $remote_protocol "https";
ssl on;
location / {
proxy_pass $remote_protocol://$host;
proxy_set_header Host $host;
}
}
В конфиге мы не стали делать SSL Offloading, сейчас сервис этого не требует.
В вопросе балансировки ldap-запросов нас поджидала аналогичная предыдущему пункту диллема: использовать native средства или же проверенное сторонее решение (под native понимается установить на каждый хост связку OID+OVD)? Аналогичным образом, решение было принято в пользу стороннего решения на базе haproxy. Решающим моментом здесь стало следующее соображение. Когда строится HA решение, всегда нужно учитывать, что любой компонент может выйти из строя. Что в таком случае прописывать в качестве IP-адреса сервера? Для клиентского доступа используется IPVS, но использовать его для связности компонент внутри системы представляется overkill. Остается localhost, т.е. каждый хост должен иметь свой собственный балансер. Устаналивать на каждый из них native средства - опять же, чрезмерно сложно. Учитывая, что для OeBS нам нужен enterprise user security и в oracle virtual directory будут ходить также все ноды real application cluster. В результате, лучшим решением стал haproxy, слушающий localhost, на каждом хосте в простейшей конфигурации:
listen OID :3061
mode tcp
option tcplog
log 127.0.0.1 local3 info
server server2 server2:3060 check
server server1 server1:3060 check backup
listen OIDS :3132
mode tcp
option tcplog
log 127.0.0.1 local3 info
server server2 server2:3131 check
server server1 server1:3131 check backup
listen OVD :6502
mode tcp
option tcplog
log 127.0.0.1 local3 info
server server2 server2:6501 check
server server1 server1:6501 check backup
Конфиг выкатывается из пакета rpm в репозитарии, так что всех забот с разворачиванием локального балансера - сказать yum install.
Это оказалось сделать проще всего :) Просто используется SCAN-адрес и адрес балансера OeBS.
P.S.. Спустя полгода после начала эксплуатации пришлось полностью перейти на nginx в качестве риала после балансировщика. К сожалению, закончился старый сертификат, а новый выпускается только с OCSP. Нормально OCSP в OHS не поддерживается. С Java и Weblogic все существенно лучше, но проблемы есть и здесь.