Skip to content

Silgy ASYNC

Jurek Muszyński edited this page Aug 2, 2019 · 25 revisions

Overview

Silgy is – like Node.js – an asynchronous, single threaded machine. This is the fastest web server design that exists today. For the simple application that doesn't use any external resources, it's perfectly fine. Each request should take no more than 10–100 µs. But when we wanted to call a remote service, like i.e. Facebook API, we should expect the call to take seconds rather than microseconds. And this would be far too long to block the main server thread, because each client would need to wait until the external call returns:

To solve this, we need some kind of parallel processing. It can either be multithreading or multiprocessing. Silgy uses multiprocessing. Communication between processess is realized via standard POSIX message queues. Apart from convenient data exchange, message queues provide natural load balancing: the first silgy_svc process that is able to receive the message, atomically removes it from the queue. CALL_ASYNC macros prepare the request, call mq_send and return without blocking of the main thread. The remaining part of the application logic will be executed by silgy_svc. After calling CALL_ASYNC, silgy_app process continues serving incoming requests and with every loop pass will check the response message queue whether silgy_svc call has returned. When it has, it will write the response back to the client:

silgy_app can then serve as a gateway or just handle those request that won't take too long. The exact treshold will depend on the required latency and the traffic, however we mostly look at the range of 1–10 ms.

Data exchange

POSIX message queues use fixed size messages. The default value for both the request and the response is 8 kB. Each request consists of the header and the data part. The sizes are reported in the beginning of the log file:

    ASYNC_REQ_MSG_SIZE = 8192 B
    ASYNC req.hdr size = 5320 B (5 kB / 0.01 MB)
 G_async_req_data_size = 2872 B (2 kB / 0.00 MB)
    ASYNC req     size = 8192 B (8 kB / 0.01 MB)

    ASYNC_RES_MSG_SIZE = 8192 B
    ASYNC res.hdr size = 4480 B (4 kB / 0.00 MB)
 G_async_res_data_size = 3712 B (3 kB / 0.00 MB)
    ASYNC res     size = 8192 B (8 kB / 0.01 MB)

The message sizes can be increased in silgy_app.h with ASYNC_REQ_MSG_SIZE and ASYNC_RES_MSG_SIZE.

Note that on some systems 8 kB may be the default maximum for an unprivileged user, so modifying msgsize_max may be required, i.e.:

echo 16384 > /proc/sys/fs/mqueue/msgsize_max

And to change this value permanently:

sudo vi /etc/sysctl.conf

Add a new line:

/proc/sys/fs/mqueue/msgsize_max = 16384

Request

The data part is used to transfer the payload. If the payload fits the message, payload_location field of the request header will be set to ASYNC_PAYLOAD_MSG. If it's too large, the payload will be written to a shared memory segment, available for silgy_svc process to read. payload_location will then be set to ASYNC_PAYLOAD_SHM. The shared memory segment will only be created at the first time it's needed, and only once and reused. It's size will be of MAX_PAYLOAD_SIZE bytes.

Response

The data part of the response message is used to transfer the content generated by the application logic (using OUT macros). If the content requires more space than a single data part can contain, silgy_svc will continue sending response messages and will flag the last one with the response header field chunk ASYNC_CHUNK_LAST bit set.

Setting up

To enable ASYNC:

  1. Add ASYNC to silgy_app.h.

  2. Increase SILGY_SVC_PROCESSES in silgystart. For the test purposes 1 will be enough. For production it will depend on the usage profile and the expected load. For typical usage it can be equal to average number of user sessions active at the same time. Keep in mind that every process will have its own log file.

Debugging

Every CALL_ASYNC is assigned its unique call_id. It is always passed to the service process. You can grep or search logs for the call_id. If logLevel is 4, the request starts with the similar line in silgy_app log:

Sending a message on behalf of ci=1, call_id=123, service [get_inpost]

Troubleshooting

error: size of array ‘data’ is too large or
error: size of array 'data' is negative

This happens when ausession_t structure is larger than the remaining space in async_req_t. There are two options:

You want to share auses with silgy_svc

Increase ASYNC_REQ_MSG_SIZE and ASYNC_RES_MSG_SIZE.

You don't want to share auses

Add ASYNC_EXCLUDE_AUSES switch to silgy_app.h.

Clone this wiki locally