在我们的每日离线数据同步任务中,需要将在线业务数据同步至离线 Hive 数仓,而离线数仓存储使用的阿里云 OSS,Spark 与 OSS 数据交互使用的连接器为 EMR-OSS。我们发现,有极低的概率会出现 SQL 执行卡住,大约几个月会出现一次,且因为问题都发生在凌晨,所以每次收到数据同步延迟告警时我都临时将对应 SQL 进行了 kill,然后手动对出错的表数据进行了校准并重新同步,然后白天使用相同的 SQL 尝试复现该问题时,一直未能复现该问题,我当时还写了个 for
循环生成不同大小的文件然后使用该连接器读取以尝试复现该异常,但是实在是太慢了,使用多线程跑了几天都没跑出一个能触发该异常的文件,而在上周的一个凌晨,问题又出现了,这一次,我保留了现场。
Debug Multithreaded Applications
在调试多线程应用程序时,有时我们需要暂停单独的线程而不是整个应用程序,此时在断点上可以设置 Suspend
为 Thread
,而不是默认的 All
。关于这两个选项的区别,在 Breakpoints | IntelliJ IDEA 中的说明如下:
The following policies are available for the breakpoints that suspend program execution:
- All: all threads are suspended when any of the threads hits the breakpoint.
- Thread: only the thread which hits the breakpoint is suspended.
References
IdentityHashMap
最近使用 ANTLR4 时看到其 ParseTreeProperty
类用到了 IdentityHashMap
,本文简要记录。
根据 IdentityHashMap
的 Java Doc 可知:
This class implements the Map interface with a hash table, using reference-equality in place of object-equality when comparing keys (and values). In other words, in an IdentityHashMap, two keys k1 and k2 are considered equal if and only if (k1==k2). (In normal Map implementations (like HashMap) two keys k1 and k2 are considered equal if and only if (k1==null ? k2==null : k1.equals(k2)).)
其与 HashMap
的最大不同为比较 key
时,IdentityHashMap
仅比较引用,而 HashMap
则是调用的 key
的 equals
方法进行比较,同时,文档中还提到:
A typical use of this class is topology-preserving object graph transformations, such as serialization or deep-copying.
Biased Locking
之前在 System.identityHashCode() 一文中我们知道,如果生成对象的 hashCode
时对象持有偏向锁,则会撤销该偏向锁。原因为对象默认的 hashCode
与偏向锁占用了对象头中的同一片区域,是不可以同时使用的。
对象头的格式可以参考 jdk/markOop.hpp at jdk8-b120 与 Dashboard - Lilliput - Main - OpenJDK Wiki。
关于偏向锁的实现原理可以参考:Dashboard - HotSpot - Main - Runtime - Synchronization - OpenJDK Wiki,其中提到了当生成对象的默认 hashCode
时,如果存在偏向锁,则会撤销偏向锁,原文如下:
The bias is also revoked when the identity hash code of an object is accessed since the hash code bits are shared with the thread ID.
值得注意的是自 JDK 15 开始,偏向锁已经被废弃了,具体原因可以参考:JEP 374: Deprecate and Disable Biased Locking,此处不再赘述。
System.identityHashCode()
之前在 Serializable 一文中简单提及了 Object.hashCode()
方法的实现,今天在看 IdentityHashMap
的源码时看到对 System.identityHashCode()
方法的调用,本文简要记录。
首先在 System.identityHashCode()
的 Java Doc 中有如下下说明:
Returns the same hash code for the given object as would be returned by the default method hashCode(), whether or not the given object’s class overrides hashCode(). The hash code for the null reference is zero.