【问题标题】:Websphere MQ as a data source for Apache Spark StreamingWebsphere MQ 作为 Apache Spark Streaming 的数据源
【发布时间】:2015-08-06 17:03:58
【问题描述】:

我正在研究将 Websphere MQ 作为 spark-streaming 的数据源的可能性,因为在我们的一个用例中需要它。 我知道MQTT 是支持来自 MQ 数据结构的通信的协议,但由于我是触发流式传输的新手,我需要一些相同的工作示例。 有没有人尝试将 MQ 与火花流连接。请为此设计最佳方式。

【问题讨论】:

  • 投票结束,因为它不符合 Stack Overflow 的问题指南。我建议在 mqseries.net 或其他在线 MQ 论坛之一上询问这些广泛的架构和可行性问题。
  • 我认为这可能只是一个措辞问题。而不是模糊的“我正在研究这件事。最好的解决方案是什么?” 你可以问一个直接的问题。 “如何通过 Apache Spark 从 Websphere MQ 读取数据?” 如果您对问题的 Websphere MQ 方面有更多了解,您可以添加更多相关信息。它支持 SQL 吗?你一般是怎么查询的?它有哪些客户?那么了解 Spark 的人可能会为您提供帮助。

标签: apache-spark ibm-mq spark-streaming


【解决方案1】:

相信你可以使用JMS来连接Websphere MQ,而Apache Camel可以用来连接Websphere MQ。您可以像这样创建自定义接收器(请注意,此模式也可以在没有 JMS 的情况下使用):

class JMSReceiver(topicName: String, cf: String, jndiProviderURL: String)
  extends Receiver[String](StorageLevel.MEMORY_AND_DISK_SER) with Serializable  {
  //Transient as this will get passed to the Workers from the Driver
  @transient
  var camelContextOption: Option[DefaultCamelContext] = None

  def onStart() = {
    camelContextOption = Some(new DefaultCamelContext())
    val camelContext = camelContextOption.get
    val env = new Properties()
    env.setProperty("java.naming.factory.initial", "???")
    env.setProperty("java.naming.provider.url", jndiProviderURL)
    env.setProperty("com.webmethods.jms.clientIDSharing", "true")
    val namingContext = new InitialContext(env);  //using the properties file to create context

    //Lookup Connection Factory
    val connectionFactory = namingContext.lookup(cf).asInstanceOf[javax.jms.ConnectionFactory]
    camelContext.addComponent("jms", JmsComponent.jmsComponentAutoAcknowledge(connectionFactory))

    val builder = new RouteBuilder() {
        def configure() = {
          from(s"jms://topic:$topicName?jmsMessageType=Object&clientId=$clientId&durableSubscriptionName=${topicName}_SparkDurable&maxConcurrentConsumers=10")
            .process(new Processor() {
            def process(exchange: Exchange) = {
              exchange.getIn.getBody match {
                case s: String => store(s)
              }
            }
          })
        }
      }
    }
    builders.foreach(camelContext.addRoutes)
    camelContext.start()
  }

  def onStop() = if(camelContextOption.isDefined) camelContextOption.get.stop()
}

然后您可以像这样创建事件的 DStream:

val myDStream = ssc.receiverStream(new JMSReceiver("MyTopic", "MyContextFactory", "MyJNDI"))

【讨论】:

  • 答案对我很有用,但我正在寻找将结果写回 Websphere MQ。有人可以为它提供解决方案。谢谢
  • 嗨@DarshanManek - 我认为你应该问一个新问题,或者搜索那个答案。它与接收器部分完全不同。
【解决方案2】:

所以,我在这里发布了用于连接 Websphere MQ 并读取数据的 CustomMQReceiver 的工作代码:

public class CustomMQReciever extends Receiver<String> { String host = null;
int port = -1;
String qm=null;
String qn=null;
String channel=null;
transient Gson gson=new Gson();
transient MQQueueConnection qCon= null;

Enumeration enumeration =null;

public CustomMQReciever(String host , int port, String qm, String channel, String qn) {
    super(StorageLevel.MEMORY_ONLY_2());
    this.host = host;
    this.port = port;
    this.qm=qm;
    this.qn=qn;
    this.channel=channel;

}

public void onStart() {
    // Start the thread that receives data over a connection
    new Thread()  {
        @Override public void run() {
            try {
                initConnection();
                receive();
            }
            catch (JMSException ex)
            {
                ex.printStackTrace();
            }
        }
    }.start();
}
public void onStop() {
    // There is nothing much to do as the thread calling receive()
    // is designed to stop by itself isStopped() returns false
}

 /** Create a MQ connection and receive data until receiver is stopped */
private void receive() {
  System.out.print("Started receiving messages from MQ");

    try {

    JMSMessage receivedMessage= null;

        while (!isStopped() && enumeration.hasMoreElements() )
        {

            receivedMessage= (JMSMessage) enumeration.nextElement();
            String userInput = convertStreamToString(receivedMessage);
            //System.out.println("Received data :'" + userInput + "'");
            store(userInput);
        }

        // Restart in an attempt to connect again when server is active again
        //restart("Trying to connect again");

        stop("No More Messages To read !");
        qCon.close();
        System.out.println("Queue Connection is Closed");

    }
    catch(Exception e)
    {
        e.printStackTrace();
        restart("Trying to connect again");
    }
    catch(Throwable t) {
        // restart if there is any other error
        restart("Error receiving data", t);
    }
    }

  public void initConnection() throws JMSException
{
    MQQueueConnectionFactory conFactory= new MQQueueConnectionFactory();
    conFactory.setHostName(host);
    conFactory.setPort(port);
    conFactory.setTransportType(JMSC.MQJMS_TP_CLIENT_MQ_TCPIP);
    conFactory.setQueueManager(qm);
    conFactory.setChannel(channel);


    qCon= (MQQueueConnection) conFactory.createQueueConnection();
    MQQueueSession qSession=(MQQueueSession) qCon.createQueueSession(false, 1);
    MQQueue queue=(MQQueue) qSession.createQueue(qn);
    MQQueueBrowser browser = (MQQueueBrowser) qSession.createBrowser(queue);
    qCon.start();

    enumeration= browser.getEnumeration();
   }

 @Override
public StorageLevel storageLevel() {
    return StorageLevel.MEMORY_ONLY_2();
}
}

【讨论】:

  • 我已经实现了相同的,但目前只有一个执行者正在使用该消息。您知道让多个执行程序并行使用消息的任何方法吗?以及您如何管理故障场景?如果流媒体应用间歇性停止,您有什么方法不会丢失消息?
  • @sparker 我认为在基于接收器的方法中,您有一个接收器,然后创建多个执行器来并行处理接收到的数据。如果您想要真正的并行度,那么我会选择 Spark+Kafka 的无接收器(直接)方法。故障处理可以在常规检查点的帮助下在火花流中完成。
猜你喜欢
  • 2016-05-07
  • 2019-07-03
  • 2018-02-10
  • 2021-05-22
  • 1970-01-01
  • 2018-01-29
  • 1970-01-01
  • 2012-03-08
  • 1970-01-01
相关资源
最近更新 更多