YupDB权限模块可以通过sql的方式管理YupDB中数据的自由隔离灵活共享
在自定义权限模块的开发过程中,遇到了因为Spark ClassLoader引起的单例问题
环境 Hive On Spark
因为业务场景基于antlr 添加了部分hive解析逻辑 并添加了 相应的执行task 其中用到了 hive metastore中的derby连接
Derby数据库有两种运行模式:
1) 内嵌模式。Derby数据库与应用程序共享同一个JVM,通常由应用程序负责启动和停止,对除启动它的应用程序外的其它应用程序不可见,即其它应用程序不可访问它;
2) 网络模式。Derby数据库独占一个JVM,做为服务器上的一个独立进程运行。在这种模式下,允许有多个应用程序来访问同一个Derby数据库。
因为hive使用的是内嵌的方式,我们尝试使用hive本身的内嵌derby metastore做自定义的meta数据存储
在实际的使用过程中发现自定义的sql 触发执行插数据task的时候derby数据库出现重复连接的情况
在分析此问题前首先查看 hive on spark 对于各种类的加载方式
查看Hive 对于不同类的Class 加载方式
1.对于隔离类,采用defineClass 的方式拷贝原有类bytes重新定义类
2.对于非共享类,采用双亲委托极致委托给父类,也就是Spark中的MutableURLClassLoader加载
3.对于其它类,采用baseClassLoader加载
private[hive] val classLoader: MutableURLClassLoader = {
val isolatedClassLoader =
if (isolationOn) {
new URLClassLoader(allJars, rootClassLoader) {
override def loadClass(name: String, resolve: Boolean): Class[_] = {
val loaded = findLoadedClass(name)
if (loaded == null) doLoadClass(name, resolve) else loaded
}
def doLoadClass(name: String, resolve: Boolean): Class[_] = {
val classFileName = name.replaceAll("\\.", "/") + ".class"
if (isBarrierClass(name)) {
// For barrier classes, we construct a new copy of the class.
val bytes = IOUtils.toByteArray(baseClassLoader.getResourceAsStream(classFileName))
logDebug(s"custom defining: $name - ${util.Arrays.hashCode(bytes)}")
defineClass(name, bytes, 0, bytes.length)
} else if (!isSharedClass(name)) {
logDebug(s"hive class: $name - ${getResource(classToPath(name))}")
super.loadClass(name, resolve)
} else {
// For shared classes, we delegate to baseClassLoader.
logDebug(s"shared class: $name")
baseClassLoader.loadClass(name)
}
}
}
} else {
baseClassLoader
}
由于这种机制,在hive exec实际执行的过程中可能出现由于不同ClassLoader 加载相同类名类引起的多个Class实例存在的单例失效问题。
在这里Spark 提供了响应的conf key修改不同类的加载方式,通过derby所有的封装类都通过BaseClassLoader 加载的方式实现了单例