Blog Post

Core Infrastructure and Security Blog
7 MIN READ

Speed-up Content Distribution with PullDPs and BranchCache

StefanRöll's avatar
StefanRöll
Icon for Microsoft rankMicrosoft
May 31, 2019

Hello Everyone! I´m Stefan Röll, Premier Field Engineer (PFE) at Microsoft Germany for System Center Configuration Manager. One of my customers was challenged with large content distributions and relative slow connections to some satellite locations .

 

 

TL;DR

Pull Distribution Points (Pull DPs) can save you a lot of Bandwidth when used together with BranchCache, especially for downloads like Office 365ProPlus Updates, Definitions for Defender and (Boot)Images.

At my customer, I can see about 30% savings compared to Standard DPs. Especially for slow connected Systems, this can be a huge benefit.

 

The Challenge

My customer is starting to deploy Office 365ProPlus Updates including multiple Languages using SCCM.

We have noticed that this will cause a huge amount of data that needs to be sent to all Distribution Points each month.

When you download a single O365 Update with multiple Languages, you quickly end up with 6-8GB of Data.

 

This is because you do not download separate Updates for Office - you download the complete setup files for Office.

 

So how to get all that Data to the Distribution Points?

 

BranchCache LocalCache

BranchCache LocalCache is one of my favourite features of BranchCache, but unfortunately not well known.

No matter in which mode you are running BranchCache (Local, Distributed or Hosted), when downloading data BranchCache will always ask its LocalCache (aka DataCache) first, before asking peers in the Subnet (Distributed) or the HostedCache Server. In LocalCache mode it will not request data from other sources.

 

Proof of Concept

First, I wanted to find out if BranchCache LocalCache can help with Office Updates.

To do that I used ddpeval.exe and checked the data source of the package.

This will give you the Data Deduplication savings, which is what you can expect as download savings:

 

 

As you can see, we can expect about 34% savings when using Data Deduplication in this example.

As BranchCache is based on the same technology, you can expect similar savings.

 

For testing, I used the following PS-Script to download two Office Language Files from a Distribution Point.

 

$Cred = Get-Credential

 

$Source1"http://" + "dp01.sccm.lab/sms_dp_smspkg$/15f39dd2-5662-49b2-a502-9367d5b6fd86/office/data/16.0.11629.20136/stream.x86.en-us.dat"

$Source2"http://" + "dp01.sccm.lab/sms_dp_smspkg$/15f39dd2-5662-49b2-a502-9367d5b6fd86/office/data/16.0.11629.20136/stream.x86.de-de.dat"

 

Start-BitsTransfer -Source $Source1 -Destination "C:\Temp\stream.x86.en-us.dat" -Priority Low -Authentication Ntlm -Credential $Cred

Start-BitsTransfer -Source $Source2 -Destination "C:\Temp\stream.x86.de-de.dat" -Priority Low -Authentication Ntlm -Credential $Cred

 

In addition, I used the following Script to monitor the download on the Client side:

 

do

{

    $FromServer = "\BranchCache\BITS: Bytes from server"

    $FromCache  = "\BranchCache\BITS: Bytes from cache"

    $Time = Get-Date -Format hh:mm:ss

 

    $TotalMegaBytesfromServer = [math]::round(((Get-Counter $FromServer).CounterSamples.CookedValue / 1024 / 1024),0)

    $TotalMegaBytesfromCache  = [math]::round(((Get-Counter $FromCache ).CounterSamples.CookedValue / 1024 / 1024),0)

 

    $Ratio = If($TotalMegaBytesfromServer -gt 0){[math]::round(($TotalMegaBytesfromCache*100/($TotalMegaBytesfromServer+$TotalMegaBytesfromCache)),2)}else{0}

 

    Write-Output "MByte from Server: $($TotalMegaBytesfromServer) - MByte from Cache: $($TotalMegaBytesfromCache) - CacheRatio: $Ratio - Time: $Time"

    Start-Sleep -Seconds 10

}

until ($false)

 

Demo Download

 

The gif above shows how BranchCache LocalCache works. For better understanding, I moved the DataCache to the D: Drive.

 

 

What can you see?

  • The script and progress to download two Office language Files from a DP ( 1 )
  • The BranchCache download statistics ( 2 )
  • Although it downloads ( 4 ) to the C: drive, you can see that the D: drive has read/write access ( 3 )

 

Once the download completes, you can see that we saved 57 MB just by using BranchCache LocalCache - fantastic!

 



Basic Implementation

Implementation in SCCM is very simple. You just need to enable BranchCache on your source DP and on your PullDP:

 

 

Distmgr will enable BranchCache on the DP

 

 

With Get-BCStatus you can check the BranchCache Configuration on the DPs.

  

Advanced Implementation

In the default configuration the DataCache for BranchCache is very small, and savings will be limited.

Therefore I´ve wrote a Baseline to tune the BranchCache settings. You still need to enable BC on your DPs as mentioned in the Basic Implementation above.

 

The Baseline checks and fixes the following things:

 

  • BranchCache Server Feature is installed
  • BranchCache Service is started and set to automatic startup
  • Configures BranchCache for LocalCache or DistributedCache
  • Moves the BranchChache Caches to the same drive as the ContentLib
    • My customer has a separate drive for the ContentLib
    • The drive has a lot of free space, so it´s ideal for BranchCache data
  • Configures BranchCache limit
    • DataCache 50% of the Drive
    • Ensures better download savings
    • HashCache 50% of the Drive
    • Helps if BranchCache enabled Clients are downloading from this DP
  • Configures a longer age time (70 days) for data in the cache
    • Ensures better download savings over time

 

You can use the Baseline as template for your environment but be sure to test it out before using it in production.

 

Discovery Script:

<#

# THIS SAMPLE CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,

# WHETHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED

# WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.

# IF THIS CODE AND INFORMATION IS MODIFIED, THE ENTIRE RISK OF USE OR RESULTS IN

# CONNECTION WITH THE USE OF THIS CODE AND INFORMATION REMAINS WITH THE USER.

#>

Import-Module BranchCache

$OK = $true

 

#Check if BranchCache Server Feature installed

$Feature = Get-WindowsFeature -Name BranchCache

if ($Feature.Installed -ne $true) {$OK = $false}

 

#Check BranchCache Service Status

$Service = Get-BCStatus

if ($Service.BranchCacheIsEnabled -ne "True") {$OK = $false}

if ($Service.ClientConfiguration.CurrentClientMode -ne "DistributedCache") {$OK = $false} #You need to decide if you want Distributed or local Cache

if ($Service.BranchCacheServiceStatus -ne "Running") {$OK = $false}

if ($Service.BranchCacheServiceStartType -ne "Automatic") {$OK = $false}

 

#Check BC location is same as SCCMContentLib

$HashCache = Get-BCHashCache -ErrorAction Stop

$DataCache = Get-BCDataCache -ErrorAction Stop

$ContentLibDrive = (Get-ItemProperty -Path "HKLM:\Software\Microsoft\SMS\DP" -Name ContentLibraryPath -ErrorAction SilentlyContinue).ContentLibraryPath

$ContentLibDrive = ($ContentLibDrive).SubString(0, 3)

$HashCacheDrive = ($HashCache.CacheFileDirectoryPath).SubString(0, 3)

$DataCacheDrive = ($DataCache.CacheFileDirectoryPath).SubString(0, 3)

if ($ContentLibDrive -ne $HashCacheDrive) {$OK = $false}

if ($ContentLibDrive -ne $DataCacheDrive) {$OK = $false}

 

#Check that Cache Sizes are correct

$HashCache = Get-ItemProperty -Path "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\PeerDist\CacheMgr\Publication" -Name SizePercent -ErrorAction SilentlyContinue

if ($HashCache.SizePercent -ne 50) {$OK = $false}

$DataCache = Get-ItemProperty -Path "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\PeerDist\CacheMgr\RePublication" -Name SizePercent -ErrorAction SilentlyContinue

if ($DataCache.SizePercent -ne 50) {$OK = $false}

 

#Check BranchCache MaxAge

$CacheAge = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\PeerDist\Retrieval" -Name SegmentTTL -ErrorAction SilentlyContinue

if ($CacheAge.SegmentTTL -ne 70) {$OK = $false}

 

return $OK

 

Remediation Script:

<#

# THIS SAMPLE CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,

# WHETHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED

# WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR PURPOSE.

# IF THIS CODE AND INFORMATION IS MODIFIED, THE ENTIRE RISK OF USE OR RESULTS IN

# CONNECTION WITH THE USE OF THIS CODE AND INFORMATION REMAINS WITH THE USER.

#>

Import-Module BranchCache

 

#Install BranchCache Server Feature if not installed

$Feature = Get-WindowsFeature -Name BranchCache

if ($Feature.Installed -ne $true) {Install-WindowsFeature -Name BranchCache}

 

#Fix BranchCache Service Status

$Service = Get-BCStatus

if ($Service.BranchCacheIsEnabled -ne "True") {Enable-BCDistributed -Force} #If you don�t want to enable Distributed Mode, use Enable-BCLocal

if ($Service.ClientConfiguration.CurrentClientMode -ne "DistributedCache") {Enable-BCDistributed -Force} #You need to decide if you want Distributed or local Cache

if ($Service.BranchCacheServiceStatus -ne "Running") {Start-Service PeerDistSvc}

if ($Service.BranchCacheServiceStartType -ne "Automatic") {Set-Service PeerDistSvc -StartupType Automatic}

 

#Fix BC location

$HashCache = Get-BCHashCache -ErrorAction Stop

$DataCache = Get-BCDataCache -ErrorAction Stop

$ContentLibDrive = (Get-ItemProperty -Path "HKLM:\Software\Microsoft\SMS\DP" -Name ContentLibraryPath -ErrorAction Stop).ContentLibraryPath

$ContentLibDrive = ($ContentLibDrive).SubString(0, 3)

$HashCacheDrive = ($HashCache.CacheFileDirectoryPath).SubString(0, 3)

$DataCacheDrive = ($DataCache.CacheFileDirectoryPath).SubString(0, 3)

$HashCacheDest = $ContentLibDrive + "BranchCache\Publication"

$DataCacheDest = $ContentLibDrive + "BranchCache\RePublication"

if ($ContentLibDrive -ne $HashCacheDrive) {

      New-Item -ItemType directory -Path $HashCacheDest -Force -ErrorAction Stop

       #Clear Cachce and restart service to ensure move works

      Clear-BCCache -Force -ErrorAction Stop

       Restart-Service PeerDistSvc -Force

       Get-BCHashCache | Set-BCCache -MoveTo $HashCacheDest -Force -ErrorAction Stop

}

if ($ContentLibDrive -ne $DataCacheDrive) {

       New-Item -ItemType directory -Path $DataCacheDest -Force -ErrorAction Stop

       #Clear Cachce and restart service to ensure move works

       Clear-BCCache -Force -ErrorAction Stop

       Restart-Service PeerDistSvc -Force

       Get-BCDataCache | Set-BCCache -MoveTo $DataCacheDest -Force -ErrorAction Stop

}

 

#FixCache Sizes

$HashCache = Get-ItemProperty -Path "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\PeerDist\CacheMgr\Publication" -Name SizePercent -ErrorAction SilentlyContinue

if ($HashCache.SizePercent -ne 50) {Get-BCHashCache | Set-BCCache -Percentage 50 -Force}

$DataCache = Get-ItemProperty -Path "HKLM:\Software\Microsoft\Windows NT\CurrentVersion\PeerDist\CacheMgr\RePublication" -Name SizePercent -ErrorAction SilentlyContinue

if ($DataCache.SizePercent -ne 50) {Get-BCDataCache | Set-BCCache -Percentage 50 -Force}

 

#Fix BranchCache MaxAge

$CacheAge = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\PeerDist\Retrieval" -Name SegmentTTL -ErrorAction SilentlyContinue

if ($CacheAge.SegmentTTL -ne 70) {Set-BCDataCacheEntryMaxAge -TimeDays 70 -Force}

 

Final Test

As a final test I have distributed four office updates with six different languages:

 

 

They have a total size of ~15GB and savings should be around 45%:

 

 

 

Mission succeeded! We have saved ~45% of data just by enabling BranchCache :-)

 

Happy BranchCaching!

 

Stefan Röll

Premier Field Engineer - Microsoft Germany

 

Changelog:

V1.0 - 05/31/2019 - initial release

V1.1 - 06/05/2019 - Fixed Bug in Discovery and Remediation Script

 

Disclaimer:
The sample scripts are not supported under any Microsoft standard support program or service. The sample scripts are provided AS IS without warranty of any kind. Microsoft further disclaims all implied warranties including, without limitation, any implied warranties of merchantability or of fitness for a particular purpose. The entire risk arising out of the use or performance of the sample scripts and documentation remains with you. In no event shall Microsoft, its authors, or anyone else involved in the creation, production, or delivery of the scripts be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the sample scripts or documentation, even if Microsoft has been advised of the possibility of such damages.
 
Updated Jun 05, 2019
Version 2.0
  • surferstylee's avatar
    surferstylee
    Brass Contributor

    Great write-up StefanRöll . . . . I can 100% echo the benefits of what you have taken the time to here to describe so well.  If you have not done it yet, try throwing some LEDBaT into that same mix and prepare to have a full-on mind explosion my friend!!!

  • kneesliding's avatar
    kneesliding
    Copper Contributor

    Hi,

     

    How would this work if I have a central Push DP and a Pull DP at a remote site? 

  • Hi kneesliding,

    you just enable BranchCache on your SourceDP and PullDP.

    When the PullDP then downloads something from the SourceDP, BranchCache will do its magic.

    Cheers,

    Stefan