1 2 3 4 Previous Next 52 Replies Latest reply on Nov 27, 2006 10:12 AM by clebert.suconic Go to original post
      • 15. Re: Server side HA and failover
        clebert.suconic

         

        Tim wrote:
        We just need to extend the model slightly to cope with this.


        Most of the time I'm spending now is looking at the code for how we could couple with this (open the failed ChannelID into a diffferent server), maybe changing Routers and other objects.
        If you think you could do this part faster it would be great.

        • 16. Re: Server side HA and failover
          timfox

           

          "clebert.suconic@jboss.com" wrote:

          Most of the time I'm spending now is looking at the code for how we could couple with this (open the failed ChannelID into a diffferent server), maybe changing Routers and other objects.
          If you think you could do this part faster it would be great.


          Ok, let me have a think about it and I'll try and come up with a more explicit/detailed solution :)

          • 17. Re: Server side HA and failover
            timfox

            Off the top of my head, this is more or less what you want to do:

            Let's say the failed node is node 1, and the fail over node is node 2.

            The post offices at node 2 will detect that a server has failed (via JGroups).

            They then look in their node->failover node mapping to determine whether it must take over responsibility for the failed node.

            node2 is marked as a failover node for node 1 in the mapping so the post offices at node 2 now realise that they must take over responsibility for the
            failed nodes queues.

            They then do the following:

            Take the name map for node 1 and move all the entries to the name map for node 1. Change the names of the queues by suffixing with node id to ensure they
            are unique.

            Replace the remote queue stubs with local clustered queues and load them, keep note of the new local clustered queues for the next step.

            Now iterate through the condition map.

            For each cluster router on each condition map entry, iterate through the entries in the router. For each one from node 1, replace with the relevant
            localclusteredQueue from the previous step.

            Server side fail over should now be complete.

            The next step will be client reconnection from the client side.

            When a consumer is reconnected to the queue, just need to look it up with the new name (the old name suffix the node id) and hey presto.

            There should be no need for any post office signature changes AFAIK.

            • 18. Re: Server side HA and failover
              clebert.suconic

              I have committed some changes regarding server side failover.

              In summary, these changes consist of:

              I - Method failover(int) on DefaultClusteredPostOffice..
              Still not integrated on JGroups:viewsChange, but that it's a trivial change (I hope). I will integrate it after I have done some more testing

              II - Signature changes on PostOffice/ClusteredPostOffice to accept bindinging from other nodeIds than the current NodeId.

              III - Changes on DefaultRouter to accept more than one local queue (created when DefaultClusteredPostOffice.failover is caleld).


              Also... It looks like we will have to send messages received from client to server. This is because we will need to remove references on the database. I'm still investigating as I'm seeing messages still on the database after being received.

              Also, you will realize a couple of TODOs on the code that are there just for tests. For example I'm ignoring some exceptions if a ACK is not found. This is just a temporary solution until I figure out what to do with pre-received messageIds. (send, ignore them, or find what's going on sometimes).

              I will solve the messageId problems by tomorrow for sure, so I'm fine with this, it's just a matter of getting the job done.


              Cheers,

              Clebert Suconic

              • 19. Re: Server side HA and failover
                clebert.suconic

                Just for reference, this method from DefaultClusteredPostOffice is going to be the heart of serverSide failover:

                 public void failOver(int nodeId) throws Exception
                 {
                 log.info("Preparing failover against node " + nodeId);
                 Map subMaps = (Map)nameMaps.get(new Integer(nodeId));
                 ArrayList namesToRemove = new ArrayList();
                 for (Iterator iterNames = subMaps.entrySet().iterator();iterNames.hasNext();)
                 {
                 Map.Entry entry = (Map.Entry)iterNames.next();
                 Binding binding = (Binding )entry.getValue();
                 if (binding.getQueue().isClustered())
                 {
                 ClusteredQueue queue = (ClusteredQueue) binding.getQueue();
                 if (!queue.isLocal())
                 {
                 namesToRemove.add(entry);
                 }
                 }
                 }
                
                 for (Iterator iterNames = namesToRemove.iterator();iterNames.hasNext();)
                 {
                 Map.Entry entry = (Map.Entry)iterNames.next();
                 DefaultBinding binding = (DefaultBinding)entry.getValue();
                 RemoteQueueStub stub = (RemoteQueueStub)binding.getQueue();
                 this.removeBinding(nodeId,(String)entry.getKey());
                
                 Binding newBinding = this.createBinding(this.nodeId,nodeId,binding.getCondition(),stub.getName(),stub.getChannelID(),stub.getFilter(),stub.isRecoverable());
                 LocalClusteredQueue clusteredQueue = (LocalClusteredQueue )newBinding.getQueue();
                 clusteredQueue.deactivate();
                 clusteredQueue.load();
                 clusteredQueue.activate();
                 addBinding(newBinding);
                 }
                 }
                
                


                • 20. Re: Server side HA and failover
                  clebert.suconic

                  Another point we will have to think about is how to resume the server back.

                  Say.. you have serverA (the failedNode) and serverB (the server that will receive serverA's queues)

                  When serverA resumes after an eventual crash, all of his queues are loaded at serverB. They will need to be transfered back to serverA, and probably we will have to send a message to all clients to reconnect back into serverA after serverA resumed.

                  Maybe we could transfer queues as they reapear on serverA, but I guess there is a problem since javax.jms.Queue could be listened by more than one client.

                  Any ideas besides redirecting clients back on ServerA?

                  • 21. Re: Server side HA and failover
                    timfox

                    This is a good point, and one that I covered in the design WIKI page: http://wiki.jboss.org/wiki/Wiki.jsp?page=NewHADesignOverview (see the end of the page)

                    Transferring queues back to a node if it recovers is a very difficult thing to do. Since consumers may be connected to the queues on the new node we can't just move them back to the old node.

                    Theoretically this is possible by effectively failing them over again to the original node, however in this case any non persistent messages unacked in their sessions will get redelivered so this is not acceptable, if the sessions have any unacked np messages.

                    This makes the whole thing complex, too complex to do initially. Eventually, if we decide to implement this it could also be used in the general case for the redistribution of connections across the cluster to best utilise available resources. But this is a nice to have and the pain to gain ratio is very high.

                    • 22. Re: Server side HA and failover
                      timfox

                      A few comments:

                      "clebert.suconic@jboss.com" wrote:
                      I have committed some changes regarding server side failover.

                      In summary, these changes consist of:

                      I - Method failover(int) on DefaultClusteredPostOffice..
                      Still not integrated on JGroups:viewsChange, but that it's a trivial change (I hope). I will integrate it after I have done some more testing


                      No need for the method to public - it will only be called from inside the post office

                      "clebert" wrote:

                      II - Signature changes on PostOffice/ClusteredPostOffice to accept bindinging from other nodeIds than the current NodeId.


                      If the failover is driven from inside the postoffice then shouldn't need this on the interface?

                      "clebert" wrote:

                      Also... It looks like we will have to send messages received from client to server. This is because we will need to remove references on the database. I'm still investigating as I'm seeing messages still on the database after being received.


                      Doesn't sound right to me. I'll have a look at the code.

                      "clebert" wrote:

                      I will solve the messageId problems by tomorrow for sure, so I'm fine with this, it's just a matter of getting the job done.


                      Great. Seems like you're making good progress :)

                      • 23. Re: Server side HA and failover
                        timfox

                         

                        "clebert.suconic@jboss.com" wrote:
                        Just for reference, this method from DefaultClusteredPostOffice is going to be the heart of serverSide failover:

                         public void failOver(int nodeId) throws Exception
                         {
                         log.info("Preparing failover against node " + nodeId);
                         Map subMaps = (Map)nameMaps.get(new Integer(nodeId));
                         ArrayList namesToRemove = new ArrayList();
                         for (Iterator iterNames = subMaps.entrySet().iterator();iterNames.hasNext();)
                         {
                         Map.Entry entry = (Map.Entry)iterNames.next();
                         Binding binding = (Binding )entry.getValue();
                         if (binding.getQueue().isClustered())
                         {
                         ClusteredQueue queue = (ClusteredQueue) binding.getQueue();
                         if (!queue.isLocal())
                        



                        There should be no need to check if the queue is clustered and not local, they will *always* be clustered and not local in the name map for a remote node, so this is redundant.

                        "clebert" wrote:

                        
                         {
                         namesToRemove.add(entry);
                         }
                         }
                         }
                        
                         for (Iterator iterNames = namesToRemove.iterator();iterNames.hasNext();)
                         {
                         Map.Entry entry = (Map.Entry)iterNames.next();
                         DefaultBinding binding = (DefaultBinding)entry.getValue();
                        


                        The correct type is Binding, not DefaultBinding?

                        "clebert" wrote:

                         RemoteQueueStub stub = (RemoteQueueStub)binding.getQueue();
                         this.removeBinding(nodeId,(String)entry.getKey());
                        



                        The remove needs to be broadcast across the cluster so other nodes can remove the binding too

                        "clebert" wrote:

                         Binding newBinding = this.createBinding(this.nodeId,nodeId,binding.getCondition(),stub.getName(),stub.getChannelID(),stub.getFilter(),stub.isRecoverable());
                         LocalClusteredQueue clusteredQueue = (LocalClusteredQueue )newBinding.getQueue();
                         clusteredQueue.deactivate();
                         clusteredQueue.load();
                         clusteredQueue.activate();
                         addBinding(newBinding);
                        



                        Isn't there going to be a problem creating two bindings with the same name?




                        • 24. Re: Server side HA and failover
                          clebert.suconic

                          I'm answering your two latest posts here...

                          Tim wrote:
                          No need for the method to public - it will only be called from inside the post office


                          I lefted it public for now only, it simplifies my tests...
                          But I might keep it public for testcases purposes.

                          Tim wrote:
                          If the failover is driven from inside the postoffice then shouldn't need this on the interface?


                          When the client fails, the client will send its original nodeID through createConsumer on ServerSessionDelegate, that method will need to create find Bindings on the PostOffice. It will need the nodeId to perform such operation. all the methods on PostOffice will have a method(nodeId...) equivalent now. I will revise maybe removing some of these methods if I don't need those.


                          Tim wrote:
                          Doesn't sound right to me. I'll have a look at the code.


                          I will comment on that after I have debuged today. But I feel like we will need for certain scenarios.

                          If the new server doesn't get for some reason a message on its references, it won't remove the reference from the database. I'm still investigating this.


                          Tim wrote:
                          There should be no need to check if the queue is clustered and not local, they will *always* be clustered and not local in the name map for a remote node, so this is redundant.


                          A double check has to be done anyway IMO. I'm only replacing ClusteredQueues and if for any reason the queue was already replaced by a local queue, I will just ignore it.


                          Tim wrote:
                          The correct type is Binding, not DefaultBinding?


                          Yep... already changed it. when I was typing this I *thought* DefaultBinding introduced extra properties I would need.


                          Tim wrote:
                          The remove needs to be broadcast across the cluster so other nodes can remove the binding too


                          I will have to think about this. Other nodes on the cluster will still need a RemoteQueueStub point to the channelID on the failedOver node.

                          Tim wrote:
                          Isn't there going to be a problem creating two bindings with the same name?


                          Not on DefaultRouter as I have changed it. I will check other data structures / make some tests.


                          Clebert

                          • 25. Re: Server side HA and failover
                            clebert.suconic

                             

                            "timfox" wrote:
                            This is a good point, and one that I covered in the design WIKI page: http://wiki.jboss.org/wiki/Wiki.jsp?page=NewHADesignOverview (see the end of the page)

                            Transferring queues back to a node if it recovers is a very difficult thing to do. Since consumers may be connected to the queues on the new node we can't just move them back to the old node.

                            Theoretically this is possible by effectively failing them over again to the original node, however in this case any non persistent messages unacked in their sessions will get redelivered so this is not acceptable, if the sessions have any unacked np messages.

                            This makes the whole thing complex, too complex to do initially. Eventually, if we decide to implement this it could also be used in the general case for the redistribution of connections across the cluster to best utilise available resources. But this is a nice to have and the pain to gain ratio is very high.


                            I'm concerned on a scenario where a client reconnects back into serverA. A failed consumer will use the nodeID as part of the key of the subscriptionID (by either implementing subscriptionName containing nodeId or by changing PostOffice's signatures the way I have done).

                            Let me explain using an example:

                            I - Client connects into serverA
                            II - Client creates durable subscriber (named subA)
                            III - serverA fails
                            IV - ServerB assumes subA
                            V - Client decided to disconnect from server (session.close())
                            VI - ServerA comes back.
                            VII - Client reconnects back (into serverA)
                            VIII - Clients creates durable subscriber (named subA)... this won't give back the same channelID as nodeB would have the channel now. This could mean loss of messages.


                            In a parallel scenario...

                            I - Client connects into serverB
                            II - Client creates durable subscriber (named subA (same name))
                            III - It won't use the same channelID as the one created from serverA as the original nodeId is different

                            So... serverB will have two subscriptions... one from failed nodeA and another from nodeB.
                            subscriptionA on serverB will be only accessible when serverA fails, and if the client reconnects back to serverA its queue won't be available there.


                            One thing that I thought to solve this was transfering the queue back on serverA once serverA is back.

                            If that's not possible maybe we could implement dependency between queues. Say.. the local queue would consume messages from the failed queue (with the same name) case the queue is empty.

                            • 26. Re: Server side HA and failover
                              timfox

                              Clebert and I have chatted, and after I complete the alpha 2 release (should be done today) I suggest spending the rest of the week working with Clebert so we can through these points together.

                              Any objections?

                              • 27. Re: Server side HA and failover
                                clebert.suconic

                                It's always good to have a very nice night of sleep...

                                I literally dreamed with an idea today :-) (Man... I'm getting that geek already :-) )

                                I was not sure what was that crazy dream... kind of hard to explain it but on my dream my bed was being invaded by HashMaps of Bindings, nodeIds and routers, and they were crashing with each other like the Brazilian flight 1907 (http://en.wikipedia.org/wiki/Gol_Transportes_A%C3%A9reos_Flight_1907)

                                Than I woke up and realized... I needed another map for failedNodes...

                                This way we could have duplicated names only on failedNodes... the client will need the channelId to be re-connected to a failedNode... and redistribution policies will take care of cases where the client also died.


                                I talked with Tim and I will be playing with this today and tomorrow, and it seems that this will solve the conceptual problems I'm having at this moment with these duplicates.


                                Kind of funny story, isn't? :-)


                                Clebert

                                • 28. Re: Server side HA and failover
                                  ovidiu.feodorov

                                  ummmmm, Clebert .... this is a public forum, everybody can read it :)

                                  Never mind, you go ahead, I am sure you'll figure out a way to overcome those invading Bindings, nodeIDs and routers :)

                                  • 29. Re: Server side HA and failover
                                    ovidiu.feodorov

                                     

                                    Tim wrote:
                                    Any objections?


                                    Not until today ... :)