Windows Azure Guest OS

by Brian Hitney 17. May 2010 20:05

In a Windows Azure project, you can specify the Guest OS version for your VM.  This is done by setting the osVersion property inside the ServiceConfiguration file:

image

If you don’t specify a version explicitly, the latest Guest OS is chosen for you.  For production applications, it’s probably best to always provide an explicit value, and I have a real world lesson that demonstrates this!

MSDN currently has a Guest OS Version and SDK Compatibility Matrix page that is extremely helpful if you’re trying to figure out which versions offer what features.  I recently ran into a problem when examining some of my performance counters – they were all zero (and shouldn’t have been)!  Curious to find out why, I did some digging (which means someone internal told me what I was doing wrong).

In short, I had specified a performance counter to monitor like so:  "\ASP.NET Applications(__Total__)\Requests/Sec".  This had worked fine, but when I next redeployed some weeks later, the new Guest OS (with .NET Fx 4.0) took this to mean 4.0 Requests/Sec, because I didn’t specify a version.   So, I was getting zero requests/sec because my app was running on the earlier runtime.  This was fixed by changing the performance counter to "\ASP.NET Apps v2.0.50727(__Total__)\Requests/Sec".  

For more information on this, check out this article on MSDN.  And thanks to the guys in the forum for getting me up and running so quickly!

Tags: , ,

Azure | Development | Tech Tips

Ip2Location (and IPinfoDB) Performance Tips

by Brian Hitney 9. March 2010 14:00

I’ve done a number of talks lately on Worldmaps and typically in side conversations/emails, people are curious about the databases and converting IP addresses to geographic locations.   And, often when you dive into using the data, it seems there are a number of performance considerations and I thought I’d share my input on these topics.

First up, the data.  Worldmaps uses two databases for IP resolution.  The primary/production database is Ip2Location.  I’ve found this database to be very accurate.  For development/demo purposes, I use IPinfoDB.  I haven’t had too much time to play with this database yet, but so far seems accurate also.   The latter is free, whereas Ip2Location is not.

In either case, the schema is nearly identical:

image

The BeginIp and EndIp columns are a clustered primary key.  In the case of IPinfoDB, there is no EndIp field (and it’s not really needed).  When performing a resolution, a string IP address is converted into a 64 bit integer and then used in searching the table.  That’s why having a clustered key on the BeginIp (and optionally EndIp) is crucial to performance.

But it doesn’t stop there.   The examples posted in the database’s respective home pages are accurate and simple, but need to be refactored for performance.  For example, to do a simple resolution on Ip2Location, according to their docs:

SELECT * FROM dbo.Ip2Location WHERE @IpNum BETWEEN BeginIp and EndIp

And for IPInfoDB:

SELECT TOP 1 * FROM IPInfoDB where BeginIp <= @IpNum ORDER BY BeginIp DESC

Both of these methods are perfectly fine, particularly for use as generic samples.  The second one is on the right track, but it doesn’t work for joins so if you’re querying over a range, you’d need to refactor.  And in the first example, using a BETWEEN operator forces a clustered index scan when joining, killing the performance.

If we run the first example across my minified Ip2LocationSmall table, we’ll see something like this (and this is running off of SQL Azure – the perf is pretty great compared to localhost!):

image

We can also look at the time:

image

Ouch!  Now, it doesn’t seem too bad, but imagine doing thousands of these requests per minute, or doing large joins. 

The goal then is to provide some hints that will optimize the query, particularly for joins.  Our indexes are correct, so we can rework the query to get rid of the BETWEEN operator – we can sacrifice a little readability and do something like:

SELECT *   
FROM (
    select
        ( select MAX(beginip)
          from dbo.Ip2LocationSmall
          where BeginIp <= @IpNum
        ) as IP_Begin           
    ) as foo
INNER JOIN dbo.Ip2LocationSmall iploc
ON iploc.BeginIp = foo.IP_Begin

The result:

image

And the time shows some improvement:

image

But the REAL benefit comes when we need to join.   Suppose I’d like to get a list of the countries for a given map (which is a parameter called MapId):

SELECT DISTINCT(ip.CountryCode)
FROM MapHits hits
INNER JOIN dbo.Ip2LocationSmall ip
    ON hits.IpNum BETWEEN ip.BeginIp AND ip.EndIp
WHERE MapId = @MapId

The query returns 95 rows, and executes in 16 seconds:

image

image

In this case, we can refactor this using the method above to something like:

SELECT
    DISTINCT(CountryCode)   
FROM (
     select IpNum,
        ( select MAX(beginip)
          from Ip2LocationSmall
          where BeginIp <= IpNum
        ) as IP_Begin
      from dbo.MapHits as hits
      where MapId = @MapId
  ) as foo
INNER JOIN Ip2LocationSmall iploc
ON iploc.BeginIp = foo.IP_Begin

Again, not as pretty looking, but boy what a difference:

image

image

We went from 16,500 milliseconds to 260 – over 60x the performance!  Mike @AngryPets would be proud.   The reason for the perf gain is we were able to eliminate the nested loop, which is (in this case) scanning the entire clustered index for the matching rows.

The second benefit is the ability to switch schemas easily between IP2Location and IPinfoDB, and we can additionally lose the EndIp column which trims the size of the table.

Tags: , , ,

SQL Azure | SQL | Tech Tips | Development

Azure Miniseries #4: Monitoring Applications

by Brian Hitney 26. February 2010 03:58

In this screencast, we'll take a look at monitoring Azure applications by capturing event logs and performance counters. We'll also look at using PowerShell to deploy and configure applications using the management API. Finally, we'll take a sneak peek at Azure Diagnostics Manager, a tool from Cerebrata that allows you explore event logs and look at performance counters visually.

Get Microsoft Silverlight

Here are some links from the screencast:

Finally, let’s get into some code snippets! Watch for wrap on the PowerShell lines, and note the single quote ` character as the line continuation:

Creating a self-signed certificate command:

makecert -r -pe -a sha1 -n "CN=Azure Service Test" -ss My -len 2048 -sp "Microsoft Enhanced RSA and AES Cryptographic Provider" -sy 24 AzureServiceTest.cer

Uploading a new deployment to the staging slot, and starting it (requires Azure CmdLets):

$cert = Get-Item cert:\CurrentUser\My\{thumbprint}
$sub = "{subscription GUID}"
$servicename = "{service name}"

$package = "CloudApp.cspkg"
$config = "ServiceConfiguration.cscfg"

[DateTime]$datelabel = Get-Date
$lbl = $datelabel.ToString("MM-dd-yyyy-HH:mm")

Write-Host "Label for deployment: " $lbl

Add-PSSnapin AzureManagementToolsSnapIn

Get-HostedService $servicename -Certificate $cert -SubscriptionId $sub |
New-Deployment -Slot Staging $package $config -Label $lbl |
Get-OperationStatus -WaitToComplete

Get-Deployment staging -serviceName $servicename -SubscriptionId $sub -Certificate $cert |
Set-DeploymentStatus running |
Get-OperationStatus -WaitToComplete

Increasing the number of instances:

Add-PSSnapin AzureManagementToolsSnapIn

$cert = Get-Item cert:\CurrentUser\My\{thumbprint}
$sub = "{subscription GUID}"
$servicename = "{service name}"
$storage = "{storage name}"

#get storage account name and key
$key = (Get-StorageKeys -ServiceName $storage -Certificate $cert -SubscriptionId $sub).Primary
$deployId = (Get-HostedService $servicename -SubscriptionId $sub -Certificate $cert | Get-Deployment Production).DeploymentId       

Get-HostedService $servicename -Certificate $cert -SubscriptionId $sub |
    Get-Deployment -Slot Staging |
    Set-DeploymentConfiguration {$_.RolesConfiguration["WebRole1"].InstanceCount += 1}

Updating the performance counters – specifically, adding total processor time, ASP.NET req/sec, and memory usage to be polled every 30 seconds, and uploaded every 1 minute:

Add-PSSnapin AzureManagementToolsSnapIn

$cert = Get-Item cert:\CurrentUser\My\{thumbprint}
$sub = "{subscription GUID}"
$servicename = "{service name}"
$storage = "{storage name}"

#get storage account name and key
$key = (Get-StorageKeys -ServiceName $storage -Certificate $cert -SubscriptionId $sub).Primary
$deployId = (Get-HostedService $servicename -SubscriptionId $sub -Certificate $cert | Get-Deployment Production).DeploymentId       

# rate at which counters are polled
$rate = [TimeSpan]::FromSeconds(30)

Get-DiagnosticAwareRoles -StorageAccountName $storage -StorageAccountKey $key -DeploymentId $deployId |
foreach {
    $role = $_
    write-host $role
    Get-DiagnosticAwareRoleInstances $role -DeploymentId $deployId `
        -StorageAccountName $storage -StorageAccountKey $key |

    foreach {
        $instance = $_

        $config = Get-DiagnosticConfiguration -RoleName $role -InstanceId $_ -StorageAccountName $storage `
             -StorageAccountKey $key -BufferName PerformanceCounters -DeploymentId $deployId            
        $processorCounter = New-Object Microsoft.WindowsAzure.Diagnostics.PerformanceCounterConfiguration `
                -Property @{CounterSpecifier='\Processor(_Total)\% Processor Time'; SampleRate=$rate }
        $memoryCounter = New-Object Microsoft.WindowsAzure.Diagnostics.PerformanceCounterConfiguration `
                -Property @{CounterSpecifier='\Memory\Available Mbytes'; SampleRate=$rate }
        $requestsCounter = New-Object Microsoft.WindowsAzure.Diagnostics.PerformanceCounterConfiguration `
                -Property @{CounterSpecifier='\ASP.NET Applications(__Total__)\Requests/Sec'; SampleRate=$rate }
        $config.DataSources.Clear()
        $config.DataSources.Add($processorCounter)
        $config.DataSources.Add($memoryCounter)
        $config.DataSources.Add($requestsCounter)
        Set-PerformanceCounter -PerformanceCounters $config.DataSources -RoleName $role `
             -InstanceId $instance -DeploymentId $deployId `
             -TransferPeriod 1 `
             -StorageAccountName $storage -StorageAccountKey $key                     
    }  
}

And finally, the webrole.cs class from the screencast:

public class WebRole : RoleEntryPoint
    {
        public override bool OnStart()
        {
            DiagnosticMonitorConfiguration diagConfig =
                DiagnosticMonitor.GetDefaultInitialConfiguration();

            diagConfig.PerformanceCounters.DataSources.Add(
                new PerformanceCounterConfiguration()
                {
                    CounterSpecifier = @"\Processor(_Total)\% Processor Time",
                    SampleRate = TimeSpan.FromSeconds(5)
                });

            diagConfig.PerformanceCounters.DataSources.Add(
                new PerformanceCounterConfiguration()
                {
                    CounterSpecifier = @"\Memory\Available Mbytes",
                    SampleRate = TimeSpan.FromSeconds(5)
                });

            diagConfig.PerformanceCounters.ScheduledTransferPeriod =
                TimeSpan.FromMinutes(1);

            diagConfig.Logs.ScheduledTransferLogLevelFilter = LogLevel.Information;
            diagConfig.Logs.ScheduledTransferPeriod = TimeSpan.FromMinutes(1);

            DiagnosticMonitor.Start("DiagnosticsConnectionString", diagConfig);

            System.Diagnostics.Trace.TraceInformation("Done configuring diagnostics.");

            // For information on handling configuration changes
            // see the MSDN topic at http://go.microsoft.com/fwlink/?LinkId=166357.
            RoleEnvironment.Changing += RoleEnvironmentChanging;

            return base.OnStart();
        }

        public override void OnStop()
        {
            System.Diagnostics.Trace.TraceWarning("Onstop called.");
            base.OnStop();
        }

        private void RoleEnvironmentChanging(object sender, RoleEnvironmentChangingEventArgs e)
        {
            // If a configuration setting is changing
            if (e.Changes.Any(change => change is RoleEnvironmentConfigurationSettingChange))
            {
                // Set e.Cancel to true to restart this role instance
                e.Cancel = true;
            }
        }
    }

Tags: , , ,

Azure | Microsoft | Tech Tips

Azure Miniseries #3: ServiceConfig vs web.config

by Brian Hitney 22. February 2010 03:32

One of the challenges developers will face when developing Windows Azure web applications is: where do I put my settings?  In the ServiceConfiguration file or the web.config?

There isn’t one correct answer.  The challenge of keeping everything in the web.config is that it makes changes and deployment much more difficult.  Because the web.config is part of the deployment, any change to the file also requires a redeployment.  If you use a build system that targets your dev/stage/QA/prod environments automatically and can provide the correct settings in the web.config for you, this might mitigate the problem.

The answer then is to migrate these settings to the ServiceConfiguration file as it requires no changes to our deployment package.  In this screencast I’ll show you some strategies for doing that for components that are more difficult to migrate, like the SqlMembershipProvider…

Get Microsoft Silverlight

Link to original post and download links.

Tags: , ,

Azure | Microsoft | Tech Tips

WCF in an Azure WorkerRole

by Brian Hitney 12. February 2010 04:16

The other day, a colleague got in touch with me looking for help in getting a WCF service working in an Azure WorkerRole.   It would work locally, but not deployed in the cloud.   This is a common problem I’ve run into – for example, calling Open() on a ServiceHost will work locally, but no in the cloud due to permissions.

I wasn’t much help in getting John’s situation resolved, but he pinged me about it a couple days later with the solution.  The first is to make sure your service has the correct behavior to respond to any address:

[ServiceBehavior(AddressFilterMode = AddressFilterMode.Any)]

The next was to make sure you explicitly set the SecurityMode in the binding:

NetTcpBinding binding = new NetTcpBinding(SecurityMode.None); 

Webroles are different as they are hosted in IIS and limited to HTTP.

Also, there are some good demos mentioned in this post on the MSDN forums that points to the Azure All-In-One demos on CodePlex. 

Tags: , ,

Azure | Tech Tips

Azure SLA Confusion

by Brian Hitney 10. February 2010 07:00

Azure SLA is something that gets discussed quite a bit but there’s something that I see causing a bit of confusion.  The SLA for Azure compute instances states:

For compute, we guarantee that when you deploy two or more role instances in different fault and upgrade domains, your internet facing roles will have external connectivity at least 99.95% of the time.

Some folks (for example, this post) incorrectly conclude that you need to deploy your solution across 2 or more datacenters to get this SLA.  Actually, that’s not true – you just need to make sure they are in different fault and upgrade domains.  This is something that is typically done by default.  You can think of a fault domain as a physical separation in a different rack, so if there’s a hardware failure on the server or switch, it only affects instances within the same fault domain.  Upgrade domains are logical groupings that control how deployments are upgraded.  For large deployments, you may have multiple upgrade domains so that all roles within an upgrade domain are upgraded as a group.

To illustrate this, I spun up 3 instances of Worldmaps running on my local Dev Fabric.  I have an admin tool in the site that shows all current instances, their role, and their domain affiliation:

image

The admin page uses the RoleEnvironment class to check status of the roles (more on this in another post), but also display their fault and upgrade domains.  (A value of “0f” is fault domain 0.  “0u” is upgrade domain 0, and so on).  So by default, my three instances are in separate fault and upgrade domains that correspond to their instance number.

All of these instances are in the same datacenter, and as I long as I have at least 2 instances and ensure they have different fault and upgrade domains (which is the default behavior), I’m covered by the SLA. 

The principal advantage of keeping everything within the same datacenter is cost savings between roles, storage, and SQL Azure.  Essentially, any bandwidth within the data center (for example, my webrole talking to SQL Azure or Azure Storage) incurs no bandwidth cost.  If I move one of my roles to another datacenter, traffic between datacenters is charged.  Note however there are still transaction costs for Azure Storage.

This last fact brings up an interesting and potentially beneficial side effect.  While I’m not trying to get into the scalability differences between Azure Table Storage and SQL Azure, from strictly a cost perspective, it could be infinitely more advantageous to go with SQL Azure in some instances.   As I mentioned in my last post, Azure Storage transaction costs might creep up and surprise you if you aren’t doing your math.  If you’re using Azure Table Storage for session and authentication information and have a medium volume site (say, less than 10 webroles but that’s just my off the cuff number – it really depends on what your applications are doing), SQL Azure represents a fixed cost whereas Table Storage will vary based on traffic to your site.

For example, a small SQL Azure instance at $9.99/month = $0.33/day.  Azure Table transactions are $0.01 per 10,000.   If each hit to your site made only 1 transaction to storage, that would mean you could have 330,000 hits per day to achieve the same cost.   Any more, and SQL Azure becomes more attractive, albeit with less scalability.   In many cases, it’s possible you wouldn’t need to go to table storage for every hit, but then again, you might make several transactions per hit, depending on what you’re doing.  This is why profiling your application is important.

More soon!

Tags: , ,

Tech Tips | Azure | Microsoft

Thoughts on Windows Azure Pricing…

by Brian Hitney 9. February 2010 08:59

There are a LOT of posts out there talking about Azure pricing.  There’s the Azure TCO Calculator, and some good practices scattered out there that demystify things.  Some of these bear repeating here, but I also wanted to take you through my math on expenses – how you design your app can have serious consequences on your pricing.  So let’s get the basic pricing out of the way first (just for the Azure platform, not AppFabric or SQL Azure):

  • Compute = $0.12 / hour
  • Storage = $0.15 / GB stored / month
  • Storage transactions = $0.01 / 10K
  • Data transfers = $0.10 in / $0.15 out / GB - ($0.30 in / $0.45 out / GB in Asia)

Myth #1:  If I shut down my application, I won’t be charged.

Fact:  You will be charged for all deployed applications, even if they aren’t running.  This is because the resources are allocated on deployment, not when the app is started.  Therefore, always be sure to remove deployments that aren’t running (unless you have a good reason to keep them there).

Myth #2:  If my application is less CPU intensive or idle, I will be charged less.

Fact:  For compute hours, you are charged the same whether your app is at 100% CPU or idle.  There’s some confusion (and I was surprised by this, too) because Azure and Cloud provisioning is often referred to as "consumption based” and (in this case, incorrectly) compared to a utility like electricity.  A better analogy is that of a hotel room.  An Azure deployment is reserving a set of resources.  Like the hotel room, whether you use it or not doesn’t change the rate.

On the plus side, Compute hours are a fairly easy thing to calculate.  It’s the number of instances in all of your roles * $.12 for small VM instances.  A medium instance (2 core) is $.24, and so on.

Myth #3:  There’s no difference between a single medium instance and two small instances.

Fact:  While there is no difference in compute price, there is significant difference in that the two small instances offer better redundancy and scalability.  It’s the difference between scaling up vs scaling out.  The ideal scenario is for an application that can add additional instances on demand, but the reality is that applications need to written to support this.

In Azure, requests are load balanced across all instances of a given webrole.   This complicates session and state management.  Many organizations do what is called sticky persistence or sticky sessions when implementing their own load balancing solution in their applications.  When a user visits a site, they will continue to visit the same server for their entire session.  The downside of this approach is that should the server go down, the user is redirected to another server and loses all state information.  However, it’s a viable solution in many scenarios, but not one that Azure load balancing offers.

Scaling up is done by increasing your VM size to medium (2 core), large (4 core), or XL (8 core), with more RAM allocated at each level.  The single instance becomes much more powerful, but your limited by the hardware of a single machine.

In Azure, the machine keys are synchronized among instances so there is no problem with cookies and authentication tokens, such as those in the ASP.NET membership providers.  If you need session state information, this is where things get more complicated.  I will probably get zinged for saying this, but there is currently no good Azure-based session management solution.  The ASP Providers contained in the SDK does have a Table Storage Session State demo, but the performance isn’t ideal.   There are a few other solutions out there, but currently the best bet is to not rely on session state and instead use cookies whenever possible.

Now, having said all this, the original purpose of the post:  I wanted to make sure folks understood transactions costs with Azure Storage.  Any time your application so much as thinks about Storage, it’s a transaction.  Let’s use my Worldmaps site as an example.  This is not how it works today, but very easy could have been.  A user visits a blog that pulls an image from Worldmaps.  Let’s follow that through:

Step Action Transaction #
1 User’s browser requests image.  
2 Worker roll checks queue. (empty) 1
3 If first hit for map (not in cache), stats/data pulled from Storage. 2
4 Application enqueues hit to Azure Queue. 3
5 Application redirects user to Blob Storage for map file. 4
6 Worker dequeues hit. 5
7 Worker deletes message from queue. 6

While #3 is only on first hit for a given map, there are other transactions going on behind the scenes and if you are using the Table Storage Session State provider … well, it’s another transaction per hit (possibly two, if session data is changed and needs to be written back to storage).

If Worldmaps does 200,000 map hits per day (not beyond the realm of possibility but currently a bit high), then 200,000 * 6 = 1,200,000 storage transactions.  They are sold in 10,000 transactions for $.01, so that’s 120 “units” or $1.20 per day.  Multiply that by 30 days, and that’s about $36/mo for storage transactions alone – not counting the bandwidth or compute time.

I realized this early on and as a result I significantly changed the way the application works.  Tips to save money:

  1. If you don’t need durability, don’t use Azure queues.  Worldmaps switches between in-memory queues and Azure queues based on load, configuration, and task.  Since queues are REST calls, you could also make a WCF call directly to another Role.
  2. Consider scaling down worker roles by multithreading particularly for IO heavy roles.  Also, a webrole’s run method (not implemented) simply calls Thread.Sleep(-1), so why not override it to do processing?  More on this soon…
  3. SQL Azure may be cheaper, depending on what you’re doing.  And potentially faster because of connection pooling.
  4. If you aren’t interested in CDN, use Azure Storage only for dynamic content.
  5. Don’t forget about LocalStorage.  While it’s volatile, you can use it as a cache to serve items from the role, instead of storage.
  6. Nifty backoff algorithms are great, but implement only to save transaction cost.  It won’t affect compute charge.
  7. Take advantage of the many programs out there, such as hours included in MSDN subscriptions, etc.

Next up will be some tips on scaling down and maximizing the compute power of each instance.

Tags: ,

Azure | Development | Tech Tips

Windows Azure Role Communication

by Brian Hitney 3. February 2010 11:07

I have a few posts along the lines of scaling an Azure application, but thought I’d throw this tidbit out.  You might be developing your own management system for your Azure deployments, and in doing so, having visibility into the roles running within your deployment is very handy.   The idea behind this series of posts is to ultimately explore how to get visibility into roles, and then a few ways we can tackle inter-role communication. 

The first task is to define internal endpoints for each of our roles.  If you don’t do this, you will only have visibility into the current role.  So, if you have a single role solution (any number of instances) than you don’t have to do this. 

Let's take a pretty simple example where we want to enumerate all the roles in our deployment, and their instances:

foreach (var appRole in RoleEnvironment.Roles)
{
    var instances = RoleEnvironment.Roles[appRole.Key].Instances;

    foreach (var instance in instances)
    {
        Response.Write(instance.Id);
    }
}

While this code will work fine, by default it will only show you the instances for the current role – other roles will show an instance count of zero.  Running this in my workerrole and trying to enumerate my webroles, I see this:

image

What we can do is define and internal endpoint for our roles that will allow this data to be discoverable.  In Visual Studio, it’s simply a matter of going into the properties of the role and defining an internal endpoint:

image

And we’re done.  Debugging the solution again:

image

We can do the same for our workerroles to be discoverable by other webroles, etc. 

In some future posts, I’ll build off this idea for doing some lightweight service management and role communication.

Tags: , ,

Azure | Development | Tech Tips

SQL Azure Transport-Level Error

by Brian Hitney 3. February 2010 10:34

If you’ve been playing with SQL Azure, you might have run into this error when opening a connection to the database:

A transport-level error has occurred when sending the request to the server. (provider: TCP Provider, error: 0 - An established connection was aborted by the software in your host machine.)

Ick!  Anything at that transport level surely can’t be a problem with my code, can it?  :)

The goods news is that you aren’t going crazy and the problem isn’t with your code.  There’s a difference in the way SQL Azure manages its connections compared to .NET connection pooling, and the result is that the connection pool is giving out connections that have already been closed.  When you try to do something with that connection, you get this error.   It’s sporadic in that only happens when you get an idle connection from the pool that has already been dropped by SQL Azure.

There are a couple of workarounds until a fix is implemented by Microsoft (I’ve been told it’s coming soon).  One method is to retry the connection (I hate this one, but it’s a viable option nonetheless).  It’s just messy and I’d have to do this in a few dozen places.  The amusing fix is to have a thread that continually pings the database, keeping every connection alive.  The best fix that I’ve found to date is to simply turn off connection pooling temporarily by adding a pooling=false option to the connection string:

image

I tested this on my webrole, leaving my workerroles as-is, and the webrole has been running for a week or two without a single error, whereas the workerrole (without disabling pooling) will get a couple errors every day.

I haven’t done any performance tests but UA testing (which is me) sees no appreciable hit, so I’ll go with this option until the permanent fix is deployed. 

Tags: , , ,

Azure | Development | SQL | Tech Tips

Robocopy in Win7

by Brian Hitney 1. February 2010 13:17

I’m surprised I didn’t realize this earlier, but Win7 introduced multithreading support in Robocopy.  I’ve always used Robocopy for copying lots of files particularly over a network, and especially over a VPN.  I’ve also always specified the /E /Z switches to copy all folders, and support file resume. 

File resume is especially helpful over a VPN because the VPN connection may be lost for any number of reasons.  I’ve had situations where my access was off for hours, and it picks up right away on reconnect.   Now in Win7, you can specify a /MT[:n] switch that specifies the number of threads (default 8) to use.  

And if you prefer a GUI, RichCopy is a nice tool as well!

Tags: ,

Microsoft | Tech Tips

your host...

Brian Hitney
Developer Evangelist
Microsoft Corp.

About Me

My Worldmap