惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

罗磊的独立博客
G
Google Developers Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
腾讯CDC
有赞技术团队
有赞技术团队
Vercel News
Vercel News
MongoDB | Blog
MongoDB | Blog
M
MIT News - Artificial intelligence
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
B
Blog RSS Feed
I
InfoQ
Blog — PlanetScale
Blog — PlanetScale
博客园_首页
The Cloudflare Blog
B
Blog
C
Check Point Blog
Stack Overflow Blog
Stack Overflow Blog
IT之家
IT之家
U
Unit 42
D
Docker
月光博客
月光博客
aimingoo的专栏
aimingoo的专栏
博客园 - Franky
A
About on SuperTechFans

Datadog | The Monitor blog

Introducing our open source AI-native SAST Instrument and monitor Boomi integration flows with OpenTelemetry and Datadog Not all index scans are equal: How we cut query latency by over 99% Platform engineering metrics: What to measure and what to ignore Integrate Recorded Future threat intelligence with Datadog Cloud SIEM CI/CD security: threat modeling using a MITRE-style threat matrix CI/CD security: How to secure your GitHub ecosystem Ingress NGINX is EOL: A practical guide for migrating to Kubernetes Gateway API Operating agentic AI with Amazon Bedrock AgentCore and Datadog LLM Observability: Lessons from NTT DATA Introducing the Datadog Code Security MCP Capture and analyze custom heatmaps in Session Replay Understand session replays faster with AI summaries and smart chapters Monitor ClickHouse query performance with Datadog Database Monitoring How we designed empathetic alert sounds for on-call engineers Search and act across Datadog to resolve issues faster with Bits Assistant Measure the business impact of every product change with Datadog Experiments Analyzing round trip query latency Configuring JavaScript caches for better performance Introducing Bits AI Dev Agent for Code Security Datadog achieves ISO 42001 certification for responsible AI Monitor Nutanix clusters, hosts, and VMs with Datadog Monitor Juniper Mist in Datadog A new Host Map for modern infrastructure Annotate traces to improve LLM quality with Datadog LLM Observability What’s new in Cloud SIEM: AI-powered investigations, enhanced threat intelligence, and scalable security operations Explore Kubernetes with native OpenTelemetry data Monitor Oracle Fusion Cloud Applications with Datadog Announcing the Datadog Terraform provider v4.0.0 Scaling Kubernetes workloads on custom metrics How to design cloud environments for AI-powered threat analysis
Optimize your .NET application performance with the Datad...
2022-09-27 · via Datadog | The Monitor blog
Bowen Chen

Bowen Chen

.NET is a framework built by Microsoft that simplifies the complexities of developing cross-platform applications. Using .NET, developers can create powerful applications with rapid response times and more. We’re excited to announce that the Datadog Continuous Profiler now provides general support for .NET applications, including .NET Framework, .NET Core, and .NET 5+. Using Continuous Profiler, you can compare the code performance of your .NET application across different versions, time frames, and environments directly in production, enabling you to identify resource bottlenecks and improve user experience.

In this post, we’ll cover how you can use Continuous Profiler’s flame graph to optimize expensive methods and leverage method-level tracing and profile comparison features to troubleshoot high CPU consumption and latency.

Continuous, low-overhead performance monitoring

Profiling tools often come with significant latency or CPU overhead since they aim to gather large volumes of information in a short time period and may also initialize with expensive settings. However, for .NET, Datadog’s Continuous Profiler has been fine-tuned to continuously collect application data in frequent sampling intervals without changing the .NET runtime behavior. This drastically reduces operational overhead and ensures that you get full visibility into application code performance even in high-scale production environments. When a production issue occurs, you’ll be able to investigate directly; that means you won’t need a separate environment to reproduce and troubleshoot the problem. Additionally, several factors such as the load, data format, security, and configuration of your production environment may be difficult to reproduce in testing.

If you already collect .NET traces with Datadog APM, no installation is required—just enable profiling for your organization. Otherwise, start by installing Datadog tracing for either .NET Core, .NET 5+, or .NET Framework on your machines or directly in your applications. You can then navigate to Profiles in APM to begin analyzing profiled services.

View your .NET traces in Datadog APM.

Troubleshoot resource bottlenecks using profiles

If you notice your .NET application performance indicators begin to lag after deploying changes, profiles can be the next step in diagnosing the underlying issue. For example, our application buggybitsservice exhibits prolonged CPU time following a recent deployment (shown below). Using the Continuous Profiler’s “Compare” tab, we can compare the current lagging service code (profile B) with the profile prior to the period of impact (profile A). The table view automatically lists methods with the greatest magnitude of change at the forefront, enabling you to quickly identify potential sources of error.

The Continous Profiler’s compare function isn’t limited to just time periods—you can also compare your .NET profiles using any combination of tags. This enables you to compare against different versions, environments (such as production and staging), data centers, Kubernetes pods, and more. Datadog will automatically discover and import available labels and environment variables as tags, but you can also assign custom tags to increase the dimensions of your service data.

Going back to our example, we can see that profile A is spending nearly 10 times as long (3.77 seconds) executing method DataLayer.ApplyDiscount compared to profile B and is also spending significant time in the Number.ThrowOverflowFormatException method. Using these context clues, we can pivot our investigation to our profiles’ “Thrown Exceptions” and query for our specific service. We can see below that buggybitsservice is throwing over 1000 exceptions, almost all from the method DataLayer.ApplyDiscount. Looking at the exception messages on the right-side panel shown below, we can gain insight into why the exception was raised. In this case, it’s possible that our application misses some edge cases when parsing input strings related to prices. However, what’s most important to solving the performance issue is not necessarily the type or the message of exceptions but understanding why the exceptions were raised and how to remediate them.

View thrown exceptions using the Continuous Profiler.
View thrown exceptions using the Continuous Profiler.

Now that we’ve narrowed our issue down to a specific method, we can dive into the application code. Below is the code for our current (lagging) profile:

public void ApplyDiscount(Product product)

{

try {

var price = double.Parse(product.Price, System.Globalization.NumberStyles.AllowDecimalPoint, System.Globalization.CultureInfo.InvariantCulture);

if (price < 200) {

product.Price = (price * 0.75).ToString();

}

}

catch (System.FormatException) {

throw new PriceException(product.Price, "Invalid price number");

}

}

public List <Product> GetProductsOnSale()

{

var allProducts = new List<Product>(10000);

for (int i = 0; i < 10000; i++) {

var product = GetProduct(i);

try {

ApplyDiscount(product);

allProducts.Add(product);

}

catch (PriceException) { continue; }

}

return allProducts;

}

To compute the variable price value, our code calls the double.Parse method, which will throw a FormatException if the input string has an incorrect number format (e.g., using ‘,’ instead of ‘.’ as a decimal separator). Our code then catches these exceptions and throws a new custom PriceException. Since we want to drastically reduce the amount of time buggybitsservice spends in this method, we need to find a way to handle these errors without throwing exceptions. Looking at our new implementation of our ApplyDiscount method shown below, we return a boolean flag instead of throwing an exception. Our new method invokes TryParse instead of ParseTryParse does not throw an exception when a parsing error is detected.

public bool TryApplyDiscount(Product product)

{

double price;

if (double.TryParse(product.Price, System.Globalization.NumberStyles.AllowDecimalPoint, System.Globalization.CultureInfo.InvariantCulture, out price)) {

if (price < 200) {

product.Price = (price * 0.75).ToString();

}

return true;

}

return false;

}

public List<Product> GetProductsOnSaleEx()

{

var allProducts = new List<Product>(10000);

for (int i = 0; i < 10000; i++) {

var product = GetProduct(i);

if (TryApplyDiscount(product)) {

allProducts.Add(product);

}

}

return allProducts;

}

With our new application code in place, we can return to the Continuous Profiler “Compare” page to test its performance. Our CPU time (profile B) has returned to normal levels (1.84 seconds), and the new TryApplyDiscount method runs in 248 ms as opposed to the prior lagging ApplyDiscount method that ran in 3.77 seconds.

View improvements following code changes when comparing profiles.

During testing, our exception-based code performed well under unit tests, end-to-end tests, and within a staging environment; however, once it was deployed to production, the high volume of exceptions raised by user requests flooded our application and heavily impacted its CPU utilization. Using the Continuous Profiler, we were able to quickly find and resolve the production issue, saving valuable resources while enhancing the performance of our application.

Optimize slow code with method-level tracing

When attempting to identify the source of an issue, different warning cues can often point to the same source. For example, we might have first been notified of an ongoing impact to buggybitsservice when observing spikes in its latency.

Abnormal telemetry in your Service Page can signal application issues.

To troubleshoot high latency, we can begin by analyzing buggybitsservice traces in APM. By inspecting a slow trace, you can break it down into individual method-level calls. With distributed tracing and profiling enabled, Datadog will automatically identify slow traces in the “Code Hotspots” tab and highlight the methods within your span and their corresponding durations. You can then select an expensive method to follow its reverse stack trace to identify the source of a bottleneck. Using Code Hotspots, you can quickly troubleshoot lagging methods to ensure fast turnaround times and quick incident resolution. In the example below, the code hotspot in our trace highlights that the ApplyDiscount method takes 1.34 seconds out of the total 1.50 second duration. This leads to the exceptions issue that we previously troubleshot.

Start analyzing .NET profiles with Datadog today

Datadog’s Continuous Profiler enables you to compare .NET application performance results between different time frames and versions and pinpoint specific lines of code degrading performance. To begin identifying bottlenecks and improving your .NET application’s user experience, you can install Datadog’s tracing libraries and enable profiling for your application today. Our profiler supports all languages targeting the .NET runtime, such as C#, F#, and Visual Basic, to give you deep visibility for all infrastructures. If you aren’t already a Datadog customer, get started with a free 14-day trial.