Pattern-type (Part 7): Scaling in/out based on OS metrics with SmartCloud Application Services

In my previous articles Pattern-type (Part 5): Scaling in/out based on your own monitoring collector with SmartCloud Application Services I explained how to Scale in/out using your own monitoring collect (ie: counting files in a directory). In noticed in the documentation (IWD Infocenter) at the end of the page a mention of a ‘CPU’ category and ‘Used’ metrics. This let me think we can re-use some embedded OS metrics in a scaling policy and I will show here how to do it.

But first I would like to stress the difference between pattern-type and pattern. A pattern-type provides all components, links, scalability rules… to build a pattern. The best example is the pattern-type for Web-Application (see demo) which provides Enterprise Application, Database components and scalability rules to design your own pattern which you will be able to deploy multiple time. So in this article we show how to create a pattern-type which requires more effort than create a pattern based on a pattern-type. ISV and/or company with home made application which not fit one of the existing pattern-type would be interested in this as pattern-type allows to put all the infrastructure intelligence in the pattern-type in order to deliver the best pattern for your customer.

The reuse of an existing metric requires changes in only two files and guess which one? Of course, the application model to collect the arguments of the scaling policy and the topology file to define the rules and implement this policy.

Application Model (metadata file)

In the application model file, we have to define the scaling policy and capture all arguments for this policy. This is very similar of what we did in the previous article when we define the polity for our own monitoring collector but here instead of defining a number of files and a directory to monitor attributes, we will define a ‘cpuUsage’ attribute which will be a percentage.

Looking at the ‘policy’ JSON element in the application model (metadata.json) of our plugin:

...,
    {
        "id": "ScalingPolicy",
        "label": "Server scaling policy",
        "type": "policy",
        "applicableTo": [
            "Server"
        ],
        "description": "Server scaling policy",
        "groups": [
            {
                "category": "Scaling Type",
                "id": "None",
                "label": "Static",
                "defaultValue": true,
                "attributes": [
                    "intialInstanceNumber"
                ],
                "description": "Description for the Slave scaling policy."
            },
            {
                "category": "Scaling Type",
                "id": "Basic",
                "label": "CPU Based",
                "defaultValue": false,
                "attributes": [
                    "cpuUsage",
                    "scaleInstanceRange1",
                    "triggerTime1"
                ],
                "description": "Indicate that the action of adding or removing instances will be triggered by average CPU usage of existing instances."
            }
        ],
        "attributes": [
            {
                "id": "intialInstanceNumber",
                "label": "Number of Instances",
                "type": "number",
                "min": 1,
                "required": true,
                "sampleValue": 1,
                "invalidMessage": "This value is required, its valid value greater or equal to 1",
                "description": "Specifies the number of cluster members that are hosting the web application. The default value is 1. Acceptable values range from 1-n."
            },
            {
                "id": "scaleInstanceRange1",
                "label": "Instance number range of scaling in/out",
                "type": "range",
                "min": 1,
                "max": 10,
                "required": true,
                "sampleValue": [
                    1,
                    10
                ],
                "description": "Specifies the scaling range for instance members that are hosting the web application. Acceptable values range from 1-10."
            },
            {
                "id": "triggerTime1",
                "label": "Minimum time (sec) to trigger add/remove",
                "type": "number",
                "max": 1800,
                "min": 30,
                "required": true,
                "sampleValue": 120,
                "invalidMessage": "This value is required, its valid value range is 30 to 1800",
                "description": "Specifies the time duration condition to start scaling activity. 
 The default value is 120 seconds. Acceptable values range from 30-1800."
            },
            {
                "id": "cpuUsage",
                "label": "Scaling in/out when CPU usage is out of threshold range(%)",
                "type": "range",
                "displayType": "percentage",
                "required": false,
                "max": 100,
                "min": 1,
                "sampleValue": [
                    20,
                    80
                ],
                "description": "Specifies the CPU threshold condition to start scaling activity. 
When the average CPU utilization of your application platform is out of this threshold range, your platform will be scaled in/out. 
The default value is 20% - 80%. Acceptable values range from 0%-100%."
            }
        ]
    }...

As in the previous article we define a ‘policy’ type element which will be applied to the ‘Server’ role. In this policy we have two groups one for a ‘Static’ scaling policy and another one for a ‘CPU Based’ policy. For the last one we define three attributes: the ‘cpuUsage’, ‘scaleInstanceRange1’ and the ‘triggerTime1’ attributes. You can choose the name you want, the only important thing is that these name must match an attribute id in the attributes list defined after that. The order of the attribute reference in the group will define the order appearance in the pattern editor.

Now we define each attribute, for example for the ‘cpuUsage’ attribute, we specify that it is a range, it should be displayed as a percentage, the min is 1, the max is 100, a default value…

We are done with our application model. Let’s look at the topology file.

Topology files (*.vm)

We have to inject the attribute captured in the application model in the topology file to define the scaling rule. This is done in the ‘scaling’ JSON attribute of the *.vm file.

We will use velocimacro to insert or not elements in the topology.

{
{
    "vm-templates": [
        {
#set( $spattrs = $provider.getPolicyAttributes($component, "ScalingPolicy") )
            "scaling":{
            	"role":"Server",
#if_value( $spattrs, "cpuUsage", '
                "triggerEvents": [
                    {
                        "metric": "CPU.Used",
                        "scaleOutThreshold": {
                            "value": $spattrs.cpuUsage.get(1),
                            "type": "CONSTANT",
                            "relation": "&gt="
                        },
                        "conjection": "OR",
                        "scaleInThreshold": {
                            "value": $spattrs.cpuUsage.get(0),
                            "type": "CONSTANT",
                            "relation": "&lt="
                        }
                    }
                ],')
#if_value( $spattrs, "intialInstanceNumber", '"min": $value,')
#if_value( $spattrs, "intialInstanceNumber", '"max": $value')
#if_value( $spattrs, "scaleInstanceRange1", '"min": $spattrs.scaleInstanceRange1.get(0),')
#if_value( $spattrs, "scaleInstanceRange1", '"max": $spattrs.scaleInstanceRange1.get(1),')
#if_value( $spattrs, "triggerTime1", '"triggerTime": $spattrs.triggerTime1')

            },
            "name": "${prefix}-Server",
            "roles": [
                {
                    "parms": {
                        "Attr1": "$attributes.Sattr1"
                    },
                    "type": "Server",
                    "name": "Server",
        			"dashboard.visible":true
                }                 
            ],

            "packages":["Server"]
        }         
    ]
}

Note: due to editor capability, I had to replace in the snippet above the ‘<‘ and ‘>’ respectively by ‘&lt’ and ‘&gt’.

First we retrieve the parameters of the scaling policy, the we test each value to know if we have to inject elements or not.

If the cpuUsage is defined (thus not a Static policy) we inject the triggerEvent along with the upper and lower limit of CPU Usage to scale in/out.

The key point of the triggerEvent is that we reuse the embedded metric “CPU.Used”. As soon as I know other metrics, I will let you know but you can always check the IWD documentation which is frequently updated with new information.

Then we inject the other attribute value, ‘initialInstanceNumber’, ‘scaleInsanceRange1’ and the ‘triggerTime1’. Of course these names are the names you defined in the application model.

As this collector is an embedded collector, there is no need to register it as we did in the previous article.

Conclusion

We can reuse existing collector and thus no need to reinvent the wheel.

References

Pattern-type (Part 6): How to add operation with SmartCloud Application Services

– Pattern-type (Part 5): Scaling in/out based on your own monitoring collector with SmartCloud Application Services

– Pattern-type (Part 4): Adding your own monitoring collector to a pattern-type with SmartCloud Application Services

– Pattern-type (Part 3): Adding Static scalability to a pattern-type with SmartCloud Application Services

– Pattern-type (Part 2): Create step-by-step a Master-Slave pattern-type with SmartCloud Application Workload Services

– Pattern-type (Part 1): Create step-by-step a simple pattern-type with SmartCloud Application Workload Services

– IWD infocenter

 

Pattern-type (Part 6): How to add operation with SmartCloud Application Services