-
-
Notifications
You must be signed in to change notification settings - Fork 981
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
Support for Redis Sentinel #131
Comments
Hi @vmattila, Having support for redis-sentinel in Predis would be awesome, unfortunately I don't have the time to investigate an implementation for it right now and I think it's not so trivial to get it right, so any contribution would be greatly appreciated. I'd start by implementing a whole new connection class, we can eventually refactor the code later to optimize everything for reusing purposes. The second parameter of
We just need to pay attention here in the client class when initializing the right connection class for the job, but I think it's not that much of a problem. Anyway to keep things simple I'd just leave changes to
PS: I just used the first name I could think of, there are probably better names for such a connection class. As for the Feel free to ask if you have doubts, I may not be able to get back to you immediately but I'll do my best! There's no hurry after all, I plan to finally ship v0.8.4 after delaying it for months for no valid reasons. EDIT: if you start working on this one please use |
Thanks @nrk for your comments and tips, I started working with this feature (based on
I had some problems with getting At least this is a good start. =) |
Seeing an actual implementation attempt made me aware of some issues coming with the overall approach, and as it turns out it isn't as easy as I thought to get sentinel right in Predis. This is a list of the problems I've found so far in you branch, minor issues and more serious ones are mixed as I wrote them down with no clear order in mind:
I'm starting to wonder if it'd be better to have a specialized client to handle sentinel-backed replication, more than a specialized connection class. Hmmm... |
Thanks @nrk for your comments. As a starter, I modified the SENTINEL command to I was wondering about using
As we always need more than one sentinel server configured, I'd like to rely on already existing Predis functionality to take care of failover to the next sentinel if one of them fails. This is why |
Yes but Predis\Connection\ConnectionFactory::create() only accepts parameters to create a single connection object at time, so you have to iterate over On a related note, I think it's really time for me to start thinking about Predis v0.9 since I have a couple of ideas (requiring a few breaking changes) born out of this discussion and that I'd like to try out as soon as possible to see if they are indeed valid or worth the effort: they could make our life easier with sentinel in the future, let alone giving Predis an even more solid design with its internal API. |
Ah, indeed. In fact Redis documentation gives already some guidelines how reconnections should be handled, so implementing more specialized logic how |
That was kind of easy refactoring in the end of the day... I am not fully satisfied how the connection stack to sentinels are handled right now ( But some questions about exceptions at this point:
|
I'm very interested in seeing this in Predis, if I can help in any way, say the word! |
Hi @nulpunkt, support for redis-sentinel will be investigated as soon as Predis v1.0.0 is released (I'm late, so damn late, but it's finally coming :-)) since the new internals of the library will allow us to implement this feature in a decent way, a thing that simply wasn't possible with v0.8. EDIT: if anyone wants to get their hands dirty, any work should be done against the current |
Cool :) I might have time to look at it on friday. Thank you for your reply! |
@integrii, you would please care to share the source of that info? Thanks, |
I take it back @adichiru ! I found where I thought I read that and it was out of context. Sorry! I'll delete my post to prevent further confusion. |
I spent a couple of minutes to go through this issue and recent modifications from master branch. At least based on my recent work there was no significant changes, namely only namespaces etc. The current setup as in A couple of notes that I found out when working with changes:
In case there is no usable slaves the |
Just a reminder: my feature branch & fork can be found from https://github.com/vmattila/predis/tree/feature-sentinel. I will convert this as a pull request later. |
I played around with the feature branch that @vmattila made and I'm quite happy with the results. The only thing I'm missing is a way to see which node was selected for a specific Redis command. But I guess that issue is not related to the Sentinel feature, but an issue related to replication in general. I'd love to see this merged in v.1.0. @vmattila can you send in the pull request? Maybe add some tests first. Some time ago I added Sentinel support to Credis, an alternative PHP client for Redis. I wrote some tests for it. Maybe this can help: https://github.com/ThijsFeryn/credis/blob/master/tests/CredisSentinelTest.php Thanks for the contribution, I'd be very excited to see this merged into Predis. |
All in all I think @vmattila's branch is good (actually I have yet to test it in practice, but the code looks fine with only a few minor adjustments needed). That said, I'm wondering if it would be possible to avoid using a new connection class that extends I'm not sure which is the best approach in practical terms but if we consider that Predis will also need replication for redis-cluster (a feature which is currently missing), it would be cool to investigate the chance of having a reusable class that can be used by both |
What's the recommended way to work with a sentinel until 1.1.0? Create a separate client for the sentinel, find master and then kill the sentinel client? |
Hi @nrk. I've looked both at Redis Cluster & the Sentinel feature branch of @vmattila and I believe his approach is the right one. I understand that you're trying to find a "one size fits all" solution that applies to Redis cluster too. But Redis cluster has built-in autofailover and read-write splitting. There is no real need to make Predis master and slave aware because the cluster handles this for you. As a consequence there is no need for Sentinel if you use Redis in cluster mode, because all the features are handled by the cluster and you can connect to a random node (either a master or a slave) and they'll handle read & write calls appropriately. Using an Aggregate Connection that inherits from "Predis\Connection\Aggregate\MasterSlaveReplication" seems like a solid decision because that's what Sentinel is for: detecting masters and slaves. Could you please reconsider accepting the pull request and merging the branch? @vmattila has done good work and a lot of people could benefit from it. Thanks |
@ThijsFeryn @vmattila I'll try looking at this again during the first week of January as I will have some time off from work and won't be travelling :-) |
Any updates, Daniele? Thx
|
Are we sure that you can read/write to any node in the cluster? The six node cluster I have setup replies with MOVED and the correct node's location. I then have to connect to that node to complete the write. Making Predis aware of shards means the process goes faster. When a MOVED comes back from a server, Predis should ask again for the node distribution. i could see this being slightly wasteful in small applications that only do one read or write, but long running applications would benefit from it greatly. Maybe caching the node information should be an option you can enable? |
I considered your advice again (using Sentinel as a strategy rather than a replication connection type). I tried implementing it as a strategy, but it felt wrong. If you look at the problem Sentinel is trying to solve, it's autofailover and that's directly linked to the replication. Unlike the other strategy patterns, this is initializing new connections. I believe the implementation of @vmattila is still the right decision. Would you please consider merging this? I could really use this feature right now. And as mentioned in one of the comments above, Redis Cluster has its own autofailover mechanism. Love to hear you opinion and plans for this feature. Thanks again |
Just got an email from a user testing my branch. He pointed out a problem with authentication, just copy-pasting the message here so we don't forget the issue: "I'm testing your feature sentinel for predis. I added $client->auth('mypassword') then it works fine for $client->get() but fails for $client->set() PHP Fatal error: Uncaught exception 'Predis\Response\ServerException' with message 'NOAUTH Authentication required.' in /home/labuser/predis-feature-sentinel/src/Client.php:348" |
@nrk, finalizing this feature would be wonderful. |
I have used the current v1.1-sentinel branch in multiple production environments without real problems. 100 ms default timeout has been slightly too low in our environment (for some reason) when sentinels have been distributed around different AWS availability zones. This is just to give heads up that most likely the timeout needs to be adjusted for each implementation for best performance. Do you think that sentinels should actually be connected in random order? As now they are connected in the same order as they are defined, there will be kind of "unnecessary" and constant delay if first sentinels are down. Of course we could implement a completely new component to provide the sentinels in any order, just thinking whether it should be part of Predis or not. |
I'm currently travelling around Taiwan so I'm basically afk for a while,
|
Alright I'm not dead. I resumed my work on Predis and am planning to tinker on the |
@vmattila I think connecting to a random sentinel makes also sense to distribute the load among the various sentinels provided via configuration, I will probably make it the default behaviour in Predis. |
Nice to hear this is moving forward. Please consider #291 (database selection) as well. I implemented a redneck version of this in traum-ferienwohnungen@5887201 |
@tback don't worry it's on the roadmap, well actually I think I'll just do something on the same line of |
First step in the right direction: forget the scary block of code previously needed to configure $sentinels = ['tcp://127.0.0.1:5380', 'tcp://127.0.0.1:5381', 'tcp://127.0.0.1:5382'];
$options = ['replication' => 'sentinel', 'service' => 'mymaster'];
$client = new Predis\Client($sentinels, $options); You can still use the |
Just added support for |
In the end I'm rewriting the whole My plan is to merge the |
@tback database selection and authentication will both be possible by setting $sentinels = ['tcp://127.0.0.1:5380', 'tcp://127.0.0.1:5381'];
$options = [
'replication' => 'sentinel',
'service' => 'mymaster',
'parameters' => ['database' => 2, 'password' => 'MYPASSWORD'],
];
$client = new Predis\Client($sentinels, $options); |
I updated class DebugConnection extends StreamConnection
{
public function connect()
{
if (!$this->isConnected()) {
echo "[$this] ** CONNECTING\n";
parent::connect();
}
}
public function disconnect()
{
if ($this->isConnected()) {
parent::disconnect();
echo "[$this] ** DISCONNECTED\n";
}
}
public function executeCommand(CommandInterface $command)
{
$response = parent::executeCommand($command);
echo "[$this] => ", $command->getId(), " ", join(" ", $command->getArguments()), "\n";
return $response;
}
} Then initialize the client like this: $client = new Predis\Client($sentinels, [
'replication' => 'sentinel',
'service' => $yourservice,
'connections' => ['tcp' => 'DebugConnection'],
]); |
That's Great! I would be very glad to follow the new approach for configuring Predis\Client to use redis-sentinel, and test the frequently used redis io features. |
Now we also have tests for PS: Predis v1.1.0 is planned to be released during the first week of June, we're almost there :) |
I went ahead and merged |
thanks @nrk |
Thanks @nrk. Any idea when the new release will be planned? Rather use a new release than dev-master in my composer.json. Cheers |
@ThijsFeryn very soon, I'd say during the he first week of June. |
JFYI Predis v1.1.0 is now available so we finally have redis-sentinel support in a stable release! Please read the release notes, it took quite some time (and in case of redis-sentinel, way too much time) but thanks for waiting! |
good! all clear thanks |
Thank you!!! |
I would be happy to contribute to predis development by implementing automatic master/slave resolution and connection based on the configured sentinels. I tried to explore the Predis codebase, but unfortunately could not figure out where to start.
In practice, we should be able to enter the sentinel addresses instead direct master/slave ip addresses and provide the name of the master. For example:
One of the configured sentinels should be connected and sent queries to get the master ip:
SENTINEL get-master-addr-by-name mymaster
, slavesSENTINEL slaves mymaster
and finally create the actual aggregated connection based on the received information.Should I create a completely new connection type, extend an existing class or modify something? I also expect that I should implement two new command classes for the two sentinel commands.
Some references:
The text was updated successfully, but these errors were encountered: