• 大数据入门第十八天——kafka整合flume、storm


    一、实时业务指标分析

      1.业务

      业务:
        订单系统---->MQ---->Kakfa--->Storm
        数据:订单编号、订单时间、支付编号、支付时间、商品编号、商家名称、商品价格、优惠价格、支付金额

        统计双十一当前的订单金额,订单数量,订单人数
        订单金额(整个网站,各个业务线,各个品类,各个店铺,各个品牌,每个商品

      架构

    支付系统+kafka+storm/Jstorm集群+redis集群
    1、支付系统发送mq到kafka集群中,编写storm程序消费kafka的数据并计算实时的订单数量、订单数量
    2、将计算的实时结果保存在redis中
    3、外部程序访问redis进群中的数据实时展示结果

      流程

    1、Spout获取外部数据源,数据源是订单的mq,mq有固定的格式,比如json串。
    2、对订单mq进行解析,得到一个对象->JavaBean
            订单编号、订单时间、支付编号、支付时间、商品编号、商家名称、商品价格、优惠价格、支付金额
    3、对指标进行计数
            //业务中一个订单包含多个商品,需要对每个商品进行指标计算
            //创建订单和取消订单两种类型,在计算总数据的是考虑将取消订单的金额减掉
            //订单中有拆单的逻辑,该如何计算
    4、保存指标数据到Redis

      2.整合flume思路

       flume官网也是对应的kafka的sink配置与讲解http://flume.apache.org/FlumeUserGuide.html#kafka-sink

        (网上的一些例如brokelist等配置已经被标记为deprecated,请参照官网的最新属性配置)

     将采集的日志文件保存到kafka中
      (source) 输入:tail -F xxxx.log
      (channel)存储:内存
      (sink) 输出:kafka

    config
      al.source = s1
      a1.channel = c1
      al.sink = k1
    
      source ==> exec tail -F xxxx.log
      channel ==> RAM
      sink ====> xxx.xxxx.xxxx.KafkaSink //该类必须存放lib目录
      sink.topic = orderMq
      sink.itcast = itcast

       // 实例参照下文

    二、整合flume

      1.编写flume配置文件

    a1.sources = s1                                                                                                                  
    a1.channels = c1                                                                                                                 
    a1.sinks = k1                                                                                                                    
                                                                                                                                          
    a1.sources.s1.type=exec                                                                                                          
    a1.sources.s1.command=tail -F /home/hadoop/kafka.log                                                                                
    a1.sources.s1.channels=c1                                                                                                        
    a1.channels.c1.type=memory                                                                                                       
    a1.channels.c1.capacity=10000                                                                                                    
    a1.channels.c1.transactionCapacity=100                                                                                           
                                                                                                                                          
    #设置Kafka接收器                                                                                                                    
    a1.sinks.k1.type= org.apache.flume.sink.kafka.KafkaSink                                                                          
    #设置Kafka的broker地址和端口号                                                                                                      
    a1.sinks.k1.brokerList=mini1:9092                                                                                               
    #设置Kafka的Topic                                                                                                                   
    a1.sinks.k1.topic=topic_1                                                                                                      
    #设置序列化方式                                                                                                                     
    a1.sinks.k1.serializer.class=kafka.serializer.StringEncoder                                                                                                                                                                                                    
    a1.sinks.k1.channel=c1 

      2.开启需要的zk以及kafka服务

    [hadoop@mini1 conf]$ start-zk.sh 
    [hadoop@mini1 conf]$ start-kafka.sh 

      // 以上两个均以编写一键启动脚本,详情参考相关篇章随笔

      启动flume:

    bin/flume-ng agent -c conf -f conf/tail-kafka.conf -n a1  -Dflume.root.logger=INFO,console

      启动消费者查看效果:

    bin/kafka-console-consumer.sh --zookeeper mini1:2181 --from-beginning --topic topic_1

      之前都是直接复制命令而不关心参数,通过官网查看可以发现查看完整参数的方法为:(网上找的基本都是这个常用参数的格式)

    All of the command line tools have additional options; running the command with no arguments will display usage information documenting them in more detail.

      这样就说明sink到了kafka了!

    三、整合storm

      1.maven依赖

        storm整合kafka需要一个中间的依赖Jar

    <!-- https://mvnrepository.com/artifact/org.apache.storm/storm-kafka -->
    <dependency>
        <groupId>org.apache.storm</groupId>
        <artifactId>storm-kafka</artifactId>
        <version>0.9.5</version>
    </dependency>

        这里指出,storm入门中使用的storm的包,应当替换为阿里的更加强大的JStorm:

    <!-- https://mvnrepository.com/artifact/com.alibaba.jstorm/jstorm-core -->
            <dependency>
                <groupId>com.alibaba.jstorm</groupId>
                <artifactId>jstorm-core</artifactId>
                <version>2.1.1</version>
                <!--<scope>provided</scope>-->
            </dependency>

        其他相关依赖如下:

     <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.36</version>
            </dependency>
            <!-- https://mvnrepository.com/artifact/redis.clients/jedis -->
            <dependency>
                <groupId>redis.clients</groupId>
                <artifactId>jedis</artifactId>
                <version>2.7.3</version>
            </dependency>

      这样,将数据提前导入redis以后,就可以写出一个demo版本的代码了:(注意MyBolt#exector()方法中需要手动调用collection.ack()进行应答)

    package kafkaAndStorm;
    
    
    import backtype.storm.Config;
    import backtype.storm.LocalCluster;
    import backtype.storm.StormSubmitter;
    import backtype.storm.topology.TopologyBuilder;
    import storm.kafka.KafkaSpout;
    import storm.kafka.SpoutConfig;
    import storm.kafka.ZkHosts;
    
    public class KafkaAndStormTopologyMain {
        public static void main(String[] args) throws Exception{
            TopologyBuilder topologyBuilder = new TopologyBuilder();
            topologyBuilder.setSpout("kafkaSpout",
                    new KafkaSpout(new SpoutConfig(
                            new ZkHosts("zk01:2181,zk02:2181,zk03:2181"),
                            "orderMq",
                            "/myKafka",
                            "kafkaSpout")),1);
            topologyBuilder.setBolt("mybolt1",new ParserOrderMqBolt(),1).shuffleGrouping("kafkaSpout");
    
            Config config = new Config();
            config.setNumWorkers(1);
    
            //3、提交任务  -----两种模式 本地模式和集群模式
            if (args.length>0) {
                StormSubmitter.submitTopology(args[0], config, topologyBuilder.createTopology());
            }else {
                LocalCluster localCluster = new LocalCluster();
                localCluster.submitTopology("storm2kafka", config, topologyBuilder.createTopology());
            }
        }
    }
    KafkaAndStormTopologyMain
    package kafkaAndStorm;
    
    import backtype.storm.task.OutputCollector;
    import backtype.storm.task.TopologyContext;
    import backtype.storm.topology.OutputFieldsDeclarer;
    import backtype.storm.topology.base.BaseRichBolt;
    import backtype.storm.tuple.Tuple;
    import com.google.gson.Gson;
    import order.OrderInfo;
    import redis.clients.jedis.Jedis;
    import redis.clients.jedis.JedisPool;
    import redis.clients.jedis.JedisPoolConfig;
    
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * Created by maoxiangyi on 2016/5/4.
     */
    public class ParserOrderMqBolt extends BaseRichBolt {
        private JedisPool pool;
        @Override
        public void prepare(Map stormConf, TopologyContext context, OutputCollector collector) {
            //change "maxActive" -> "maxTotal" and "maxWait" -> "maxWaitMillis" in all examples
            JedisPoolConfig config = new JedisPoolConfig();
            //控制一个pool最多有多少个状态为idle(空闲的)的jedis实例。
            config.setMaxIdle(5);
            //控制一个pool可分配多少个jedis实例,通过pool.getResource()来获取;
            //如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。
            //在borrow一个jedis实例时,是否提前进行validate操作;如果为true,则得到的jedis实例均是可用的;
            config.setMaxTotal(1000 * 100);
            //表示当borrow(引入)一个jedis实例时,最大的等待时间,如果超过等待时间,则直接抛出JedisConnectionException;
            config.setMaxWaitMillis(30);
            config.setTestOnBorrow(true);
            config.setTestOnReturn(true);
            /**
             *如果你遇到 java.net.SocketTimeoutException: Read timed out exception的异常信息
             *请尝试在构造JedisPool的时候设置自己的超时值. JedisPool默认的超时时间是2秒(单位毫秒)
             */
            pool = new JedisPool(config, "127.0.0.1", 6379);
        }
    
        @Override
        public void execute(Tuple input) {
            Jedis jedis = pool.getResource();
            //获取kafkaSpout发送过来的数据,是一个json
            String string = new String((byte[]) input.getValue(0));
            //解析json
            OrderInfo orderInfo = (OrderInfo) new  Gson().fromJson(string, OrderInfo.class);
            //整个网站,各个业务线,各个品类,各个店铺,各个品牌,每个商品
            //获取整个网站的金额统计指标
    //        String totalAmount =  jedis.get("totalAmount");
            jedis.incrBy("totalAmount",orderInfo.getProductPrice());
            //获取商品所属业务线的指标信息
            String bid =  getBubyProductId(orderInfo.getProductId(),"b");
    //        String bAmout =  jedis.get(bid+"Amout");
            jedis.incrBy(bid+"Amount",orderInfo.getProductPrice());
            jedis.close();
        }
    
        private String getBubyProductId(String productId,String type) {
    //        key:value
            //index:productID:info---->Map
            //  productId-----<各个业务线,各个品类,各个店铺,各个品牌,每个商品>
            Map<String,String> map =  new HashMap<>();
            map.put("b","3c");
            map.put("c","phone");
            map.put("s","121");
            map.put("p","iphone");
            return map.get(type);
        }
    
        @Override
        public void declareOutputFields(OutputFieldsDeclarer declarer) {
    
        }
    }
    ParserOrderMqBolt

      有关redis的章节,参考redis随笔http://www.cnblogs.com/jiangbei/p/7255994.html

  • 相关阅读:
    我理解的 js 异步成长总结
    小程序 获取地理位置-- wx.getLocation
    H5页面在微信端的分享
    ES6 我的总结学习
    5 分钟掌握 JS 实用窍门技巧,帮你快速撸码--- 删除数组尾部元素、E6对象解构、async/await、 操作平铺嵌套多维数组等
    小程序 video 层级,原生组件
    React 事件 传参
    微信小程序中如何使用setData --- 修改数组对象、修改对象
    流氓式--小程序用户授权 --- 小程序授权、获取用户信息
    深度学习的反向传播笔记
  • 原文地址:https://www.cnblogs.com/jiangbei/p/8550605.html
Copyright © 2020-2023  润新知