/* * Copyright MapR Technologies, 2013 * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.mapr.franz; import com.google.protobuf.ServiceException; import com.googlecode.protobuf.pro.duplex.PeerInfo; import com.mapr.franz.catcher.Client; import com.mapr.franz.stats.History; import org.apache.mahout.common.RandomUtils; import org.apache.mahout.math.jet.random.Exponential; import org.apache.mahout.math.random.ChineseRestaurant; import org.kohsuke.args4j.CmdLineException; import org.kohsuke.args4j.CmdLineParser; import org.kohsuke.args4j.Option; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.util.Collections; import java.util.Random; /** * Generates traffic with strong peak rates for a variety of topics. */ public class Traffic { private static Logger log = LoggerFactory.getLogger(Traffic.class); public static void main(String[] args) throws InterruptedException, IOException, ServiceException { Options options = parseOptions(args); log.warn("Options = {}", options.toString()); double scale = Math.log(options.ratio) / 2; Client client = new Client(Collections.singleton(new PeerInfo(options.host, options.port))); History recorder = new History(1, 10, 30).logTicks(); Random gen = RandomUtils.getRandom(); ChineseRestaurant topicSampler = new ChineseRestaurant(options.alpha); Exponential interval = new Exponential(1, gen); double t = 0; long t0 = System.nanoTime(); long messageId = 0; while (messageId < options.max) { double rate = options.peak * Math.exp(-scale * (Math.cos(2 * Math.PI * t / options.period) + 1)); double dt = interval.nextDouble() / rate; t += dt; double now = (System.nanoTime() - t0) / 1e9; if (t > now + 0.01) { double millis = Math.floor((t - now) * 1000); double nanos = Math.rint((t - now) * 1e9 - millis * 1e6); Thread.sleep((long) millis, (int) nanos); } String topic = "topic-" + topicSampler.sample(); String message = "m-" + (++messageId); client.sendMessage(topic, message); recorder.message(topic); log.debug("Sent {} / {}", topic, message); if ((messageId % 10000) == 0) { log.warn("Sent {} messages", messageId); } } } private static Options parseOptions(String[] args) { Options opts = new Options(); CmdLineParser parser = new CmdLineParser(opts); try { parser.parseArgument(args); } catch (CmdLineException e) { e.printStackTrace(System.err); parser.printUsage(System.err); System.exit(1); } return opts; } private static class Options { @Option(name = "-host", required = true, usage = "Name of the catcher server host to connect to.") String host; @Option(name = "-port", usage = "Port for the catcher server") int port = 5900; @Option(name = "-peak", usage = "The peak rate for transactions summed across all topics. Current generator can only do about 5000 msg/s") double peak = 1000; @Option(name = "-ratio", usage = "The peak to valley ratio for transaction rate. Default is 5") double ratio = 5; @Option(name = "-period", usage = "The periodicity of the traffic waves expressed in seconds per wave. Default is 60s") double period = 60; @Option(name = "-alpha", usage = "The topic generator parameter. Bigger gives more topics. Default of 10 gives about 100 topics after about 100K messages") double alpha = 10; @Option(name = "-max", usage = "The maximum number of messages to send. Default is 1 thousand.") public long max = 1000000; @Override public String toString() { return "Options{" + "alpha=" + alpha + ", host='" + host + '\'' + ", port=" + port + ", peak=" + peak + ", ratio=" + ratio + ", period=" + period + ", max=" + max + '}'; } } }