NGINX.COM
Web Server Load Balancing with NGINX Plus

On December 28 of last year, we released the third beta version of NGINX Unit, our new dynamic web and application server. In this blog post, we discuss the latest changes in detail.

If you installed Unit 0.2 from our package repositories, use your package manager to upgrade. If you are performing a fresh installation, see the installation documentation at https://unit.nginx.org/installation/. (We now provide prebuilt packages for more operating systems.)

NGINX Unit is under active development. It’s likely that at the time you read this blog post, even more recent releases will be available. Check https://unit.nginx.org/CHANGES.txt for details on the latest release.

HTTP Keep-Alive

HTTP persistent connections, or HTTP keepalives, is the technology used to keep TCP connections open between requests. This reduces latency and improves website. NGINX Unit now uses keepalive connections by default (no configuration is necessary on the Unit side).

Keepalive functionality is managed by the HTTP headers Connection and Keep-Alive. Unit sets the keepalive timeout to 65 seconds. The value will become configurable in a future release.

When Unit is installed behind NGINX, to use HTTP keepalives you need to configure NGINX as shown below. Specifically, you need to:

  • Add the keepalive directive in the upstream block
  • Set proxy_http_version to 1.1 so that HTTP/1.1 is used for proxying requests to the upstream servers, as required for keepalives
  • Remove any Connection headers that might be included in client requests

See the following short example of NGINX configuration with these directives in use.

http {
    upstream unit {
        server 127.0.0.1:8080;
        keepalive 32;
    }

    server {
        location / {
            proxy_pass http://unit;
            proxy_set_header Connection '';
            proxy_http_version 1.1;
        }
    }
}

Python Virtual Environments

With Python, you can create isolated virtual environments for your applications. This feature is useful for creating multiple apps that use different versions of Python, different packages, and/or different libraries, and that need to run simultaneously on the same system. Running a virtual environment also, in many cases, eliminates the need for developers to have root access to the system. With Unit 0.3, you can use virtual environments across multiple Python applications.

You can use the virtualenv tool to create a virtual environment. Once you create a virtual environment, you can define it with the Unit API, using the home parameter of your application. If you did not configure PYTHONPATH inside your virtual environment, you still need to set up the path and home parameters in the configuration of your application through the Unit API. They might refer to the same, or to different directories.

Here’s a sample Unit configuration:

{
    "listeners": {
        "*:8080": {
            "application": "example-myblog"
        }
    },

    "applications": {
        "example-myblog": {
                "type": "python 3",
                "workers": 2,
                "module": "wsgi",
                "user": "nick",
                "group": "nick",
                "path": "/home/nick/myblog-virtualenv/scripts",
                "home": "/home/nick/myblog-virtualenv"
        }
    }
}

This example shows how to configure the following environment:

  • Unit listens on port 8080 for all IP addresses of the system
  • The example-myblog application is created by the Unit administrator
  • A virtual environment is created by user nick in the directory /home/nick/myblog-virtualenv
  • Python scripts are located in /home/nick/myblog-virtualenv/scripts

Alternatively, you can set both path and home relative to the value of working_directory:

...
"working_directory": "/home/nick/myblog-virtualenv",
"path": "scripts",
"home": ".",
...

To change an existing application object to use virtual environments, use the Unit API to change one parameter directly. You don’t have to reload or restart the server. The current state of Unit is preserved automatically. Here’s an example:

$ curl -X PUT -d '"/home/nick/myblog-virtualenv"' --unix-socket /path/to/control.unit.sock http://localhost/applications/example-myblog/home

To display the current value of the home parameter, send a GET request to the API:

$ curl -X GET --unix-socket /path/to/control.unit.sock http://localhost/applications/example-myblog/home

Python atexit

The atexit module in Python defines a single function to register clean‑up functions. The functions run when an application process performs a normal shutdown. Unit now supports atexit behavior. You don’t have to change anything in the application or in Unit configuration in order to use atexit. See https://github.com/nginx/unit/issues/65 and https://github.com/nginx/unit/commit/be36cf52c8b092ebb688784a1c10626cac2138d7 for implementation details.

Go Package Changes

The Go package name for Unit has changed from unit to nginx/unit. This name is more consistent with other packages in the Go ecosystem. Prior to compiling your Go app for Unit, compile and install the package. For supported systems, you can install the unit-go package from our repositories. Then, in the source of the Go app, import the nginx/unit package, together with the net/http package:

import (
    "fmt"
    "net/http"
    "nginx/unit"
)

Application Timeouts

Unit can now respond with an HTTP error to the client when workers exceed their execution timeout. With version 0.3, the application start time and time in the queue are no longer included in the timeout calculation.

To enable timeouts for workers, use the API to change the limits.timeout property of the application.

$ curl -X PUT -d '{"timeout": 10}' --unix-socket http://localhost:8088/applications/example-myblog/limits

The timeout value is defined in seconds.

A full application object example with the timeout value defined looks like the following.

{
    "type": "python 3",
    "workers": 2,
    "module": "wsgi",
    "user": "nick",
    "group": "nick",
    "path": "/home/nick/myblog-virtualenv/scripts",
    "home": "/home/nick/myblog-virtualenv",
    "limits": {
        "timeout": 10
    }
}

Timeouts can be enabled for all supported application languages: PHP, Python, and Go.

In larger deployments, various URLs, scripts, or workflows might need different timeout restrictions. In that case, define the different paths as different locations in the NGINX reverse proxy, then create several different applications in Unit. You can have different applications use the same directories and application files, or various directories and application files.

Number of Requests per Worker

Unit can now limit the number of requests executed in one worker process of the application. When the number is exceeded, it will restart the worker. This feature is particularly useful when applications tend to leak memory, or otherwise misbehave after too many requests.

To enable this, use the API to change the limits.requests property of the application.

$ curl -X PUT -d '{"requests": 1000}' --unix-socket http://localhost:8088/applications/example-myblog/limits

A full application object example, with the number of requests per worker enabled, looks like the following.

{
    "type": "python 3",
    "workers": 2,
    "module": "wsgi",
    "user": "nick",
    "group": "nick",
    "path": "/home/nick/myblog-virtualenv/scripts",
    "home": "/home/nick/myblog-virtualenv",
    "limits": {
        "timeout": 10,
        "requests": 1000
    }
}

This limit can be enabled for all supported application languages: PHP, Python, and Go.

Miscellaneous

In addition to the features described above, we added a number of smaller bug fixes and minor changes. These include:

  • Precompiled packages for more operating systems in our repositories:
    • CentOS 6
    • CentOS 7
    • Debian 8 (Jessie)
    • Debian 9 (Stretch)
    • Ubuntu 16.04
    • Ubuntu 17.04
    • Ubuntu 17.10
  • Various Go package improvements that simplify the code and increase performance through better integration between Unit’s C code and the Go code.
  • The Unit version is now verified in the Go package to avoid incompatible package usage.
  • Improved application worker selection, request canceling, and request rescheduling. A new algorithm minimizes request‑processing latency.
  • Addition of a new testing framework. With this release, Unit has a number of functionality tests that we run regularly. See them in the test directory in the repositories. We will be regularly adding more tests to improve test coverage in future.

If you want to see where the project is going and read the roadmap, take a look at the Progress and Next Steps blog post.

The full changelog for Unit development is available in the source code repositories https://hg.nginx.org/unit/file/tip/CHANGES, https://github.com/nginx/unit/blob/master/CHANGES, and the Unit documentation website: https://unit.nginx.org/CHANGES.txt.

Watch our code repository on GitHub and join the discussions and development: https://github.com/nginx/unit.

If you wish to become a full‑time engineer for NGINX, check our job board.

Hero image

Learn how to deploy, configure, manage, secure, and monitor your Kubernetes Ingress controller with NGINX to deliver apps and APIs on-premises and in the cloud.



About The Author

Nick Shadrin

Software Architect

About F5 NGINX

F5, Inc. is the company behind NGINX, the popular open source project. We offer a suite of technologies for developing and delivering modern applications. Together with F5, our combined solution bridges the gap between NetOps and DevOps, with multi-cloud application services that span from code to customer.

Learn more at nginx.com or join the conversation by following @nginx on Twitter.