Support for dynamic upstreams that will enable dynamic load balancing per API.
# sample upstream block:
upstream backend {
server 127.0.0.1:12354;
server 127.0.0.1:12355;
server 127.0.0.1:12356 backup;
}
So we can proxy_pass like:
proxy_pass http://backend;
I'd love to see that too. My use-case is routing requests to dynamic mesos tasks with zoidberg, kong would be a good candidate to do the routing part. I was going to use nginx with 2 ports anyway. Let me know if it makes sense to use kong for this.
Here are the options I see:
Reloading nginx is not an option since it triggers graceful restart for all the worker processes. We use that mechanism with haproxy in marathoner, but long-lived sessions force previous instances of haproxy to stay alive for extended periods of time. Nginx is using more processes than haproxy, so it would be even worse. Deploying a lot can cause spinning thousands of proxying processes for no good reason.
Nginx can already do this in the Plus version: http://nginx.com/products/on-the-fly-reconfiguration/
Yep, that's another option starting at $7000 annually for 5 servers.
You can also buy the license for one server at $1500 per year: http://nginx.com/products/pricing/. I'm not saying it's cheap or anything but it's an alternative if people wasn't aware of it.
Another option: https://github.com/yzprofile/ngx_http_dyups_module
Looks like dyups can do the trick: https://github.com/bobrik/zoidberg-nginx. Nginx config and lua scripts could give an idea how it works.
I'm not sure about stability of this thing, though.
Just a quick update on this, this feature is important and we feel like an initial implementation should be done. It's not going to make it into 0.3.0 (currently working on implementing other major features, including SSL support and path-based routing), but it definitely should show up within the next two releases. We are trying to keep the release cycles very short, so it shouldn't take too much time.
Of course pull-requests are also welcome.
Can you tell me how this is going to be implemented?
On Wednesday, May 20, 2015, Marco Palladino [email protected]
wrote:
Just a quick update on this, this feature is important and we feel like an
initial implementation should be done. It's not going to make it into
0.3.0 (currently working on implementing other major features, including
SSL support and path-based routing), but it definitely should show up
within the next two releases. We are trying to keep the release cycles very
short, so it shouldn't take too much time.—
Reply to this email directly or view it on GitHub
https://github.com/Mashape/kong/issues/157#issuecomment-103832824.
Regards, Ian Babrou
http://bobrik.name http://twitter.com/ibobrik skype:i.babrou
@bobrik As you pointed out in one of your links, apparently the creator of OpenResty is building a balancer_by_lua functionality which should do the job - so I am investigating this option.
The alternative is taking one of the existing pull requests on the lua-upstream module and contribute to them to make them acceptable and implement any missing feature we might need.
@thefosk the only public info about balancer_by_lua is the tweet by @agentzh. Contributing to existing PRs to lua-upstream module also involves his approval :)
Take a look at ngx_http_dyups_module, this stuff reuses logic from nginx, as opposed to balancer_by_lua. It worked for me in my tests without crashes: 1-100 upstreams, updating every second with full gradual upstream list replace, 8k rps on 1 core with literally no lua code execution when serving user requests. Not sure about keepalive to upstreams, https and tcp upstreams, though.
@bobrik yes, we will start working on this feature in the next releases, so we will monitor any announcement about balancer_by_lua in the meanwhile. If balancer_by_lua won't be released publicly during this time, then we will need to find another solution.
The requirement for Kong would be to dynamically create an upstream configuration from Lua, then dynamically populate the upstream object with servers and use it in the proxy_pass directive. Do you think we can invoke ngx_http_dyups_module functions directly from Lua bypassing its RESTful API?
The use case wouldn't be to update an existing upstream configuration, but to create a brand new from scratch, in pseudo-code:
set $upstream nil;
access_by_lua '
local upstream = upstream:new()
upstream.add_server("backend1.example.com", { weight = 5 })
upstream.add_server("backend2.example.com:8080", { fail_timeout = 5, slow_start = 30 })
ngx.var.upstream = upstream
';
proxy_pass http://$upstream
@thefosk I create upstreams on the fly and update them on the fly with ngx_http_dyups_module. Moreover, I do it from lua code in RESTful API.
Take a look:
https://github.com/bobrik/zoidberg-nginx/blob/master/nginx.conf
https://github.com/bobrik/zoidberg-nginx/blob/master/zoidberg-state-handler.lua
https://github.com/bobrik/zoidberg-nginx/blob/master/zoidberg-proxy-rewrite.lua
Your pseudo-code implies that you create upstream on every request, I only do that on every upstream update. In zoidberg-nginx there is also some code for checking if upstream exists to prevent endless loops, but I found out that it is avoidable with this trick:
location / {
set $where where-am-i.zoidberg;
proxy_pass http://$where;
}
Upstream where-am-i.zoidberg is created on the fly and it's not a real domain name, no recurse proxying to itself until worker_connections are exhausted happens.
@bobrik thank you, I will look into this
I'm also looking at an API manager that makes sense for mesos/marathon. After spending much time with my friend Google I came to the conclusion that right now there is only one option available : choose a service discovery (consul, haproxy brige, zoidberg,...) and add an API Proxy on top of it (Kong, Repose, Tyk, ApiAxle, WSO2 AM, etc.).
Frankly I don't see why I should put a proxy on front of a proxy. It would make a lot of sense to have a lightweight API manager+service discovery service in one piece of middleware. So +1 for this feature. What is the planing state?
+1 for this feature
same here :+1:
Another +1 for me good sir
The balancer_by_lua* directives from ngx_lua will get opensourced soon, in the next 3 months or so.
@agentzh very good news, looking forward to trying it
@thefosk +1
+1
@agentzh any chance to get TCP support in balancer_by_lua as well?
@bobrik I'm not sure I understand that question. Are you talking about doing cosockets in the Lua code run by balancer_by_lua or you mean using balancer_by_lua in stream {} configuration blocks instead of http {} blocks?
@agentzh I'm talking about using balancer_by_lua in stream blocks.
@bobrik Then it's the duty of ngx_stream_lua_module while the current one is ngx_http_lua_module. Different thing :)
Different subsystems, got it. Link with more info from you:
+1 I am really looking forward to this and more specifically pairing with Consul and possibly Consul-template
+1, this is the missing part in my CoreOS setup. I need to loadbalance request to dynamically created instances of my microservice.
+1
+1
I just opensourced balancer_by_lua* in GitHub's balancer-by-lua branch, with the permissions from CloudFlare:
https://github.com/openresty/lua-nginx-module/tree/balancer-by-lua
It currently lacks documentation but its declarative test suite can serve this purpose (I hope):
https://github.com/openresty/lua-nginx-module/blob/balancer-by-lua/t/133-balancer.t
Please let me know if it works for you. Thank you.
@agentzh thank you, I will take a look at it now
Thanks @agentzh, great news!
:beers:
Wondering if this issue should be implemented into Kong core, or into a Plugin.
I first thought it should be into core, but then @sinzone sparked the idea that if it was a plugin, then we could enabled very powerful use-cases, like:
Having the Load Balancing feature as a plugin raises a couple of new question though:
upstream_url, because the Load Balancing plugin will inject the upstream server address every time.upstream_url. Maybe I don't want to load balance a specific consumer to a set of upstream servers, maybe I want to load balance it to only one specific upstream_url, which logically means that.....upstream_url could be replaced by having the Load Balancing plugin configured with just one backend URL.I am just thinking out loud, any feedback?
why not both? load balancing in the core, plugin adds customization (per consumer, #505)
How do you know if a customer is enterprise? Authorisation? Then Maybe you can put a flag there if you make it a core functionality to say "hey careful, upstream this guy to the most stable upstream url" something like route_privileges in authorisation, which then routes to the number one priority upstream url defined in the core & the kong admin can define the priority list
@thibaultCha @Tieske what do you think?
I like that this feature is coming =)
If I can give advice on the plugin/core debate. I like that the core of kong is really simple and fits a lot of use cases by itself with just proxying to one upstream. It reduces the "time to first api" for newcomers.
So I'd say
@Floby I agree, that seems to be the best decision, and if core keeps working as it is it will also not affect users who are not planning to use the Load Balancing feature.
Or simply transform the current upstream_url in core in an array of upstreams which must contain at least 1 element. After all, it won't affect any user since a simple migration would do the job of migrating the old model to the new one, as always. It would also avoid creating yet one more Cassandra table (more queries to retrieve data, and more tables for Cassandra to maintain in the cluster).
I like @thibaultCha's suggestion better :+1:
we can still create a "multi-upstream"-like plugin if further functionality might be required beyond the scope of "load balancing"
Both are viable solutions, one adheres more to the "everything should be a plugin" mantra, the other one extends the core.
I prefer things to do one thing well. Simple is most often preferable to
powerful. In this case adding the multi upstream to the core forces
newcomers to learn more concepts than they need to in order to get started.
When choosing an API gateway tool, I also stumbled across Tyk which is a
single piece of software. It's incredibly harder to get your first API
running because you have to set many upstreams, your API version, tag it
for a specific environment, configure ACL and so on.
So I actually would like load balancing for my APIs =) but I think it's
better for Kong as a product to have it done in a plugin
Le 8 déc. 2015 03:05, "Marco Palladino" [email protected] a écrit :
Both are viable solutions, one adheres more to the "everything should be a
plugin" mantra, the other one extends the core.—
Reply to this email directly or view it on GitHub
https://github.com/Mashape/kong/issues/157#issuecomment-162735518.
Before taking any decision, we need a proof of concept with the balancer_by_lua directive anyways. Because of the way Kong is built, it might make more sense and be less clumsy to implement this in the core, or it might be possible to robustly implement this as a plugin, we do not know yet.
Once we have a POC, we can take arguments into account and chose an implementation.
Makes 100% sense
Le 8 déc. 2015 09:09, "Thibault Charbonnier" [email protected] a
écrit :Before taking any decision, we need a proof of concept with the
balancer_by_lua directive anyways. Because of the way Kong is built, it
might make more sense and be more less clumsy to implement this in the
core, or it might be possible to robustly implement this as a plugin, we do
now know yet.Once we have a POC, we can take arguments into account and chose an
implementation.—
Reply to this email directly or view it on GitHub
https://github.com/Mashape/kong/issues/157#issuecomment-162809157.
@floby's point on simplicity persuaded me :)
@thibaultcha is correct in needing a POC first.
:+1:
+1
I've been looking into this, and it seems there is little we can reuse.
Considering that we have multiple api's to support, which must be configured with their own set of peers. Within this set we must load balance requests.
With the tools at hand, we cannot dynamically create upstreams (upstream per api). We also cannot dynamically add servers to an upstream. So if that cannot be done, then the only benefit that can be derived from using the core nginx loadbalancer must be based on settings that can be used on a per request basis.
This leaves only the set_more_tries function in the new balancer_by_luacontext.
But if we use it (with only one upstream), we can only set the reasons for failure globally in the nginx config file (whether something failed is determined by nginx). But we weant to be able to specify failure reasons per api.
Conclusion: we must rebuild in Lua, cannot use any of the existing stuff. Except the healthcheck module, which can be reused with minor adjustments.
Am I missing something? thoughts?
FWIW, @doujiang24 is building dynamic consistent hash balancing Lua libraries with Lua and C, which aims for the context of balancer_by_lua*. His work is meant to be included in the official OpenResty distribution, eventually :)
:+1:
+1
Also querying the DNS interface for SRV records returns a list of service instances, using this approach you could define the upstream url as one domain (like _contents._tcp.service.consul [RFC 2782]) and then pick up one of the instances proposed. Maybe not the best approach because of the random selection of the instance.
Some service discovery expose an HTTP API, it would be a good datasource for the upstream list. Consul-Template use this approach to dynamically generate nginx configuration.
Actually we're using a mixed approach: the api has one upstream url pointing to a container running consul template which acts as load balancer.
@vinceferro This would indeed be very helpful since this approach could live without an extra upstream registration. Just an api configuration property which tells kong to do a SRV lookup for the host (with an optional TTL for the results).
The random selection you mentioned could later be handled by a preference list stored in an api config.
@sbuettner Yes, using SRV lookup also gives you some kind of flexibility cause every service discovery system exposing a DNS interface responds the same way.
About api config, consul-template has some instructions to get extra info about the service and the environment, and those info can be used to improve the lookup configuration.
I like using DNS for this =)
On 25 February 2016 at 17:45, Vincenzo Ferrara [email protected]
wrote:
@sbuettner https://github.com/sbuettner Yes, using SRV lookup also
gives you some kind of flexibility cause every service discovery system
exposing a DNS interface responds the same way.About api config though, consul-template has some instructions to get
extra info about the service and the environment, and those info can be
used to improve the lookup configuration.—
Reply to this email directly or view it on GitHub
https://github.com/Mashape/kong/issues/157#issuecomment-188871884.
@agentzh Has there been any movement on this for openresty?
@esatterwhite I'm not sure what you are asking for exactly. OpenResty already has balancer_by_lua* as well as the lua-resty-dns library.
@agentzh I think in reference to this
@ahmadnassri See lua-resty-chash: https://github.com/agentzh/lua-resty-chash Other balancers like round-robin should be much easier than this.
@agentzh yes, I was under the impression that this ticket was still waiting the balancer by lua branch to be merged.
@thefosk What is the general statea of this ticket / feature.
+1 for SRV lookup based solution. Would make it easy to configure e.g. with mesos-dns for failover and load balancing.
Very interested in this feature - any better idea as to when it might hit the mat? Thanks!
Something would be better than nothing at this point. We effectively have to have 3 load balancers in place for each of our services.
Yeah, similar kind of story in a planned deployment of mine too.
Same here - Except that i have a reverse load balancer. All my slaves connects to my load balancer and all work get distributed from an open socket. Since I don't have a public ip address and also sitting behind a firewall/router that i don't have access to
The great thing about this is that I can very easily just add another slave without configure the load balancer, heck even a browser tab can become a slave using websocket if I want to
well, _stricto sensu_ you then only have 2 load balancers since kong is not
one at this point ;)
can the load balancer in front of kong be just several A records in a DNS ?
On 5 April 2016 at 16:30, esatterwhite [email protected] wrote:
Something would be better than nothing at this point. We effectively have
to have 3 load balancers in place for each of our services.
- A load balancer in front of Kong
- Kong it self
- a load balancer behind kong infront of a service
—
You are receiving this because you were mentioned.
Reply to this email directly or view it on GitHub
https://github.com/Mashape/kong/issues/157#issuecomment-205833973
This issue is currently blocked by #369 - as a workaround for the moment would be to use DNS-level load balancing, especially if you are adopting service discovery tools like Consul. Basically Consul (or equivalent) supports resolving a hostname to different addresses every time a DNS resolution is attempted, effectively load balancing the load.
@thefosk Using DNS is perfectly fine but are there any plans to support SRV for dynamic port lookup?
@sbuettner we're working on a basic LB implementation, which will not include SRV. Once that lands well probably extend the capabilities.
On a side note with @thibaultCha we are working towards implementing a more performant proxying using the nginx upstream directive that will also allow us to use nginx's keepalive. Using the nginx upstream directive will force us to adopt https://github.com/openresty/lua-resty-dns for DNS resolutions, which I think supports SRV records. This should be ready by v0.9.0.
@Tieske @thefosk Thanks for the insights.
Any news on this you can share?
We are trying to release support for SRV record resolution in 0.9.x - which means that in order to achieve this capability you will need to have a service discovery tool like Consul or etcd, basically delegating to them the effort of load balancing requests through their DNS resolution.
That said, I heard that somebody has already achieved SRV resolutions support by leveraging the dnsmasq server that already comes with Kong, I have never tried myself but that _could be_ an option for the time being.
Also if your DNS resolutions don't also return a port number (and so you are not using SRV records, but only A records), you can currently load-balance requests using existing service discovery tools (by manually specifying the DNS server in the kong.yml configuration under the dns_resolvers_available property).
The more I think about this, the more I think load balancing shouldn't be
handled by Kong.
Any advanced cloud solution has a notion of autoscaling group which works
with dedicated software or hardware with tools like VIP or Load Balancer
application like HAProxy. Using these tools for scalability means Kong can
stay simple and elastic on its own.
On 23 June 2016 at 01:18, Marco Palladino [email protected] wrote:
We are trying to release support for SRV record resolution in 0.9.x -
which means that in order to achieve this capability you will need to have
a service discovery tool like Consul or etcd, basically delegating to them
the effort of load balancing requests through their DNS resolution.That said, I heard that somebody has already achieved SRV resolutions
support by leveraging the dnsmasq server that already comes with Kong, I
have never tried myself but that _could be_ an option for the time being.Also if your DNS resolutions don't also return a port number by leveraging
SRV records, you can currently load-balance requests using existing
service discovery tools (by manually specifying the DNS server in the
kong.yml configuration - that would only work for A records).—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
https://github.com/Mashape/kong/issues/157#issuecomment-227905804, or mute
the thread
https://github.com/notifications/unsubscribe/AAOYMgxI1HpzAjxkqOnZ3giif0OyI2avks5qOcK8gaJpZM4EHfDx
.
Auto scaling solutions make a lot of assumptions about your infrastructure and even how your applications are distributed in a cluster. They also tend to be focused on the scaling of hardware / vm rather than running applications. Add in docker, a complex network mesh and application scheduling, auto scaling just can't help you and will end being more of a pain than any help
+1 for this feature!
+1 for this feature!!!
So I've been working on this and this is how I am currently implementing it;
As Kong supports multiple apis, we als need multiple sets of hosts it can load balance on. As such I'm defining a virtual host, that gets redirected to a set of real hosts. This requires a new data-entity in Kong.
Using terminology upstream (a loadbalanced pool of targets) and target (an individual target; host + port combo)
On the Kong mgt api;
POST /upstreams/
name=service-xyz-v1
POST /upstreams/service-xyz-v1/targets
target=internal.host1:80
weight=3
POST /upstreams/service-xyz-v1/targets
target=internal.host2:80
weight=2
To use this, use the upstream name as the hostname in the upstream_url
POST /apis/
request_path = "/xyz/v1"
upstream_url=http://service-xyz-v1/
Currently using the resty-dns library to do DNS resolution. For resolving A, AAAA and SRV records. The balancer will incorporate the DNS results into the algorithm. As a note; port and weight ,in the example above, will be ignored for SRV records, as the DNS will provide that information.
The balancer_by_lua directive will be used to set the targets in nginx.
So if in the above example the internal.host1 resolves to an A-record with 2 entries, and the internal.host2 resolves to an SRV record with 3 entries then the resulting balancer pool will be;
name ip port weight
---------------------------------------------
internal.host1 192.168.23.1 80 3 -> port and weight from mgt api
internal.host1 192.168.23.2 80 3
internal.host2 192.168.23.51 8000 5 -> port and weight from the SRV record
internal.host2 192.168.23.51 8001 5
internal.host2 192.168.23.52 8000 10
For regular upstream_url entries, the resty-dns library will also be used to resolve A, AAAA and SRV records. But only the first entry returned will be used, such that load-balancing is left to the DNS server.
Results;
Though there is still lots of work to do, these are the lines along which I'm implementing it.
@Tieske Hi Tieske, what is Kong mgt API? And how to use POST /upstreams ? I didn't find reference in Kong document(v0.8) . I also need this feature, but I don't know how to do. :-(
@andy-zhangtao this feature is currently being built. We are aiming to release it in the 0.10 version.
@Tieske Got it! Thanks Tieske
@thefosk awesome!
We dream to build microservice that can be autoregistered against kong <3
We dream to build microservice that can be autoregistered against kong <3
@iam-merlin this is exactly our vision. The next couple of releases will be very exciting for what it concerns microservices orchestration.
btw, @Tieske , if you want a beta tester or a feedback, don't hesitate to ping me. I've some code ready for that :D (I started to write an autoregister library... before I found that kong does not have this feature yet :'( )
We dream to build microservice that can be autoregistered against kong <3
@iam-merlin @thefosk how about a Kong adapter for registrator? This could register Docker-based services with Kong, if the service has the environment SERVICE_TAGS=kong for example.
n.b. this wouldn't replace other registrator adapters e.g. the Consul adapter, it would compliment them (i.e. could be used in combination, or just use the Kong adapter on it's own).
I am planning to deploy Kong for a work project when it supports SRV records fully, in the meantime I have a nginx Docker container which dynamically adds upstreams based on SERVICE_TAGS=nginx.
@alzadude , I don't know registrator but from my point of view (and what I read), registrator needs to be ran on each host... with a feature like this issue, you don't need docker (and consul or other service registry), just a Plain Old Request (^^) and maybe we will have health check after (in another plugin).
From my point of view, Consul is very heavy for microservice... I really like the simplicity with Kong (and no dependencies) but right now... doing a microservice architecture with Kong and without a service registry is a pain.
Anyway, I don't think my point of view is relevant... I'm just a user of kong, not the best one and not a lua developer :P xD.
Just so you know, once @Tieske finishes this implementation, I will provide some sample Docker-Compose templates that show how to use Kong with a microservice orchestration pattern.
I do personally like ContainerPilot more than registrator though.
We will also be able to provide a pattern that doesn't involve having any third-party service discovery in place because, effectively, Kong's new /upstreams will become the service discovery layer.
A PR with intermediate status is available now (see #1541)
Any input and testing is highly appreciated, see https://github.com/Mashape/kong/pull/1541#issuecomment-242846402
so if anyone else wants to test like @iam-merlin, please check it out.
@Tieske it works xD
I've made some tests and it seems to works as expected (just the dns part, I didn't test yet balancer_by_lua).
It seems dns is missing in your requirement (I'm not a lua dev) and I've to installed it manually (I got on error at the first start and I install https://github.com/Mashape/dns.lua).
Do you have any documentation about your code or this will be ready later?
@iam-merlin thx for testing :+1:. Docs will be later, as it might still change.
besides #1541 (internal dns) there is now #1735 which implements the upstreams feature discussed above (1735 builds on top of 1541).
testing is once again highly appreciated!
Cant not deploy load balancing with round robin. We need least open connections or fastest response time - anything but round robin.
'least open connections' does not make sense in a Kong cluster. 'response time' is being considered, but not prioritized yet.
closing this as #1735 has been merged into the next branch for the upcoming release.
How to implement keep_alive without upstream? Because upstream doesn't support dynamic IP resolution and we cannot use keep_alive outside of upstream.
Most helpful comment
The balancer_by_lua* directives from ngx_lua will get opensourced soon, in the next 3 months or so.