Group Policy – Monolithic vs Functional Design and Performance Evaluation

Group Policy – Monolithic vs Functional Design and Performance Evaluation

2018-04-09
/ /
in Blog
/

Group Policy Design is a hotly discussed topic, with lots of different ideas and discussions.  However, there is not a whole lot of actual metrics.  ADM and ADMX templates apply registry keys in an ‘enforced’ manner.  That is, if you or the machine has access to read the policies, the registry keys within are applied.  If you stuck purely to ADM/ADMX policies but wanted to do dynamic filtering or application of the keys/values based on a set of criteria you’d probably design multiple policies and nested organizational units (OUs).  From here, you could filter certain policies based on the machine or user location in the OU structure or by filtering on the policies themselves and denying access to certain groups or doing explicit allows to certain groups.  This design style, back in the day, was called “functional” design.

 

However, the alternative style, “monolithic” design, simplifies the group policy object (GPO) design into much fewer GPO’s.

 

Setup

My test setup is very simple; a organizational unit (OU) with inheritance blocked to control the application of the GPO’s.  I created 100 individual GPO’s with a single registry value, and 1 GPO with 100 values.  I chose to do a simple registry addition as it should be the best performance option for group policy.  I created a custom ADMX file for this purpose:

Monolithic simulation:

 

Functional simulation:

 

Testing

In testing these two designs I elected to focus on the one factor that would have the most impact: latency.  I setup my client machine in the OU, put a WAN emulator that can manipulate latency and measured the performance between the functional and monolithic designs at varying latencies.  I looked for the following event ID’s: 4257, 5257, 4016, 5016.  The x257 events correspond to when group policy downloads the group policy objects off the SYSVOL file share.  The x016 event’s determine how long it took the policy to be processed.

 

The results:

 

Raw Data:

Functional GPO – applying 100 registry values
Event ID 4016 to 5016 (ms)
Latency Time (ms)
0 271
10 4089
25 8078
50 15315
75 22904
100 29820
Event ID 4257 to 5257 – Starting to download policies
Latency Time (s)
0 0
10 3
25 6
50 12
75 17
100 22

 

Monolithic GPO – applying 100 registry values
Event ID 4016 to 5016 (ms)
Latency Time (ms)
0 117
10 156
25 198
50 284
75 336
100 435
Event ID 4257 to 5257 – Starting to download policies
Latency Time (s)
0 0
10 0
25 1
50 1
75 1
100 1

 

Analysis:

There is a huge edge to the monolithic design.  Both in terms of how long it takes to process a single policy vs multiple policies and the resiliency to the effects of latency.  Even ‘light’ latency can have a profound impact on performance.  Going from 0ms to 10ms increased the length of time to process a functional design by 15 times!  The monolithic design, on the other hand, was barely impacted.  Even with a latency of 100ms, it only added ~300ms of time to process the policy.  I would consider this imperceptible in the real world, where as the functional design going from ~271ms to ~4000ms would be an extremely noticeable impact!  Let alone about 30 seconds at 100ms!

Another factor is how much additional time is required to download the policies.  This is time in addition to the processing time.  This probably shouldn’t be a huge surprise, it appears that group policies are downloaded and processed sequentially, in an order.  I’m sure this is necessary to maintain some semblance of prediction if you have conflicting policies settings, the one last in the list (whether sorted alphabetically or what have you) can be relied on to be the winner.

Adding latency, even just a little latency, has a noticeable impact.  And the more policies, the more traffic, the more the impact of latency.  Again, a loss for a functional design and a win for a more monolithic design.

Conclusion:

Group Policy Objects can have a large impact on user experience.  The goal should be to minimize them to as few as possible.  As with everything, there are exceptions to the rules, but for Group Policy it’s important to try and maintain this rule.  Even just a little latency between the domain controller and the client can have a massive impact in group policy performance.  This can impact the length of time it takes a machine to boot, to delaying a user logging into a system.

 

4 Comments

  1. David Taylor 2018-04-11 1:24 pm

    In the specific test scenario you gave, a monolithic policy will perform better. However, there are many scenarios and factors that come into play that can and do make the monolithic design less than optimal. Ultimately, environment-specific testing is required and there are very good tools to do that. The tool of choice is Windows Performance Toolkit (WPA/WPR) for Windows 8+ and Xperf for older Windows OSes. https://docs.microsoft.com/en-us/windows-hardware/test/wpt.

    Group policy application consists of both foreground and background (refresh) processing. Foreground happens for computers at startup, and for users at login. Background happens by default at random 60-120 minutes (default setting of 90min +/- 30 min random factor) later, except on Domain Controllers where it happens by default every 5 minutes. The distinction is important between these to (foreground/background) as the processing load may be different due to the Client Side Extensions choice of whether or not to process all, some, or none, of the settings during the background processing. During background refresh, processing by default, the client side extensions only reapply settings if they detect a change to one of the GPOs or to the list of GPOs in scope (as that could mean order of precedence change).

    Consider; if you set up exactly as you have for test: If no policy is changed, background processing will be fast for either as neither will need processing. If only one setting changes in the monolithic policy, the entire policy must be downloaded and reapplied. But in the ‘functional’ design: only one tiny part needs to be re-applied. This may not seem like a big deal as it’s only 1/100th of the settings and surely the wrapper on each policy and packet flow adds up to a lot anyhow, right? It becomes a big deal if the setting that did not change the policy but must be executed during the refresh is a significant process/load item. In the real world application, the effects of the simple registry change very. Every change does not have the same resulting load on the client. However, in the monolithic design, every change has all the effects on the client.

    Generally, if you cannot do the testing, my advice is to consolidate all ‘simple’ settings that have little CSE impact into as few policies as you need. If they are all the same level, have the same filtering, and do not do major CSE impact, keep them together. If the scope differs, create the new policy. If the estimate of CSE load is that it will be higher cost, create a new policy for it and it’s related settings.

    Darren Mar-Elias, MVP has great guidance on this that lines up with my experience from back when I was a Premier Field Engineer for Microsoft (I work at Oracle; this is my opinion and may not reflect the opinions of my current or former employer(s).

    Reply
    • David Taylor 2018-04-11 1:26 pm

      I forgot to add this link Darren’s post on Technet: https://technet.microsoft.com/en-us/library/2008.01.gpperf.aspx

      Reply
    • trententtye 2018-04-11 9:42 pm

      Awesome response David!

      You are absolutely correct that a variety of factors need to come into play into making an informed decision that works best for your organization. Excluding CSE’s as a topic of discussion, monolithic design would not work if you require some form of dynamic application of policies and you only want to rely on administrative templates. A more functional design + OU’s + Security filtering might have to be the design choice at that time…

      One of the issues I have with the “only one tiny part needs to be re-applied” is that registery.pol files are *tiny* anyways. Applying the policy is /fast/.

      Doing a quick test, I created a GPO with over a thousand registry values and the total size of the .pol is 92KB. Applying all of those different values/keys took ~480ms. So I’m curious if the “only apply one tiny part” is an old school way of thinking, maybe more relevant to the days of 150MHz Pentiums as opposed to 1.2GHz machines we have now. (I’ll also add that your supporting article is from a decade ago and probably could probably be updated with real testing. I struggle with articles that are “trust me, I know best” even if it’s direct from the vendor — like Microsoft) 🙂

      Reply
      • David Taylor 2018-04-12 8:54 am

        I agree the registry changes themselves do not add up to much in total size. However, small changes to any policy can trigger processing of unchanged elements in the same GPO. Monolithic policies have more such settings and increase the chances of this happening. This seems inefficient; to the point of being unbelievable. However, it can happen because, whenever policy change occurs, the version number for the change portion (user/computer, or both) is incremented. When incremented, that entire portion of the GPO may be re-evaluated by each CSE that depends upon to inform the CSE’s actions. Only the CSE knows what keys it must evaluate when it is invoked. This is why I said, ‘ It becomes a big deal if the setting that did not change the policy but must be executed during the refresh is a significant process/load item.’ Microsoft does not make all of the CSEs that may apply to any client. 3rd party vendors code their own. It should not be expected that they will all behave well. CSE’s are called if there are settings in a changed policy even if the setting itself has not changed. And, the author of the CSE decides how the CSE will respond. In many cases, the author chooses to have the settings reinforced. Another consideration is that policy changes may also include files that must be transferred. While those files used in policy creation should be small they often are larger than what should be in real-world environments.

        The key thing is that Microsoft (my past employer) has been pretty consistent about this since the inception of Group Policy until today: The only way to know for sure is to test for each specific scenario. That is because they don’t own every CSE and cannot test every CSE combination people might use in varied environments.

        Reply

Post a Comment

Your email address will not be published. Required fields are marked *

*