Skip to content
This repository has been archived by the owner on Jan 5, 2021. It is now read-only.

Commit

Permalink
Add line wraps and fix spelling
Browse files Browse the repository at this point in the history
For readability while editing and reviewing pull requests.
  • Loading branch information
jspiewak committed Sep 15, 2016
1 parent e639079 commit 7e90141
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 43 deletions.
76 changes: 57 additions & 19 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,56 @@
redx
======

Redx (or redis-nginx) is an embedded lua based approach of having a dynamic configuration of nginx of frontends and backends with redis as its data store. It was inspired by [hipache](https://github.com/hipache/hipache). It has a restful API (that runs within nginx itself) to manage the many-to-one relationships between frontends to backends, set configurations, and more.
Redx (or redis-nginx) is an embedded lua based approach of having a dynamic configuration of nginx of frontends and
backends with redis as its data store. It was inspired by [hipache](https://github.com/hipache/hipache). It has a
RESTful API (that runs within nginx itself) to manage the many-to-one relationships between frontends to backends, set
configurations, and more.

One of the main benefits of redx is the ability to update your nginx config without needing to reload nginx. This is useful for environments with a highly dynamic topology where backends and frontends are added/removed several times a second (ie Paas). Also, this allows you to have a single nginx config across multiple nginx servers making it easier to have true high availability and scalability on your load balancing layer.
One of the main benefits of redx is the ability to update your nginx config without needing to reload nginx. This is
useful for environments with a highly dynamic topology where backends and frontends are added/removed several times a
second (ie PaaS). Also, this allows you to have a single nginx config across multiple nginx servers making it easier to
have true high availability and scalability on your load balancing layer.

Redx is licensed under the [2-Clause BSD License](https://opensource.org/licenses/BSD-2-Clause).

Project Status
==============

At [rstudio](http://www.rstudio.com/), we are using it in production serving all web traffic for [shinyapps](https://www.shinyapps.io/).
At [RStudio](http://www.rstudio.com/), we are using it in production serving all web traffic for
[shinyapps.io](https://www.shinyapps.io/).

How it works
============

## The Components
Redx is composed of two components; the api and main. The api is a restful api embedded in lua and runs within the nginx process. It runs on its own port (for ease of firewall security) and is manages the frontends and backends in the nginx config by editing the redis database.
Redx is composed of two components; the api and main. The api is a restful api embedded in lua and runs within the nginx
process. It runs on its own port (for ease of firewall security) and is manages the frontends and backends in the nginx
config by editing the redis database.

The other component is main, and this is what takes regular traffic from your users. It looks up the proper backend to proxy the request to based on the host and path.
The other component is main, and this is what takes regular traffic from your users. It looks up the proper backend to
proxy the request to based on the host and path.

## The fallback
In the event that there isn't a frontend or backend match for an incoming request **OR** the backend server (ie a cache miss), the request was proxied to a server that isn't responding, the request is sent to the `fallback`. This is typically your application server, which handles these failure scenario. Several headers are added to the request to help your application server understand the context in which the request is coming in (ie cache miss vs port not open). In some cases, you may want to update redx by hitting the API and insert the missing frontend and/or backend and send them back to nginx to try again, or maybe you want to forward them to a custom 404 page. Its up to you to decide what the behavior you want it to be.
In the event that there isn't a frontend or backend match for an incoming request **OR** the backend server
(ie a cache miss), the request was proxied to a server that isn't responding, the request is sent to the `fallback`.
This is typically your application server, which handles these failure scenario. Several headers are added to the
request to help your application server understand the context in which the request is coming in
(ie cache miss vs. port not open). In some cases, you may want to update redx by hitting the API and insert the missing
frontend and/or backend and send them back to nginx to try again, or maybe you want to forward them to a
custom 404 page. Its up to you to decide what the behavior you want it to be.

Performance
===========

At [rstudio](http://www.rstudio.com/), we find that redx performs slightly slower than regular redis config files. Of course, this makes sense, as you're now querying a remote redis server to lookup frontends and backends, instead of caching all that in local memory. In our unofficial benchmarks, we see a 10ms increase in response time with using a third party redis hosting service. Of course latency to your redis server is a big factor. Redx though, keeps a pool of connections that are reused instead of making separate calls on each request.
That being said, the payoff of having dynamic configuration and being able to easily do high availability with active active nginx load balancers is well worth the 10ms cost in my opinion. Each environment is different and has different requirements, goals, etc. So its up to you to decide what is worth what.
At [RStudio](http://www.rstudio.com/), we find that redx performs slightly slower than regular redis config files.
Of course, this makes sense, as you're now querying a remote redis server to lookup frontends and backends, instead of
caching all that in local memory. In our unofficial benchmarks, we see a 10ms increase in response time with using a
third party redis hosting service. Of course latency to your redis server is a big factor. Redx though, keeps a pool of
connections that are reused instead of making separate calls on each request.

That being said, the payoff of having dynamic configuration and being able to easily do high availability with active
active nginx load balancers is well worth the 10ms cost in my opinion. Each environment is different and has different
requirements, goals, etc. So its up to you to decide what is worth what.

Requirements
============
Expand All @@ -50,13 +73,16 @@ Setup and start vagrant
vagrant up
```

The redx code on your local workstation is run within vagrant (due to sharing the redx directory with vagrant at `/home/vagrant/redx`). As you make code changes, they should take affect immediately and do not require reloading nginx. You will however need to reload nginx when you change the nginx config located `vagrant://etc/nginx/sites-available/redx.conf`.
To see redx logs, see `/var/log/nginx/[access,error].log`
The redx code on your local workstation is run within vagrant (due to sharing the redx directory with vagrant at
`/home/vagrant/redx`). As you make code changes, they should take affect immediately and do not require reloading nginx.
You will however need to reload nginx when you change the nginx config located
`vagrant://etc/nginx/sites-available/redx.conf`. To see redx logs, see `/var/log/nginx/[access,error].log`

## Git Hooks
It is recommended that you setup two git hooks.

The pre-commit hook (`./git/hooks/pre-commit`) should be used to ensure you don't make changes to the moonscript code without recompiling the lua code.
The pre-commit hook (`./git/hooks/pre-commit`) should be used to ensure you don't make changes to the moonscript code
without recompiling the lua code.
```bash
#!/bin/sh

Expand All @@ -73,7 +99,8 @@ busted lua/spec/
Testing
=======

Redx uses a testing framework, [busted](http://olivinelabs.com/busted/), to run integration tests. To run these tests, execute `busted lua/spec`. Continuous integration is setup with [travis ci](https://travis-ci.org/rstudio/redx).
Redx uses a testing framework, [busted](http://olivinelabs.com/busted/), to run integration tests. To run these tests,
execute `busted lua/spec`. Continuous integration is setup with [travis ci](https://travis-ci.org/rstudio/redx).

Configuration
=============
Expand All @@ -99,14 +126,23 @@ The pool size of keepalive connections to maintain, per nginx worker.
max idle timeout for keepalive connection, in milliseconds

##### max\_path\_length
The max number of parts to the path to look up. This defines the max length of a path to be to looked up to a corresponding frontend in redis.
The max number of parts to the path to look up. This defines the max length of a path to be to looked up to a
corresponding frontend in redis.

Say in your service, your path always consists of an account name and service name ( ie http://sasservice.com/jdoe/app1). So the max path length you want to support for your application here is 2. If the user, comes into nginx with more to the path than that (ie http://sasservice.com/jdoe/app1/static/js/base.js), but when request comes in, redx will only search for "sasservice.com/jdoe/app1" first and "sasservice.com/jdoe" second and "sasservice.com" third, for frontends in the database.
Say in your service, your path always consists of an account name and service name (ie http://sasservice.com/jdoe/app1).
So the max path length you want to support for your application here is 2. If the user, comes into nginx with more to
the path than that (ie http://sasservice.com/jdoe/app1/static/js/base.js), but when request comes in, redx will only
search for "sasservice.com/jdoe/app1" first and "sasservice.com/jdoe" second and "sasservice.com" third, for frontends
in the database.

For another example, say you only want to route traffic based on the domain (ie 'chad.myserver.com'). Setting the max\_path\_length to 0 will cause redx to only look for frontends on the domain with no path.
For another example, say you only want to route traffic based on the domain (ie 'chad.myserver.com'). Setting the
max\_path\_length to 0 will cause redx to only look for frontends on the domain with no path.

##### plugins
A list of plugins to enable. Plugins are executed in the order they are given. If you wish to pass a parameter to a plugin, make a plugin an array, where the first element is the plugin name and the second is the parameter. Here is an example.
A list of plugins to enable. Plugins are executed in the order they are given. If you wish to pass a parameter to a
plugin, make a plugin an array, where the first element is the plugin name and the second is the parameter.

Here is an example.
```lua
M.plugins = {
'stickiness',
Expand All @@ -116,10 +152,12 @@ M.plugins = {
```

##### session\_length
The amount of time (in seconds) you wish the session cookie to keep alive. This is applicable when using cookies as a user specific persistence datastore (ie stickiness).
The amount of time (in seconds) you wish the session cookie to keep alive. This is applicable when using cookies as a
user specific persistence datastore (ie stickiness).

##### default\_score
The default score is the score that is inserted into backends in the case where a score is not provided (ie batch upating). If this config option isn't specified, it defaults to 0 (zero).
The default score is the score that is inserted into backends in the case where a score is not provided
(ie batch updating). If this config option isn't specified, it defaults to 0 (zero).

API
===
Expand All @@ -129,6 +167,6 @@ The api is [documented here](https://github.com/rstudio/redx/blob/master/docs/ap
Plugins
=======

Redx has a plugin architecture to allow others to easily expand its capability to do more (publically or privately).
Redx has a plugin architecture to allow others to easily expand its capability to do more (publicly or privately).

See the [plugins documentation](https://github.com/rstudio/redx/blob/master/docs/plugins.md)
32 changes: 23 additions & 9 deletions docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ curl localhost:8081/frontends

### (GET|POST|PUT|DELETE) /frontends/\<url\>/\<backend_name\>

The `frontends` endpoint allows you to get, update, or delete a frontend. Take note that `POST` and `PUT` are treated the same on this endpoint. It is also important that you character escape the frontend url properly.
The `frontends` endpoint allows you to get, update, or delete a frontend. Take note that `POST` and `PUT` are treated
the same on this endpoint. It is also important that you character escape the frontend url properly.

#### Examples

Expand Down Expand Up @@ -46,7 +47,9 @@ curl localhost:8081/backends

### (GET|POST|PUT|DELETE) /backends/\<name\>/\<server\>

The `backends` endpoint allows you to get, update, replace, or delete a backend. Using the `POST` method will "append-only" to the backend, while the `PUT` method will replace what is there in a single redis commit. Be sure to character escape as needed.
The `backends` endpoint allows you to get, update, replace, or delete a backend. Using the `POST` method will
"append-only" to the backend, while the `PUT` method will replace what is there in a single redis commit. Be sure to
character escape as needed.

#### Examples

Expand All @@ -70,7 +73,9 @@ curl -X DELETE localhost:8081/backends/mybackend/google.com%3A80

### (PUT) /backends/\<name\>/\<server\>/score/\<score>

The `backend score` endpoint allows you to update the score a backend has. This score is used by the `least-score` and `most-score` load balancing algorithm to probabilistically send incoming requests to the most probably backend with the least or most score.
The `backend score` endpoint allows you to update the score a backend has. This score is used by the `least-score`
and `most-score` load balancing algorithm to probabilistically send incoming requests to the most probably backend with
the least or most score.

#### Examples

Expand All @@ -81,7 +86,8 @@ curl -X PUT localhost:8081/backends/mybackend/google.com%3A80/score/31

### (GET|PUT|DELETE) /backends/\<name\>/config/\<config_name\>/\<config_value\>

The `backend configuration` endpoint allows you to get, update, or replace a backend config. Be sure to character escape as needed.
The `backend configuration` endpoint allows you to get, update, or replace a backend config. Be sure to character
escape as needed.

#### Examples

Expand All @@ -102,7 +108,8 @@ curl -X DELETE localhost:8081/backends/mybackend/config/max_score

### (DELETE) /flush

Flush clears the redis database of all data. Its literally runs the [`FLUSHDB`](http://redis.io/commands/flushdb) command within redis.
Flush clears the redis database of all data. Its literally runs the [`FLUSHDB`](http://redis.io/commands/flushdb)
command within redis.

#### Examples

Expand All @@ -111,11 +118,15 @@ Flush clears the redis database of all data. Its literally runs the [`FLUSHDB`](
```
curl -X DELETE localhost:8081/flush
```

### (POST|PUT|DELETE) /batch

Batch allows you to make multiple edits in a single http request and redis commit. You **MUST** have a json body with your http request. Similar to the `backends` endpoint, the `POST` method will "append-only" to the backend, while the `PUT` method will replace what is there in a single redis commit.
Batch allows you to make multiple edits in a single http request and redis commit. You **MUST** have a json body with
your http request. Similar to the `backends` endpoint, the `POST` method will "append-only" to the backend, while the
`PUT` method will replace what is there in a single redis commit.

The json body must follow this json structure exactly. The list of backend servers can be either a string (the server address) or an array (the server address and score value).
The json body must follow this json structure exactly. The list of backend servers can be either a string (the server
address) or an array (the server address and score value).

```
{
Expand Down Expand Up @@ -206,15 +217,18 @@ curl -X DELETE localhost:8081/batch -d '{
```

### (GET) /health
This endpoint is designed to be used to check the health of redx. When you hit this endpoint, redx with attempt to write, read, and delete a key in redis to confirm that its capable of accessing redis. Getting a `200` response code from this endpoint should mean that the redx service is healthy.
This endpoint is designed to be used to check the health of redx. When you hit this endpoint, redx with attempt to
write, read, and delete a key in redis to confirm that its capable of accessing redis. Getting a `200` response code
from this endpoint should mean that the redx service is healthy.

##### `GET` example
```
curl localhost:8081/health
```

### (GET|DELETE) /orphans
Will return or delete any frontends and backends that are orphans. Meaning a list of any frontends that point to a missing backend, or any backends that don't have a frontend pointing to it.
Will return or delete any frontends and backends that are orphans. Meaning a list of any frontends that point to a
missing backend, or any backends that don't have a frontend pointing to it.

##### `GET` example
```
Expand Down
Loading

0 comments on commit 7e90141

Please sign in to comment.