Zudoku
Features

Scale-to-Zero

With conventional cloud platforms you need to keep at least one instance running always to be able to respond to incoming requests. Performing a just-in-time cold boot is too time-consuming and would create a response latency of many seconds or worse. This isn't the case with Unikraft Cloud. Unikraft Cloud is lightweight and based on Unikraft technology. Instances on Unikraft Cloud can cold boot within milliseconds, while providing the same strong, hardware-level isolation afforded by virtual machines.

Millisecond cold boots allow performing low-latency scale-to-zero. As long as no traffic is flowing through your instance, it consumes no resources. When the next connection arrives, Unikraft Cloud takes care of transparently cold booting (is it cold booting if it's milliseconds?) your instance and replying. All within a negligible amount of time compared to Internet round-trip times, and so unbeknownst to your end users.

By default, Unikraft Cloud reduces network and cloud stack cold start time to a minimum. Some apps take a while to initialize (for example, Spring Boot, Puppeteer, etc). If you need to deploy such an app and still want millisecond cold starts, Unikraft Cloud offers a stateful feature.

If you add instances to a service, the service will load balance traffic across them and Unikraft Cloud will wake up each instance as needed. This differs from autoscale, in which you don't specify the number of instances. The platform does this for you based on traffic load.

Policies

With the scale-to-zero policy you define under which circumstances Unikraft Cloud should put your instance into standby.

Unikraft Cloud currently supports the following scale-to-zero policies:

PolicyDescription
offDisables scale-to-zero. The instance keeps on running until manually stopped.
onEnables scale-to-zero. When there are no TCP connections or HTTP requests during the cooldown time, the instance goes into standby.
idleSame as on, but also puts the instance into standby when there are TCP connections established that have been inactive during the cooldown time. The connections remain established and incoming packets wake up the instance. Scale-to-zero doesn't happen while there are active HTTP requests (that is, traffic on ports which use the http handler).

Unikraft Cloud supports scale-to-zero for traffic going through the proxy, as well as internal traffic via Private FQDNs.

Application support for scale-to-zero

Most apps can use scale-to-zero without any special support. Cases exist where making your app aware of scale-to-zero makes sense.

  • Background Jobs: For example, you want to run background jobs after your app has responded to a request (for example, send trace information to a logging server). In this case, you may want to temporarily disable scale-to-zero to ensure your instance isn't put to sleep while still performing work.

  • Long Request Processing: The same is true if your app can have long request processing times. Consider a setup where you use the idle policy with plain TCP connections and configure a cooldown time of 10s. Sometimes if it takes your app 15s to process a request until the first response data gets sent, Unikraft Cloud will prematurely scale your instance to zero1.

Configuring a longer cooldown time can be a simple solution sometimes. But this isn't possible if the max duration of background jobs or request processing phases is unknown. It also means that you have to compromise between cost efficiency and reliability of your service.

Unikraft Cloud allows your app to temporarily disable scale-to-zero. You can have both a short cooldown phase and reliable operation no matter how long things may take. To control scale-to-zero from within your app, instances on Unikraft Cloud provide a special file-based interface:

PathDescription
/uk/libukp/scale_to_zero_disableAllows to temporarily disable scale-to-zero.

The scale_to_zero_disable pseudo file keeps track of the count of concurrent disable requests. If the count reaches 0, scale-to-zero remains active2. Any number larger than 0 means scale-to-zero is temporarily inactive. Using a count instead of a boolean value is helpful when you have many independent workers. Your app workers can disable scale-to-zero individually by incrementing and decrementing the count without having to synchronize.

Reading the file returns the current count. The system prefixes the value with an equals sign (that is, =X with X being the current count). Writing to the file modifies the count. You can use the following strings:

StringDescription
+Increment the current count by one.
-Decrement the current count by one.
=XSet the count to X.
+XIncrement the current count by X.
-XDecrement the current count by X.

Any attempt to write an invalid string to the file returns an EINVAL error. Any attempt to set a count less than 0 or larger than 2^64 returns an ERANGE error.

Writing to the file to disable scale-to-zero doesn't atomically disable scale-to-zero. There can be a short delay (a few milliseconds) until the Unikraft Cloud controller receives the changed value and makes scale-to-zero decisions accordingly. Ensure you configure a cooldown time large enough to accommodate for potential signal delay.

Notification signal

Before the platform suspends an instance, it can send a notification signal to the guest, giving it time to finish in-flight work before suspension begins.

The platform delivers the notification over vsock on port 138. It sends the literal string scaletozero to the guest at the configured lead time before suspension.

Your app can listen on vsock port 138 and use the signal to:

  • Drain in-flight requests
  • Flush write buffers
  • Update any external state

Configuring the notification lead time

When creating or updating an instance, you can specify the number of milliseconds before the scaletozero event when the platform should send the notification signal:

unikraft run --metro fra \ -p 443:8080/http+tls \ --scale-to-zero policy=on,cooldown-time=2000,notify-time=1000 \ ...

This sends the notification 1 second before the cooldown expires and suspension begins.

notify_time_ms must be less than cooldown_time_ms. If notify_time_ms is 0 (the default), the platform skips the notification and suspends the instance immediately when the cooldown expires, without informing the guest.

Stateful scale-to-zero

Some apps have a long cold boot phase or experience large first response latency. For example, to run just-in-time compilation and fill caches. Using stateful scale-to-zero can dramatically reduce the response time of your service. With stateful scale-to-zero Unikraft Cloud takes a snapshot of the instance state before putting it into standby. When incoming network traffic triggers a wake-up, Unikraft Cloud loads the snapshot in milliseconds. The instance resumes execution where it left off—with caches already warm.

Stateful scale-to-zero can also enable scale-to-zero for apps that need to keep state for functional correctness. This works even if cold boot times are no concern. If your app doesn't require maintaining state and has a satisfactorily short boot time, you might prefer to disable stateful scale-to-zero to save disk space.

The time to load an instance snapshot is constant and in the order of a few milliseconds. This is what the boot time metrics report. The system loads the actual memory contents from the snapshot only at first access. This reduces response latency by loading only what's necessary to process the request. This means that the first few requests might take longer until all required memory comes back.

The time to take an instance snapshot during scale-to-zero depends on the amount of memory touched by the app since the last start.

Best practices

Cooldown configuration

Choosing the optimal cooldown period depends on your app's start-up time and traffic patterns. The default cooldown is 1 second, which works well for simple apps. For larger apps with longer boot times, start with a conservative cooldown (for example, 5-10 seconds) and gradually lower it while monitoring behavior.

If your app takes a long time to initialize, you might encounter issues where it scales down before serving the first request if the cooldown is too short. Strategies to mitigate this include:

  1. Stateful Scale-to-Zero: Enabling stateful mode saves memory to disk, reducing wake-up time for complex apps.
  2. Startup Protection: Use the manual disable mechanism to temporarily turn off scale-to-zero during your app's boot sequence, then re-enable it once ready to serve.

Continuous connections

Apps using long-lived connections with frequent keep-alive messages (for example, WebSockets, HTTP/2, HMR) may prevent the instance from scaling to zero. To allow the instance to sleep:

  • Increase the interval between keep-alive messages.
  • Use a more aggressive cooldown period if appropriate.
  • If requiring continuous connectivity, consider disabling scale-to-zero for these workloads.

Example

You can enable millisecond scale-to-zero with the --scale-to-zero flag in relevant CLI subcommands.

TerminalCode
git clone https://github.com/unikraft-cloud/examples cd examples/nginx/ unikraft build . --output <my-org>/nginx:latest unikraft run --metro fra \ -m 256M \ -p 443:8080/http+tls \ --scale-to-zero policy=on,cooldown-time=1000 \ --image <my-org>/nginx:latest

This command will create the NGINX instance with scale-to-zero enabled, with a cooldown time of 1 second:

TerminalCode
metro: fra name: nginx-67zbu uuid: 8a8bc1b9-0af6-420e-a426-190dc2da9eaa state: starting image: <my-org>/nginx resources: memory: 256MiB vcpus: 1 service: uuid: a942b9b5-ad17-3ffe-dcd2-ef4331f9087a name: nameless-fog-0tvh1uov domains: - fqdn: nameless-fog-0tvh1uov.fra.unikraft.app networks: - uuid: 62d9bbf0-aec8-61f6-7bdb-86edf63dd068 private-ip: 10.0.3.3 mac: 12:b0:c6:23:ed:15 timestamps: created: just now scale-to-zero: enabled: true policy: on cooldown-time: 1s

Note that at first the system starts the instance as usual. Check the instance's status:

TerminalCode
unikraft instances list

You should see output like:

TerminalCode
METRO NAME STATE IMAGE ARGS MEMORY VCPUS FQDN CREATED fra nginx-67zbu standby <my-org>/nginx 256MiB 1 nameless-fog-0tvh1uov.fra.unikraft.app 2 minutes ago

Notice the state is now set to standby? At first, unikraft run sets the state to running. Unikraft Cloud then puts the instance to sleep (it stops it, but keeps state to start it again when needed).

You can also check that scale-to-zero gets enabled by grabbing the instance details

TerminalCode
unikraft instance get nginx-67zbu

which outputs:

TerminalCode
metro: fra name: nginx-67zbu uuid: 8a8bc1b9-0af6-420e-a426-190dc2da9eaa state: standby image: <my-org>/nginx resources: memory: 256MiB vcpus: 1 service: uuid: a942b9b5-ad17-3ffe-dcd2-ef4331f9087a name: nameless-fog-0tvh1uov domains: - fqdn: nameless-fog-0tvh1uov.fra.unikraft.app networks: - uuid: 62d9bbf0-aec8-61f6-7bdb-86edf63dd068 private-ip: 10.0.3.3 mac: 12:b0:c6:23:ed:15 timestamps: created: just now scale-to-zero: enabled: true policy: on cooldown-time: 1s stop: reason: platform stop exit-code: 0

Try using curl or your browser to see scale-to-zero (well, scale-to-one in this case!) in action:

TerminalCode
curl https://nameless-fog-0tvh1uov.fra.unikraft.app

You should get an NGINX response with no noticeable delay. For fun, try to use the following command to see if you can catch the instance's STATE field changing from standby to running:

TerminalCode
unikraft instances list --watch=0.5s

If you curl enough, you should see the STATE turn to a green running from time to time.

You can use scale-to-zero in conjunction with autoscale. This ensures that as you scale back down, if traffic dies, your last instance gets removed. You're not charged for the service in this state.

Learn more

Footnotes

  1. This is never the case for ports of your service that have the http handler set. ↩

  2. If it's actually enabled, depends on the instance configuration. ↩

Last modified on