Monday, 29 June 2020 12:38

Deploying .NET code on HANA XS Advanced

Written by Vasily Sukhanov
Rate this item
(0 votes)
“© 2020. SAP SE or an SAP affiliate company. All rights reserved.” “Used with permission of SAP SE”

SAP has implemented Cloud Foundry (CF) on its SAP Cloud Platform, as a next-generation Platform as a Service (PaaS) as a development and runtime environment. CF offers a set of tools and services to run applications developed with different programming models.

SAP HANA® in-memory database also provides an application platform called SAP HANA® extended application services (XS Advanced or XSA). XSA is available on-premise and follows development paradigm compatible with CF.

We will cover specific aspects on how to prepare your XSA execution environment for Go-Live phase and make sure your applications run safely with given constraints on memory resources.

A Software Developer is free to choose almost any IDE, programming language and development environment to deploy applications using Сloud Foundry on SAP Cloud Platform. SCP is an excellent solution for companies that plan to make cloud services out of existing software running on-premise.

Before doing architecture development your Software Architect should be familiar with Cloud Foundry execution and deployment tools and features to in order to plan the software migration to the cloud.

XSA runtime platform inherits the same architecture as Cloud Foundry and runs on-premise as part of SAP HANA. That means that most of the design concepts of XSA are almost identical to CF and can be found here.

In this blog post we will point out some XSA tweaks while configuring the runtime environment for Microsoft .NET and share our experiences gained in a  customer’s implementation project. This concept is applicable for any available runtime environment including Microsoft .NET.

Preparing computing environment for application deployment to XSA

SAP HANA Platform includes both scale-up and scale-out configuration options that provide different benefits for developers and end-users. Basically scale-out configurations provide fault-tolerance by distributing XSA applications among different servers (nodes).

Each node running XSA can hold different roles like xs_worker and xs_standby that help initiate application failover to the standby node in case the worker node fails.

According to the XSA architecture shown below (Figure. 1), there is one master XSA node running xs_controller and multiple xs_worker nodes. XSA scale-out concept details are described in the SAP HANA Administration guide, in the chapter about “Scale-Out Architecture of SAP HANA XS Advanced Runtime Platform” at http://help.sap.com.

Figure%201%20%u2013%20HANA%20XS%20Advanced%20Scale-Out%20Configuration

Figure 1 – XS Advanced Scale-Out Configuration

XSA Scale-out is capable of doing load balancing by putting Failover Router (Figure .1) in front of XSA nodes. In order to get proper access to the applications, you should plan and configure one of the routing modes:

  • Port-based routing,
  • Hostname-based routing.

Hostname-based routing prepares URLS to access the applications by using common domain name, for instance: https://app1.domain.corp, https://app2.domain.corp, etc.

While doing DNS configuration to satisfy hostname-based routing for XSA, you should maintain at least two records:

  • domain.corp IN A <ip_address_master_hana_xsa_node>,
  • *.domain.corp IN CNAME domain.corp (where <ip_address_master_hana_xsa_node> is an IP address of XSA node with xs_controller and xsuaaserver processes running).

All network related configurations for XSA Scale-Out require careful planning according to the information described in the  SAP HANA Administration Guide, chapter “Scaling SAP HANA”. Proper network configuration basically helps isolating internal XSA traffic and the network traffic from business users by placing them on different network interfaces.

Plan workload profile for XSA

In order to plan the sizing of XSA nodes you should refer to the SAP HANA Administration guide, chapter “Platform Sizing in XS Advanced” at help.sap.com. There are two profiles available for XSA depending on usage: PlatformUsage and AppUsage. The second one AppUsage is intended to establish reliable service of running applications for business users and sized upon the number of concurrent application requests (check the table below).

Profile size (Short)Profile size (Long)Max. concurrent application requests
SSmall100
MMedium2000
LLarge8000
XLExtra Large32000

Develop sizing for XSA Scale-Out

What are the benefits of XSA Scale-Out configuration?

  • Protect HANA memory consumption by isolating XSA on different physical servers
  • Protect HANA service availability against memory outages caused by application server
  • Provide load balancing and failover for applications

An example of configuration steps for XSA will be provided in a subsequent blog posts, here we will only cover the basic principles of landscape layout to set up Multi-Host XSA.

In order to prepare the final memory requirements for XSA scale-out nodes, you should take your application requirements into account based on workload profile per user.

For standard memory requirements for XSA you should refer to the SAP note 2618752 «Resource consumption of SAP HANA extended application services, advanced model».

Select hardware platform based on sizing requirements

Supported hardware requirements for XSA can be found at SAP HANA Hardware Directory.

While planning XSA nodes configuration you may select any available hardware platform to distribute applications workload on physically isolated server.

Design and build custom buildpack for Microsoft .NET Runtime

XSA architecture contains a mechanisms for creation of a custom runtime environment for different languages so-called «buildpacks» that help with application deployment and perform the following scenario:

  • Deploy compiler or runtime environment (like JVM or .Net) in an isolated folder on the server (possibly download the necessary version according to the application settings)
  • Check necessary dependencies before compilation (required libraries, frameworks, project structure and other settings)
  • Compile the app from sources and place the result in an isolated folder on the server
  • Configure the environment variables (like PATH)
  • Run the application and provide necessary routing for Web requests together with authentication services running as part of CF or XSA
  • Provide failover and load balancing for the application

The buildpack itself is a set of scripts and binaries that perform the scenario described above and actually can be customized and configured to satisfy specific constraints like compiler’s version, specific memory constraints for JVM, patch dependencies, etc.

Detailed steps to build custom buildpack can be found here -> help.sap.com (SAP HANA Developer Guide for XS Advanced Model, chapter “Create a PHP Buildpack for XS Advanced”).

In order to get buildpack created for  Microsoft .Net Core Runtime 3.1 on XSA 2.0 (HANA 2.0 SP4), you should implement the following steps:

  • Download .NET Core Runtime 3.1 from Microsoft website and install it to a local directory on the Linux machine running XSA. (by default .NET Core Runtime is installed in a directory .dotnet for the current user).
  • Create a gzip archive and place the content of .dotnet folder in there.
  • Prepare shell scripts: compile, detect, release.
  • Prepare a final buildpack zip archive and place all artifacts created above (1-3) in there.
  • Install the buildpack by executing the cli command xs create-buildpack (sap.com->SAP HANA Developer Guide for XS Advanced Model, chapter “Create a PHP Buildpack for XS Advanced”)

All these steps described above you can follow by watching the video below.

You can download the buildpack to run .NET Core Runtime 3.1 for XSA using the link.

All buildpack concepts are well described on CF website and can be found here.

Below you can find an example of sources for XSA buildpack to run .NET Core Runtime 3.1.

The core logic of buildpack implemented by scripts : compile, detect, release. The following example is tested using .Net Core Runtime 3.1 on XSA 2.0 (HANA 2.0 SP4).

  • “compile” script should check preliminary requirements to compile an application from sources, check availability of necessary assemblies, frameworks, etc. The current script unpacks the .net core runtime to the directory prepared by HANA XSA during application deployment.

Source code for the compile script>>

#!/bin/bash # bin/compile <build-dir> <cache-dir> BUILD_DIR=$1 BIN_DIR=`dirname $0` BUILD_PACK_DIR=`dirname ${BIN_DIR}` echo "Extracting .NET runtime into..." echo ${BUILD_DIR} cd ${BUILD_DIR} tar xzvf ${BIN_DIR}/../runtime/runtime.tgz echo "Extracting .NET runtime Done." 

Current CF version does not use compile script, it was replaced by finalize and supply.

  • “detect” script should check different configurations options and settings.

Source code for detect script>>

#!/bin/bash # bin/detect <build-dir> if [ -f $1/appsettings.json ]; then exit 0 fi exit 1 
  • “release” script generates yaml file to run the application.

Source code for release script>>

#!/bin/bash # bin/release cat <<EOF --- config_vars: addons: default_process_types: web: /bin/bash ./start.sh EOF 

In total you should have the following folder structure for buildpack:

..  
bin

bin\detect

bin\compile

bin\release

Scripts for buildpack
runtimeruntime\runtime.tgzBinaries for .net core 3.1 runtime

How to protect applications running by XSA against memory leaks?

Deploying XSA applications requires careful memory planning and usually application runtime supports all means to prevent from memory leaks.

Which options do exist to minimize system downtime due to  application crash caused by memory leaks ? Linux OS supports mechanism called Control Groups (Cgroups) which represents powerful and convenient way to define memory and cpu resource constraints for any application.

It is important to note that Cgroups is part of the Linux kernel and requires root privileges to be executed. Standard Linux user requires sudo access rights to use Cgroups directly. Also Cgroups are widely implemented by systemd, which provides the easiest way to control resource limits.

Anyway we decided to have implemented Cgroups directly, a working example of script “start.sh” that runs by buildpack for .NET Core 3.1 shown below:

Source code of start.sh script>>

#!/bin/bash if [ -z "$CGNAME" ] then echo "[ERR]Please check CGNAME to place cgroup name limits." exit 1 else echo "[OK] CGNAME is set to '$CGNAME'" fi if [ -z "$MemoryLimitInMB" ] then echo "[ERR] Please check memory limit settings." exit 1 else echo "[OK] MemoryLimitInMB is set to '$MemoryLimitInMB'." fi if [[ ! $(sudo echo 0) ]]; then echo "[ERR] sudo rights for user '$USER' needed.";exit 1; else echo "[OK] sudo rights for user '$USER' exist"; fi create_cgroup_for_space(){ if [[ $(sudo mkdir /sys/fs/cgroup/memory/$CGNAME) ]]; then echo "[ERR] can not create cgroup with name '$CGNAME'."; exit 1; else echo "[OK] cgroup '$CGNAME' successfully created."; fi } if [[ ! $(sudo ls /sys/fs/cgroup/memory/$CGNAME 2>/dev/null) ]] then echo "[WRN] cgroup '$CGNAME' is not set." create_cgroup_for_space else echo "[OK] cgroup '$CGNAME' is set." fi if [[ $(sudo sh -c "echo $MemoryLimitInMB > /sys/fs/cgroup/memory/$CGNAME/memory.limit_in_bytes") ]] then echo "[ERR] Can not set memory limit for app." exit 1 else echo "[OK] Successfully set memory limit to '$MemoryLimitInMB'." fi ATTACH=`awk '/^__MS_DOT_NET_RUN__/ {print NR + 1; exit 0; }' $0` tail -n+$ATTACH $0 > ./run.sh _PID=`echo $$` if [[ ! $(sudo sh -c "echo $_PID > /sys/fs/cgroup/memory/$CGNAME/tasks") ]] then chmod +x ./run.sh && /bin/bash ./run.sh else echo "[ERR] Unable to start app" exit 1 fi exit 0 __MS_DOT_NET_RUN__ #!/bin/bash trap "exit" INT TERM ERR trap "kill 0" EXIT export ASPNETCORE_URLS="http://localhost:$VCAP_APP_PORT" echo "ASPNETCORE_URLS: '$ASPNETCORE_URLS'"; # Getting runnable dll. runtimeconfigs=($(ls *.runtimeconfig.json)); if [ ${#runtimeconfigs[@]} -gt 1 ] ; then echo "Error! Found '${#runtimeconfigs[@]}' *.runtimeconfig.json files! Expecting only one. Files: '${runtimeconfigs[@]}'.'" 1>&2; exit 1; fi; if [[ ${#runtimeconfigs[@]} -eq 0 ]] ; then echo "Error! Can't find *.runtimeconfig.json file!" 1>&2; exit 1; fi; exeFile=$(echo "${runtimeconfigs[0]//.runtimeconfig.json/}") if [ -f $exeFile ] then echo "starting '$exeFile'..."; exec "./$exeFile" --urls $ASPNETCORE_URLS; exit; fi dllFile=$(echo "${runtimeconfigs[0]//.runtimeconfig.json/.dll}") if [[ !(-e $dllFile) ]] ; then echo "File '$dllFile' is not found." 1>&2; exit 1; fi exec ./dotnet $dllFile --urls $ASPNETCORE_URLS; 

In total the following example uses shell script start.sh to run by buildpack during application deployment when running command – “ xs push -f manifest.yaml”. The script “start.sh” should be placed in the root folder containing .NET application code.

The following example of manifest.yaml given below contains two parameters: “MemoryLimitInMB” and “CGNAME”, where CGNAME stands for Linux control group name and MemoryLimitInMB stands for upper memory limit constraint for the application.

During “push” operation XSA reads manifest.yaml and sets two environment variables $CGNAME and $MemoryLimitInMB for reading by start.sh script.

Basically the start.sh helper script is just an example on how to set up memory usage constraints for your application and minimize system downtime due to application crash caused by memory leaks.

We hope that this blog post was helpful for understanding how to create buildpacks for XSA and apply it in real-life scenarios.

Vasily Sukhanov

Lead Co-Innovation Architect COIL CIS

Read 35 times

Leave a comment

Make sure you enter all the required information, indicated by an asterisk (*). HTML code is not allowed.