days
1
2
hours
2
1
minutes
1
1
seconds
3
0
Analyzing the synergy between the performance of WSO2 MSF4J and the agility of Spring

Performance advantages WSO2 Microservices Framework for Java 2.0 brings to Spring

Afkham Azeez
WSO2
New home image via Shutterstock

WSO2 Microservices Framework for Java (WSO2 MSF4J) first launched in March 2016, providing developers the ability to quickly and easily create secure, high-performance microservices in Java that support container-based deployments. WSO2 Director of Architecture, Apache member and long-time open source contributor, Afkham Azeez talks about version 2.0 of WSO2 MSF4J, which was released in late July 2016 and adds support for the widely adopted Spring application framework, among other features.

Enhancing Spring-based microservice development

When we first rolled out WSO2 Microservices Framework for Java, we knew we wanted to quickly follow up with a release that would enable developers to take advantage of the ease of development offered by the Spring framework, as well as the JAX-RS specification for RESTful weWb services.

Of course, some may wonder why the world needs another microservices framework for Spring when other options, such as Spring Boot, already exist. However, we see a nice synergy between the small footprint and high performance of WSO2 MSF4J and the agility of Spring.

With that in mind, this article examines some of the performance advantages that WSO2 MSF4J 2.0 brings to Spring. Then it looks at how developers can create a Spring service using the functionality in version 2.0 of the framework.

Why build another microservices framework based on Spring?

Spring Boot is a popular framework for building Java microservices. So, why do we need yet another microservices framework which supports Spring? The primary design goals of MSF4J include:

  • A very fast startup time
  • Low memory footprint
  • Small pack size
  • High throughput and low latency

With respect to these design goals, let us look at some of the advantages MSF4J has to offer.

Throughput

To validate the framework’s performance, we have developed a benchmark for performance-testing microservices frameworks. It includes a simple echo test, which echoes back the request message. It also incorporates a test of I/O, which takes the form of the service request that results in the writing and reading of a file before a response is sent back. We then ran WSO2 MSF4J and Spring Boot through the tests with the default configurations of the respective frameworks. As can be seen below, MSF4J has a slightly higher throughput.

pic 1

 

 

 

 

 

 

 

image 2

 

 

 

 

 

 

 

 

 

Memory consumption

While running the benchmark tests, we also monitored the memory consumption of both frameworks. WSO2 MSF4J outperformed Spring Boot here as well as demonstrated by the two diagrams below. In fact, in a separate test, we were able to stream files greater than 1GB in size with a max memory of 15MB allocated to WSO2 MSF4J.

pic3

 

 

 

 

 

 

 

 

bext pic

 

 

 

 

 

 

 

 

 

Latency

The benchmark also compares the latencies of the two frameworks. The following graphs show the comparison of mean, median, 90th percentile, 95th percentile, and 99th percentile latencies.

a

 

 

 

 

 

 

b

 

 

 

 

 

 

c

 

 

 

 

 

 

 

d

 

 

 

 

 

 

e

 

 

 

 

 

 

 

It is evident that at lower concurrencies, both frameworks display similar latency characteristics. However, at higher concurrencies, MSF4J displays better latency behavior.

Here is a summary of how MSF4J 2.0 compares against Spring Boot 1.3.5.

Screen Shot 2016-08-12 at 10.16.48 AM

Using WSO2 MSF4J 2.0 Microservices Functionality with Spring

WSO2 MSF4J supports a Spring-native programming model that allows developers to write WSO2 MSF4J microservices, Interceptors, ExceptionMappers, and configurations as Spring beans and wire them up at runtime.

To understand how WSO2 MSF4J works with Spring, lets look at a simple example. Following is a service that allows products to be added and retrieved. Data will be persisted using an in-memory HSQLDB database. We will interact with the database via Java Persistence API (JPA) and use the Hibernate object relational mapping (ORM) framework. The complete code is available at https://github.com/afkham/msf4j-spring-sample/tree/master/.

There is an application class with a main method that creates a Spring context using a spring.xml file in the classpath as shown below.

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Application {

    public static void main(String[] args) {
        new ClassPathXmlApplicationContext("classpath:/spring.xml");
    }
}

Here is the spring.xml file used above, which mainly defines JPA Entity Manager and Transaction Manager details.

    <!-- Scans the classpath for annotated components that will be auto-registered as Spring beans -->
    <context:component-scan base-package="org.example.service, org.wso2.msf4j" />
    <!-- Activates various annotations to be detected in bean classes e.g: @Autowired -->
    <context:annotation-config />

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="org.hsqldb.jdbcDriver" />
        <property name="url" value="jdbc:hsqldb:mem://productDb" />
        <property name="username" value="sa" />
        <property name="password" value="" />
    </bean>

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" p:packagesToScan="org.example.service" p:dataSource-ref="dataSource">
        <property name="jpaVendorAdapter">
    <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
                <property name="generateDdl" value="true" />
                <property name="showSql" value="true" />
            </bean>
        </property>
    </bean>

    <!-- Transactions -->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
    <!-- enable the configuration of transactional behavior based on annotations -->
    <tx:annotation-driven transaction-manager="transactionManager" />

Next we have the WSO2 MSF4J service called ProductService, which has defined two operations. Note the @Component Spring annotation in addition to the JAX-RS resource annotations. We have also autowired the ProductUtil and Util classes.

@Component
@Path("/")
public class ProductService {

    @Autowired
    private ProductUtil productUtil;

    @Autowired
    private Util util;

    @GET
    @Path("/{id}")
    public Response get(@PathParam("id") int id) {
        util.print("Getting product with ID " + id);
        Product product = productUtil.find(id);
        return Response.status(Response.Status.OK).entity(product).build();
    }

    @POST
    @Consumes("application/json")
    public void add(@ApiParam(value = "Product object", required = true) Product product) {
        productUtil.add(product);
        util.print(productUtil.find(product.getId()).toString());
    }
}

Then we have a POJO, which represents a product. This is a JPA entity as well as the object, which maps to the incoming HTTP JSON payload.

@Entity
public class Product {

    @Id
    private Integer id;
    private String name;

    public Product() {
    }

    public Product(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Product [id=" + id + ", name=" + name + "]";
    }

}

We also have a simple utility, called Util, which is used for printing out messages to System.out. It gets autowired to the respective WSO2 MSF4J service and other objects.

@Component
public class Util {

    public void print(String msg) {
        System.out.println(msg);
    }
}

Similarly we have an AutoWired object called, ProductUtil, which has some CRUD operations related to the product.
In order to configure the transports, we have a configuration class. Here we are setting the HTTP port to 9090.

@Configuration
public class TransportConfiguration {

    @Bean
    public HTTPTransportConfig http() {
        return new HTTPTransportConfig(9090);
    }
}

We include a couple of Exception Mappers, which map exceptions that could occur when data is inserted into or retrieved from the database, to proper HTTP responses. These are wired in using the @Component Spring annotation.

@Component
public class DataIntegrityViolationExceptionMapper implements ExceptionMapper<DataIntegrityViolationException> {
    @Override
    public Response toResponse(DataIntegrityViolationException e) {
        return Response.status(Response.Status.CONFLICT).type("text/plain").entity("Data integrity violation").build();
    }
}
@Component
public class NoResultExceptionMapper implements ExceptionMapper<NoResultException> {

    @Override
    public Response toResponse(NoResultException e) {
        return Response.status(Response.Status.NOT_FOUND).type("text/plain").entity(e.getMessage()).build();
    }
}

You can checkout the sample from GitHub and then build it using Maven, execute the Jar file, and invoke the service using cURL. Here are the steps for running the sample, adding a product & retrieving the product:

  • Run the service:
    java -jar target/msf4j-spring-example-0.0.1-SNAPSHOT.jar
  • Add a product:
    curl -v -X POST -H “Content-Type:application/json” -d ‘{“id”:1,”name”:”soap”}’http://localhost:9090/
  • Get a product: curl -v http://localhost:9090/1

Conclusion

WSO2 MSF4J 2.0 combines the best of both worlds in supporting the development of Java microservices: the Spring framework’s ease of development and WSO2 MSF4J’s lightweight structure and fast performance. Developers interested in exploring the capabilities can access WSO2 MSF4J on Github here and access the documentation here.

Author

Afkham Azeez

Azeez is the Director of Architecture  at WSO2. In this role, he drives efforts focused on the development and enhancement of WSO2 middleware.

Azeez is an elected member of the Apache Software Foundation and also a Project Management Committee member and long-time committer for a number of projects. He specializes in distributed computing, highly available and scalable applications, Java 2 Platform Enterprise Edition (J2EE) technologies, and service oriented architecture. Azeez is the author of the book Clustering Implementation for Apache Axis2, and a co-author of the book, Axis2 Web Services.

He has presented at a number of conferences, including ApacheCon and OSCON, and has conducted technical workshops on SOA and cloud implementation best practices. Azeez holds a first class honors degree in Computer Science and Engineering and a masters degree in Computer Science from the University of Moratuwa, Sri Lanka. He was awarded a gold medal, recognizing him for the highest grade point average for his MSc in Computer Science.

Read Azeez’s blog http://blog.afkham.org or follow Azeez on Twitter http://twitter.com/afkham_azeez.


Comments
comments powered by Disqus