• Druid Json查询interval时间问题

    前天在使用Druid完成一个新项目时遇到了查询时间错误的问题。就是日志一直在往Druid里灌,但是查近一个小时的数据怎么也查不到。经检查,日志消费情况,时间戳的填充也都是没有问题的。后来尝试将查询起始时间往前推了1天,总算查到了数据(查询时间巨长)。而且根据查询结果中的一些时间字段来看,还是有最近一个小时的记录的。这说明我的查询json是OK的,问题出在时间上。 尝试调整了几次interval时间后,确定了要把查询起止时间往前推8个小时才能查到预期的结果。8 这个数字引起了我的注意——我们通常采用的北京时间就是东八区时区时间。是不是向Druid写入日志时,把时间戳给处理成0时区时间了。赶紧和Druid管理员沟通,确定了如我猜测:如果写入的时间是时间戳格式就会被处理成0时区UTC时间。 再说下解决方案。大体有仨: 调整Druid时区配置 我将日志中的时间戳(13位长整型毫秒值)改为格式化后的时间(如:2019-03-01 12:12:12)。 接受现状,查询时把时间往前推8小时 接受现状是不可能的,因为不符合个人美学。 其中第一个方案,我记得Druid官方文档是有说明的,这个应该可以改。(查了下官网,具体在JVM调优这一节)。但是不能指望运维改,毕竟在线服务都跑了好久了,贸然改了默认时区线上服务是要受影响的。 因此只剩第二个选项了。和运维沟通后,确认了虽然我之前写的是时间戳,但现在直接改成格式化后的时间也是OK的,只是会损失一些数据。最终定下了就采用这种方式。(今天试了下,不能直接改,之前写入的数据被丢弃了,运维重置了元数据才搞定) 其实还可以从其他方向考虑下,大概有两种: 第一种:使用Druid SQL来查询,查询时间仍然采用长整型时间戳,下面是一个范例: 另外使用Druid SQL查询时也可以在context中通过sqlTimeZone设置查询时区(知道有,但没试过)。 但是我不喜欢使用Druid SQL(有一点点性能的考虑)。PASS! 第二种:使用period Granularities,在查询时指定查询使用的时区。这个在官网有一个例子:Period Granularities。但是嫌繁琐,而且结果未必尽如人意,仍然PASS! 另外,这次我还开发了一些Druid JSON查询的工具类,如果有需要可以从GitHub拉取:zhyea / druid-explore 。代码中仅包括我现在用到的功能,后续用到了其他功能(如Filter)也会继续补充。 扯点儿闲白:这篇文我从早上就开始酝酿,但是先后出现了博客服务器问题,游戏晋级,零食,水果等种种阻碍,终于才能开始着手写,然后在半个多小时的时间内一气完成——但是完成时天色已全黑。再次感叹之前多次的感叹:小事开头难,大事坚持难。 END!!

    [阅读更多...]
  • Excel导出超过65535行报异常

    工程中在使用POI导出Excel数据,某次因为导出的数据量比较大就报了下面的错误: 查了下资料,了解到问题在于使用了HSSFWorkbook。HSSFWorkbook用来操作Excel2003以前(包括2003)的版本,限制了每个Sheet导出的行数至多为65535行。 要修复这个问题可以考虑使用XSSFWorkbook或者SXSSFWorkbook。如果要导出的数据量特别大,建议使用后者。因为XSSFWorkbook会将全部要写入Excel中的数据保存在内存中,数据量太大的话就会导致内存溢出错误。 SXSSFWorkbook是在POI3.8版本时出现的,对XSSFWorkbook做了一些优化,通过采用将一定数量的数据写入硬盘临时文件的机制减轻了内存的压力。 参考文档 HSSF XSSF SXSSF

    [阅读更多...]
  • SpringBoot读写xml上传到S3

    最近的工作涉及到了生成xml文件并上传到AWS存储服务S3这样的处理。期间遇到了两个问题,简单记录下: springboot读取xml模板异常 将生成的xml上传到S3的问题 springboot的版本是2.1.9.RELEASE,读写xml文件使用的是Dom4J,版本是2.1.3。逐个说明下遇到的这几个问题。 1.springboot读取xml模板异常 现阶段是将xml模板文件存储在springboot项目的resource目录下的。具体路径为 最初是通过类加载器获取文件路径后再尝试读取模板文件的: 通过类加器获取到的文件路径是: 不过我们都知道,springboot是将整个工程包括配置文件打成一个jar包后再直接运行。这样想在linux的服务器上通过文件路径找文件是注定找不到的。 后来改成直接通过SpringBoot提供的ClassResource类来获取resource路径下的配置文件: 这里直接使用InputStream读取的模板文件。注意不要再尝试通过调用ClassResource实例的getFile()方法来获取文件,不然会遇到和之前同样的问题。 额,期间还发生了无法将模板文件打进springboot项目运行时的jar文件这样的问题。因为是将模板文件存储在了resources的子目录下,需要调整下maven打包的配置: 下面这几行如果没有的话需要加上,不然会读取不到子目录中的配置文件: 2.将生成的xml上传到S3 AWS提供的最便捷的上传文件接口是这个: 这个接口通过File实例来执行上传。所以我一开始的想法是先生成一个临时文件保存在服务器本地,读取本地临时文件为File执行上传,最后再删掉本地的临时文件。这个思路是没问题的,在本地执行也OK。但是在生产环境,由于权限相关的问题,生成临时文件失败了。 不想再去折腾权限相关的事情,所以将出路寄托在了AWS提供的另一个接口上: 也就是说考虑将xml文件内容输出到InputStream,然后再将InputStream上传到S3。一切都在内存里执行,不依赖外部文件系统也就不会有文件权限的问题。 这个方案的问题在于ObjectMetaData这个类有点儿黑箱的意思。该怎么设置需要进行一些摸索。看了一遍这个类的接口文档,需要调用的也就这两个set方法: 其中后者(文件长度)是AWS建议设置的,不设置会在处理的时候给出WARN。根据方法文档也可以看到,如果不设置,在上传的时候就会在内存中缓存整个信息流来计算文件长度。 至于前者是上传到S3文件的缓存过期时间,酌情设置即可。 另一个需要解决的问题就是怎么将Dom4j生成的Document输出再读取到InputStream中。这里用到了XmlWritter类,具体实现如下: 验证了一下,这个方法是可行的。修改后生产环境没有再报错。 向AWS S3存储服务上传文件的实现代码在这篇文章里:Java实现上传文件到AWS S3 End!

    [阅读更多...]
  • JetBrains DataGrip的JavaFx错误提示及修复

    这两天(20200409)手欠升级了DataGrip(JetBrains的数据处理工具),没想到升级完成后一打开就报了下面的错误: Tried to use preview panel provider (JavaFX WebView), but it is unavailable. Reverting to default. 后来发现是markdown文档插件的问题。关键是这个Markdown插件是JetBrains官方提供的,没想到居然也会报错。 因为吃过一次类似的亏,所以后来注意到错误提示中的JavaFx字样后第一反应就是“是不是DataGrip嵌入的JRE升级到了JDK11”。 查看DataGrip的about信息,看到JDK版本是11.05。看样子就是这个问题了。 第一个思路是将JavaFx的相关依赖放到Markdown插件的lib目录下。去官网下载了JavaFx,解压后将lib目录下的jar文件放到Markdown插件的lib目录下,重启,继续报错。该方案失败! 第二个思路很直接,既然放在插件目录下不行,那就放到DataGrip的依赖目录下。这次尝试将JavaFx的jar放到DataGrip安装目录下的lib目录下。重启DataGrip,打开Markdown文件后没有报错,我一度以为我成功了,但是接下来就发现DataGrip卡死了。只好杀死进程,删除放到DataGrip安装路径lib目录下的JavaFx相关jar后再想其他办法。 第三个方案是在JetBrains社区找到的,是可行的。所以简要介绍下步骤: 安装插件Choose Runtime,重启DataGrip 在菜单栏中选择Help->Find Action(快捷键Ctrl+Shift+A)打开快捷窗口,在Actions选项卡下输入Choose Runtime,然后Enter调用ChooseRuntime插件 选择JRE,可以直接选择自己安装的JRE,也可以选择下载JetBrains提供的JRE并安装,完成后DataGrip会重启 重启后打开Markdown文件不再报错。问题得到解决。不过,美中不足的是发现打开的DataGrip多了一个难看的Windows标题栏。解决的方法也比较简单,换一个本机安装的JetBrains其它产品(比如IDEA或PyCharm)的嵌入JRE就可以了。 JetBrains也有提供独立的JRE,点击此处进行下载。 修改“idea.config.path\<product>.exe.jdk”文件也可以完成JRE的配置。 JetBrains嵌入的JRE在本机的地址为产品安装目录下的jbr目录,比如我机器上DataGrip嵌入的JRE路径如下: 就这样!End!

    [阅读更多...]
  • Gradle Refresh异常: Could not HEAD

    在idea中使用Gradle的时候遇到了一个奇怪的异常:获取公司内部repository中的包是正常的,但是获取jar源文件的时候却遇到了一些异常。 异常信息可以通过执行“Refresh All Gradle Projects”操作,在Gradle View中看到。 异常信息简略如下: 完整异常信息如下,我做了折叠: 根据异常信息可以看出,是访问公司库发生了异常。检查过repository的配置,用户名和密码都是正确的。后来想到公司的repository是 需要通过https访问的,可能是证书的问题。 找到repository的证书,将证书放到JAVA_HOME/jre/lib/security目录下,重启idea,再次执行“Refresh All Gradle Projects”可以看到不再报异常了。 #######

    [阅读更多...]
  • spark使用kafka报NoSuchMethodError

    运行spark任务消费kafka时,报了如下的异常: 使用的spark版本是1.6.1,kafka版本是0.8.2.1。 根据异常信息猜测应该是scala版本导致的问题。 查看了一下依赖的spark和kafka的配置为: 依赖项直接copy自mvnrepository网站。 使用gradle dependencies指令查看了依赖详情:kafka依赖的scala的版本是2.11.5,spark依赖的scala版本是2.11.6。而spark集群服务器部署的scala版本是2.11.8。 照说都是在2.11.*范围内,不应该报错的。 反复测试了几次之后忽然想到spark集群使用的scala版本也许不是2.11.8,也就是说spark集群的scala版本和服务器scala环境的版本也许不一致,我之前的意识是错误的。 需要测试一下,依稀有些印象可以使用2.10.4版本的scala进行编译,所以得先把依赖调整一下: kafka和spark依赖的name后面的数字,如“kafka_2.10”中的2.10指的是采用scala 2.10.*编译打包的。 打包上传后,测试通过,不再报那个异常了。 该如何确认spark集群使用的scala的版本呢。第一个思路是看spark集群lib目录下的依赖是不是会有相关的提示。看了一下比较失望: 就这么几个包,一点儿信息都没有。 不死心,用vi查看了一下。在spark-1.6.1-yarn-shuffle.jar的DEPENDENCIES文件中找到些许证明: 提示了spark-network-common_2.10是用scala 2.10编译的。 又查了一些资料,可以简单进行判断: 如果是spark1,用的scala版本通常是2.10,spark2则通常对应2.11版的scala。 就这样。 ########

    [阅读更多...]
  • Unsupported major.minor version

    又遇到了Unsupported major.minor version 52.0这个问题。很清楚这是编译打包时使用的jdk版本与运行环境jre版本不一致导致的。但是总是记不住具体的jdk版本与major version的对应关系。在这里记一下: Java SE 9 = 53 (0x35 hex),[3]Java SE 8 = 52 (0x34 hex),Java SE 7 = 51 (0x33 hex),Java SE 6.0 = 50 (0x32 hex),Java SE 5.0 = 49 (0x31 hex),JDK 1.4 = 48 (0x30 hex),JDK 1.3 = 47 (0x2F hex),JDK 1.2 = 46 (0x2E hex),JDK 1.1 = 45 (0x2D hex). 信息来自Wikipedia。 #######

    [阅读更多...]
  • hbase.fs.tmp.dir 导致的错误

    在执行BulkLoad的时候报了如下的错误: 使用的HBase版本是1.1.2. 从错误日志中可以看到导致这个问题的是HFileOutputFormat2类中的这一行: 关键是“hbase.fs.tmp.dir”这个配置信息。注意这个配置不是“hbase.tmp.dir”。“hbase.tmp.dir”是本地文件系统上的一个目录,“hbase.fs.tmp.dir”是HDFS上的一个目录。 在hbase-default.xml中找到的对应配置信息如下: 问题在于这个配置对应的目录并不存在,根据一些建议手动设置了下这个配置: 就这样,问题修复了。 下面是一些关于这个问题的讨论: Set default value for hbase.fs.tmp.dir rather than fully depend on hbase-default.xml Use HDFS for HFileOutputFormat2 partitioner’s path ############

    [阅读更多...]
  • 解决Gson 处理Map将整型处理为浮点型的问题

    gson一直是我用着非常得心应手的json处理工具。但是最近遇到了一个坑,就是在处理java.util.Map型json字符串的时候会把整型转为浮点型。 示例程序如下: 执行结果如下: 原因在于json的语法中关于数值只有一个number类型,而不会去判断这个number具体是整型是浮点型还是长整型。而Gson处理的时候也确实是偷懒了,统一将之视为浮点型。可以在Gson的ObjectTypeAdapter类中看到: 在case NUMBER这一行可以看到,数值型的数据都被处理为Double型的值。此外因为这里使用的Map的value类型是Object,在示例代码中就涉及到了Integer、Double和String。所以也不能使用TypeToken这样的解决方案。使用TypeToken的方式如下,适用于有明确的泛型说明的情况: 其它的解决方案也简单:1. 使用其他的json库,比如jackson和fastjson,亲测过,都没有这种问题;2. 添加自定义模块,修改这个问题。 详细说明下方案2。Gson支持添加自定义解析方案,可以使用GsonBuilder的registerTypeAdapter和registerTypeHierarchyAdapter。前者只针对设置的类进行序列化及反序列化,后者可以对设置的类及其子类进行序列化。可以添加的解析类的类型包括JsonSerializer、JsonDeserializer和TypeAdapter这三个接口的实现类。下面是一个使用自定义的JsonDeserializer方案: 这个方案也是有局限性的,只适用于Map的key和value都是数值型和字符串的情况(也可以添加对boolean的支持)。对于复杂的Map结构就有些无力了。 此外另一个方案是根据ObjectTypeAdapter自定义TypeAdapter。这个我也试过,功能支持还算可以,它解析json的方式是分层实现的。不过如果目标是具体类还可以,对于抽象类或接口的适用性就差一些。因为关键是json最外层的解析,如果是json对应的是对象的话,也就只能封装成一个目标类型对象或其超类对象。 先就这样。 #############

    [阅读更多...]
  • 需要class,interface或enum

    引入github上的一个项目后在编译时收到了“需要class,interface或enum”这样的错误。就像下图: 图片是我随便找的,不过错误是一样的。 这样的错误通常是由编码问题导致的,只需要修改文件编码或项目编码就可以了,然而随之而来的另一个问题就是代码中的中文可能会丢失。后来找的解决方案是这样的,在pom中指定项目编码: 还有就是在编译时指定编码格式,具体怎么做也忘了,请自行百度或谷歌吧。

    [阅读更多...]