React Server Side Rendering

What is Server Side Rendering

Server rendering generates the full HTML for a page on the server in response to navigation. Server-side rendering is a technique for rendering a normally client-side only single page app (SPA) on the server and then sending a fully rendered page to the browser.

Why Server Side Rendering

  • SEO friendly – SSR guarantees your pages are easily indexable by search engines.
  • Better performance for the user – User will see the content faster.
  • Social Media Optimization: When people try to post your link on Facebook, Twitter, etc. then a nice preview will show up with the page title, description, and image.
  • Shared code with backend service.
  • User-machine is less busy.

Reasons we choose server side rendering

  • With the introduction of server-side (universal) React, The initial page is rendered from the server, meaning the subsequent pages load directly from the client.
  •  A universal app sends to the browser a page populated with data.
  • Then the app loads its JavaScript and rehydrates the page to get a fully client-side rendered app.
  • Often referred to as Universal Rendering or simply “SSR”, this approach attempts to smooth over the trade-offs between Client-Side Rendering and Server Rendering by doing both.
  •  Navigation requests like full page loads or reloads are handled by a server that renders the application to HTML, then the JavaScript and data used for rendering is embedded into the resulting document.
  •  When implemented carefully, this achieves a fast First Contentful Paint just like Server Rendering, then “picks up” by rendering again on the client using a  technique called (re)hydration.

React 16 SSR so much faster than React 15

In React 15, the server and client rendering paths were more or less the same code. This meant that all of the data structures needed to maintain a virtual DOM were being set up when server rendering, even though that vDOM was thrown away as soon as the call to renderToString returned. This meant there was a lot of wasted work on the server render path. In React 16, though, the core team rewrote the server renderer from scratch, and it doesn’t do any vDOM work at all. This means it can be much, much faster.

More info :- https://reactjs.org/docs/react-dom-server.html

React 16 Supports Streaming

React 16 now supports rendering directly to a Node stream. Rendering to a stream can reduce the time to first byte (TTFB) for your content, sending the beginning of the document down the wire to the browser before the next part of the document has even been generated.

SSR vs CSR

Features SSR(Universal) CSR(Client Side Rendering)
Initial Load Fast
Seo  If not implemented correctly
Performance (mobile/ slow internet)
Fast render after initial load
Web crawling
TTFB(Time to first byte)  Can be improved
Html doc size  Bigger  Smaller
Largest Contentful Paint  Sonner  Takes time
First Input Dealy  Takes time

Performance with Bluehost maestro

 We implemented React server side rendering for our maestro application.

Challenges

  • Initial setup is complicated
  • Redux configuration is complicated
  • Hot module reload is difficult to setup
  • Lazy loading setup is complicated (It can be done by using loadable)

Outcome

  • Faster page load
  • Improved performance

Why build custom React framework

  • More control over the application
  • Better handling of the components
  • Better dependency management
  • Less or no bloat npm packages

Comparison with Next.js and Gatsby

  • No Framework specific knowledge required in React SSR
  • Smaller Builds
  • Adaptable to new changes published by react team related to server side rendering
  • Static html pages can be created for pre login screens
  • Prefetching React for subsequent pages

Ways to Improve Performance Of React SSR

  • Using rendertoNodeStream instead of rendertoString
  • Link preload/prefetch
  • Lazy loading of assets
  • Using Brotli compression format
  • Code splitting

React SSR framework

Coming soon

Using WordPress Platform to Build Scalable Blogs

As all of us are working from home these days due to the COVID-19 situation, there is an opportunity for us to try and build that blogging website we’ve always wanted to but couldn’t due to a busy schedule, deadline pressure, or sheer laziness.

Sadly enough, laziness has no solution yet. So for all you lazy folks, we thought why don’t we share how we use WordPress to serve the blogs of our Retail Brands like HostGator, bluehost and BigRock in the APAC Region. Maybe that’ll motivate you to build that blogging website of your dreams!

Our Humble Beginnings

We started with a fairly simple infra setup where we proxied all the /blog/* traffic to our Blog Cluster (Powered By WordPress), and the rest of the traffic flows to our E-commerce Cluster.

Earlier, even the blog cluster was pretty simple and old school. We hosted WordPress application and MySql DB on the same machine but we had at least 2 VPS to maintain the High Availability of the cluster along with ample of monitoring via Nagios and Pingdom/Site 24×7.

The Current State

Over the years, the blog cluster has evolved and what you see below is the latest setup which is equipped with Layer 7 Load Balancer (HAProxy). To uphold the principle of SoC (Separation of Concern), we moved our Application (WordPress) and MySql DB to their own instances which are load-balanced by HAProxy at 2 levels.

As we truly believe in dogfooding (Eating Our Own Dog Food), hence we have the WordPress application nodes set up using our own Optimized WordPress Hosting and MySql on our VPS servers.

Blogs served by this infra
Next Steps
  1. Move from VM/VPS to containers managed by Openshift or Public Cloud.
  2. Migrate MySql cluster from master-master to Cluster (Galera or InnoDB).
  3. Move from Monitoring to Observability.

If you are also bored (or full of excitement!), and want to blog about your experiences then please don’t hold back and start writing NOW.

As the great Indian poet, Kabir Das said,

काल करे सो आज कर, आज करे सो अब। 

पल में प्रलय होएगी, बहुरि करेगा कब॥

Long story short, he says “Just do it right now! Tomorrow might never come.”

If you need any kind of help on WordPress or High Availability infra setup, please drop us an email at apac-tech-help@endurance.com.

Stay Safe, Wash Hands and Happy Blogging!!!

Cron framework options in cloud environment

This blog post is for all developers, who need to start fresh or refactor existing cron implementation. In this post, we will detail insights about 3 of popular cron frameworks that we have gone through for cloud environment.

At Endurance, we empower more than 15 million domain names.

We were faced with the task of building a service which is responsible for all activities related to provisioning and management of domain names. A critical part of this service was to run background jobs/crons and audit logging was advisable for these crons.

Development teams typically want their crons to run on a separate Instance/Cluster, keeping scale and separation of concern in mind, even having their own codebase.

In our case,

  • We did not have a separate code
  • A lot of common code written in the service itself
  • We did not anticipate resource-intensive tasks
  • We did not foresee crons affecting production traffic
  • Thus, no requirement was there to spin off a separate cron cluster.

The service was going to be deployed on AWS. Every instance in the cluster would have both the service code and the cron logic embedded within it. A few of the crons had an additional requirement that at any given time, we had to ensure that only a single instance of that particular cron could execute. Considering that the codebase was in spring boot, any solutions which had a direct spring boot integration would be an added bonus.

To implement the requirements defined above, we evaluated three options

  • Spring boot @Scheduled: Spring native support for task scheduling
  • AWS CloudWatch Events + Lambda/API: Scheduling tasks on AWS with minimal resources. This would mean that we would have the scheduling done via AWS lambdas, which would trigger the cron jobs on the service instances via the load balancer.
  • Quartz framework: Popular + Widely used open-source framework for job scheduling

We compared each of the alternatives with our desired features to identify the best fit.

Spring boot @Scheduled:

This is the simplest approach that spring provides out of the box. The simple rules that need to be followed to annotate a method with @Scheduled are:

  • The method should have void return type
  • The method should not accept any parameters

Once methods are annotated as such, they will get executed based on the cron expression defined in the annotation. Unfortunately, this approach does not allow us to constrain the execution in a way to restrict only execution of a single cron at any given time across all instances.

AWS CloudWatch Events + Lambda/API

 

aws setup with crons via apiThis is a hybrid approach where we could have scheduled events to trigger lambda which could, in turn, invoke the API on the load balancer, which would, in turn, hit the load balancer. These APIs would be responsible for the actual cron execution. Since the API would be invoked via the load balancer, it would automatically ensure that the actual cron job is executed on only 1 of the service instances. The lambda’s however, typically have an execution limit of ~15 minutes. So the caller would not be able to record whether a given cron job has executed successfully or not if it took more time to run. As a result, we would have to implement more functionality to guarantee the execution of these cron jobs.

 

 

Quartz framework

Quartz is a feature-rich scheduling library that can be easily integrated within Spring boot. It has out of the box support for features such a clustering  – fail-over, load- balancing, listeners and plugins which could help with maintaining history. This seemed like the ideal solution for our use-case since it provided a solution for almost all of our constraints.

 

Added below is a comparison table on the various aspects that we evaluated these approaches on

 

Feature Quartz Spring boot @Scheduled AWS CloudWatch Events + Lambda/API call
Job triggering Maximum number of options compared to the rest (including cron expressions) Cron expressions, fixed-rate or fixed-delay based Cron expressions
Job definition Any java class that implements the Job interface

eg:

public class CronJOb implements Job{

@Override
public void execute (JobExecutionContext context){..}

}

Any method with the @Scheduled annotation

eg:

@Scheduled(cron=”0 0 * * * *”)
public void cronJob () {… }

Two parts :

  • Lambda function which needs to be triggered based on an event. This will be responsible for invoking the API
  • API call defined on a service which will have the core implementation of the cron job
Clustering support Provides load-balancing, automatic fail-over out of the box using JDBC persistence. No support out of the box We won’t need separate clustering support in this case, as only a single instance of the API will get invoked via the lambda. However, it would need additional effort to build load balancing and fail-over.
Listeners and plugin support A number of listeners and plugins are available to support audit logging,  loading job definitions via xml etc No We can add Listeners like triggering an AWS SNS event at the completion of execution and use it however we want. This can also be used to keep the history of job execution.
Cons No support for ensuring a single instance of cron job executes at a given time. No persistence option out of the box. The feature set is quite limited.

Maximum Execution for lambda is 15 minutes. So we cannot invoke crons synchronously.

Also, this approach is tightly coupled with AWS services hence it would make moving out of AWS more difficult in the future.

References:

http://www.quartz-scheduler.org/
https://spring.io/guides/gs/scheduling-tasks/
https://blog.readme.io/writing-a-cron-job-microservice-with-serverless-and-aws-lambda/
https://docs.aws.amazon.com/lambda/latest/dg/limits.html

A Beginner’s Guide to Distributed Systems & Scaling Them

This article introduces distributed systems, the motivations behind their usage, and various aspects of scaling them.

Demystifying Distributed Systems
As per Andrew Tannenbaum, ‘A distributed system is a collection of independent computers that appears to its users as a single coherent system.’

Example: google.com is a distributed system because to a user it looks like one system, although it’s powered by huge clusters of computers.

Why Distribute a System?
Dealing with distributed systems is a pain! Compared to a single computer, they’re hard to deploy, maintain, debug, and even reason about. So why would one want to tread down this terrible path?

Always remember, systems are distributed by necessity, not by choice!

It would be wonderful to not have to deal with the complexities distributed systems bring. But today’s web-scale and Big Data needs have made them a necessary evil.

The biggest benefit of distributed systems is that they’re inherently more scalable than a single computer.

Now that we’ve talked about scalability, let’s discuss it in a little more detail.

Scalability
Assume you’ve been given a task to increase the request handling capability of a database. How would you do it?

One possible way to do it is to upgrade the hardware it’s running on. This process is called scaling vertically, or scaling up.

The same problem can be solved by adding more computing nodes to the system. This is called scaling horizontally or scaling out.

Source

Why, then, would one not scale only vertically, and avoid the hassles of a distributed system?

There are multiple factors which come into play here:

  • There’s a technological limit to upgrading the hardware of one single computer. And even the latest hardware technologies are insufficient to serve the needs of technology companies with moderate to high workload.
  • After a certain point, scaling horizontally proves to be more economical compared to its vertical counterpart.
  • There’s no theoretical limit on how much a system can be scaled horizontally. It’s potentially infinitely scalable.
  • Horizontal scaling makes a system more fault-tolerant, and therefore more available.  A cluster of, say, ten machines is naturally more fault-tolerant than a single machine.
  • Horizontal scaling can potentially make a system have low latency. At first sight, it might seem counter-intuitive. But consider this scenario: The time for a network packet to travel the world is physically bound by the speed of light.

For example, the shortest possible round-trip time for a request in a fibre-optic cable between New York & London is 90ms. With distributed systems you can have a node in both cities, permitting traffic to hit the node that is closest to it.
Conclusion

So this was a short introduction to Distributed Systems and how to scale them. We’ll see more advanced stuff on these subjects in upcoming articles. Stay tuned!

 

Designing Scalable and Highly Available Applications – Check Availability Service

Introduction

 

Our Check Availability(CA) service is responsible to determine whether a requested domain name is available for purchase under the given Top Level Domains. The scalability and availability of this service is very critical for our EIG brands like BigRock, HostGator, BlueHost, etc.

We will go through some of the key architectural decisions in building our CA service and also, the general approach for building applications that are scalable and highly available across multiple data centers.

Microservices-based architecture

 

In a monolithic architecture, one misbehaving component can bring down the entire system. With the microservices approach, if there is an issue in one of the services then that service will only be impacted and the other services will continue to work. Other benefits of microservices-based architecture include (a) polyglot programming and persistence,  (b) developed and deployed independently, (c) decentralized continuous delivery

For the reasons mentioned above, we built Check Availability as a microservice with the tech stack – (a) Cassandra Database,  (b) Jersey RESTful services, (c) Spring Dependency Injection

Choosing the appropriate data store

 

A complex enterprise application uses different kinds of data and we could apply different persistence technologies depending on how the data is used. This is referred to as Polyglot Persistence. We should use Relational Databases for transactional data and choose appropriate NoSQL databases for non-transactional data.

Horizontal Scaling or Scale-Out is the ability to increase the capacity of a system by adding more nodes and it is harder to achieve with Relational Databases due to their design(ACID model).  Most of the NoSQL databases are cluster-friendly as they are designed with the BASE(Basically Available, Soft State, Eventual Consistency) model. Graph databases are an exception as they use ACID model.

We have non-transactional data for Check Availability service and we wanted to use appropriate NoSQL database rather than our PostgreSQL database. This would also help in reducing the huge traffic from CA service to our transactional database.

We have evaluated Redis, a Key-Value NoSQL database which guarantees very high consistency. Redis cluster uses master-slave model which would cause downtime when a master node is unavailable as there would be some delay in electing one of its slaves as the master. We have evaluated Cassandra, a Column-Family NoSQL database which guarantees very high availability. Cassandra cluster uses masterless model which makes it massively scalable.

We would need very high availability for our CA service compared to consistency and hence we decided to go with Cassandra cluster. Majority of the traffic to our Cassandra database are read requests. We have setup Cassandra cluster of 3 nodes with (a) Replication Factor as 2, (b) Write Consistency Level as LOCAL_QUORUM, (c) Read Consistency Level as ONE. So, all the read requests can be handled even if one of the nodes in the cluster is up.

Active-Active setup within a Data Center(DC)

 

We have our CA service setup in multiple DCs. Within a DC, we have 2 CA web nodes with active-active setup under HAProxy load balancer. All of the CA web nodes connect to Cassandra cluster within the same DC.

Web node arch
Web Node Architecture

 

To deploy a newer version of CA service, we repeat the following steps for all the web nodes one by one – (a) remove the web node out of the load balancer, (b) deploy the latest version of CA service, (c) add it back to the load balancer. So, there would be zero downtime for deploying the service.

With the increasing traffic to CA web nodes/Cassandra cluster, we can easily scale-out by adding more nodes.

Active-Active setup across multiple data centers

 

In order to achieve zero downtime for the application/service even when there is disaster within a DC, we could go with active-active setup for the application/service across DCs. We can use Round-robin DNS, Cloudflare Traffic Manager, etc to manage the traffic to the web nodes across the DCs.

At the time of writing this blog, we are in the process of completing the active-active setup of our CA service across two of our DCs in US location.

Even though Cassandra cluster supports cross-dc replication, we have taken the decision to eliminate cross-dc dependencies as much as possible. Hence one of the DCs going down would not have any impact on the other DCs.

Conclusion

 

It is very important to pro-actively monitor the application/service availability, correctness and performance along with the hardware health. This would help in reducing the downtime and improving the customer experiences. We have automated tests scheduled to run periodically in our production environment to check the health of our applications/services. Also, we monitor the application logs to identify critical errors/issues  and send alerts to relevant teams in near real-time.

We have seen in detail some of the key architectural decisions for building scalable and highly available applications(like our Check Availability service) across multiple DCs. Happy learning!

 

Authored by : Sudheer Meesala