Мы пишем программный инструмент, который позволяет использовать механизм аутентификации Active Directory. Он периодически синхронизирует группы пользователей между AD и инструментом. Некоторые из наших клиентов заметили, что во время операции синхронизации высока нагрузка на ЦП на серверах AD.
Я искал возможные причины, которые могут вызвать проблему. Одна из них - вложенные группы.
Также я обнаружил в Интернете, что у других людей тоже были такие проблемы, и когда они сменили порт AD, проблема исчезла. Я хотел бы знать, реалистичен ли последний сценарий (для меня немного странно, что изменение порта AD может решить проблему) и есть ли другие распространенные причины, которые могут вызвать проблему.
Мы используем следующий запрос для sync:
(&(memberof:1.2.840.113556.1.4.1941:=group_DN)(objectclass=user)(!(objectclass=computer))
Не используйте переходную оценку правила соответствия LDAP для рекурсивного членства в группах. Оно пресловуто медленное, особенно при большом количестве каталогов/групп. членства.
http://dunnry.com/blog/TransitiveLinkValueFilterEvaluation.aspx
https://stackoverflow.com/questions/9534669/improving-recursive-active-directory-function
Так получилось выяснилось, что проблема действительно была во вложенных группах. Я «перенес» логику рекурсии на клиентскую сторону, и это сократило время выполнения примерно в 10 раз. Я не знаю, насколько увеличится сетевой трафик. В любом случае, вот фрагмент кода, который я использовал, на тот случай, если кому-то интересно:
public Set<String> getUsersInGroup(String groupDN) throws NamingException {
Set<String> ret = new HashSet<>();
Queue<String> bfsQueue = new LinkedList<>();
bfsQueue.add(groupDN);
Set<String> visitedGroups = new HashSet<>();
LdapContext ctx = getLdapContext(MAX_SEARCH_TIME, false);
String[] attrIDs = getUserReturnAttrs().toArray(new String[0]);
while (!bfsQueue.isEmpty()) {
String current = bfsQueue.element();
bfsQueue.remove();
visitedGroups.add(current);
String userFilter = "(&(objectclass=user)(!(objectclass=computer)))";
String groupFilter = "(&(objectclass=group)(!(objectclass=computer)))";
String memberOfFilter = String.format("(memberof=%s)", current);
String userQuery = String.format("(&%s%s)", memberOfFilter, userFilter);
String groupQuery = String.format("(&%s%s)", memberOfFilter, groupFilter);
Set<SearchResult> groups = search(ctx, getSearchBase(), groupQuery, SearchControls.SUBTREE_SCOPE,
new String[] { "distinguishedName" }, NO_COUNT_LIMIT);
for (SearchResult g : groups) {
Attributes attrs = g.getAttributes();
String gDN = parseAttribute(attrs, "distinguishedName");
if (!visitedGroups.contains(gDN)) bfsQueue.add(gDN);
}
Set<SearchResult> users = search(ctx, getSearchBase(), userQuery, SearchControls.SUBTREE_SCOPE,
attrIDs, NO_COUNT_LIMIT);
for (SearchResult u : users) {
Attributes attrs = u.getAttributes();
String uDN = parseAttribute(attrs, "userPrincipalName");
ret.add(uDN);
}
}
return ret;
}