Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Slow processing on a remote server #102

Open
sej69 opened this issue Nov 2, 2020 · 7 comments
Open

Slow processing on a remote server #102

sej69 opened this issue Nov 2, 2020 · 7 comments
Labels

Comments

@sej69
Copy link

sej69 commented Nov 2, 2020

I'm working on migrating code over to your library because of the async methods. In MSAD I opened the connection and maintained that throughout the processing because of the time it took to initiate the connection. But this doesn't seem to have any affect in processing with your library. I created two button methods to initiate the async. One is to my domain in which my dev computer is connected to, the other is to a domain controller on the same network, but the computer is not joined to the domain.

    private async void btnStartTest_Click(object sender, EventArgs e)
    {
        tbxProcess.Text = string.Empty;
        tbxTiming.Text = string.Empty;
        using (var cn = new LdapConnection())
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            // connect
            cn.Connect();
            tbxTiming.Text += "Connect " + sw.Elapsed + "\r\n";
            // bind using kerberos credential cache file
            await cn.BindAsync();
            tbxTiming.Text += "Bind " + sw.Elapsed + "\r\n";
            // call ldap op
            var entries = await cn.SearchAsync("dc=mynetwork,dc=local", "(objectClass=group)");
            tbxTiming.Text += "Pull Entries " + sw.Elapsed + "\r\n";
            foreach (var item in entries)
            {
                tbxProcess.Text += item.Dn + "\r\n";
            }
            sw.Stop();
            lblProcessed.Text = "Processed time: " + sw.Elapsed;
        }
    }

    // test domain not authenticated to by computer
    private async void btnButton2_Click(object sender, EventArgs e)
    {
        tbxProcess.Text = string.Empty;
        tbxTiming.Text = string.Empty;
        using (var cn = new LdapConnection())
        {
            Stopwatch sw = new Stopwatch();
            sw.Start();
            cn.Timeout = new TimeSpan(0, 0, 2); 
            // connect
            cn.Connect("10.1.1.11",389);
            tbxTiming.Text += "Connect " + sw.Elapsed + "\r\n";
            // bind using kerberos credential cache file
            await cn.BindAsync("GSSAPI","[email protected]","mypass");
            tbxTiming.Text += "Bind " + sw.Elapsed + "\r\n";

            // call ldap op
            var entries = await cn.SearchAsync("dc=testdomain1, dc=local", "(objectClass=group)");
            tbxTiming.Text += "Pull Entries " + sw.Elapsed + "\r\n";
            foreach (var item in entries)
            {
                tbxProcess.Text += item.Dn + "\r\n";
            }
            sw.Stop();
            lblProcessed.Text = "Processed time: " + sw.Elapsed;
        }
    }

When I hit the first button I get the response:
Connect 00:00:00.0091144
Bind 00:00:00.0277939
Pull Entries 00:00:00.3237716

and subsequent hits are very similar in time.

For the second button (to the domain not authenticated by the computer but on the SAME network) I get this:

Connect 00:00:00.0002284
Bind 00:00:00.0101008
Pull Entries 00:00:06.3929474

The time is between 5-7 seconds on each hit which makes this too slow to use.

I then created a third button to try to keep the connection open using this:

    LdapConnection remoteCN = null;

    // test domain not authenticated to by computer reusing connection
    private async void btnButton3_Click(object sender, EventArgs e)
    {
        tbxProcess.Text = string.Empty;
        tbxTiming.Text = string.Empty;

        Stopwatch sw = new Stopwatch();
        sw.Start();
        if (remoteCN == null)
        {
            remoteCN = new LdapConnection();
            remoteCN.Timeout = new TimeSpan(0, 0, 2); // 1 minute
            // connect
            remoteCN.Connect("10.1.1.11", 389);
            tbxTiming.Text += "Connect " + sw.Elapsed + "\r\n";
            // bind using kerberos credential cache file
            await remoteCN.BindAsync("GSSAPI", "[email protected]", "mypass");
            tbxTiming.Text += "Bind " + sw.Elapsed + "\r\n";
        }

        // call ldap op
        var entries = await remoteCN.SearchAsync("dc=testdomain1, dc=local", "(objectClass=group)");
        tbxTiming.Text += "Pull Entries " + sw.Elapsed + "\r\n";
        foreach (var item in entries)
        {
            tbxProcess.Text += item.Dn + "\r\n";
        }
        sw.Stop();
        lblProcessed.Text = "Processed time: " + sw.Elapsed;
    }

Clicking the button the first time I get:
Connect 00:00:00.0081138
Bind 00:00:00.0294921
Pull Entries 00:00:05.0790592

subsequent responses I get something similar to this:
Pull Entries 00:00:05.0610168

I see there is a feature request for connection pooling, but with what I'm seeing here I'm not sure that would fix anything...? Is there a way I can speed up these requests?

MSAD, winform (for quick testing), library 2.7.11

UPDATE:
In playing with this some more, it appears the directory searcher itself is much slower. I played with modifying an account and if I know the DN or SID it's fast:

Connect 00:00:00.0079363
Bind 00:00:00.0278668
Modify Entry 00:00:00.0144028

While not ideal, I can make this work for about 90% of cases by caching the SID on the account. But when processing a new account to see if it exists before trying to create, this will still create an issue...

Using's MS's directory searcher is fast, but it's not async.

@flamencist
Copy link
Owner

I guess that ms directory searcher cached connection.

@sej69
Copy link
Author

sej69 commented Nov 2, 2020

Ah, are you saying the connection is closed each time even in the third button scenario?

@flamencist
Copy link
Owner

I think that AD server has limit allowed connections. And in all examples you created new connection. Try to reuse your connection and check performance again

@sej69
Copy link
Author

sej69 commented Nov 2, 2020

It's better but it's still happening. This is the new code here:

    LdapConnection remoteCN = null;

    private async Task DoNextCache(string UserToProcess, int nCount)
    {
        if (remoteCN == null)
        {
            remoteCN = new LdapConnection();
            remoteCN.Timeout = new TimeSpan(0, 0, 2); // 1 minute
                                                      // connect
            remoteCN.Connect("10.1.1.11", 389);
            await remoteCN.BindAsync("GSSAPI", "[email protected]", "mypass");
        }

        await remoteCN.ModifyAsync(new LdapModifyEntry
        {
            Dn = "CN=Hand Created,CN=Users,DC=TestDomain1,DC=local",// entries[0].Dn,
            Attributes = new List<LdapModifyAttribute>
            {
                new LdapModifyAttribute
                {
                    LdapModOperation = LdapModOperation.LDAP_MOD_REPLACE,
                    Type = "department",
                    Values = new List<string> { "testDept " + nCount }
                }
            }
        });
    }

@flamencist
Copy link
Owner

Looks like its server issue. Try check performance on server side. Maybe some replication issue or not optimized query.

@sej69
Copy link
Author

sej69 commented Nov 2, 2020

This is a test server that I just spun up last week on it's own domain and the only server / computer on that domain... No repllications, no additional domain controllers; just this server.

@AmirHJabari
Copy link

AmirHJabari commented Dec 16, 2023

I have kinda the same problem and I used System.DirectoryServices it was so fast.
but the problem is System.DirectoryServices package is supported only on windows hosts
@flamencist

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants