Evolving Core Stack of Azure SDK for JS: A Tale of Enhanced Performance, Usability, and Convenience
@azure/core-http, which served as the runtime for routing HTTP requests through a pipeline of policies such as retry, logging, and tracing.
However, as we continued to develop and ship more client libraries, we realized that
@azure/core-http had some limitations in terms of maintainability and performance.
One of the decisions was to split
@azure/core-http into three separate packages:
@azure/core-xml. This separation would enable smaller dependency graphs and bundles for individual client libraries. In particular, the xml related modules or helpers are only used by a few services. Thus, the separation would also facilitate the creation of plug-in libraries based on new requirements, instead of expanding a single monolithic core library. Another significant benefit included improvements to the request pipeline system.
While a major version change can be disruptive, Azure customers typically interact with
@azure/core-http indirectly via the SDKs for various Azure services, and so we believe the transition to the new core package wouldn’t cause significant disruption. To ensure compatibility and simplify servicing, we introduced a new package called
@azure/core-http-compat along with the
A Deep Dive into the Evolution of Core Stack
Tracing the Roots: The History of
The origin and evolution of this change can be traced back to the creation of SDKs for Node.js to interact with Azure services using AutoRest. At the heart of it all,
@azure/core-http was a common reusable core for performing HTTP operations
ms-rest-azure was added to make it Azure-friendly that included Azure-specific bits and bobs, like authentication stuff for different credentials. TypeScript support was later added through hand-authored type declaration files.
Finally, there was a desire for isomorphic packages that could run both in the browser and on Node.js, which meant a new runtime, code generator, and repository. During the revamp,
ms-rest went through a makeover and became
@azure/ms-rest-js to provide the same capabilities in both environments. The authentication pieces from
ms-rest-azure were moved to
@azure/ms-rest-nodeauth, and an equivalent package was created for the browser called
@azure/ms-rest-browserauth. All remaining parts of
ms-rest-azure were placed into
Back in November 2018, an initiative to revamp the Azure SDKs came into play and established guidelines on how to craft an Azure SDK using TypeScript. To stick to these guidelines, we built a fresh package called
@azure/core-http on top of the existing
@azure/ms-rest-js. The core package got some upgrades when it hit version 1.0 in November 2020; however, a chunk of code piled up over the years, carrying some unnecessary or outdated stuff that was gathering dust and serving no real purpose.
After much deliberation, a plan was cooked up to give
@azure/core-http a modern makeover. The technical debt that had built up in this package was making it hard to maintain and was slowing down the library’s performance. It needed a revamp, a more modern and tougher version to lay down a sturdier foundation for future building.
The Vision Behind Core Stack Upgrade: Setting New Goals
We had a few main goals in mind for the upgrade. First, we wanted to make the request pipeline reusable outside of AutoRest generated code so that different client libraries and consumers can use it. We also aimed to simplify customization for those client libraries and consumers. Performance and memory efficiency were also high on our priority list, especially for the most common use cases. Finally, we wanted to set up things so that future improvements to the code generator would be a breeze to integrate.
We broke the library into three separate packages:
@azure/core-xml. This move helps keep things neat and tidy, with smaller dependency graphs and bundles for each client library. The first package,
@azure/core-rest-pipeline, isn’t just for AutoRest; any client that wants to make requests using a pipeline, following our SDK design guidelines can use it.
@azure/core-client is there to be a runtime dependency for any AutoRest-generated client library, providing all the necessary helpers except for XML. If a package needs XML support, it can depend on
@azure/core-xml, which makes sense because not all services require XML.
The old JS Core had a weakness in that the request pipeline system was a pain to customize at the library level, as it put numerous strains on library authors and increased support costs. Our new pipeline design fixes that by providing a new abstraction which simplifies application of ordered policies with minimal configuration. This means it’s simpler and more flexible to add and arrange policies. This change is all about making life easier and more efficient for everyone involved.
The Transformation: Key Enhancements in the Upgraded Core Stack
The new core stack project brings several benefits to the Azure SDKs for JS, such as:
- Performance: The new core stack is optimized for performance and provides significant performance improvements over
@azure/core-http. Tests show it’s either as good or even better in most scenarios, with some tests (discussed below) showing some seriously impressive improvements.
- Consistency: With new core stack, Azure SDKs across all languages use a consistent core implementation that helps in reducing inconsistencies and improve compatibility across SDKs and among languages.
- Enhanced Authentication: The new core stack presents improved authentication support, featuring compatibility with the new Azure Identity library. This library offers a unified approach to authentication with various credentials and Azure services, simplifying the process of authenticating with Azure services.
- Flexibility: The new core stack is designed to be super flexible and open for all sorts of customizations. Unlike the old
@azure/core-http, it’s more customizable, allowing for better integration with other Azure services.
- Bundle size: The new Azure REST-level client libraries are built with web apps in mind. They’re compact and super-efficient for apps with limited storage. They’re lightweight, at around 10 KB in size, and they share the same runtime code. Adding one more Azure REST library won’t bulk up your app’s bundle size by much, thanks to the magic of a core package named
- Other improvements:
- Legacy Browser Support Dropped: We no longer support legacy web browsers. This change made bundled code simpler, resulting in a reduction in code size.
- Code Cleanup and Simplification: We cleaned up our code extensively, eliminating unnecessary and outdated dependencies such as
node-fetch. Additionally, we removed portions of the API that are no longer in our scope of support.
- Enhanced Error Handling: We made numerous improvements in our error handling mechanisms. They now provide more detailed and actionable error messages and offer increased transparency regarding the underlying HTTP requests and responses.
Benchmarking the Progress: Performance Gains
While we built the new core stack with a focus on convenience and flexibility, we also wanted to make sure there were no performance regressions.
For testing the performance, we picked the “download blob scenario with sas url” as the benchmarking scenario, where we generate a sas url using the
@azure/storage-blob SDK and use
@azure/core-rest-pipeline (the new Core package) along with a few other third-party libraries by passing the SAS URL to download the blob.
The charts show how many operations each library can handle in parallel.
- The test scenario is “downloading a blob using a sas url” with each library
@azure/core-rest-pipelineis the new core stack that replaces
Note: These charts don’t represent the performance of the storage service, they only show the improvement from
@azure/core-rest-pipeline in similar ideal conditions, RAM and CPU.
Based on the results observed in 2021, it’s evident that the new core stack, in its minimalist form, exhibits superior performance in comparison to its predecessor in certain scenarios. In situations where requests aren’t heavily dependent on network constraints or extensive service processing, the throughput of the new core stack showcases a potential enhancement of two to three times when compared to
So, the final step was the migration of all Azure JS SDKs to utilize
@azure/core-rest-pipeline instead of their dependence on the monolithic
@azure/core-http. Following this transition over the past couple of years, further internal testing affirms the substantial improvements attained, providing concrete evidence of the enhancements made.
A New Chapter for Storage SDKs: Post-Migration Improvements
We migrated all storage SDKs in JS like
@azure/storage-blob to use
@azure/core-rest-pipeline instead of
@azure/core-http. Following this transition, a comprehensive battery of tests encompassing download, upload, and listing operations was conducted. The results consistently demonstrated that these operations either showcased improved performance or were at par with the previous versions reliant on
- Download (10 KB) is almost 4x faster, and upload (10 KB) and list-blobs (5) are two times faster than before.
- The performance gains should apply to all the Azure SDKs, not limited to storage SDKs.
The upcoming versions of storage packages such as
@azure/storage-blob should generally yield better performance as they depend on the upgraded core, moving away from the
@azure/core-http. This means that operations like downloading, uploading, and listing blobs are likely faster and more efficient than ever before.
Wrapping Up: The Impacts and Future of the Core Stack in Azure SDKs for JS
Furthermore, the performance enhancements delivered by the new core stack are truly noteworthy. These improvements particularly shine in scenarios where requests aren’t network-bound or don’t involve substantial service processing. Our commitment to flexibility and extensibility is evident in the new core’s design, offering developers the versatility to tailor it to their specific requirements.
For developers utilizing the Azure SDKs for JS/TS, reaping the rewards of these enhancements is as straightforward as upgrading your Azure SDK dependencies to the
"latest" version. This simple step grants you access to all the performance enhancements and novel features we’ve been working on diligently.
Thank you for choosing Azure!