2015-01-18 3 views
10

Я использую библиотеку Apache Curator для проведения выборов лидеров в Zookeeper. У меня есть код приложения, развернутый на разных машинах, и мне нужно выполнить мой код только с одной машины, поэтому я делаю выборы лидеров в zookeeper, чтобы я мог проверить, являюсь ли я лидером, а затем выполняю этот код.Как эффективно использовать рецепт LeaderElection, используя куратор для Zookeeper?

Ниже мой класс, который LeaderElectionExecutor делает, что я имею один экземпляр Куратор каждого приложения

public class LeaderElectionExecutor { 

    private ZookeeperClient zookClient; 

    private static final String LEADER_NODE = "/testleader"; 

    private static class Holder { 
     static final LeaderElectionExecutor INSTANCE = new LeaderElectionExecutor(); 
    } 

    public static LeaderElectionExecutor getInstance() { 
     return Holder.INSTANCE; 
    } 

    private LeaderElectionExecutor() { 
     try { 
      String hostname = Utils.getHostName(); 

      String nodes = "host1:2181,host2:2181; 

      zookClient = new ZookeeperClient(nodes, LEADER_NODE, hostname); 
      zookClient.start(); 

      // added sleep specifically for the leader to get selected 
      // since I cannot call isLeader method immediately after starting the latch 
      TimeUnit.MINUTES.sleep(1); 
     } catch (Exception ex) { 
      // logging error 
      System.exit(1); 
     } 
    } 

    public ZookeeperClient getZookClient() { 
     return zookClient; 
    } 
} 

А ниже мой ZookeeperClient код -

// can this class be improved in any ways? 
public class ZookeeperClient { 

    private CuratorFramework client; 
    private String latchPath; 
    private String id; 
    private LeaderLatch leaderLatch; 

    public ZookeeperClient(String connString, String latchPath, String id) { 
     client = CuratorFrameworkFactory.newClient(connString, new ExponentialBackoffRetry(1000, Integer.MAX_VALUE)); 
     this.id = id; 
     this.latchPath = latchPath; 
    } 

    public void start() throws Exception { 
     client.start(); 
     leaderLatch = new LeaderLatch(client, latchPath, id); 
     leaderLatch.start(); 
    } 

    public boolean isLeader() { 
     return leaderLatch.hasLeadership(); 
    } 

    public Participant currentLeader() throws Exception { 
     return leaderLatch.getLeader(); 
    } 

    public void close() throws IOException { 
     leaderLatch.close(); 
     client.close(); 
    } 

    public CuratorFramework getClient() { 
     return client; 
    } 

    public String getLatchPath() { 
     return latchPath; 
    } 

    public String getId() { 
     return id; 
    } 

    public LeaderLatch getLeaderLatch() { 
     return leaderLatch; 
    } 
} 

Теперь в моем приложении, я использую код как этот -

public void method01() { 
    ZookeeperClient zookClient = LeaderElectionExecutor.getInstance().getZookClient(); 
    if (zookClient.isLeader()) { 
     // do something 
    } 
} 

public void method02() { 
    ZookeeperClient zookClient = LeaderElectionExecutor.getInstance().getZookClient(); 
    if (zookClient.isLeader()) { 
     // do something 
    } 
} 

Заявление о проблемах: -

В библиотеке куратора - вызов isLeader() сразу после запуска защелки не будет работать. Для лидера требуется время. И только по этой причине я добавил спать 1 минуту в моем LeaderElectionExecutor коде, который отлично работает, но я думаю, что это неправильный способ сделать это.

Есть ли лучший способ сделать это? Помня об этом, мне нужен способ проверить, являюсь ли я лидером, затем исполню этот кусок кода. Я не могу сделать все в одном методе, поэтому мне нужно вызвать метод isLeader из разных классов и методов, чтобы проверить, являюсь ли я лидером, затем выполняю только этот кусок кода.

Я использую Zookeeper 3.4.5 и версию Curator 1.7.1.

ответ

-1

Раньше я не работал с зоопарком или куратором, поэтому возьмите мой ответ с солью.

Установите флаг.

Boolean isLeaderSelected = false;

В начале защелки установите флаг в значение false. Когда лидер выбран, установите флаг в значение true.

В функции isLeader():

isLeader(){ 
while(!isLeaderSelected){} //waits until leader is selected 

//do the rest of the function 
} 

Это также относительно Hacky обходного путь, но он должен позволить метод isLeader выполнить, как только это возможно. В случае, если они находятся в разных классах, геттер должен иметь возможность предоставлять isLeaderSelected.

1

Как только я решил проблему, очень похожую на вашу. Вот как я это сделал.

Во-первых, у меня были объекты, управляемые весной. Итак, у меня был LeaderLatch, который можно вводить через контейнер. Одним из компонентов, которые использовали LeaderLatch, была LeadershipWatcher, реализация интерфейса Runnable, которая отправила событие лидерства другим компонентам. Этими последними компонентами были реализации интерфейса, который я назвал LeadershipObserver.Реализация LeadershipWatcher в основном как следующий код:

@Component 
public class LeadershipWatcher implements Runnable { 
    private final LeaderLatch leaderLatch; 
    private final Collection<LeadershipObserver> leadershipObservers; 

    /* constructor with @Inject */ 

    @Override 
    public void run() { 
    try { 
     leaderLatch.await(); 

     for (LeadershipObserver observer : leadershipObservers) { 
     observer.granted(); 
     } 
    } catch (InterruptedException e) { 
     for (LeadershipObserver observer : leadershipObservers) { 
     observer.interrupted(); 
     } 
    } 
    } 
} 

Поскольку это только эскиз вверх, я рекомендую вам расширить этот код, может быть, применяя шаблон команды для вызова наблюдателей, или даже представления наблюдателей в пулы потоков, если их работа блокирует или требует длительных задач интенсивной работы с ЦП.

0
leaderLatch = new LeaderLatch(curatorClient, zkPath, String.valueOf(new Random().nextInt())); 
leaderLatch.start(); 
Participant participant; 
while(true) { 
    participant = leaderLatch.getLeader(); 
    // Leader election happens asynchronously after calling start, this is a hack to wait until election happens 
    if (!(participant.getId().isEmpty() || participant.getId().equalsIgnoreCase(""))) { 
    break; 
    } 
} 
if(leaderLatch.hasLeadership()) { 
... 
} 

Обратите внимание, что getLeader возвращает фиктивного участника с идентификатором "", пока он не выберет лидера.

0

Вот оживлению старый вопрос ...

Это похоже на ответ srav дал, но я хотел бы предостеречь против использования этого кода, поскольку она использует занятая-ждать и может вызвать определенные функции обратного вызова, которые выдаются в -что никогда нельзя называть, возможно, навсегда заблокировать. Кроме того, он может повторять навсегда, если есть реальные проблемы.

Это было мое решение, в котором используется политика повторения КуратораКлиента, чтобы попытаться в ожидании выбора руководства, если это необходимо.

RetryPolicy retryPolicy = _client.getZookeeperClient().getRetryPolicy(); 
    RetrySleeper awaitLeadership = _leaderLatch::await; 

    final long start = System.currentTimeMillis(); 
    int count = 0; 

    do { 
     try { 
      // curator will return a dummy leader in the case when a leader has 
      // not yet actually been elected. This dummy leader will have isLeader 
      // set to false, so we need to check that we got a true leader 
      if (_leaderLatch.getLeader().isLeader()) { 
       return; 
      } 
     } catch (KeeperException.NoNodeException e) { 
      // this is the case when the leader node has not yet been created 
      // by any client - this is fine because we are still waiting for 
      // the algorithm to start up so we ignore the error 
     } 
    } while (retryPolicy.allowRetry(count++, System.currentTimeMillis() - start, awaitLeadership)); 

    // we have exhausted the retry policy and still have not elected a leader 
    throw new IOException("No leader was elected within the specified retry policy!"); 

Хотя взглянуть на инициализации CuratorFramework я предостерегаю против использования Integer.MAX_VALUE при определении политики повторных попыток ...

Я надеюсь, что это помогает!

 Смежные вопросы

  • Нет связанных вопросов^_^