/** * Calculate the average number of topics on the currently active hubs and release topics if * required. We shed topics if we currently hold topics greater than average + average * * tolerancePercentage/100.0 We shed a maximum of maxLoadToShed topics We also hold on to at least * one topic. * * @param loadMap * @param callback A return value of true means we tried to rebalance. False means that there was * no need to rebalance. * @param ctx */ public void shedLoad( final Map<HubInfo, HubLoad> loadMap, final Callback<Boolean> callback, final Object ctx) { long totalTopics = 0L; for (Map.Entry<HubInfo, HubLoad> entry : loadMap.entrySet()) { if (null == entry.getKey() || null == entry.getValue()) { continue; } totalTopics += entry.getValue().toHubLoadData().getNumTopics(); } double averageTopics = (double) totalTopics / loadMap.size(); logger.info("Total topics in the cluster : {}. Average : {}.", totalTopics, averageTopics); // Handle the case when averageTopics == 0. We hold on to at least 1 topic. long permissibleTopics = Math.max(1L, (long) Math.ceil(averageTopics + averageTopics * tolerancePercentage / 100.0)); logger.info( "Permissible topics : {}. Number of topics this hub holds : {}.", permissibleTopics, numTopics); if (numTopics <= permissibleTopics) { // My owned topics are less than those permitted by the current tolerance level. No need to // release // any topics. callback.operationFinished(ctx, false); return; } // The number of topics I own is more than what I should be holding. We shall now attempt to // shed some load. // We shed at most maxLoadToShed number of topics. We also hold on to at least 1 topic. long targetNumTopics = Math.max(1L, Math.max((long) Math.ceil(averageTopics), numTopics - maxLoadToShed)); // Reduce the load on the current hub to the target load we calculated above. logger.info("Reducing load on this hub to {} topics.", targetNumTopics); reduceLoadTo( new HubLoad(targetNumTopics), new Callback<Long>() { @Override public void operationFinished(Object ctx, Long numReleased) { logger.info("Released {} topics to shed load.", numReleased); callback.operationFinished(ctx, true); } @Override public void operationFailed(Object ctx, PubSubException e) { callback.operationFailed(ctx, e); } }, ctx); }
@Override public void serveSubscribeRequest( ByteString topic, SubscribeRequest subRequest, MessageSeqId consumeSeqId, Callback<SubscriptionData> callback, Object ctx) { if (fail) { callback.operationFailed(ctx, new PubSubException.ServiceDownException("Asked to fail")); return; } super.serveSubscribeRequest(topic, subRequest, consumeSeqId, callback, ctx); }
/** * Reduce the load on the current hub so that it reaches the target load. We reduce load by * releasing topics using the {@link TopicManager} passed to the constructor. We use {@link * TopicManager#releaseTopics(int, org.apache.hedwig.util.Callback, Object)} to actually release * topics. * * @param targetLoad * @param callback a Callback<Long> that indicates how many topics we tried to release. * @param ctx */ public void reduceLoadTo(HubLoad targetLoad, final Callback<Long> callback, final Object ctx) { int targetTopics = (int) targetLoad.toHubLoadData().getNumTopics(); int numTopicsToRelease = (int) numTopics - targetTopics; // The number of topics we own is less than the target topic size. We don't release // any topics in this case. if (numTopicsToRelease <= 0) { callback.operationFinished(ctx, 0L); return; } // Call releaseTopics() on the topic manager to do this. We let the manager handle the release // policy. tm.releaseTopics(numTopicsToRelease, callback, ctx); }
@Override public void deliver( ByteString topic, ByteString subscriberId, Message msg, Callback<Void> callback, Object context) { System.out.println( "Received message from topic " + topic.toStringUtf8() + " for subscriber " + subscriberId.toStringUtf8() + " : " + msg.getBody().toStringUtf8()); callback.operationFinished(context, null); }
@Override public void deliver( ByteString t, ByteString s, org.apache.hedwig.protocol.PubSubProtocol.Message msg, org.apache.hedwig.util.Callback<Void> callback, Object context) { if (!t.equals(topic) || !s.equals(subId)) { return; } int num = Integer.parseInt(msg.getBody().toStringUtf8()); if (num == next) { latch.countDown(); ++next; } callback.operationFinished(context, null); }