SaaS Bits 01

So you want to build a SaaS/SaaS like solution? Yes!. But what is a SaaS solution?

You can look up the definition at Wikipedia, spend hours discussing it at Reddit or discuss the architecture philosophies behind at your favorite tech group(s). For the purpose of this blog entry (and those to follow) we will define it as “A hosted software that scale and descale according to demand or configurable parameters”.

While there is a lot of literature around SaaS challenges, components that fits within SaaS architecture or general how-to architecture; there is a limited literature that ties everything together and allow you to actually link all these learned lessons together. This is exactly the focus of this blog series. The focus is to provide a detailed – as much as we can - descriptive guidance on building SaaS infrastructure. And to provide – as much as we can – of the SaaS infrastructure actual building blocks. It will not focus on building the actual SaaS (your CRM, billing, tax etc.).

Few words before we begin, I follow sketch, detail then repeat approach similar to this. That means broad strokes first and it also means that we will make mistakes (intentionally and unintentionally) and we will fix them as go.

As we go I will be adapting code (there is plenty already written that we can refactor for our purposes), referencing external materials for you to learn more and build a wider understanding of an architecture like this.

Let us begin

General Requirements:

  1. SaaS Clients types: Browsers, desktop apps, mobile or others backend solutions (for B2B scenarios).

  2. SaaS solution components: The solution can run anything that is based on HTTP/HTTPs (this means Web, Web API, Web Sockets). It will not include lower level protocols such as AMQP, MQTT etc. (at least for this stage)

  3. Offerings Types – for whatever the SaaS:

    1. Private Jet/Platinum: Those who are premium customers served at the highest performance and availability SLA.  Those might include customers with higher level of isolation (government/public sector and so forth).

    2. First Class/ Gold: lower performance and so on.

    3. Business Class: …

    4. Econ Class:….

  4. The system must allow scaling response to the demand or scheduling scaling.

  5. The system must be flexible to allow seasonal customer type changes (customer Xyz is an econ customer but wants to use private jets during the last 5 days of the month).  

  6. The system must allow different versions of the SaaS software running side by side (to allow early adapters, A/B testing and so on).

  7. The system must allow private/public cloud deployment.

  8. The system must allow deployment of different SaaS software on the same platform (for example crm.contoso.com, taxes.contoso.com, hr.contoso.com).

  9. The system must have the lowest footprint/ties possible on/with the underlying platform (azure, private cloud etc.). You will need that to:

    1. Make use of different features from the underlying platform as they get released (without ripping your solution apart).

    2. Shift different parts of the solution to different clouds private/public(s) as needed.

  10. Billing/subscription schemes? (Check: https://msdn.microsoft.com/en-us/library/ff966499.aspx MSFT P&P Developing Multi-tenant Applications for the Cloud, 3rd Edition). As we add more to our SaaS infrastructure we will be seeing the impact on different billing/subscription types.

  11. For different types SLAs and impact on architecture also check “Developing Multi-tenant Applications for the Cloud, 3rd Edition”

 

The above defines broad strokes, let us begin to define our SaaS infrastructure conceptual architecture.

 

 

The easiest way to describe the above conceptual architecture is to walkthrough it. As the following

  1. A user or a system (client) will authenticate (as a result of redirection) against the AuthN component.

  2. The AuthN component will generate a token for the client.

  3. The client will use the token to connect to SaaS infrastructure (via the gateway).

  4. The gateway will unpack the token to acquire enough information about the user (example tenant ID, group id etc).

  5. Using this info the gateway will connect to the capacity and scale component CSC asking “where should I send this request to”.

  6. The CSC will decide which “pod” should respond to this user request. It can also decide to create more Pod as needed.  

  7. Gateway routes the request to the pod load balancer based on the CSC answer.

Few Extra Notes:

  1. The above happens for each request (to allow temporal subscriptions i.e. give me the highest performance last 5 days of the fiscal month).

  2. The details of how CSC is making decisions is not relevant now, and will be discussed later.

  3. A Pod is a collection of same instances serving the software itself, the instances are behind a load balancer (something we should not write ourselves, details later).

  4. A Pod scales within (number of instances can increase up to the highest limits).

  5. The AuthN engine is expected to normalize tokens, authentication protocols into one gateway specific protocol.  

  6. The gateway must not retain any shared state to allow multiple instances of the gateway (load balancing) to run without the need to write a shared state component.  

Implementation

I have selected to start with gateway/router. The gateway is based on the James Baker’s Service Gateway published here (https://sg.codeplex.com/) for more information visit (https://channel9.msdn.com/Shows/Web+Camps+TV/Decoupling-Large-Applications-with-the-Service-Gateway):

The gateway is based on

  1. IIS ARR Reverse Proxy + Custom URL Rewrite Provider.

  2. Hosted as a Azure Web Role

For more info:

 

My applicationhost.config looks like (under system.webserver section):

<rewrite>

 <allowedServerVariables>

          <add name="x_custom_header" />

        </allowedServerVariables>

            <globalRules>

                <rule name="ARR_server_proxy" enabled="true" patternSyntax="ECMAScript" stopProcessing="true">

                    <match url="^(.*)$" />

                    <action type="Rewrite" url="{SaaSUrlExec:{C:0}[***]{R:0}}" appendQueryString="true" />

                    <conditions logicalGrouping="MatchAny" trackAllCaptures="true">

                        <add input="{HTTP_xHEADER}" pattern="(.*)" />

                    </conditions>

                    <serverVariables />

                </rule>

            </globalRules>

            <providers>

                <provider name="SaaSUrlExec" type="Saas.Gateway.UrlRouter.RouterExec, Saas.Gateway.UrlRouter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=f94e44481a93f173">

                    <settings />

                </provider>

            </providers>

        </rewrite>                                                                     

        <proxy enabled="true" reverseRewriteHostInResponseHeaders="true">

            <cache />

        </proxy>

 

Basically it is a server wide rule that captures a custom header called xHeader and the Request Path then passes them as to our custom URL rewrite provider as <<xHeader>>[***]<<path>> which currently as a POC routes based on the xHeader content to one of two hard coded URLs (which for me was an empty page that spits “server 1 “ (as deployed on server 1) and “server 2“ (as deployed on server 2).

The rest of the code written at this stage is packaging and deployment code to Azure Web roles (ARR/IIS installation and configuration).

Note: in the code there is a console application that performs tests to confirm that the request has been routed successfully.

 

 

Code is published on https://github.com/khenidak/SaaSBits (with Feb 19th date). Once we have something stable enough we will move it to the root folder.

 

Notes:

  1. We are currently installing ARR 2.5 (we will need to reconfigure for ARR 3.0 as it supports web sockets).

 

Till next time..