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!

Tuesday, September 15, 2020

Microservice Architectures with Azure Functions

 

Synchronous Requests

If you want to communicate synchronously from a client to a function (HTTP request with HTTP response), then functions offer the possibility to be called via HTTP triggers. 
But the initially simple thought, is followed by some some issues regarding asynchrony concerning a microservice architecture.

As shown, it is technically possible to make functions communicate directly (synchronously) with each other (using HTTP triggers). 

However, this does not correspond to the official Microservice-Patterns, since direct dependencies are created here. 
Microsft even calls this an ANTI-PATTERN:

(Source: https://docs.microsoft.com/de-de/dotnet/standard/microservices-architecture/architect-microservice-container-applications/communication-in-microservice-architecture)

If you still want a connected client to be able to retrieve data directly from a function synchronously, the logical idea is that the functions call each other asynchonously (via HTTP trigger, EventHub or ServiceBus). 
However, the good idea initially disappoints quickly, because it is not technically possible due to the statelessness of the functions to wait asynchronously for a response from one or more functions.

Thus a synchronous call of a function by a client can only responded synchronously if the requested function don´t need to speak with any other functions at all. 
While this is basically possible, the practical use cases of micoservices show, that a state in which a microservice does not have to talk to other services does not last long. 
Progressive development and new features quickly create new dependencies that require communication between the microservices.

REPORT THIS AD

Due to the mentioned points, the synchronous communication of clients with the functions based on a microservice architecture is not recommended and principles for an asynchronous communication should be used.

2. Asynchronous Communication via Broker/Hub

So if asynchronous communication within functions is not possible, the first logical idea is to set up the architecture without functions.
First, you have to consider how to make it possible for the client (frontend) to get replies asynchronously. The usual approach for this is real time web frameworks, such as eg. SignalR, Grpc and others. 
Although Grpc itself can hardly be surpassed in terms of latency and speed, it is difficult to integrate it into a React or Angular web app with the usual board tools. Common methods for this are currently the detour via an Envoy Proxy. 
However, during the development of such an environment, it soon becomes apparent that this technology does not seem to have matured yet. 
For example, generating the prototype files for TypeScript involves significant problems. For sustainable and stabile environments you should better resort to battle-proofed technologies. Here is SignalR quite a good choice

Now that the return channel to the client has been clarified, the question is how the individual services communicate with each other. 
To ensure complete asynchrony of the services it should be advantageous if the services do not know each other. 
Consequently, a distribution point would make sense here. Here, the PUB / SUB pattern is a popular method. GRPC would therefore need its own GRPC broker and SignalR would need its own HUB.
Without going too deeply into detail, you quickly realizes that such an architecture always involves a single point of failure.

3. Asynchronous Communication One-to-One

If now the communication of the services via a broker/hub is not considered meaningful, a direct (but asynchronously) communication of the services with each other is the only thing that remains.
After some research, you quickly gets the idea to use EventHub triggers or ServiceBus triggers in combination with functions. Here, a message is passed through as a relay race to the involved functions on the appropriate trigger and returned at the end again by SignalR.

Passing messages like a relay race, can quickly lead to problems. If you think to an aggregation function, data must be collected from other services and thus it is difficult to treat the message in the sense of a relay race.

The officially microsoft recommended technology for asynchronous communication within functions are so-called durable functions.
However, there were significant lags in the perfomance test. 2 out of 10 calls showed response times of over 15 seconds. And event the other 80 percent of the requests take up to 0,7 sec for a response. Due to this fact, durable functions were not considered further.

In order to realize ideas like an aggregation function, stateful services are required which are capable of waiting asynchronously for a response message. 
With the idea of ​​direct service communication without a broker / hub, the idea of ​​peer to peer services lends itself. For this GRPC is a very good choice.

To overcome the problem of the Envoy Proxies, we simply use a function that acts as a gateway to send messages to the Grpc serives. 
Thus, you can also be prevented that a client must know all the service addresses, these can be very well processed in the sense of a gateway here. 
Because Azure’s functions/gateways scale horizontally and Azure ensures high availability, we do not consider such a gateway a single point of failure.

To find the way back to the client, we use a function in the same way to return the messages on the SignalR channel.

4. Result

You can say that functions have their justification, eg. the approach of database-triggers is quite a smart approach to bring events to the client quickly without the effort of extra business logic to operate.
However, you can not ignore the fact of their latency (especially with Durable Functions). In view of the asynchronicity of a microservice environment, they are not to be regarded as a panacea. Much more they should be chosen for a meaningful combination of stateful services together with stateless functions.

Here an idea of a meaningful architecture combined with statefull container services and sateless functions.

Werbeanzeigen