Thursday, September 24, 2020

How to improve the performance of ASP.Net Core applications -GOOD ONE and Simple to understand

 ASP.Net Core is a fast, lightweight, open-source, cross-platform rewrite of the ASP.Net framework that runs on Windows, Linux, and even Mac OS X. Speed is one of the key features of ASP.Net Core, meaning that the ASP.Net Core framework is optimized for better performance. Nevertheless, there are some best practices and strategies you can adopt to improve the performance of your applications that leverage the .Net Core runtime.

The essence of improving application performance is ensuring that you build applications that consume the least amount of resources to produce the desired output. This article presents a discussion of the best practices you can adopt to improve the performance of ASP.Net Core applications.

Inline methods

Inlining methods improves performance as it saves the cost of jumps, passing arguments, and saving and restoring registers. Note that a method that contains a throw statement will not be inlined by the JIT (just-in-time) compiler. To solve this, you can take advantage of a static helper method to contain the throw statement.

Minimize virtual calls

Calls to virtual members are slower because virtual calls require indirection. Devirtualization is a feature of JIT compilers and a devirtualized method can become a candidate for inlining. When the type of an object is known, RyuJIT — the JIT for .Net Core — can devirtualize non-sealed method calls. To avoid virtual calls, you can follow these guidelines:

  • Mark classes or methods as sealed by default
  • Mark overridden methods as sealed as well
  • Use concrete types in lieu of interfaces

Pool HTTP connections

Although HttpClient implements the IDisposable interface, it is advisable to reuse HttpClient instances. The reason is that HttpClient leaves the socket open and in the wait state for a short duration of time even after it has been closed. So, if you try to create new HttpClient instances every time a HttpClient is needed, you might run out of available sockets.

With this in mind, HttpClientFactory was introduced in ASP.Net Core 2.1 to pool HTTP connections. By pooling connections, HttpClientFactory optimizes performance, scalability, and reliability. So, avoid creating and destroying HttpClient instances directly, and use the HttpCLientFactory to retrieve HttpClient instances.

Reduce allocations

The introduction of new types like System.ValueTuple and Span<T> provide new ideas for improving performance. Take advantage of System.ValueTuple to reduce allocations when you are trying to return multiple values from a method. And take advantage of Span<T> to avoid array allocations and data copying.

Cache aggressively

Caching is one of the best ways to improve performance. You should cache aggressively and cache any data that is relatively stale. ASP.Net Core provides support for response caching middleware, which you can use to implement response caching. Response caching is an enhanced form of output caching. It refers to the ability to cache web server responses using cache-related headers in the HTTP response objects. You can learn more by reading my article on using response caching middleware in ASP.Net Core

You can also take advantage of a distributed cache like NCache to cache data that is relatively stale. NCache is an extremely fast and scalable in-memory distributed cache that is easy to configure and use. You can read my article on using NCache in ASP.Net Core

Enable compression

Reducing the size of the response improves the performance of the application because less data is transferred between the server and the client. You can take advantage of response compression in ASP.Net Core to shrink the response and reduce bandwidth requirements. Response compression in ASP.Net Core is available as a middleware component. The following code snippet shows how you can add response compression middleware to the request processing pipeline.

    public void ConfigureServices(IServiceCollection services) 
    { 
        services.AddResponseCompression(); 
        services.Configure<GzipCompressionProviderOptions>
        (options => 
        { 
            options.Level = CompressionLevel.Fastest; 
        }); 
    }

You can also take advantage of ASP.Net Core’s built-in support for bundling and minifying client files or assets to improve performance.

For more information, you can read my article on using response compression in ASP.Net Core

Reduce HTTP requests

Every time the web browser opens a connection to the server, there is TCP/IP overhead. A great optimization tip is reducing the number of HTTP requests. You can also take advantage of HTTP/2 — this new version of HTTP introduces some useful optimizations. You should avoid client-side redirects and cache your web pages to reduce the number of connections made to the web server. If you minify the files and then bundle them, the data will load faster and reduce the number of HTTP requests that are needed to render the web page.

Avoid blocking calls

You should avoid blocking calls as they might lead to performance degradation. If you have too many synchronous blocking calls, you might encounter a thread starvation problem. You shouldn’t block asynchronous execution by using Task.Wait or Task.Result. You should make hot code paths asynchronous — e.g., data access and long running operations should be called asynchronously. You can take advantage of performance profilers like PerfView to examine the thread behavior. For more information, you can read my article on understanding the .Net CLR thread pool

Minimize large object allocations

The .Net Core garbage collector is adept at releasing memory occupied by objects in the managed heap. However, freeing up objects can take up CPU time, especially when the objects are large objects (85 Kbytes or more). Garbage collection happens in four generations — generations 0, 1, and 2 and the large object heap (LOH). The garbage collector works much more frequently in the lower generations than in the higher ones.

Garbage collection of large objects is expensive. To minimize large object allocations, you should take advantage of pool buffers using ArrayPool<T> and cache large objects that are used frequently. You should not acquire locks on common code paths and avoid allocating too many short-lived objects on hot code paths.

Use exceptions only when necessary

It should be noted that throwing and catching exceptions is expensive. Hence, exceptions should be used only when they are needed. You should minimize the use of exceptions in your application and avoid using exception handling to control program flow. You can read my article on best practices for exception handling to learn more. 

Optimize data access

Remember that data access is one of the slowest operations in an application. You should call all data access APIs asynchronously. You should minimize roundtrips to the database and retrieve only the data that is needed. Avoid using projection queries on collections.

If you are using Entity Framework Core for data access, follow the recommended guidelines and practices in Entity Framework Core. If you are reading data that won’t be modified by the application, you should take advantage of no-tracking queries in Entity Framework Core. See my article on best practices for Entity Framework to learn how to improve Entity Framework performance. 

While web application performance tuning is complicated, there are some common techniques and recommended practices you can take advantage of to improve the performance of your ASP.Net Core applications. You can also leverage certain tools like MiniProfilerGlimpseApplication Insights, and Stackify Retrace to measure application performance, detect the performance bottlenecks, and determine the appropriate remedies to fix them. 

Avoid synchronous and use asynchronous

Try to avoid synchronous calling when developing ASP.NET Core 3.0 applications. Synchronous calling blocks the next execution until the current execution is completed. While fetching data from an API or performing operations like I/O operations or independent calling, execute the call in an asynchronous manner.

Avoid using Task.Wait and Task.Result, and try to use await. The following code shows how to do this.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
public class WebHost
{
    public virtual async Task StartAsync(CancellationToken cancellationToken = default)
    {
 
        // Fire IHostedService.Start
        await _hostedServiceExecutor.StartAsync(cancellationToken).ConfigureAwait(false);
 
        // More setup
        await Server.StartAsync(hostingApp, cancellationToken).ConfigureAwait(false);
 
        // Fire IApplicationLifetime.Started
        _applicationLifetime?.NotifyStarted();
 
        // Remaining setup
    }
}

Entity Framework 3.0 Core also provides a set of async extension methods, similar to LINQ methods, that execute a query and return results.

Asynchronous querying

Asynchronous queries avoid blocking a thread while the query is executed in the database. Async queries are important for quick, responsive client applications.

Examples:

  • ToListAsync()
  • ToArrayAsync()
  • SingleAsync()
1
2
3
4
5
6
7
public async Task<List> GetBlogsAsync()
{
    using (var context = new BloggingContext())
    {
        return await context.Blogs.ToListAsync();
    }
}

Asynchronous saving

Asynchronous saving avoids a thread block while changes are written to the database. It provides DbContext.SaveChangesAsync() as an asynchronous alternative to DbContext.SaveChanges().

1
2
3
4
5
6
7
8
9
public static async Task AddBlogAsync(string url)
{
    using (var context = new BloggingContext())
    {
        var blogContent = new BlogContent { Url = url };
        context.Blogs.Add(blogContent);
        await context.SaveChangesAsync();
    }
}

Optimize data access

Improve the performance of an application by optimizing its data access logic. Most applications are totally dependent on a database. They have to fetch data from the database, process the data, and then display it. If it is time-consuming, then the application will take much more time to load.

Recommendations:

  • Call all data access APIs asynchronously.
  • Don’t try to get data that is not required in advance.
  • Try to use no-tracking queries in Entity Framework Core when accessing data for read-only purposes.
  • Use filter and aggregate LINQ queries (with .Where.Select, or .Sum statements), so filtering can be performed by the database.

You can find approaches that may improve performance of your high-scale apps in the new features of EF Core 3.0.

Use caching technology

Increase the performance of an application by reducing the number of requests to the server. Avoid calling the server every time and cache the data instead. Store the response for the future, and use it the next time you make a call for the same response.

These are some caching techniques:

  • In-memory caching.
  • Distributed cache.
  • Cache tag helper.
  • Distributed cache tag helper.

Use response caching middleware

Middleware controls when responses are cacheable. It stores responses and serves them from the cache. It is available in the Microsoft.AspNetCore.ResponseCaching package, which was implicitly added to ASP.NET Core.

In Startup.ConfigureServices, add the Response Caching Middleware to the service collection.

1
2
3
4
5
public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCaching();
    services.AddRazorPages();
}

Use JSON serialization

ASP.NET Core 3.0 uses System.Text.Json for JSON serialization by default. Now, you can read and write JSON asynchronously. This improves performance better than Newtonsoft.Json. The System.Text.Json namespace provides the following features for processing JSON:

  • High performance.
  • Low allocation.
  • Standards-compliant capabilities.
  • Serializing objects to JSON text and deserializing JSON text to objects.

Reduce HTTP requests

Reducing the number of HTTP requests is one of the major optimizations. Cache the webpages and avoid client-side redirects to reduce the number of connections made to the web server.

Use the following techniques to reduce the HTTP requests:

  1. Use minification.
  2. Use bundling.
  3. Use sprite images.

By reducing HTTP requests, these techniques help pages load faster.

Use exceptions only when necessary

Exceptions should be rare. Throwing and catching exceptions will consume more time relative to other code flow patterns.

  • Don’t throw and catch exceptions in normal program flow.
  • Use exceptions only when they are needed.

Use response compression

Response compression, which compresses the size of a file, is another factor in improving performance. In ASP.NET Core, response compression is available as a middleware component.

Usually, responses are not natively compressed. This typically includes CSS, JavaScript, HTML, XML, and JSON.

  • Don’t compress natively compressed assets, such as PNG files.
  • Don’t compress files smaller than about 150-1000 bytes

(sourcehttps://github.com/davidfowl/AspNetCoreDiagnosticScenarios/blob/master/AspNetCoreGuidance.md
Package: Microsoft.AspNetCore.ResponseCompression is implicitly included in ASP.NET Core apps.

The following sample code shows how to enable Response Compression Middleware for the default MIME types and compression providers.

01
02
03
04
05
06
07
08
09
10
11
public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddResponseCompression();
    }
    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseResponseCompression();
    }
}

These are the providers:

01
02
03
04
05
06
07
08
09
10
11
12
public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression(options =>
    {
        options.Providers.Add<BrotliCompressionProvider>();
        options.Providers.Add<GzipCompressionProvider>();
        options.Providers.Add<CustomCompressionProvider>();
        options.MimeTypes =
            ResponseCompressionDefaults.MimeTypes.Concat(
                new[] { "image/svg+xml" });
    });
}

HttpContext accessibility improvements

HttpContext accessibility is only valid as long as there is an active HTTP request in ASP.NET Core. Here are some suggestions for accessing HttpContext from Microsoft’s documentation:

Client-side improvements

Client-side optimization is one important aspect of improving performance. When creating a website using ASP.Net Core, consider the following tips:

Bundling

Bundling combines multiple files into a single file, reducing the number of server requests. You can use multiple individual bundles in a webpage.

Minification

Minification removes unnecessary characters from code without changing any functionality, also reducing file size. After applying minification, variable names are shortened to one character and comments and unnecessary whitespace are removed.

Loading JavaScript at last

Load JavaScript files at the end. If you do that, static content will show faster, so users won’t have to wait to see the content.

Use a content delivery network

Use a content delivery network (CDN) to load static files such as images, JS, CSS, etc. This keeps your data close to your consumers, serving it from the nearest local server

Friday, September 18, 2020

Steps to Deploy Angular application on Kubernetes -- very good

 Summary : Excellent article which cover complete docker deployments for angular app.

Create agnular app  with ng new


Design  nginx-custom.conf so that it can handle redirects, gzip and other things.

 
Create docker file to multistage build and deploy with custom ngix-custom.conf.


Build and push docker images
    *docker build and docker push.


Publish docker to Kubbernetes cluster 
  • Create a deployment in Kubernetes cluster (kubectl apply -f spa-deployment.yaml)
  • Create a ClusterIP service.kubeclt apply -f SPA-service.yaml
  • Create a load balancer service to access it via some External IP, provided by the service.kubeclt apply -f SPA-load-balancer-service.yaml
  • kubectl get svc -owide
  Now angular appliation avialble with public IP address. 


Introduction

Angular is a JavaScript framework for building web applications and apps in JavaScript, HTML, and TypeScript, which is a superset of JavaScript. Angular provides built-in features for animation, HTTP service, and materials which in turn has features such as auto-complete, navigation, toolbar, menus, etc. The code is written in TypeScript, which compiles to JavaScript and displays the same in the browser.

In this tutorial, we will create a basic angular app. Write a docker file to build a compressed angular app and then create deployment manifest for angular application.

Steps to Deploy Angular application on KubernetesSteps to Deploy Angular application on Kubernetes

Prerequisite

Angular: A little knowledge of angular.

Nodejs: To run the application locally, we need node environment.

Docker: Docker CLI should be installed in your system to build and push the image. You can also set up a CI tool to build the docker image. I will talk about this in the next tutorial.

Nginx: Basic knowledge of Nginx configuration.

Kubernetes: Kubernetes is an orchestration tool, where we will deploy the application. For the demo sake, you can use minikube as well.

What we will do

1: Create an Angular application

2: Write custom Nginx config

3: Write a multistage docker file

3: Create a K8s deployment manifest and service manifest

4: Test the application

Step 1: Create an Angular application

Now, let’s create an Angular Application. By running the below command, angular will create and initialize a new Angular app, which we will use to deploy.

ng new spa-demo

After completion of above command, go inside the directory.

cd spa-demo

Run the development server.

ng serve

Now, at visiting http://localhost:4200/, you will see the view of this Angular app.

Angular app is ready for productionView of Angular App

Step 2: Write a custom config for Nginx

First, add an Nginx custom configuration file inside the new spa-demo directory, named nginx-custom.conf. Here is the gist link.

# Expires map
map $sent_http_content_type $expires {
default off;
text/html epoch;
text/css max;
application/json max;
application/javascript max;
~image/ max;
}

server {
listen 80;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html =404;
}
expires $expires;
gzip on;
}

The above Nginx custom config contains:

  • Expiration header for images and other content (CSS, HTML etc), which travels through the web to the browser for the maximum amount of time but do change it according to need.
  • Every single page application uses its routing module to go to its route, but it needs to go through its home route, so we need to redirect every route to home route, then the single page application will take care of rest of the thing.
  • At last, we enable gzip compression.

Step 3: Create a multistage docker file to build the angular application

Now, create a Dockerfile inside the spa-demo project directory, named- Dockerfile. Here is the gist link.

# Stage 0, "build-stage", based on Node.js, to build and compile the frontend
FROM node:10.8.0 as build-stage
WORKDIR /app
COPY package*.json /app/
RUN npm install
COPY ./ /app/
ARG configuration=production
RUN npm run build -- --output-path=./dist/out --configuration $configuration

# Stage 1, based on Nginx, to have only the compiled app, ready for production with Nginx
FROM nginx:1.15
#Copy ci-dashboard-dist
COPY --from=build-stage /app/dist/out/ /usr/share/nginx/html
#Copy default nginx configuration
COPY ./nginx-custom.conf /etc/nginx/conf.d/default.conf

The above Dockerfile consists of two stages:

First stage: Create a node environment and build the angular application with production configuration.

Second stage: Copy the dist folder from the previous stage to Nginx container and copy nginx-custom.conf inside the nginx

Build and push the docker image

Docker build command

docker build -t inyee/spa-demo:v1 .
docker push inyee/spa-demo:v1

Docker push to docker registry.

docker push inyee/spa-demo:v1

Step 4: Create a K8s deployment manifest and service manifest

To deploy the Angular application in any of the Kubernetes environments, the deployment manifest for angular is listed below. Before deploying the application to production, make sure you modify the manifest file to best suit your needs. You can change the name of the Deployment and the labels, and change your Docker registry and image tag accordingly.

The deployment manifest gist link.

apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: deployment-name
spec:
replicas: 1
template:
metadata:
labels:
label-key : label-value
spec:
containers:
- name: deploment-container-name
image: inyee/spa-demo:v1
imagePullPolicy: Always
ports:
- containerPort: 80

Create a normal service to access the application internally, or you can use this service in ingress to expose it to some domain, named SPA-service.yaml

apiVersion: v1
kind: Service
metadata:
labels:
service-label-key: service-label-value
name: service-name
spec:
type: ClusterIP
ports:
- name: service-port-name
port: 80
protocol: TCP
selector:
deployment-label-key: deployment-label-value

For the demo purpose, create a load balancer service file to access it outside the Kubernetes cluster. Make sure Lable selector is the same as the deployment label, named SPA-load-balancer-service.yaml

apiVersion: v1
kind: Service
metadata:
labels:
service-label-key: service-label-value
name: service-name-loadbalancer
spec:
type: LoadBalancer
ports:
- name: service-port-name
port: 80
protocol: TCP
selector:
deployment-label-key: deployment-label-value
#for creating a deployment in kubernetes
kubectl apply -f spa-deployment.yaml
#for internal communicating to angualar application
kubeclt apply -f SPA-service.yaml
#for access the angular application outside kubernetes
kubeclt apply -f SPA-load-balancer-service.yaml

Run the command listed below to deploy the angular application in Kubernetes environment.

  • Create a deployment in Kubernetes cluster
 kubectl apply -f spa-deployment.yaml
  • Create a ClusterIP service.
kubeclt apply -f SPA-service.yaml
  • Create a load balancer service to access it via some External IP, provided by the service.

kubeclt apply -f SPA-load-balancer-service.yaml
kubectl get svc -owide
  • Run the below command to get External IP of the of service.
kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service-name ClusterIP xx.xx.xx.xx <none> 80:31527/TCP 1d
service-name-loadbalancer LoadBalancer xx.xx.xx.xx xx.xx.xx.xx 80:31202/TCP 1d

Go to the external IP on the browser, you will see the same angular app which we had created initially.

Angular app is ready for productionAngular app is ready for production

That’s it! Now our Angular app is ready for production!