-
Notifications
You must be signed in to change notification settings - Fork 695
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC: more advanced app clustering #28
Comments
i am really interested in that, and i have a customer constantly asking me for such a feature. The only thing i am not sure about if it is better to follow a master-locker approach (like the one you described) or a fully distributed one, like paxos http://en.wikipedia.org/wiki/Paxos_%28computer_science%29 |
Why not use a Zookeeper ensemble for that? That's what I do. I'm afraid someday uWSGI will become sentient with all this new functionality. :) |
I'm not very familiar with ZooKeeper, can post more details on how do You use it for cron tasks? |
Let me clarify what I would like uWSGI to handle:
What I would "outsource" to other tools:
Bonus features:
uWSGI provides single environment for both web apps and cron tasks those apps require to run, what we need is a way to make those cron tasks executed in a coordinated way across cluster of uWSGI nodes. |
What you said you would "outsource" is what I recommend Zookeeper for. It's fault tolerant and provides CAS operations and shared storage. Perfect for locks, coordination or just shared configuration. As for running cron jobs, I use cron. :) Of course, I have to embed functionality in these scripts to talk with Zookeeper and decide what to do. I guess I just find it weird that what I consider an excellent web server/application server can also be an excellent tool for everything you describe. Seems like a whole different functionality. But I don't doubt that uWSGI does that job just as well. :) |
Zookeeper does look like the right tool for this job, I'll look into into it. |
It will require lot of work so I will aim for 1.6 with that, hopefully this will keep me from falling into winter sleep. |
Ok, i have started investigating better integration with various clustering infrastructures/products. Currently the exposed api is the following (take it as a draft even if i have implemented all of them in my company private repository) uwsgi.cluster_members() -> returns the list of cluster members The only developed backend is for the redhat cluster suite (cman/dlm) I plan to add zookeeper and pacemaker soon after. Both legion and cluster subsystem will be available as backend even if they need some kind of work as they could overlap. Some other project to look at in this area ? |
IMHO most people (including me) does not need anything more sophisticated than a redis server (and with redis-sentinel it should be easy to have decent HA in place now) and I think that the goal in the first place should be to create something that is both: easy to use and "good enough" for non-critical tasks. I would rather use legion and storage plugins to do this job. Legion can talk over multicast so there is no need to have a full list of nodes, no configuration You need to recreate every time You add or remove a node. And with storage plugin I can share some data between nodes (like last run time). Legion just needs few more touches like way of handling nodes with same valor. |
Let me show you an example of the proposed cluster api using redis: uwsgi --cluster-engine redis --cluster 192.168.0.17:4000 --ini cluster://foobar.ini that means: join (see below) the cluster managed by the redis server 192.168.0.17 port 4000 and get instance configuration using the object foobar.ini (that in redis could be a simple key) uWSGI configure its internals (redis-specific) and then gets the instance configurations and (if all goes well) starts accepting requests. An additional thread (in the master) starts waiting for redis event (read: redis-sentinel events) and checks for deadlocks (see below). The app want to lock a shared resource and calls uwsgi.cluster_lock("item001") internally the request is mapped to The address of the redis instance is in a shared memory area managed by the master-thread. If the sentinel notify of changed master the value is changed accordingly, and pending locks (or deadlocks) are managed (whenever a core is cluster locking something a global table is filled, so the master-thread can check it) This is for the locking part. Regarding routers (fastrouter,httprouter...) when the instance joins the cluster an internal list is filled with the instance address and the router can use that list (asynchronously managed by the master-thread) for load balancing. Regarding cron locking, i believe the best approach would be improving the legion subsystem, as for the nature of the system it is better to ensure a single node "hold" a resource (the cron task) indefinitely. |
Isn't this emperor with redis backend? What advantages does it offer over emperor? The only difference would be reading node list from redis rather than from subscription table (?) |
configuration download is only to be backward-compatible with the old (current) clustering subsystem, i do not think there are cases where emperor is not the best choice. The same for the subscription system (even if storing nodes data in different storage could be interesting). Main purpose (for me) of the new infrastructure will be node synchronization So, to sum up: redhat (config, nodes, locking, messaging) will be the backends exporting various features via the clustering api. Currently i needed only the redhat plugin for a customer and the redis setnx support for another (this second one is still in development). I suppose you are suggesting a more modular approach where we simply have "cluster-locking" plugins, "emperor-storage" and simply drop messaging (little use as no one asked for it in the past :P). Nodes infos are irrelevant in the choice as i think the subscription system is versatile enough to make everyone happy. |
With legion subsystem and this toy plugin one can have such crons, but it needs more work to be really usable. This will probably not happen in 1.5 since there are other things cooking there. |
update: --legion-cron command was added by Roberto yesterday, it will run all cron tasks only on node which is lord for given legion (you can use multiple legions and spread cron tasks manually). I need more features for crons so I'm working on plugin that will implement them (storing job history somewhere, spreading jobs across all nodes based on few factors and so). |
Legion subsystem was added to 1.9 and in current master there is legion-cron, so this we have working solution for this issue, closing |
Most apps running production code are run on several nodes and there are many cases when some kind of coordination between those nodes is required (for example to ensure that only one app at a time does some specific work), most of the time this is done using database (by creating locks or writing some metadata). uWSGI can be used to run some code (like daemons or crons) but AFAIK it lacks any kind of cluster wide cooperation, if I want to run cron task in my cluster than should only run on single node at any given time, than I need to ensure than no other node will execute it, this can be achieved either by:
I believable that we can add clustered and coordinated cron execution across cluster of nodes without too much work, pieces required:
cluster locking so that uWSGI can create lock across cluster, we can also call that remote locking and use redis with SETNX command to provide locks (or even maybe create locking subsystem with pluggable lockers: redis, mongodb, whatever), such locks could be added to API
with cluster wide locks we can promote one node to cluster master, in case of redis that would be the first node that got lock (locks should expire and master should update them and reset ttl before they will expire)
with one node being master we can coordinate what node will execute what task but now we need to have the list of all cron commands but since cron settings doesn't need to be the same on all nodes than we should be able to define cron tasks in few different ways:
Every node should communicate with master and send him the list of defined --cluster-cron options.
Master than would would setup schedules for next round of each cron executions, pseudo metadata:
now each node would read metadata from master every minute and check if it should run any command, master should provide desired cron distribution algorithm so that one node will not be hammered
beside cron tasks we could add cluster wide singleton lock for daemon execution, so we could run daemon that should only be executed on single node and if this node dies it should be restarted on another node (for example celery beat - periodic task scheduler for celery tasks)
This is general idea, it might not be the best one but it provides starting point. Questions to be answered first:
I wanted to discuss this before I start hacking any code, all comments are welcome.
The text was updated successfully, but these errors were encountered: