When you spin up an Azure Media Services instance in Azure, you are prompted with a choice: How many Media Reserved Units do you want? and what horsepower do you want behind them?
Well, that exactly does that mean?
Reserving a Unit means that when you submit a job to Media Services, you wont go in a public queue in order for your submitted job to start. This is important, because if the public queue is busy, it could take quite a while for your job to get picked up. If you have all the time in the world for your job to complete, this isn’t a big deal, but if you are like me with a customer waiting on the job, speed is a priority. You can choose from 1-10 reserved units (you can request more via a support request), and they come at a cost. Also, when you reserve a unit, it has be a specific speed (S1, S2, or S3).
So if you want to have 10 reserved units at all times, and you want S3 so the job completes the fastest that Azure offers, that is 80 cents an hour, and that can add up over time. I should also note that you can NOT reserve zero S2 or S3 units. If you want to be in the public pool, it has to be S1. Therefore, you are 4 cents an hour at the very least if you want to have an immediate response time of your jobs by reserving one S1. I should also note that if you made a support request to get more than 10 units, when you change the speed of those reserved units, the MaxReservableUnits gets reset to 10, and your support request is essentially lost. I have spoken with Azure support on this, and while they don’t call it a bug, it is something they are addressing in a future release of AMS.
So, the solution I came up with was to auto scale our units with C#.
When a message is sent to my worker role to work with Azure Media Services, I reserve (currently reserved units + 1) S3 units, and when it is done I decrement one S3 unit. When I hit 0 units, I set the speed back to S1 (because remember you can only have zero units if you are set to S1)
internal static async Task ReserveMediaEncodingUnit(MediaContextBase context, int amount) { if (ConfigurationProvider.AutoScaleMRU()) { IEncodingReservedUnit encodingReservedUnit = context.EncodingReservedUnits.FirstOrDefault(); //there is always only one of these (https://github.com/Azure/azure-sdk-for-media-services/blob/dev/test/net/Scenario/EncodingReservedUnitDataTests.cs) if (encodingReservedUnit != null) { encodingReservedUnit.CurrentReservedUnits = Math.Min(amount, ConfigurationProvider.MaxMRUProvisioned() == 0 ? encodingReservedUnit.MaxReservableUnits : ConfigurationProvider.MaxMRUProvisioned()); encodingReservedUnit.ReservedUnitType = ReservedUnitType.Premium; await encodingReservedUnit.UpdateAsync(); } } }
ConfigurationProvider.MaxMRUProvisioned() is a setting I have that is equal to 10. I did that because I initially put in the service request to get more than 10, only to find out it gets reset back to 10 if you change the speed. If Microsoft changes this behavior, I can set my setting to 0 and user their variable MaxReservedUnits, without any code changes.
Deallocating units:
internal static async Task DeallocateMediaEncodingUnit(MediaContextBase context, int amount) { if (ConfigurationProvider.AutoScaleMRU()) { IEncodingReservedUnit encodingReservedUnit = context.EncodingReservedUnits.FirstOrDefault(); //there is always only one of these (https://github.com/Azure/azure-sdk-for-media-services/blob/dev/test/net/Scenario/EncodingReservedUnitDataTests.cs) if (encodingReservedUnit != null) { encodingReservedUnit.CurrentReservedUnits = Math.Max(0, amount); encodingReservedUnit.ReservedUnitType = encodingReservedUnit.CurrentReservedUnits == 0 ? ReservedUnitType.Basic : ReservedUnitType.Premium; await encodingReservedUnit.UpdateAsync(); } } }
If I hit 0 units I can reset:
private static async Task ResetMediaEncodingUnits(MediaContextBase context) { if (ConfigurationProvider.AutoScaleMRU()) { IEncodingReservedUnit encodingReservedUnit = context.EncodingReservedUnits.FirstOrDefault(); //there is always only one of these (https://github.com/Azure/azure-sdk-for-media-services/blob/dev/test/net/Scenario/EncodingReservedUnitDataTests.cs) if (encodingReservedUnit != null) { encodingReservedUnit.CurrentReservedUnits = 0; encodingReservedUnit.ReservedUnitType = ReservedUnitType.Basic; await encodingReservedUnit.UpdateAsync(); } } }
So now, when my users aren’t transcoding anything, and my AMS instance is sitting idle, I will incur no cost. And, when they submit a job, I allocate a unit to avoid going to the public pool and the job gets submitted right away and completed with premium speeds. I can’t guarantee this hack will work forever; when speaking with MS they told me this code has prompted them to think about how reserved units work in AMS, and may change this behavior in the future.
Happy transcoding!
Be First to Comment