Architecture Overview - Skullabs/kikaha GitHub Wiki
When you are designing a software which requires a good performance is important to understand exactly what may happen and be prepared to any surprise. The follow picture will help you to understand exactly what Kikaha does provide on its stack.
As you can see Kikaha is just a tiny layer around most of functionalities Undertow has. The blue blocks represents modules that developers may, or not, include on its stack when they are developing an application. Most of these modules has its default properties already set, thus developers could enable (or disable) them as easy as including one - or more - modules as dependency on your project.
Every configuration process is started by the Module Loader, provided by the Kikaha Core Module. In fact, all steps needed to start and configure Undertow's internals and deploy HTTP routes are split into a few modules which is loaded by the Module Loader. The following picture will show you an overview of Kikaha's Module Lifecycle.
The first thing is loaded once you start a Kikaha application is the Dependency Injection Context. It is responsible for look into the ClassPath and pre-load all SPI implementations and Singletons. Once CDI is started all configuration files are loaded and made available for the entire application. Then Module Loader takes place and it will ensure any implementation of kikaha.core.modules.Module
interface available on ClassPath will be carefully loaded.
Bellow a basic overview of all modules available out-of-box on Kikaha and you can add it into your project.
A basic configuration layer which developers are allowed to configure their softwares through human readable YML files.
<dependency>
<groupId>io.skullabs.kikaha</groupId>
<version>PUT-KIKAHA-VERSION-HERE</version>
<artifactId>kikaha-config</artifactId>
</dependency>
A very tiny Dependency Injection context. It is quite fast once it was designed to retrieve all information required to the injection process during the source code compilation.
<dependency>
<groupId>io.skullabs.kikaha</groupId>
<version>PUT-KIKAHA-VERSION-HERE</version>
<artifactId>kikaha-injection</artifactId>
</dependency>
<!-- required at compilation time only -->
<dependency>
<groupId>io.skullabs.kikaha</groupId>
<version>PUT-KIKAHA-VERSION-HERE</version>
<artifactId>kikaha-injection-processor</artifactId>
<scope>provided</scope>
</dependency>
Contains the routines that loads all modules, configure all smart routes and start the Undertow server. During this process all CDI elements are read, all Singleton objects and all configuration read from the Classpath are made available to the entire application.
<dependency>
<groupId>io.skullabs.kikaha</groupId>
<version>PUT-KIKAHA-VERSION-HERE</version>
<artifactId>kikaha-core</artifactId>
</dependency>
Automates a few daily routines a developer may has while using Kikaha such as creating a zip package or running the current project. You can see it in action on the Getting Started guide.
<plugin>
<groupId>io.skullabs.kikaha</groupId>
<version>PUT-KIKAHA-VERSION-HERE</version>
<artifactId>kikaha-maven-plugin</artifactId>
</plugin>
Provide a tiny abstraction over ViburDBCP connection pool. It reads all database configuration and provide a ready-to-inject DataSource
object. You can see more about details about this module here.
<dependency>
<groupId>io.skullabs.kikaha</groupId>
<version>PUT-KIKAHA-VERSION-HERE</version>
<artifactId>kikaha-db</artifactId>
</dependency>
Automates the most important routines when dealing with Hazelcast Distributed Structures. Also, is the Kikaha's Session Clustering main implementation. There is a Hazelcast topic covering most of its functionalities here.
<dependency>
<groupId>io.skullabs.kikaha</groupId>
<version>PUT-KIKAHA-VERSION-HERE</version>
<!-- on Kikaha's 2.0.x version you should change the artifactId to kikaha-hazelcast -->
<artifactId>kikaha-cloud-hazelcast</artifactId>
</dependency>
An API heavily inspired on JAX-RS to allow developers map HTTP endpoints through annotations. As happens with CDI routines, it is Reflection-free and provide no overhead at runtime once it converts annotated methods in Undertow routes at compile time.
<dependency>
<groupId>io.skullabs.kikaha</groupId>
<version>PUT-KIKAHA-VERSION-HERE</version>
<artifactId>kikaha-urouting</artifactId>
</dependency>
Adds JSON serialization support to the uRouting API through the Jackson library.
<dependency>
<groupId>io.skullabs.kikaha</groupId>
<version>PUT-KIKAHA-VERSION-HERE</version>
<artifactId>kikaha-jackson</artifactId>
</dependency>
Renders HTML templates using the Mustache Syntax.
<dependency>
<groupId>io.skullabs.kikaha</groupId>
<version>PUT-KIKAHA-VERSION-HERE</version>
<artifactId>kikaha-mustache</artifactId>
</dependency>
An actor-like API to handle and distribute high work loads.
<dependency>
<groupId>io.skullabs.kikaha</groupId>
<version>PUT-KIKAHA-VERSION-HERE</version>
<artifactId>kikaha-uworkers</artifactId>
</dependency>
Kikaha was designed to be small, and thus, it means its dependency tree was carefully chosen. Bellow are the minimal dependencies you need in order to have a Kikaha application running.
- Undertow - The main Kikaha's dependency. Basically, Kikaha was developed to be a tiny layer between the developer and Undertow
- SnakeYAML - Very simple Yaml parser used for configuration propose only.
- SLF4j - The Kikaha's main logger. See Logging Configuration for more details.
- JSR-330 - Dependency Injection for Java 1.0 Final Release.
Undertow is directly responsible for Kikaha's throughput performance. So, to obtain the best performance results from Kikaha we have to understand the Undertow architecture.
Basically, Undertow have three important things:
- IO Threads - responsible to handle incoming requests
- Worker Threads - responsible to handle requests that take too much time
- Connectors - responsible to handle different protocols, like HTTP, HTTPS and AJP.
Once an HTTP(S) request has arrived in the Undertow connector, an IO Thread handles the connection. It will delegate the connection to your HttpHandler
[1] implementation.
The XNIO worker manages both the IO threads, and a thread pool that can be used for blocking tasks. In general non-blocking handlers will run from withing an IO thread, while blocking tasks such as Servlet invocations will be dispatched to the worker thread pool. [2]
1 - More details about Undertow's HttpHandler.
2 - Management of IO and Worker Threads
Kikaha micro Routing API creates a tiny layer between the developer code and Undertow to avoid repetitive boilerplate code. This layer is generated at compilation time, which makes easy to debug your code and find implementation bugs.
There is no magic code here. Basically it:
- extract parameters
- un-serializes incomming request body
- call your route method
- serializes you response back
Every blocking requests is run under a Worker Thread. Keep in mind that the Worker Thread is configurable through server.undertow.worker-threads
parameter at configuration file. The default value is 200.
If you don't plan to use any IO Blocking operation on your route method, we encourage you to use Asynchronous Routing. This will make you request to be handled in the IO Thread. IO Thread is faster, but have limited resources - usually the number of IO Thread is the same of the number of CPU processors available on you server. You can set your own value changing the server.undertow.io-threads
parameter on your configuration file (default is -1
- setting to the number of CPU processors on the server).
Also, you can set custom Undertow and XNIO (the IO backend used by Undertow) parameters to improve the application performance. All Undertow options can be set at server.undertow.server-options
. XNIO options can be set at server.undertow.socket-options
. All available options are better described here, at the Undertow documentation.
Bellow is a configuration file that configures Kikaha to behave exactly as Undertow was configured to the Techempower Performance Benchmark.
server:
undertow:
io-threads: -1
worker-threads: 200
buffer-size: 16384 # 1024*16
socket-options:
BACKLOG: 10000
server-options:
ALWAYS_SET_KEEP_ALIVE: false
ALWAYS_SET_DATE: true
ENABLE_CONNECTOR_STATISTICS: false
RECORD_REQUEST_START_TIME: false