Skip to main content

Upstream

Upstreams are the backends that routes and services send traffic to.

In the console UpstreamsEngine resource upstream

What an upstream is​

An upstream is a set of backend instances, its nodes, kept once under a name. Every route or service that chooses it under Target sends its requests to these nodes, spread over them by Type.

With an Active health check, the gateway probes every node and takes one that fails its probes out of rotation until it passes them again. Without one, every node stays in rotation whatever its state, and a request a stopped node refuses is tried on another node.

How the health check decides​

With Active health check on, the gateway sends a request to Path on every node:

  • A node in rotation is probed every Healthy › Interval seconds, a node taken out every Unhealthy › Interval seconds.
  • A probe answered with one of Healthy › HTTP statuses counts as a success. Unless you change them, those are 200 and 302.
  • A probe answered with one of Unhealthy › HTTP statuses counts as a failure. 404, 500 and 503 are among them.
  • The node is taken out of rotation after a run of failed probes as long as HTTP failures. A run of probes that cannot connect, as to a stopped instance, counts under TCP failures, and a run left unanswered under Timeouts.
  • A run of successes as long as Successes brings it back into rotation.

While another node is in rotation, a node taken out receives no requests.

When to use it​

  • Several routes send to the same backend instances, and you want to list them, and change them, in one place.
  • An instance is restarted now and then, and requests should stop going to it until it answers again.
  • A backend expects its own host name rather than the one clients call.
  • Requests of one session have to keep reaching the same instance, or the instances are found through DNS rather than listed.

Guides​

Pages that walk through a job with a upstream, step by step.

Set it up​

Take a backend node out of rotation while it fails its probe, and back once it answers​

Each backend node must answer GET /health with 200 while it is well. Both intervals are set on purpose: the probes of healthy nodes run every Healthy interval, those of a node taken out every Unhealthy interval.

Under General set Name to orders. Under Targets choose Nodes and fill Nodes as in the JSON below. Under Balancing leave Type at roundrobin. Under Health checks fill Health checks as in the JSON below.

The Health checks section of the console's New upstream form, filled with this example.
upstream · as the console saves it
{
"name": "orders",
"type": "roundrobin",
"nodes": {
"10.0.1.10:8080": 1,
"10.0.1.11:8080": 1
},
"checks": {
"active": {
"http_path": "/health",
"healthy": {
"interval": 1,
"successes": 2
},
"unhealthy": {
"interval": 1,
"http_failures": 2
}
}
}
}

What you will see​

  • While both backend nodes pass their probes, repeated requests are shared by the two, each answered 200.
  • Each backend node receives GET /health from the gateway: the probe that decides whether it stays in rotation.
  • Once the second backend node has failed its probe twice in a row, every request is answered 200 by the first: the second is out of rotation.
  • Once the second backend node answers GET /health with 200 again, it is back in rotation and the two share the requests again.

More scenarios​

Present the host name a backend expects

With verification on, the certificate of the node must be valid for orders.example.com, the name the request now carries.

Under General set Name to orders-public. Under Targets choose Nodes and fill Nodes as in the JSON below. Under Balancing leave Type at roundrobin, set Scheme to https, set Host passing to rewrite and set Upstream host to orders.example.com. Under TLS fill TLS as in the JSON below.

upstream · as the console saves it
{
"name": "orders-public",
"type": "roundrobin",
"scheme": "https",
"nodes": {
"10.0.1.20:443": 1
},
"pass_host": "rewrite",
"upstream_host": "orders.example.com",
"tls": {
"verify": true
}
}

What you will see​

  • The backend receives the request with the host name orders.example.com and answers 200.
  • A route that sets a Host of its own with proxy-rewrite does not change it: the backend still receives orders.example.com.
Keep each session on the same instance

Requests that carry the same session_id cookie reach the same instance; one without the cookie is placed by its client address instead, so that client, and every client behind the same address, always reaches the same instance.

Under General set Name to checkout. Under Targets choose Nodes and fill Nodes as in the JSON below. Under Balancing set Type to chash, set Hash on to cookie and set Key to session_id.

upstream · as the console saves it
{
"name": "checkout",
"type": "chash",
"hash_on": "cookie",
"key": "session_id",
"nodes": {
"10.0.1.10:8080": 1,
"10.0.1.11:8080": 1
}
}
Ramp an instance added later up before it takes its full share

An instance added to the list later starts at 10 percent of its weight of 100 and reaches the whole of it over 60 seconds; the instances present when the upstream is created take their full share from the start.

Under General set Name to orders-warmed. Under Targets choose Nodes and fill Nodes as in the JSON below. Under Balancing leave Type at roundrobin and fill Slow start as in the JSON below.

upstream · as the console saves it
{
"name": "orders-warmed",
"type": "roundrobin",
"nodes": {
"10.0.1.10:8080": 100,
"10.0.1.11:8080": 100
},
"warm_up_conf": {
"slow_start_time_seconds": 60,
"min_weight_percent": 10,
"interval": 5
}
}
Balance the orders service over two instances

Under General set Name to orders and set Description to Both instances take an equal share. Under Targets choose Nodes and fill Nodes as in the JSON below. Under Balancing leave Type at roundrobin.

upstream · as the console saves it
{
"name": "orders",
"desc": "Both instances take an equal share",
"type": "roundrobin",
"nodes": {
"10.0.1.10:8080": 1,
"10.0.1.11:8080": 1
}
}

What you will see​

  • Repeated requests are all answered 200, some by the first instance and some by the second: the two share the traffic.
Find the instances of the orders service through DNS

DNS discovery must be enabled in the gateway's static configuration first; without it every request is refused with 503.

Under General set Name to orders-discovered. Under Targets choose Service discovery, set Discovery type to dns and set Service name to orders.internal.example.com:8080. Under Balancing leave Type at roundrobin.

upstream · as the console saves it
{
"name": "orders-discovered",
"type": "roundrobin",
"discovery_type": "dns",
"service_name": "orders.internal.example.com:8080"
}

Things to know​

  • Slow start — Read only on a roundrobin upstream whose nodes share one priority; nodes of different priorities are refused at save.
  • Refresh interval — Not above the ramp-up time: the engine refuses a larger interval at save.
  • Trusted CA certificates — Not read beside a ws or wss scheme: the engine refuses the list at save when either is set.
  • The engine assigns the id when the object is created; it is not the name, and it is what other objects refer to.
  • Path — Point it at an address every instance answers with 200 while it is well. A probe answered with 404, as many APIs answer at the default /, counts as a failure. An instance that fails as many probes in a row as HTTP failures says is taken out of rotation as if it had stopped.
  • AdviceGive the service a health address of its own, for example /health, that answers fast and answers 200 only while the instance can really serve requests.
  • Retries — Left empty, a request an instance refuses is tried on the other node, a GET and a POST alike: while one of two instances is stopped, clients are still answered by the other.
  • Host passing — At rewrite every instance receives the name under Upstream host, also from a route that sets another Host with proxy-rewrite.
  • Host passing — At pass, the default, a route that sets a Host with proxy-rewrite sends that Host to the instances.

Settings​

The fields as the console shows them, section by section. A field under “When … is …” is there only while that value is set.

General​

NamenamestringRequired
1 to 256 characters
Descriptiondescstring
up to 256 characters
Labelslabelsobject

Key and value pairs of your own, for grouping and filtering. They change nothing about traffic. An object whose keys are any name, each with a string as its value.

Targets​

Where the traffic goes. Weight 0 keeps a node in the list without sending it traffic; a lower priority value is used only when every higher one is down.

Choose one:

  • NodesA fixed list of hosts, ports and weights.
  • Service discoveryThe engine resolves the nodes from a registry at run time.

Nodes​

Nodesnodesobject or array of objectsRequired

Also stored as a map from host:port to the weight.

Hostnodes[].hoststringRequired
a host name, with an optional leading wildcard, or * alone
pattern^\*$|^\*?[0-9a-zA-Z-._\[\]:]+$
Weightnodes[].weightintegerRequired
at least 0
Metadatanodes[].metadataobject

Free JSON kept beside the node. The engine compares nodes by it when a list is refreshed.

Portnodes[].portinteger
1 to 65535
Prioritynodes[].priorityintegerdefault 0

Service discovery​

Discovery argumentsdiscovery_argsobject
Group namediscovery_args.group_namestring
Namespace IDdiscovery_args.namespace_idstring
Discovery typediscovery_typestringRequired

The discovery driver must be enabled in the engine's configuration (dns, consul, nacos, eureka, kubernetes…).

Service nameservice_namestringRequired
1 to 256 characters

Balancing​

Typetypestringdefault roundrobin

How requests are spread over the nodes; a hash type groups them by the key below.

one of chash, ewma, least_conn, roundrobin

When Type is chash​

Hash onhash_onstringdefault vars

What Key names. vars: a variable such as remote_addr. header or cookie: its name. vars_combinations: variables joined, like $host$uri. consumer: Key is unused; the consumer name is hashed.

one of consumer, cookie, header, vars, vars_combinations
KeykeystringRequired when Hash on is not consumer

What the consistent hash groups requests by, such as remote_addr, a header or a cookie. A request that carries no value for Key is placed by its client address instead, with no error: such a client, and every client behind the same address, always reaches the same node.

When Type is roundrobin· 6 fields
Slow startwarm_up_confobject

Ramps a node that just appeared up to its full weight instead of handing it its whole share at once.

Starting weightwarm_up_conf.min_weight_percentintegerRequired

The share of its weight, in percent, a new node begins with.

1 to 100
Ramp-up timewarm_up_conf.slow_start_time_secondsintegerRequired

How long a new node takes to reach its full weight.

at least 1 · in seconds
Ramp shapewarm_up_conf.aggressionnumberdefault 1

Linear at the default; a higher value front-loads the increase, a lower one holds it back.

at least 0.01
Refresh intervalwarm_up_conf.intervalintegerdefault 1

How often the effective weight is recomputed during the ramp.

at least 1 · in seconds
Startup grace periodwarm_up_conf.startup_grace_period_secondsintegerdefault 0

For this long after the data plane starts, a node seen for the first time counts as mature and skips the ramp.

at least 0 · in seconds
Schemeschemestringdefault http

How the engine speaks to the nodes: plain or TLS HTTP, gRPC, WebSocket, a raw TCP, TLS or UDP stream, or Kafka through the built-in pub/sub bridge.

one of grpc, grpcs, http, https, kafka, tcp, tls, udp, ws, wss
Host passingpass_hoststringdefault pass

The Host header the node receives: the request's own, the node's address, or a value written here.

one of node, pass, rewrite

When Host passing is rewrite​

Upstream hostupstream_hoststringRequired

Host header sent to the nodes when host passing is rewrite.

a host name, with an optional leading wildcard, or * alone
pattern^\*$|^\*?[0-9a-zA-Z-._\[\]:]+$
Retriesretriesinteger

Attempts on another node after a failure. Left empty, each other node is tried once.

at least 0
Retry timeoutretry_timeoutnumber

How long the retries of one request may take in total. 0 means no limit.

at least 0 · in seconds

Health checks​

Health checkschecksobject
Active health checkchecks.activeobjectRequired

The engine probes every node on its own schedule. Without it, every node stays in rotation regardless of its state.

Concurrencychecks.active.concurrencyintegerdefault 10

How many nodes are probed at the same time.

Healthychecks.active.healthyobject
HTTP statuseschecks.active.healthy.http_statusesarray of integersdefault [200,302]

A probe answered with one of these statuses counts as a success.

at least 1 item; each 200 to 599
Intervalchecks.active.healthy.intervalintegerdefault 1

How often a node counted as healthy is probed.

at least 1 · in seconds
Successeschecks.active.healthy.successesintegerdefault 2

Successful probes in a row before an unhealthy node is taken back into rotation.

1 to 254
Hostchecks.active.hoststring

Host header of the probe. Empty uses the node.

a host name, with an optional leading wildcard, or * alone
pattern^\*$|^\*?[0-9a-zA-Z-._\[\]:]+$
HTTP methodchecks.active.http_methodstringdefault GET

The method the probe request is sent with.

one of CONNECT, DELETE, GET, HEAD, OPTIONS, PATCH, POST, PURGE, PUT, TRACE
Pathchecks.active.http_pathstringdefault /

The path the probe requests on every node.

Request bodychecks.active.http_req_bodystringdefault
Verify the certificatechecks.active.https_verify_certificatebooleandefault true

Applies to HTTPS probes: the probe checks the node's certificate against the trusted CAs.

Portchecks.active.portinteger

Empty uses the node port.

1 to 65535
Request headerschecks.active.req_headersarray of strings
at least 1 item
Timeoutchecks.active.timeoutnumberdefault 1

How long a probe waits for the node to answer before it counts as a timeout.

in seconds
Typechecks.active.typestringdefault http

What a probe is: an HTTP or HTTPS request to the path below, or only a TCP connection.

one of http, https, tcp
Unhealthychecks.active.unhealthyobject
HTTP failureschecks.active.unhealthy.http_failuresintegerdefault 5

Probes in a row answered with an unhealthy status before the node is taken out of rotation.

1 to 254
HTTP statuseschecks.active.unhealthy.http_statusesarray of integersdefault [429,404,500,501,502,503,504,505]

A probe answered with one of these statuses counts as an HTTP failure.

at least 1 item; each 200 to 599
Intervalchecks.active.unhealthy.intervalintegerdefault 1

How often a node counted as unhealthy is probed.

at least 1 · in seconds
TCP failureschecks.active.unhealthy.tcp_failuresintegerdefault 2

Probes in a row that cannot connect before the node is taken out of rotation.

1 to 254
Timeoutschecks.active.unhealthy.timeoutsintegerdefault 3

Probes in a row left unanswered in time before the node is taken out of rotation.

1 to 254
Passive health checkchecks.passiveobject

Marks nodes from real traffic. The engine allows it only together with the active check.

Healthychecks.passive.healthyobject
HTTP statuseschecks.passive.healthy.http_statusesarray of integersdefault [200,201,202,203,204,205,206,207,208,226,300,301,302,303,304,305,306,307,308]

An answer to live traffic with one of these statuses counts as a success.

at least 1 item; each 200 to 599
Successeschecks.passive.healthy.successesintegerdefault 5

Answers in a row with a healthy status before an unhealthy node is taken back into rotation.

0 to 254
Typechecks.passive.typestringdefault http

What live traffic is judged by: the HTTP answers the node gives, or only whether the TCP connection succeeds.

one of http, https, tcp
Unhealthychecks.passive.unhealthyobject
HTTP failureschecks.passive.unhealthy.http_failuresintegerdefault 5

Answers in a row to live traffic with an unhealthy status before the node is taken out of rotation.

0 to 254
HTTP statuseschecks.passive.unhealthy.http_statusesarray of integersdefault [429,500,503]

An answer to live traffic with one of these statuses counts as an HTTP failure.

at least 1 item; each 200 to 599
TCP failureschecks.passive.unhealthy.tcp_failuresintegerdefault 2

Requests in a row that cannot connect before the node is taken out of rotation.

0 to 254
Timeoutschecks.passive.unhealthy.timeoutsintegerdefault 7

Requests in a row left unanswered in time before the node is taken out of rotation.

0 to 254

Timeouts​

Custom timeoutstimeoutobject

Set together: once any of connect, send and read is given, all three are required. Left out, the engine's own timeouts apply.

Connecttimeout.connectnumberRequired
over 0 · in seconds
Readtimeout.readnumberRequired
over 0 · in seconds
Sendtimeout.sendnumberRequired
over 0 · in seconds

TLS​

TLStlsobject

How the engine identifies itself to the nodes.

Trusted CA certificatestls.ca_certsarray of strings

PEM certificates the node certificates are checked against when verification is on.

at least 1 item; each 128 to 65536 characters

Choose one:

  • Client certificate from CertificatesA certificate of type client, kept under Certificates.
  • Inline certificate and keyStored on this upstream only.
  • NoneNo client certificate is presented to the nodes.

Client certificate from Certificates​

Client certificatetls.client_cert_idstring or integer

A certificate of type client, kept under Certificates. Not stored beside Client certificate and Private key together.

string 1 to 64 characters or integer at least 1 · letters, digits, dots, hyphens and underscores
pattern^[a-zA-Z0-9-_.]+$

Inline certificate and key​

Client certificatetls.client_certstring

Needs Private key beside it.

128 to 65536 characters
Private keytls.client_keystring

The engine stores the key sealed and never returns it in readable form. Needs Client certificate beside it.

64 to 65536 characters
Verify the server certificatetls.verifyboolean

Checks the node's certificate on https, grpcs, kafka and wss nodes; left out, an https, grpcs or wss node's certificate is not checked and any one is accepted. A stream route never checks it, and an upstream written inline under traffic-split checks it only over wss.

Keepalive​

Keepalivekeepalive_poolobject

Connections the engine keeps open to the nodes.

Idle timeoutkeepalive_pool.idle_timeoutnumberdefault 60

How long an idle connection waits in the pool before it is closed.

at least 0 · in seconds
Requests per connectionkeepalive_pool.requestsintegerdefault 1000

How many requests one pooled connection carries before it is closed and replaced.

at least 1
Pool sizekeepalive_pool.sizeintegerdefault 320

How many idle connections to the nodes each worker keeps open for reuse.

at least 1
G8 dev · Apache APISIX® 3.19.0
Apache, Apache APISIX and APISIX are trademarks of The Apache Software Foundation.