Spark运用与注意

原创 2018年04月17日 11:03:17

在java中Spark以main函数的方式运行spark程序,进行大数据读取、计算、统计与相关落盘操作。

遇到的问题与注意点:

  1. spark运行倾斜。

    数据分布不均匀,导致task数据运行时间差异过大,此种情况可以对数据集JavaRDD进行rePartition,rePartition支持自定义的分区方式,从而将数据更好地分布到不同的task中,进行均匀计算。

  2. mongo数据读取及写入过慢。

    采用hdfs落盘与读取可提高大数据读取效率,mongo使用过慢。

  3. SparkConf与SparkSession的紧密运用。

    SparkConf conf = new SparkConf().setAppName("SparkJob");
    conf.set("es.index.auto.create", "true")
          .set("es.nodes", esClusterInfo[1])
          .set("es.nodes.client.only", "true")
          .set("es.batch.write.retry.wait", "30s")
          .set("es.batch.size.bytes", "5mb")
          .set("es.port", Integer.toString(Constants.ES_WRITE_NODE_HTTP_PORT))
          .set("spark.executor.heartbeatInterval","30s");
    
    SparkSession ss = SparkSession.builder()
          .config(conf)
          .enableHiveSupport()
          .getOrCreate();
    
    final Logger logger = ss.log();
    

    SparkConf可以进行spark相关的配置,如spark连接ES、ES读写相关设置。SparkSession是spark快捷使用的上下文,设置Hive支持等,通过getOrCreate()进行获取。
    ss.log获取spark自带的log日志进行打印。

  4. 使用sql进行hive数据读取。

    hive数据的读取使用ss.sql(String sqlStr)进行读取,读取后为Row类型的Dataset数据集,可通过toJavaRDD转换为Java可识别的数据集类型,从而进行map、reduce等操作。

  5. map操作请使用mapPartitions进行分区遍历。

    mapPartitions,设置分区数据,分区内可使用局部变量与频繁创建的对象,避免资源浪费。注意分区数据大小,小心OOM。

  6. Dataset与JavaRDD有很多实用性方法。

    Dataset与JavaRDD可以互相转化。
    Dataset.toJavaRDD();
    Dataset = SparkSession.createDataset(JavaRDD.rdd(), Encoders.bean(T.class));

    Dataset有很多统计方法,如groupBy、max等,可以组合操作。
    JavaRDD有很多mapReduce方法,如filter、map、mapPartition等。

  7. gson设置时间格式化与时区问题。

    在应用过程中发现,由于大数据机器时区不同导致gson序列化时间出现类似8小时差异。
    解决办法采用gson的序列化器与反序列化器,时间格式化时区设置。

    public class DateDeserializer implements JsonDeserializer<Date> {
    
        private static final Logger logger = LoggerFactory.getLogger(DateDeserializer.class);
    
        @Override
        public Date deserialize(JsonElement element, Type arg1, JsonDeserializationContext arg2) throws JsonParseException {
    
            String date = element.getAsString();
    
            SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
            formatter.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
    
            try {
                return formatter.parse(date);
            } catch (ParseException e) {
                logger.error("日期转化出现错误!",e);
                return null;
            }
        }
    }
    
    public class DateSerializer implements JsonSerializer<Date> {
    
    private static final Logger logger = LoggerFactory.getLogger(DateSerializer.class);
    
    @Override
    public JsonElement serialize(Date date, Type typeOfSrc, JsonSerializationContext context) {
    
        if(date==null){
            return null;
        }
    
        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
        formatter.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
    
        return new JsonPrimitive(formatter.format(date));
    
        }
    }
    
    private static DateSerializer dateSerializer = new DateSerializer();
    private static DateDeserializer dateDeserializer = new DateDeserializer();
    
    private static Gson gson = new GsonBuilder().registerTypeAdapter(Date.class, dateSerializer).registerTypeAdapter(Date.class, dateDeserializer).create();
    

    设置GsonBuilder进行类型适配器设置,设置特定时间格式序列化的方式。

  8. ES与spark进行协作。

    JavaEsSpark.saveJsonToEs(JavaRDD, resouceUrlStr, ImmutableMap.of("es.mapping.id", Constants.ES_GOODS_INDEX_ID_NAME));
    

    第一个入参为数据集,第二个为es中数据库表地址,第三个为特别设置项,如选定某一个key作为ES数据的id。
    JavaEsSpark为spark为ES及java选定的ES操作工具,相关配置信息如esNode等都以spark中的config为准,如SparkConfig设置的信息。

  9. ES连接方式,分为HTTP与TCP两种。

    新的ES版本主要支持TCP的客户端方式,使用TransportClient进行操作。

    try {
        logger.info("ES连接初始化TransportClient...,clusterFlag:["+clusterFlag+"]。");
        //设置集群名称
        Settings settings = Settings.builder().put("cluster.name", clusterName).put("transport.type","netty3").build();
        //创建client
        transportClient  = new PreBuiltTransportClient(settings);
        String esIps[] = esServerIps.split(Constants.ES_WRITE_NODE_IPS_SPLIT);
        for (String esIp : esIps) {
            TransportAddress transportAddress =  new InetSocketTransportAddress(InetAddresses.forString(esIp),Constants.ES_WRITE_NODE_TCP_PORT);
            transportClient.addTransportAddresses(transportAddress);
        }
        logger.info("ES连接初始化TransportClient...success");
    }catch (Exception e){
        logger.error("ES连接初始化TransportClient...fail", e);
        throw e;
    }
    
  10. spark读取文件与数据。

    JavaSparkContext javaSparkContext = new JavaSparkContext(ss.sparkContext());
    JavaRDD<T> = javaSparkContext.objectFile(hdfsUrlStr);
    JavaRDD<String> = javaSparkContext.textFile(hdfsUrlStr);
    

    两种文件读取方式,支持对象序列化与json序列化。

spark 写 ElasticSearch 提升性能解决方案

ES 官网提供了一套Spark写ES接口 参见 : https://www.elastic.co/guide/en/elasticsearch/hadoop/current/spark.html在...
  • zhixingheyi_tian
  • zhixingheyi_tian
  • 2017-08-30 10:18:18
  • 790

Spark 与 Elasticsearch交互的一些配置和问题解决

java.lang.NoClassDefFoundError: scala/collection/GenTraversableOnce$class问题解决 Spark Elasticsearch交互...
  • dlj2324
  • dlj2324
  • 2017-04-20 11:23:36
  • 4917

使用spark与ElasticSearch交互

因为业务需求将数据从es中导出写入到hdfs需要elasticsearch-hadoop的依赖,自行添加sbt或mvn依赖,也可直接下载jar使用,链接在下方。 elasticsearch-hado...
  • lsshlsw
  • lsshlsw
  • 2015-10-09 21:57:11
  • 18099

memcpy使用注意点

memcpy使用注意点:void *memcpy( void *dest, const void *src, size_t count ); 1. 确保dest 和 src指向的内存区域至少包含 co...
  • zhangxiuyuan
  • zhangxiuyuan
  • 2009-07-05 18:12:00
  • 1634

Spark编程注意事项

SimpleDateFormat我们使用spark做数据处理最频繁使用的就是simpleDateFormat来转化日期格式,在实践中发现,sdf总是莫名其妙的出现错误,例如:“java.lang.Nu...
  • wzq294328238
  • wzq294328238
  • 2015-08-31 13:38:50
  • 974

Spark写ES的遇到的坑

由于项目需要,最近搞Spark Streaming做数据分析,并最终将分析完的数据写入ElasticSearch。我们项目使用的是Spark 2.1.0,而我们公司的ElasticSearch版本使用...
  • u013709270
  • u013709270
  • 2017-04-11 20:31:50
  • 6008

spark2.0 TransportClient

/** * Client for fetching consecutive chunks of a pre-negotiated stream. This API is intended to al...
  • houzhizhen
  • houzhizhen
  • 2016-11-15 14:44:19
  • 481

一个Spark缓存的使用示例

之前一直不是非常理解Spark的缓存应该如何使用 今天在使用的时候, 为了提高性能, 尝试使用了一下Cache, 并收到了明显的效果之前一直不是非常理解Spark的缓存应该如何使用. 今天在使用的时候...
  • chenyulancn
  • chenyulancn
  • 2018-03-07 16:39:42
  • 79

memcpy 函数需要注意的事项

memcpy 函数需要注意的事项
  • pyjfoot
  • pyjfoot
  • 2012-10-15 10:23:05
  • 746

Spark通过https的方式读取elasticsearch中的数据

为了安全起见,es中配置了https访问方式,但是spark读取es中的数据的时候是通过普通的http的方式访问的,现在读取的话肯定报错,找了一圈,上代码 val conf=new Spar...
  • u012940753
  • u012940753
  • 2016-12-13 16:54:36
  • 2433
收藏助手
不良信息举报
您举报文章:Spark运用与注意
举报原因:
原因补充:

(最多只允许输入30个字)