Rethinking Service Integrations With Microservices Architecture
Ballerina is an open-source language for implementing integration services in MSA. It provides a place to design, develop, document, test, and deploy workflows.
Join the DZone community and get the full member experience.
Join For FreeThe dawn of the microservices architecture (MSA) began to revolutionize the software paradigm in the past few years by revealing a new architectural style for optimizing the infrastructure usage to its optimal level. MSA defines a complete methodology for developing software applications as a collection of independently deployable, lightweight services in which each service runs on a dedicated process with decentralized control of languages and data.
In spite of the wide variety of frameworks introduced during past few years for implementing business services in this architectural style, nearly none were introduced for implementing service integrations. Very recently, WSO2 initiated a new open-source programming language and a complete ecosystem for this specific purpose.
A new programming language? Yes, you heard it right. It’s not another integration framework with many different domain-specific languages (DSLs). It’s a purposely built programming language for integration, with native constructs for implementing enterprise integration patterns (EIPs), including support for industry standard protocols, message formats, etc. and optimized for containerized environments.
It may be worth to note that Ballerina is designed from the ground up with nearly a decade of experience in implementing integration solutions at WSO2 with the vision of making service integrations much more easier to design, implement, deployable, and more importantly adhere to MSA.
The Impact on Microservices Architecture
Figure 1: Using a monolithic ESB in outer architecture.
Today, most enterprises seek for mechanisms for integrating services from various internal and external service providers for meeting their business needs. Traditionally, this could be achieved using an integration framework, ESB, or integration suite, depending on the complexity of the integrations. As illustrated in Figure 1, one option would be to use a monolithic ESB in the outer architecture while implementing business services in the inner architecture in line with MSA.
Despite the fact that it is technically feasible, it may contradict the main design goals of MSA, as an ESB or an integration suite would consume a considerable amount of resources while taking longer to bootstrap, having to use in-process multi-tenancy, with comparatively higher development and deployment cost, etc.
For an example, WSO2 ESB would need around 2 GB of memory for running a typical integration solution. It would take around 20 to 30 seconds to bootstrap, and it may not evenly share resources among all the tenants with in-JVM multi-tenancy. The development process may take longer, as it may depend on a single set of configurations and data stores. Finally, the deployment would utilize more resources than optimally needed. Considering all of the above plus the vision of adapting serverless architecture, a much lighter, ultra-fast integration framework with a higher throughput would be needed for gaining the best out of MSA.
Figure 2: A reference architecture for implementing integration services in MSA.
The above figure illustrates a reference architecture for implementing integration services in MSA. Unlike an ESB where a collection of integration workflows are deployed in a single process, in this architecture, each integration workflow will have its own process and a container.
Hence, services can be independently designed, developed, deployed, scaled, and managed. More importantly, it will allow resources to be specifically allocated for each integration service container cluster for optimizing the overall resource usage. Moreover, container cluster managers such as Kubernetes provide completely isolated contexts within a single container host cluster for managing multi-tenancy. Therefore, this approach would naturally fit in MSA for implementing integration services.
Ballerina Language Design
As explained earlier, Ballerina language has been carefully designed by studying constructs of widely used programming languages such as Java, Golang, C, C++, etc. The following section illustrates the high-level language design in brief.
Packages
The package is the topmost container in Ballerina, which holds functions or services. It is important to note that package definition is optional and if a package is defined, ballerina source files need to be stored in a hierarchical folder structure according to its package hierarchy.
Functions
A function represents a set of instructions that performs a specific task that is intended to be reusable. Mainly, there are two types of functions: native functions, which support returning multiple return parameters, and throwing exceptions.
Main Function
The main function is the entry point in Ballerina executable programs. Executables can be used for implementing integration logic which needs to be run in the background on a time interval or an event trigger.
Services
Ballerina services allow integration workflows to be exposed as services. Services are protocol agnostic and can be extended to work with any messaging protocol with required message formats. Currently, services can be exposed as HTTP REST APIs, WebSockets, and HTTP/2 services. Messages can also be delivered to mediation pipelines via JMS topics/queues (using an external broker), and files.
Resources
A resource represents a functional unit of a ballerina service. A service exposed via a given protocol would use resources for managing different types of messages. For an example, HTTP REST API would use resources for implementing API resources and a JMS service would use resources for receiving messages from a topic/queue.
Workers
A worker is a thread according to general programming terms. Workers provide the ability to execute a series of integration functions in parallel for reducing the overall mediation latency of an integration service.
Connectors
Connectors provide language extensions for talking to well known external services from ballerina such as Twitter, Google, Medium, etcd, Kubernetes, etc. Moreover, it also provides the ability to plug-in authentication and authorization features to the language.
Ballerina Composer
Figure 3: ballerina composer design view.
The composer is the visual designer tool of the Ballerina language. It has been designed as a web application and shipped with the Ballerina Tools distribution. Execute the below set of commands to download it and run, once started access http://localhost:9091 in a web browser:
$ version=0.8.1 # change this to the latest version
$ wget http://ballerinalang.org/downloads/ballerina-tools/ballerina-tools-${version}.zip
$ unzip ballerina-tools-${version}.zip
$ cd ballerina-tools-${version} # consider this as [ballerina.home]
# cd bin/
$ ./composer
Not only does Composer provides a charming graphical designer — it also provides a text editor with syntax highlighting and code completion features and a Swagger editor for HTTP-based services. Composer provides all language constructs and native functions needed for implementing integration programs and services. More interestingly, those can be run and debugged using the same editor.
Figure 4: Ballerina Composer source view.
For detailed information on Composer, please refer this article article.
Ballerina CLI
Ballerina ships two distributions: one for the Ballerina runtime and the other for the tooling. Ballerina runtime only includes features required for running Ballerina programs and services. The tools distribution include features for executing test cases, generating API documentation, generating swagger definitions, and building Docker images:
$ cd [ballerina.home]/bin/
$ ./ballerina --help
Ballerina is a flexible, powerful and beautiful programming language designed for integration.
* Find more information at http://ballerinalang.org
Usage:
ballerina [command] [options]
Available Commands:
run run Ballerina main/service programs
build create Ballerina program archives
docker create docker images for Ballerina program archives
doc generate Ballerina API documentation
swagger Generate connector/service using swagger definition
test test Ballerina program
Flags:
--help, -h for more information
Use "ballerina help [command]" for more information about a command.
Ballerina Packaging Model
Ballerina programs and services can be packaged into archive files for distribution. These files will take the extension BSZ. Consider the below sample HTTP service. The source code of this can be found here.
.
└── hello-ballerina
├── README.md
└── org
└── foo
└── bar
├── helloWorldService.bal
└── helloWorldServiceTest.bal
The following command can be executed for generating an archive file for this service:
$ cd /path/to/hello-service/
$ /path/to/ballerina-home/bin/ballerina build service org/foo/bar/
The generated bar.bsz
file would contain following files:
.
├── BAL_INF
│ └── ballerina.conf
├── ballerina
│ └── test
│ └── assert.bal
└── org
└── foo
└── bar
├── helloWorldService.bal
└── helloWorldServiceTest.bal
Ballerina API Documentation Generator
Ballerina tools distribution ships an API documentation generation tool called Docerina as a part of the Ballerina CLI. This allows developers to generate API documentation for Ballerina functions, connectors, structs, and type mappers. Currently, it does not include API documentation generation for Ballerina services, as they are already supported with the Swagger integration for HTTP-based services. In a future release, it may support non-HTTP services such as JMS and file.
API documentation of Ballerina native functions of v0.8 release can be found here. Execute ballerina doc help command for more information on generating API documentation for Ballerina code:
$ cd ballerina-tools-${version}/bin/
$ ./ballerina doc --help
generate Ballerina API documentation
Usage:
ballerina doc <sourcepath>... [-o outputdir] [-n] [-e excludedpackages] [-v]
sourcepath:
Paths to the directories where Ballerina source files reside or a path to
a Ballerina file which does not belong to a package
Flags:
--output, -o path to the output directory where the API documentation will be written to
--native, -n read the source as native ballerina code
--exclude, -e a comma separated list of package names to be filtered from the documentation
--verbose, -v enable debug level logs
Ballerina Test Framework
Ballerina provides a test framework called Testerina for implementing unit tests for Ballerina code. In the v0.8 release, the following native test functions are available for starting services, asserting values and setting mock values:
package ballerina.test;
startService(string servicename)
assertTrue(boolean condition)
assertTrue(boolean condition, string message)
assertFalse(boolean condition)
assertFalse(boolean condition, string message)
assertEquals(string actual, string expected)
assertEquals(string actual, string expected, string message)
assertEquals(int actual, int expected)
assertEquals(int actual, int expected, string message)
assertEquals(float actual, float expected)
assertEquals(float actual, float expected, string message)
assertEquals(boolean actual, boolean expected)
assertEquals(boolean actual, boolean expected, string message)
assertEquals(string[] actual, string[] expected)
assertEquals(string[] actual, string[] expected, string message)
assertEquals(float[] actual, float[] expected)
assertEquals(float[] actual, float[] expected, string message)
assertEquals(int[] actual, int[] expected)
assertEquals(int[] actual, int[] expected, string message)
package ballerina.mock;
setValue(string pathExpressionToMockableConnector)
It can be tested by implementing a test case as follows:
package org.foo.bar;
import ballerina.lang.messages as message;
import ballerina.test;
import ballerina.net.http;
function testHelloService () {
message request = {};
message response = {};
string responseString;
string serviceURL = test:startService("helloService");
http:ClientConnector endpoint = create http:ClientConnector(serviceURL);
response = http:ClientConnector.get(endpoint, "/hello", request);
responseString = message:getStringPayload(response);
test:assertEquals(responseString, "Hello world!");
}
Conclusion
Ballerina is a brand new open-source programming language purposely built for implementing integration services in MSA. It provides a complete ecosystem for designing, developing, documenting, testing, and deploying integration workflows. Feel free to try it out, give feedback, report issues and most importantly to contribute back. Happy dancing with Ballerina!
References
Published at DZone with permission of Imesh Gunaratne. See the original article here.
Opinions expressed by DZone contributors are their own.
Trending
-
WireMock: The Ridiculously Easy Way (For Spring Microservices)
-
DevOps Pipeline and Its Essential Tools
-
How To Backup and Restore a PostgreSQL Database
-
What I Learned From Crawling 100+ Websites
Comments