[ 
https://issues.apache.org/jira/browse/SOLR-5495?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Timothy Potter updated SOLR-5495:
---------------------------------

    Attachment: SOLR-5495.patch

Here is a first patch that shows the direction I'm heading with this. A few 
things to note about this patch that are worth discussing (sorry it's a bit 
long winded but want to be sure we're all on the same page about this solution):

1) I found a handy class named SocketProxy in the ActiveMQ project and 
"borrowed" it here to help simulate network partitions, such as between the 
leader and replica, while keeping the ZooKeeper connection alive. I'm aware of 
the IpTables class (from SOLR-5482) but the advantage of SocketProxy is it is 
just native Java so runs w/o sudo and on any platforms that don't have 
iptables. This of course requires a little trickery when setting up your test 
as you need to insert the proxy in-front of the Jetty nodes, which is being 
accomplished by setting a proxyPort on the JettySolrRunner, see 
HttpPartitionTest.createJetty. I'm guessing we can build this into a test base 
class if we like this approach and think it will be useful for other tests.

2) I ended up going with Mark's idea #1 except I don't see where / why we need 
to worry about the replica publishing it's own state? In other words, what 
really matters, is that the leader cannot send a request to the replica, so to 
me, the leader's view of the replica is what matters. In my patch, the leader 
will publish the state of the replica as "down" when it encounters a 
communication error when trying to send a request to a replica. See 
ZkController.ensureReplicaInLeaderInitiatedRecovery() method, which is called 
from the DistributedUpdateProcessor.doFinish() method.

So I've thought about this in some detail and I think it will work itself out 
without us having to coordinate state changes. So let's just say the leader set 
the state to "down" and for some weird reason (which I can't really see how it 
would happen), the replica reset it's state to "active". This would make the 
replica a candidate for receiving requests again, which would just lead to 
another error, leading to the leader re-setting the state to "down". In a 
nutshell, if the leader can't talk to the replica over http, it's state gets 
set to "down".

One idea I did have for this is to have the leader pass the 
ClusterState.zkClusterStateVersion along in every request, thus allowing the 
replica to compare the version it is working with and if they are different, 
then have the replica force a state update from ZK and act accordingly. It 
shouldn't be too bad to implement this if we think it will be useful? Version 
would be passed along like the distrib.update param is today.

3) Even if more coordination is needed for #2 ^ at some point the replica gets 
marked as being in the down state. This ensures the leader stops trying to send 
requests to that replica (via the DOWN filter in the call to getReplicaProps to 
determine the set of Nodes to forward requests to). The leader also needs to 
determine if it should send the CoreAdminAction.REQUESTRECOVERY command to the 
downed replica's core. This occurs over HTTP, which I think is correct because 
if the leader can't send the recover command to the replica, then sending docs 
is futile as well. What I've done here is to build upon the existing code in 
DistributedUpdateProcessor's doFinish method to attempt sending that command 
every 5 secs for up to 10 minutes so long as the node is still listed as a 
/live_nodes in ZK. If that changes, I stop trying to hit that node from the 
leader since a node that is no longer live will do full recovery when it comes 
back.

I like this leader-initiated recovery approach because the leader's view of the 
replica is what matters, so I felt creating a self-initiating recovery process 
by which the replica realizes its state got changed by the leader doesn't do 
much if the HTTP connection between the leader and replica is still down.

4) Of course, there's no guarantee that connectivity will be restored within 10 
minutes, so the re-try loop described in #3 ^ will timeout and the leader will 
stop trying to tell the replica to recover. At this point, the replica should 
be marked down so at least the leader is no longer trying to send requests to 
it, so I think the shard is in a safe state wrt consistency but after the 10 
minutes, there's nothing to tell the replica to recover from the down state. Do 
we want the leader to just try forever? Seems like not ... Maybe this is where 
an ops alert could be inserted to have someone go investigate why the partition 
is longer than 10 minutes. Appreciate any advice on how to handle this better.

5) You'll notice that I'm using a HashSet containing replicaUrl's in 
ZkController to keep track of replicas that are in the "leader-initiated" 
recovery process, see: ZkController.replicasInLeaderInitiatedRecoveryHandling. 
This approach is needed because there are many DistributedUpdateProcessor's 
that may be receiving a flood of errors concurrently when connectivity to a 
replica is lost. I didn't want the leader trying to set the state to DOWN more 
than once when it sees a bunch of errors or to have more than one thread per 
replica trying to send the recovery command. There might be a better location 
for this code than the ZkController (maybe ZkStateReader).

As for testing, I think the unit test (HttpPartitionTest) is pretty close to 
the scenario we're trying to capture in this ticket.

Specifically, it tests the following process:

a. setup proxies in-front of all Jetty servers (3 in this test) by overriding 
the createJetty method.
b. create a collection with 1 shard and rf=2
c. send doc 1 to leader, which gets forwarded to replica successfully
d. partition occurs (using SocketProxy); however the ZK connection between the 
replica remains in tact (which is the crux of this issue); the leader remains 
the same throughout this test
e. send doc 2 to leader
f. leader send doc 2 to replica fails due to comm error, asynchronous call to 
doFinish starts the leader-initiated recovery process
g. leader marks replica as being down, which means it will stop trying to send 
requests to the replica until the situation improves as the 
ZkStateReader.getReplicaProps() filters out "downed" nodes. At this point, the 
leader is also trying to tell the replica to recover from a background thread.
h. partition is restored
i. send doc 3
j. replica recovery succeeds asynchronously, test waits until it sees the 
replica in the "active" state
k. test verifies both the leader and the replica have docs 1,2,3 using requests 
to the /get handler

Next, the test performs the same basic process but for 1000 docs while dropping 
and restoring the connectivity between the leader and replica every 100 docs.

I should mention that without the code in this patch, the replica will most 
certainly be out of sync and not know it, which of course is a no-no for a CP 
system (btw: I used real test-driven development methodology here by writing 
the test first and then implementing until the test passes).

The one minor concern I have with this test right now is the Thread.sleep(2000) 
before restoring connectivity with the proxy. I had to introduce this because 
the test was progressing too fast for the recovery process to kick-in, thus 
leading to test failures. I think this is OK to wait a little bit because that 
is more reflective of a running cluster and things do take a little time to 
propagate around the cluster. Just wanted to draw attention to this so you're 
clear it was intentional to give things time to work.

> Recovery strategy for leader partitioned from replica case.
> -----------------------------------------------------------
>
>                 Key: SOLR-5495
>                 URL: https://issues.apache.org/jira/browse/SOLR-5495
>             Project: Solr
>          Issue Type: Bug
>            Reporter: Mark Miller
>         Attachments: SOLR-5495.patch
>
>
> We need to work out a strategy for the case of:
> Leader and replicas can still talk to ZooKeeper, Leader cannot talk to 
> replica.
> We punted on this in initial design, but I'd like to get something in.



--
This message was sent by Atlassian JIRA
(v6.2#6252)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to