I was using storm previously and I need to more batching capabilities so I searched for batching in storm.
And I found out Trident which do micro-batching in real-time.
But somehow, I cannot figure out how Trident handle micro-batching (flow, batch size, batch interval) to know it really has what I need.
What I would like to do is to collect/save tuples emitted by a spout in an interval and re-emit them to downstream component/bolt/function with another interval of time.
(For example, spout emit one tuple per second, next trident function will collect/save tuples and emit 50 tuples per minute to next function.)
Can somebody guide me how I can apply Trident in this case?
Or any other applicable way using storm features?
Excellent question! But sadly this kind of micro batching is not supported out of the Trident box.
But you can try implementing your own frequency driven micro-batching. Something like this skeleton example:
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import org.apache.storm.task.OutputCollector;
import org.apache.storm.task.TopologyContext;
import org.apache.storm.topology.OutputFieldsDeclarer;
import org.apache.storm.topology.base.BaseRichBolt;
import org.apache.storm.tuple.Tuple;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MicroBatchingBolt extends BaseRichBolt {
private static final long serialVersionUID = 8500984730263268589L;
private static final Logger LOG = LoggerFactory.getLogger(MicroBatchingBolt.class);
protected LinkedBlockingQueue<Tuple> queue = new LinkedBlockingQueue<Tuple>();
/** The threshold after which the batch should be flushed out. */
int batchSize = 100;
/**
* The batch interval in sec. Minimum time between flushes if the batch sizes
* are not met. This should typically be equal to
* topology.tick.tuple.freq.secs and half of topology.message.timeout.secs
*/
int batchIntervalInSec = 45;
/** The last batch process time seconds. Used for tracking purpose */
long lastBatchProcessTimeSeconds = 0;
private OutputCollector collector;
#Override
#SuppressWarnings("rawtypes")
public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
this.collector = collector;
}
#Override
public void execute(Tuple tuple) {
// Check if the tuple is of type Tick Tuple
if (isTickTuple(tuple)) {
// If so, it is indication for batch flush. But don't flush if previous
// flush was done very recently (either due to batch size threshold was
// crossed or because of another tick tuple
if ((System.currentTimeMillis() / 1000 - lastBatchProcessTimeSeconds) >= batchIntervalInSec) {
LOG.debug("Current queue size is " + this.queue.size()
+ ". But received tick tuple so executing the batch");
finishBatch();
} else {
LOG.debug("Current queue size is " + this.queue.size()
+ ". Received tick tuple but last batch was executed "
+ (System.currentTimeMillis() / 1000 - lastBatchProcessTimeSeconds)
+ " seconds back that is less than " + batchIntervalInSec
+ " so ignoring the tick tuple");
}
} else {
// Add the tuple to queue. But don't ack it yet.
this.queue.add(tuple);
int queueSize = this.queue.size();
LOG.debug("current queue size is " + queueSize);
if (queueSize >= batchSize) {
LOG.debug("Current queue size is >= " + batchSize
+ " executing the batch");
finishBatch();
}
}
}
private boolean isTickTuple(Tuple tuple) {
// Check if it is tick tuple here
return false;
}
/**
* Finish batch.
*/
public void finishBatch() {
LOG.debug("Finishing batch of size " + queue.size());
lastBatchProcessTimeSeconds = System.currentTimeMillis() / 1000;
List<Tuple> tuples = new ArrayList<Tuple>();
queue.drainTo(tuples);
for (Tuple tuple : tuples) {
// Prepare your batch here (may it be JDBC, HBase, ElasticSearch, Solr or
// anything else.
// List<Response> responses = externalApi.get("...");
}
try {
// Execute your batch here and ack or fail the tuples
LOG.debug("Executed the batch. Processing responses.");
// for (int counter = 0; counter < responses.length; counter++) {
// if (response.isFailed()) {
// LOG.error("Failed to process tuple # " + counter);
// this.collector.fail(tuples.get(counter));
// } else {
// LOG.debug("Successfully processed tuple # " + counter);
// this.collector.ack(tuples.get(counter));
// }
// }
} catch (Exception e) {
LOG.error("Unable to process " + tuples.size() + " tuples", e);
// Fail entire batch
for (Tuple tuple : tuples) {
this.collector.fail(tuple);
}
}
}
#Override
public void declareOutputFields(OutputFieldsDeclarer declarer) {
// ...
}
}
Source: http://hortonworks.com/blog/apache-storm-design-pattern-micro-batching/ and Using tick tuples with trident in storm
Related
I use redis++ library and have a redis db which contains keys with ttl set. I want to be informed for all updates to my db. I set __keyevent#0__:set and a subscriber callback like this
subscriber.on_message([&keys = updated_redis_keys](std::string, std::string key) {
keys.push_back(std::move(key));
});
and use a while loop to consume events:
while (true)
{
try
{
subscriber.consume();
for (const auto &key : keys)
pipeline.get(key).ttl(key);
auto replies = pipeline.exec();
for (std::size_t i = 0; i < keys.size(); ++i)
{
static constexpr std::size_t ValueIndex = 0;
static constexpr std::size_t TtlIndex = 1;
const auto value = replies.get<std::optional<std::string>>(i * 2 + ValueIndex);
const auto ttl = replies.get<long long>(i * 2 + TtlIndex);
const auto entry = Entry(std::move(updated_redis_keys[i]), *value, static_cast<std::size_t>(ttl));
do_something_with(entry);
}
keys.clear();
}
catch (const sw::redis::Error &err)
{
}
}
I tried to accumulate keys in keys vector and use pipeline.exec() to get values and ttl of all updated keys at once. But i think subscriber.consume(); just consumes a single event each time so keys.size() always equals to 1.
How can i get better performance by stacking more keys before running exec()?
You can collect a batch of keys by running multiple consume()s before running the pipeline. Even better, you can have a time window threshold, and run the pipeline when reaching the threshold (even if we have not collected enough keys).
const int batch_size = 10;
const std::chrono::seconds time_threshold(30);
while (true) {
auto cnt = 0;
auto begin = std::chrono::steady_clock::now();
std::vector<std::string> keys;
while (cnt < batch_size && std::chrono::steady_clock::now() - begin < time_threshold) {
// Not get enough keys, and we still have time, do consume.
try {
subscriber.consume();
} catch (const Error &e) {
// handle errors.
}
++cnt;
}
// now we've gotten a batch of keys or reached the time threshold. do the pipeline job.
// your original code here.
}
having code in akka and playing with become() need to understand why it receive only first msg and then it ignores ...
package ping_pong;
import akka.actor.AbstractActor;
import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
public class PingPongActor extends AbstractActor {
public static void main(String[] args) throws Exception {
ActorSystem _system = ActorSystem.create("PingPongActorApp");
ActorRef masterpp = _system.actorOf(Props.create(PingPongActor.class), "pp");
masterpp.tell(PING, masterpp);
System.out.println("after first msg");
masterpp.tell(PING, masterpp);
masterpp.tell(PING, masterpp);
masterpp.tell(PING, masterpp);
masterpp.tell(PING, masterpp);
masterpp.tell(PING, masterpp);
System.out.println("last msg");
}
static String PING = "PING";
static String PONG = "PONG";
int count = 0;
#Override
public Receive createReceive() {
return receiveBuilder().match(String.class, ua -> {
if (ua.matches(PING)) {
System.out.println("PING" + count);
count += 1;
Thread.sleep(100);
if (count <= 10) {
getSelf().tell(PONG, getSelf());
}
getContext().become(receiveBuilder().match(String.class, ua1 -> {
if (ua1.matches(PONG)) {
System.out.println("PONG" + count);
count += 1;
Thread.sleep(100);
getContext().unbecome();
}
}).build());
if (count > 10) {
System.out.println("DONE" + count);
getContext().stop(getSelf());
}
}
}
).build();
}
}
It gives result:
21:36:34.098 [PingPongActorApp-akka.actor.default-dispatcher-4] INFO
akka.event.slf4j.Slf4jLogger - Slf4jLogger started after first msg
last msg PING0 PONG1
the question is why it ignores the other PING or also PONG messages ... ?
When you getContext().become, you are replacing the entire Receive for that actor, so
getContext().become(receiveBuilder().match(String.class, ua1 -> {
if (ua1.matches(PONG)) {
System.out.println("PONG" + count);
count += 1;
Thread.sleep(100);
getContext().unbecome();
}
}).build());
You are installing a Receive which will only respond to messages matching PONG.
As an aside: Thread.sleep is basically the single worst thing you can do in an actor, as it prevents the actor from doing anything and also consumes a dispatcher thread. It would be a much better idea to schedule a message to yourself in 100 millis which would then trigger the unbecome.
I am trying to calculate the message delivery ratio using TraCIDemo.
In sendBeacon I am incrementing messageDeliverySend every time I send a message and in processBeacon I increment the messageDeliveryReceive parameter based on the sending node.
In processBeacon I do a string compare with node[0], but I want to check this parameter dynamically. How do I do the dynamic check part for this code?
My scenario will be if there are multiple nodes transmitting to node[1] for example I want to record values only from node[0].
void ROAMER::sendBeacon(ROAMERBeacon * beacon, double delay) {
ROAMER_EV << "Sending beacon: address = " << beacon->getAddress()
<< ", position = " << beacon->getPosition() << endl;
IPv4ControlInfo * networkProtocolControlInfo = new IPv4ControlInfo();
networkProtocolControlInfo->setProtocol(IP_PROT_MANET);
networkProtocolControlInfo->setTimeToLive(255);
networkProtocolControlInfo->setDestAddr(IPv4Address::LL_MANET_ROUTERS);
networkProtocolControlInfo->setSrcAddr(getSelfAddress().get4());
messageDeliverySend++;
delayTime = simTime();
UDPPacket * udpPacket = new UDPPacket(beacon->getName());
udpPacket->encapsulate(beacon);
udpPacket->setSourcePort(ROAMER_UDP_PORT);
udpPacket->setDestinationPort(ROAMER_UDP_PORT);
udpPacket->setControlInfo(networkProtocolControlInfo);
sendUDPPacket(udpPacket, delay);
}
void ROAMER::processBeacon(ROAMERBeacon * beacon) {
if(strcmp(beacon->getSenderAddress(),"node[0]") == 0){
messageDeliveryReceive++;
}
}
void ROAMER::finish(){
messageDeliveryRatio = messageDeliveryReceive/messageDeliverySend;
recordScalar("Message Delivery Ratio",messageDeliveryVecRatio);
}
I'm trying to use the given code within steptimer.h to set up code that will run every two seconds. However with the code below, timer.GetTotalSeconds() always returns 0.
Unfortunately there isn't much information readily available on StepTimer.h (at least I believe due to a lack of useful search results), so I was hoping someone might be able to shed some light as to why the timer isn't recording the elapsed seconds. Am I using it incorrectly?
Code from Game.h, Game.cpp and StepTimer.h are included below. Any help is greatly appreciated.
From Game.cpp:
double time = timer.GetTotalSeconds();
if (time >= 2) {
laser_power++;
timer.ResetElapsedTime();
}
Initialised in Game.h:
DX::StepTimer timer;
From Common/StepTimer.h:
#pragma once
#include <wrl.h>
namespace DX
{
// Helper class for animation and simulation timing.
class StepTimer
{
public:
StepTimer() :
m_elapsedTicks(0),
m_totalTicks(0),
m_leftOverTicks(0),
m_frameCount(0),
m_framesPerSecond(0),
m_framesThisSecond(0),
m_qpcSecondCounter(0),
m_isFixedTimeStep(false),
m_targetElapsedTicks(TicksPerSecond / 60)
{
if (!QueryPerformanceFrequency(&m_qpcFrequency))
{
throw ref new Platform::FailureException();
}
if (!QueryPerformanceCounter(&m_qpcLastTime))
{
throw ref new Platform::FailureException();
}
// Initialize max delta to 1/10 of a second.
m_qpcMaxDelta = m_qpcFrequency.QuadPart / 10;
}
// Get elapsed time since the previous Update call.
uint64 GetElapsedTicks() const { return m_elapsedTicks; }
double GetElapsedSeconds() const { return TicksToSeconds(m_elapsedTicks); }
// Get total time since the start of the program.
uint64 GetTotalTicks() const { return m_totalTicks; }
double GetTotalSeconds() const { return TicksToSeconds(m_totalTicks); }
// Get total number of updates since start of the program.
uint32 GetFrameCount() const { return m_frameCount; }
// Get the current framerate.
uint32 GetFramesPerSecond() const { return m_framesPerSecond; }
// Set whether to use fixed or variable timestep mode.
void SetFixedTimeStep(bool isFixedTimestep) { m_isFixedTimeStep = isFixedTimestep; }
// Set how often to call Update when in fixed timestep mode.
void SetTargetElapsedTicks(uint64 targetElapsed) { m_targetElapsedTicks = targetElapsed; }
void SetTargetElapsedSeconds(double targetElapsed) { m_targetElapsedTicks = SecondsToTicks(targetElapsed); }
// Integer format represents time using 10,000,000 ticks per second.
static const uint64 TicksPerSecond = 10000000;
static double TicksToSeconds(uint64 ticks) { return static_cast<double>(ticks) / TicksPerSecond; }
static uint64 SecondsToTicks(double seconds) { return static_cast<uint64>(seconds * TicksPerSecond); }
// After an intentional timing discontinuity (for instance a blocking IO operation)
// call this to avoid having the fixed timestep logic attempt a set of catch-up
// Update calls.
void ResetElapsedTime()
{
if (!QueryPerformanceCounter(&m_qpcLastTime))
{
throw ref new Platform::FailureException();
}
m_leftOverTicks = 0;
m_framesPerSecond = 0;
m_framesThisSecond = 0;
m_qpcSecondCounter = 0;
}
// Update timer state, calling the specified Update function the appropriate number of times.
template<typename TUpdate>
void Tick(const TUpdate& update)
{
// Query the current time.
LARGE_INTEGER currentTime;
if (!QueryPerformanceCounter(¤tTime))
{
throw ref new Platform::FailureException();
}
uint64 timeDelta = currentTime.QuadPart - m_qpcLastTime.QuadPart;
m_qpcLastTime = currentTime;
m_qpcSecondCounter += timeDelta;
// Clamp excessively large time deltas (e.g. after paused in the debugger).
if (timeDelta > m_qpcMaxDelta)
{
timeDelta = m_qpcMaxDelta;
}
// Convert QPC units into a canonical tick format. This cannot overflow due to the previous clamp.
timeDelta *= TicksPerSecond;
timeDelta /= m_qpcFrequency.QuadPart;
uint32 lastFrameCount = m_frameCount;
if (m_isFixedTimeStep)
{
// Fixed timestep update logic
// If the app is running very close to the target elapsed time (within 1/4 of a millisecond) just clamp
// the clock to exactly match the target value. This prevents tiny and irrelevant errors
// from accumulating over time. Without this clamping, a game that requested a 60 fps
// fixed update, running with vsync enabled on a 59.94 NTSC display, would eventually
// accumulate enough tiny errors that it would drop a frame. It is better to just round
// small deviations down to zero to leave things running smoothly.
if (abs(static_cast<int64>(timeDelta - m_targetElapsedTicks)) < TicksPerSecond / 4000)
{
timeDelta = m_targetElapsedTicks;
}
m_leftOverTicks += timeDelta;
while (m_leftOverTicks >= m_targetElapsedTicks)
{
m_elapsedTicks = m_targetElapsedTicks;
m_totalTicks += m_targetElapsedTicks;
m_leftOverTicks -= m_targetElapsedTicks;
m_frameCount++;
update();
}
}
else
{
// Variable timestep update logic.
m_elapsedTicks = timeDelta;
m_totalTicks += timeDelta;
m_leftOverTicks = 0;
m_frameCount++;
update();
}
// Track the current framerate.
if (m_frameCount != lastFrameCount)
{
m_framesThisSecond++;
}
if (m_qpcSecondCounter >= static_cast<uint64>(m_qpcFrequency.QuadPart))
{
m_framesPerSecond = m_framesThisSecond;
m_framesThisSecond = 0;
m_qpcSecondCounter %= m_qpcFrequency.QuadPart;
}
}
private:
// Source timing data uses QPC units.
LARGE_INTEGER m_qpcFrequency;
LARGE_INTEGER m_qpcLastTime;
uint64 m_qpcMaxDelta;
// Derived timing data uses a canonical tick format.
uint64 m_elapsedTicks;
uint64 m_totalTicks;
uint64 m_leftOverTicks;
// Members for tracking the framerate.
uint32 m_frameCount;
uint32 m_framesPerSecond;
uint32 m_framesThisSecond;
uint64 m_qpcSecondCounter;
// Members for configuring fixed timestep mode.
bool m_isFixedTimeStep;
uint64 m_targetElapsedTicks;
};
}
Alrighty got what I wanted with the code below. Was missing the .Tick(####) call.
timer.Tick([&]() {
double time = timer.GetTotalSeconds();
if (time >= checkpt) {
laser_power++;
checkpt += 2;
}
});
Just fixed an integer checkpt to increment by 2 each time so that it runs every 2 seconds. There's probably a better way to do it, but it's 3.30am so I'm being lazy for the sake of putting my mind at ease.
I am learning fork-join technique in java and have written the following program. I am running a for loop (5 times) and I want to run the contents of the for loop in separate threads. This is happening correctly. The problem is that when all the threads are finished, I want a vector of size 5 and it must contain the result of execution of thread 1 at index 0, result of execution of thread 2 at index 1 ............ result of execution of thread 5 at index 4. I am cleanly visualize what I want to achieve but don't know the syntax for it.
Currently I just get 1 number in my vector.
import java.util.Random;
import java.util.Vector;
import java.util.concurrent.*;
public class App {
public static void main(String[] args) {
// TODO Auto-generated method stub
ExecutorService executor = Executors.newCachedThreadPool();
Future<Vector<Integer> > futureResult = null;
for(int i = 0; i < 5; i++){
futureResult = executor.submit(new Callable<Vector<Integer> >(){
#Override
public Vector<Integer> call() throws Exception {
Random random = new Random();
int duration = random.nextInt(4000);
Vector<Integer> v = new Vector<Integer>();
v.add(duration);
return v;
}
});
}
executor.shutdown();
try {
System.out.println(futureResult.get());
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
You're creating a new vector in every thread, without any connection with the shared memory. You could just pass the index to write on to every thread, and also change the vector to an array or something pre-allocated.
Another option would be to allocate the 5 vector positions and send every Integer object to its thread.