Syncronizing large number of users (over 500,000)

Syncronizing large number of users (over 500,000)

by Scott Karren -
Number of replies: 25
All

I am using CAS authentication and trying to get the cas_ldap_sync_users.php script working. I am able to authenticate and all user fields are being mapped so I know that a connection to the LDAP server is being established.

When I try the sync script it connects, creates the temp table, sits there for 30 minutes and then returns "Did not get any users from LDAP error? exiting" I have a feeling that it is related to the number of users in our LDAP dir, just over 645,000.

I am able to browse the directory through an LDAP browser just fine and like I said before if I login it maps fields perfectly for each individual user.

Is there a timeout setting in the authentication scripts somewhere that I can play with to see if it is timeing out before getting all users or some way that I can limit the number of users I get from LDAP?

Scott Karren
Average of ratings: -
In reply to Scott Karren

Re: Syncronizing large number of users (over 500,000)

by Scott Karren -
Anyone have any thoughts on this? I have tested it several times and every time it sits for 30 minutes and them returns the above error.

I forgot this before but here are my specs

Windows 2003 Virtual Server
PHP 5.2.5
Moodle 1.9.3+
Mysql 5.01b
Apache 2.2.8

Scott Karren
In reply to Scott Karren

Re: Syncronizing large number of users (over 500,000)

by HJWUCGA INC. -
Is your LDAP active directory? Tell us more about your LDAP configuration.

If I'm not mistaken, there is a limit by default, the number of records return on an ldap query.
In reply to HJWUCGA INC.

Re: Syncronizing large number of users (over 500,000)

by Scott Karren -
Chris

It is a Sun Directory Server, Here is my ldap config.

Version - 3
LDAP encoding - utf-8
UserType - PosixAccount(Rfc2307)
Contexts ou=utah.edu
Search Subcontexts - Yes
Deference Alias - No
User attribute - unid
member attribute - blank
member attribute uses DN - blank
Object Class - *


Scott Karren
In reply to Scott Karren

Re: Syncronizing large number of users (over 500,000)

by Scott Karren -

I have narrowed the problem down to the fact that the LDAP server is timing out trying to get 645,000 users.  No amount of tweaking on the Moodle side has helped and the group that manages the LDAP is unable to reset the timeout or max query size.  Because the LDAP is part of UEN (Utah Education Network) it includes all prospective university students (all senior and graduated high school students).  I don't needs these people.  Is there someplace in the auth.php file that I can hardcode the search query for the attributes that I want to get?

Any help is appreciated.

Scott Karren

In reply to Scott Karren

Re: Syncronizing large number of users (over 500,000)

by Iñaki Arenaza -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

If you are using a recent 1.8 or 1.9 version (later than 2008.08.24), you can set the objecClass setting to any valid LDAP filter to select the users subset you are interested in.

For example you can set it to:

(&(objectClass=user)(postalCode=20500))

and you'll only get those users whose postal code is 20500.

Saludos. Iñaki.

In reply to Iñaki Arenaza

Re: Syncronizing large number of users (over 500,000)

by Scott Karren -
Inaki

Let me make sure I understand correctly. Would this filter go in the objectclass setting in the LDAP settings screen? If so would that filter only allow users with the postal code of 20500 to login to the system?

I am using CAS authentication but I need to sync users from the LDAP that I am connecting to. I am mainly concerned with being able to sync employees, but I need to leave the system accessible to students as well.

In looking at the auth.php in the CAS directory I noticed these lines of code

////
//// get user's list from ldap to sql in a scalable fashion
////
// prepare some data we'll need
$filter = "(&(".$this->config->user_attribute."=*)(".$this->config->objectclass."))";

Can I rewrite this line to look only for uuemployee=uuCurrentEmployee for the sync only?

Scott
In reply to Scott Karren

Re: Syncronizing large number of users (over 500,000)

by Iñaki Arenaza -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

Would this filter go in the objectclass setting in the LDAP settings screen?

Yes, the filter would go in the objectclass setting in the LDAP settings screen. But this is only available in the LDAP plugin, not the CAS plugin (even if you use LDAP as the CAS backend; both plugins are completely independent from 1.8 on).

If so would that filter only allow users with the postal code of 20500 to login to the system?

No, login doesn't have into account the objectclass value, but the user attribute setting only. So any user inside the configured contexts should be able to log in.

Can I rewrite this line to look only for uuemployee=uuCurrentEmployee for the sync only?

Sure you can smile Just make sure you rewrite it again every time you upgrade your moodle install!

Saludos. Iñaki.

In reply to Iñaki Arenaza

Re: Syncronizing large number of users (over 500,000)

by Scott Karren -
Thanks for the info, I appreciate it. So not being the PHP developer that I would like to be. What changes would I make to the following line of code to sync only current employees?

$filter = "(&(".$this->config->user_attribute."=*)(".$this->config->objectclass."))";

I have tried $filter = '(&('.$this->config->user_attribute.'=*)'.$this->config->objectclass.'=uuCurrentEmployee)';

But this just results in an argument error on a different line. Can you help me here?

Scott
In reply to Scott Karren

Re: Syncronizing large number of users (over 500,000)

by Iñaki Arenaza -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

Assuming that 'uuemployee' is the attribute you want to check for, and that 'uuCurrentEmployee' is the value that attribute should have, something like the following should do the trick:

$filter = "(&(".$this->config->user_attribute."=*)(".$this->config->objectclass.")(uuemployee=uuCurrentEmployee))";

Saludos. Iñaki.

In reply to Iñaki Arenaza

Re: Syncronizing large number of users (over 500,000)

by Scott Karren -
Inaki

Thank you!! That filter worked very well for me. My LDAP result set is down from 645,000 to just under 30,000.

The script connects and runs and starts to either insert or update users, but is stopping after 30 minutes with the error "LDAP Module cannot connect to any servers" It does not seem to matter what I do to tweak config settings it still stops at 30 minutes (+/- a couple of minutes). Any ideas what might be happening here?

Scott Karren
In reply to Scott Karren

Re: Syncronizing large number of users (over 500,000)

by Alan Zaitchik -
I have a similar problem, and looking at the TCP/IP connections I see hundreds of them entering a wait state. I posted a separate query just a little while ago here:
http://moodle.org/mod/forum/discuss.php?d=115460
which may be the same issue. It seems that the connections do not close.
In my case I am calling sync_users(1000) but I tried sync_users(1) without any benefit. Also, I tweaked LDAP's MAXPAGESIZE without any noticeable effect.
Alan
In reply to Alan Zaitchik

Re: Syncronizing large number of users (over 500,000)

by Scott Karren -
Alan

This is very interesting, are you seeing these connections on your webserver or on the LDAP server? In looking at my webserver with the sync script running I have almost 500000 active tcp connections, when the script closes that number drops just a little bit.

Are you able to sync any users or does the script just sit there? I have tried variations on both the sync_users and bulk_insert with the same results.

Scott Karren
In reply to Alan Zaitchik

Re: Syncronizing large number of users (over 500,000)

by Iñaki Arenaza -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

The wait state is a normal state. After TCP closes a connection, the standard mandates that the socket associated with that connection must remain in a waiting state for some time (up to four minutes!) before we can reuse it, to make really sure both ends have closed it properly.

The problem you are seeing is a mix of the way Moodle queries the LDAP server (it opens a new connection to get the user details, once it has determined the user has to be added/updated) and your LDAP server not expiring closed connections fast enough (and probably imposing a hard limit on the number of 'active/waiting' connections).

You should probably file a bug in the tracker, pointing it to this thread, and post the bug number here, so we can track it smile

Saludos. Iñaki.

In reply to Iñaki Arenaza

Re: Syncronizing large number of users (over 500,000)

by Scott Karren -
MDL-18130 has been logged. Please add further details if I missed anything.

Scott Karren
In reply to Scott Karren

Re: Syncronizing large number of users (over 500,000)

by Iñaki Arenaza -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

What command line are you using to run the script? It might happen that PHP is terminating the script because it has reached the max_execution_time value (beware that PHP doesn't count system calls as execution time, so time spent inside ldap connections, etc won't count towards that time limit). Also the script might be reaching the memory_limit value.

For a user set that big, setting generous limits for both max_execution_time and memory_limit is usually a good idea, in addition to enabling debugging and logging options, as recommended at the top of the auth_ldap_sync_users.php script.

Saludos. Iñaki.

In reply to Iñaki Arenaza

Re: Syncronizing large number of users (over 500,000)

by Scott Karren -
Here is the command line that I run C:\php\edutest\php-win.exe -d memory_limit=512M -f C:\inetroot\edutest\educationroot\auth\cas\cas_ldap_sync_users.php > c:\weblogs\test\cron\syncfile.log


Right now max_execution_time=30, max_input_time=60, and memory limit=128M are what are set in the php.ini file.

What would you suggest for the max_execution_time and memory_limit?

Scott Karren
In reply to Scott Karren

Re: Syncronizing large number of users (over 500,000)

by Iñaki Arenaza -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

Humm, you are using CAS. I don't know why but I thought you were using LDAP. Will have to recheck some things, as the CAS plugin and the LDAP plugin are no longer using the same code, so things could work a little bit different.

The memory_limit value is probably ok. I'd set the max_execution_time to 900 or even '0' (to disable it completely). Hmmmm, acording to http://www.php.net/manual/en/info.configuration.php#ini.max-execution-time max_execution_time is set to 0 when running php on the command line, so doesn't look like this could be the problem.

Anyway, adding the debugging and logging options could shed some light, so I'd run it like this:

C:\php\edutest\php-win.exe -d memory_limit=512M -d log_errors=1 -d error_reporting=E_ALL -d display_errors=0 -d html_errors=0 -d error_log=C:\weblogs\test\cron\syncfile-errors.log-f C:\inetroot\edutest\educationroot\auth\cas\cas_ldap_sync_users.php > C:\weblogs\test\cron\syncfile.log

And then, in addition to having a look at syncfile.log, you should have a look at the syncfile-errors.log (that will hold the PHP errors, if any).

Saludos. Iñaki.

In reply to Iñaki Arenaza

Re: Syncronizing large number of users (over 500,000)

by Scott Karren -

Iñaki

I ran the command line that you suggested and am attaching the resulting files. Even increasing the memory and execution time did not help.  Any thoughts.

Scott Karren

In reply to Scott Karren

Re: Syncronizing large number of users (over 500,000)

by Iñaki Arenaza -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

It seems the LDAP server is refusing connections after some time. You could probably be suffering the same problem as Alan Zaitchnik, but after a longer period of time.

I'll see if I can come up with a patch to reuse connections, instead of opening a new one for each user we are updating or creating anew, and see if that makes a difference.

Saludos. Iñaki.

In reply to Iñaki Arenaza

Re: Syncronizing large number of users (over 500,000)

by Scott Karren -
Iñaki

That would be great!! Please let me know what I can do to assist.

Scott Karren
In reply to Scott Karren

Re: Syncronizing large number of users (over 500,000)

by Iñaki Arenaza -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

Scott,

here's a patch you can try. I've tested it locally with 700 users and it keeps only one connection open for the whole sync run.

In addition to that, it lowers the total run time from 18 seconds to 9 seconds (which I suspect is due to LDAP connections setup and tear down time).

Can you try it in a test box and see if it makes a difference for you? Put the file at the top or your moodle installation directory and then follow the steps outlined in http://docs.moodle.org/en/Development:How_to_apply_a_patch

Saludos. Iñaki.

In reply to Iñaki Arenaza

Re: Syncronizing large number of users (over 500,000)

by Scott Karren -
Iñaki

Thank you very much for this, I have one question. The diff file patches the auth.php file in the auth/ldap dir, since I use CAS authentication and I know the auth.php in the auth/cas dir is different will this patch still work?

I am working on bringing the auth.php in the cas dir more up to date, but I am not as proficient as I would like to be.

Scott Karren
In reply to Scott Karren

Re: Syncronizing large number of users (over 500,000)

by Iñaki Arenaza -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

I keep on forgetting that you are using CAS instead of LDAP sad. Anyway, here's the same patch for the CAS auth plugin. Note that I haven't tested it, as I don't have a CAS server to test it, but it's almost a clone of the LDAP patch (I've just added a couple of missing calls to ldap_close(), but they shouldn't be called from sync_users(), so that shouldn't really make a difference).

Saludos. Iñaki.

In reply to Iñaki Arenaza

Re: Syncronizing large number of users (over 500,000)

by Scott Karren -
Iñaki

Ok, so I have tested your patch numerous times this morning. It picked up the correct number of users, inserted/updated them accordingly and did it in half the time it used to take. 29711 users doing a full insert takes 21 minutes (emptying the user table and repopulating it), doing an update takes 16 minutes. And it did all of this using just one connection. I still need to test it and see how it does against suspending internal accounts, but as of right now it is working very well. I would definitely reccomend throwing both of these patches into core. Thank you!!!

Scott Karren
In reply to Scott Karren

Re: Syncronizing large number of users (over 500,000)

by Iñaki Arenaza -
Picture of Core developers Picture of Documentation writers Picture of Particularly helpful Moodlers Picture of Peer reviewers Picture of Plugin developers

I have just committed both patches in 1.9 and HEAD (the future 2.0).

Saludos. Iñaki.