LDAP连接超时需调TCP keepalive而非仅timeout参数;AD分页须用RFC 2696控件并传递cookie;0x71错误主因是MaxResultSetSize超限,非权限问题;同步须用uSNChanged而非whenChanged。
LDAP连接超时:不是改timeout参数就能解决
ldap连接超时往往不是网络延迟导致,而是客户端在等待服务器响应时,被中间代理(如负载均衡器、防火墙)主动断连。openldap客户端默认的ldap_set_option(ld, ldap_opt_timeout, &tv)只控制本地socket读写超时,对tcp空闲断连无效。
真正起作用的是底层TCP keepalive参数:
-
net.ipv4.tcp_keepalive_time(Linux)需设为小于代理的空闲切断阈值(常见是300秒),建议调至240 - Java应用要显式启用:启动时加
-Dcom.sun.jndi.ldap.connect.pool.timeout=5000,并确保java.naming.ldap.factory.socket指向自定义SocketFactory以设置SO_KEEPALIVE - Python的
ldap3库需在Server初始化时传get_info=ALL并手动调用connection.open()后立即发connection.search保活,否则首次search可能触发静默重连失败
LDAP分页查询被截断:别信“一页1000条很安全”
Active Directory默认硬限制PageSize=1000,但实际能返回多少取决于MaxResultSetSize策略(域控制器组策略中配置),常被误设为5000甚至更低。单纯增大客户端size_limit或page_size参数毫无意义——服务器直接拒绝或静默截断。
必须用RFC 2696标准分页控件(Paged Results Control),且每次请求必须携带上一次返回的cookie:
- Python
ldap3:用paged_size=500+paging=True,循环中检查response['controls']['1.2.840.113556.1.4.319']['value']['cookie']是否为空 - Java JNDI:必须用
Control[]传入PagedResultsControl,且每次DirContext.search()前要更新cookie,漏掉一步就停在第一页 - 错误现象:返回结果突然变少、
javax.naming.PartialResultException、或ldap_search_ext_s: Timelimit exceeded(其实是分页cookie失效被当超时)
AD域控返回“0x71 LDAP_ADMIN_LIMIT_EXCEEDED”:这不是配额问题
这个错误码(LDAP_ADMIN_LIMIT_EXCEEDED)常被当成账号权限不足,实际90%是服务端对单次查询的**总条目数限制**被突破,和分页无关。AD默认MaxQueryDuration(150秒)和MaxResultSetSize(通常10000)共同作用——即使你分页取,只要累计匹配条目超过MaxResultSetSize,整个search操作就会被终止。
绕过方法只有两个:
- 加更精确的filter,例如把
(objectClass=user)拆成(sAMAccountName>=a)(sAMAccountName按字母分段查 - 改用
attributeScoping缩小属性范围,避免*或+通配,尤其禁用memberOf这类高开销属性(它会触发递归组解析) - 绝对不要在生产环境临时修改
MaxResultSetSize——该值由域策略统一推送,改了可能被覆盖,且影响所有应用
数据库最大分页限制(如MySQL 5.7的SQL_CALC_FOUND_ROWS):和LDAP无关但常被混搭出问题
有些系统把LDAP同步数据存进MySQL再分页展示,这时容易把LDAP分页逻辑和数据库LIMIT混用。典型错误是:LDAP已用Paged Results取回全部用户,却还在MySQL层做LIMIT 0,20,导致前端永远只看到第一页数据。
正确做法是明确分层责任:
- LDAP层只负责“拉全量增量”,用
changeNotification控件或USNChanged属性做变更捕获,避免全量轮询 - 数据库层只负责“查缓存”,分页由MySQL的
OFFSET/LIMIT或游标式WHERE id > ? ORDER BY id LIMIT 20完成 - 如果必须LDAP直查+DB分页,得在应用层做两级缓存:先用LDAP Paged Results加载到内存List,再按需切片——但仅限万级以下数据,否则OOM
最易被忽略的一点:AD的whenChanged精度是1秒,同一秒内多笔修改会导致同步丢失,必须结合uSNChanged(64位递增整数)做严格序号比对。










