项目的缓存中用到了rocksdb,实例化时报错了:
Related cause:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.beans.factory.config.MethodInvokingFactoryBean#1' defined in class path resource [spring-core.xml]: Cannot resolve reference to bean 'milletContext' while setting bean property 'arguments' with key [0]; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'milletContext' defined in class path resource [spring-core.xml]: Invocation of init method failed; nested exception is java.lang.UnsatisfiedLinkError: C:\Users\Administrator\AppData\Local\Temp\librocksdbjni3696928169151614297.dll: �
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:359)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveManagedList(BeanDefinitionValueResolver.java:382)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:157)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1531)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1276)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getTypeForFactoryBean(AbstractBeanFactory.java:1508)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.getTypeForFactoryBean(AbstractAutowireCapableBeanFactory.java:816)
at org.springframework.beans.factory.support.AbstractBeanFactory.isTypeMatch(AbstractBeanFactory.java:558)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:432)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:403)
at org.springframework.beans.factory.BeanFactoryUtils.beanNamesForTypeIncludingAncestors(BeanFactoryUtils.java:220)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1267)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1101)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1066)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:585)
at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:761)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543)
at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:443)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:325)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:107)
at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4745)
at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5207)
at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:752)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:728)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:734)
at org.apache.catalina.startup.HostConfig.deployDirectory(HostConfig.java:1144)
at org.apache.catalina.startup.HostConfig$DeployDirectory.run(HostConfig.java:1878)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'milletContext' defined in class path resource [spring-core.xml]: Invocation of init method failed; nested exception is java.lang.UnsatisfiedLinkError: C:\Users\Administrator\AppData\Local\Temp\librocksdbjni3696928169151614297.dll: �
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1628)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:555)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:351)
... 48 more
Caused by: java.lang.UnsatisfiedLinkError: C:\Users\Administrator\AppData\Local\Temp\librocksdbjni3696928169151614297.dll: �
at java.lang.ClassLoader$NativeLibrary.load(Native Method)
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1941)
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1824)
at java.lang.Runtime.load0(Runtime.java:809)
at java.lang.System.load(System.java:1086)
at org.rocksdb.NativeLibraryLoader.loadLibraryFromJar(NativeLibraryLoader.java:78)
at org.rocksdb.NativeLibraryLoader.loadLibrary(NativeLibraryLoader.java:56)
at org.rocksdb.RocksDB.loadLibrary(RocksDB.java:64)
at org.rocksdb.RocksDB.<clinit>(RocksDB.java:35)
at org.rocksdb.Options.<clinit>(Options.java:25)
at cn.migu.millet.common.CacheStorage.open(CacheStorage.java:31)
at cn.migu.millet.MilletContext.init(MilletContext.java:169)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(AbstractAutowireCapableBeanFactory.java:1758)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1695)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1624)
... 55 more
问题现象:类加载失败引起的一系列后续问题:类找不到、实例加载失败、容器加载失败。
问题定位:代码跟踪
public static CacheStorage open(String path) {
try (final Options options = new Options()) {
options.setCreateIfMissing(true);
try {
return new CacheStorage(RocksDB.open(options, path));
} catch (RocksDBException e) {
logger.error("open cache db error, path={}, e={}", path, e.getMessage());
return null;
}
}
}
public class Options extends RocksObject
implements DBOptionsInterface<Options>, ColumnFamilyOptionsInterface<Options>,
MutableColumnFamilyOptionsInterface<Options> {
static {
RocksDB.loadLibrary();
}
进入到RocksDB类,实例化rocksDB,先读取是否已加载标志位,没加载过才会去加载:
/**
* Loads the necessary library files.
* Calling this method twice will have no effect.
* By default the method extracts the shared library for loading at
* java.io.tmpdir, however, you can override this temporary location by
* setting the environment variable ROCKSDB_SHAREDLIB_DIR.
*/
public static void loadLibrary() {
if (libraryLoaded.get() == LibraryState.LOADED) {
return;
} if (libraryLoaded.compareAndSet(LibraryState.NOT_LOADED,
LibraryState.LOADING)) {
final String tmpDir = System.getenv("ROCKSDB_SHAREDLIB_DIR");
// loading possibly necessary libraries.
for (final CompressionType compressionType : CompressionType.values()) {
try {
if (compressionType.getLibraryName() != null) {
System.loadLibrary(compressionType.getLibraryName());
}
} catch (UnsatisfiedLinkError e) {
// since it may be optional, we ignore its loading failure here.
}
}
try {
NativeLibraryLoader.getInstance().loadLibrary(tmpDir);
} catch (IOException e) {
libraryLoaded.set(LibraryState.NOT_LOADED);
throw new RuntimeException("Unable to load the RocksDB shared library"
+ e);
} libraryLoaded.set(LibraryState.LOADED);
return;
} while (libraryLoaded.get() == LibraryState.LOADING) {
try {
Thread.sleep(10);
} catch(final InterruptedException e) {
//ignore
}
}
}
注意一点,临时目录是从环境变量ROCKSDB_SHAREDLIB_DIR读取的,所以可以通过设置该环境变量改变临时目录路径(日志里的C:\Users\Administrator\AppData\Local\Temp\librocksdbjni3696928169151614297.dll)。接着进入到NativeLibraryLoader看RocksDB的实例化详情:
/**
* Firstly attempts to load the library from <i>java.library.path</i>,
* if that fails then it falls back to extracting
* the library from the classpath
* {@link org.rocksdb.NativeLibraryLoader#loadLibraryFromJar(java.lang.String)}
*
* @param tmpDir A temporary directory to use
* to copy the native library to when loading from the classpath.
* If null, or the empty string, we rely on Java's
* {@link java.io.File#createTempFile(String, String)}
* function to provide a temporary location.
* The temporary file will be registered for deletion
* on exit.
*
* @throws java.io.IOException if a filesystem operation fails.
*/
public synchronized void loadLibrary(final String tmpDir) throws IOException {
try {
System.loadLibrary(sharedLibraryName);
} catch(final UnsatisfiedLinkError ule1) {
try {
System.loadLibrary(jniLibraryName);
} catch(final UnsatisfiedLinkError ule2) {
loadLibraryFromJar(tmpDir);
}
}
} /**
* Attempts to extract the native RocksDB library
* from the classpath and load it
*
* @param tmpDir A temporary directory to use
* to copy the native library to. If null,
* or the empty string, we rely on Java's
* {@link java.io.File#createTempFile(String, String)}
* function to provide a temporary location.
* The temporary file will be registered for deletion
* on exit.
*
* @throws java.io.IOException if a filesystem operation fails.
*/
void loadLibraryFromJar(final String tmpDir)
throws IOException {
if (!initialized) {
System.load(loadLibraryFromJarToTemp(tmpDir).getAbsolutePath());
initialized = true;
}
} File loadLibraryFromJarToTemp(final String tmpDir)
throws IOException {
final File temp;
if (tmpDir == null || tmpDir.isEmpty()) {
temp = File.createTempFile(tempFilePrefix, tempFileSuffix);
} else {
temp = new File(tmpDir, jniLibraryFileName);
if (temp.exists() && !temp.delete()) {
throw new RuntimeException("File: " + temp.getAbsolutePath()
+ " already exists and cannot be removed.");
}
if (!temp.createNewFile()) {
throw new RuntimeException("File: " + temp.getAbsolutePath()
+ " could not be created.");
}
} if (!temp.exists()) {
throw new RuntimeException("File " + temp.getAbsolutePath() + " does not exist.");
} else {
temp.deleteOnExit();
} // attempt to copy the library from the Jar file to the temp destination
try (final InputStream is = getClass().getClassLoader().
getResourceAsStream(jniLibraryFileName)) {
if (is == null) {
throw new RuntimeException(jniLibraryFileName + " was not found inside JAR.");
} else {
Files.copy(is, temp.toPath(), StandardCopyOption.REPLACE_EXISTING);
}
} return temp;
}
先从sharedLibraryName(rocksdbjni)实例化,再从jniLibraryName(rocksdbjni-win64)实例化,最后从临时目录实例化。第一步是从JDK环境变量(即java.library.path,本机是D:\Dev\Java\jdk1.8.0_102\jre\bin)加载rocksdbjni,失败再从类路径加载rocksdbjni-win64,最后从本地临时目录加载librocksdbjni-win64.dll。这三部曲是rocksDB实例化的精髓。而最后一步是最复杂的,需要创建一个临时文件,然后从rocksdbjni这个jar包中把librocksdbjni-win64.dll复制到本地C:\Users\Administrator\AppData\Local\Temp\librocksdbjni3696928169151614297.dll,最后用org.rocksdb.NativeLibraryLoader这个类加载器来加载librocksdbjni3696928169151614297.dll得到rocksdb的实例,然后把这个DLL文件加入到加载类库中,后续容器重复加载时无需再次复制DLL文件。
上面的三部曲都需要利用java.lang包的工具来进行类加载,用的到类有System、Runtime和ClassLoader:
/**
* Loads the native library specified by the filename argument. The filename
* argument must be an absolute path name.
*
* If the filename argument, when stripped of any platform-specific library
* prefix, path, and file extension, indicates a library whose name is,
* for example, L, and a native library called L is statically linked
* with the VM, then the JNI_OnLoad_L function exported by the library
* is invoked rather than attempting to load a dynamic library.
* A filename matching the argument does not have to exist in the
* file system.
* See the JNI Specification for more details.
*
* Otherwise, the filename argument is mapped to a native library image in
* an implementation-dependent manner.
*
* <p>
* The call <code>System.load(name)</code> is effectively equivalent
* to the call:
* <blockquote><pre>
* Runtime.getRuntime().load(name)
* </pre></blockquote>
*
* @param filename the file to load.
* @exception SecurityException if a security manager exists and its
* <code>checkLink</code> method doesn't allow
* loading of the specified dynamic library
* @exception UnsatisfiedLinkError if either the filename is not an
* absolute path name, the native library is not statically
* linked with the VM, or the library cannot be mapped to
* a native library image by the host system.
* @exception NullPointerException if <code>filename</code> is
* <code>null</code>
* @see java.lang.Runtime#load(java.lang.String)
* @see java.lang.SecurityManager#checkLink(java.lang.String)
*/
@CallerSensitive
public static void load(String filename) {
Runtime.getRuntime().load0(Reflection.getCallerClass(), filename);
}
/**
* Loads the native library specified by the filename argument. The filename
* argument must be an absolute path name.
* (for example
* <code>Runtime.getRuntime().load("/home/avh/lib/libX11.so");</code>).
*
* If the filename argument, when stripped of any platform-specific library
* prefix, path, and file extension, indicates a library whose name is,
* for example, L, and a native library called L is statically linked
* with the VM, then the JNI_OnLoad_L function exported by the library
* is invoked rather than attempting to load a dynamic library.
* A filename matching the argument does not have to exist in the file
* system. See the JNI Specification for more details.
*
* Otherwise, the filename argument is mapped to a native library image in
* an implementation-dependent manner.
* <p>
* First, if there is a security manager, its <code>checkLink</code>
* method is called with the <code>filename</code> as its argument.
* This may result in a security exception.
* <p>
* This is similar to the method {@link #loadLibrary(String)}, but it
* accepts a general file name as an argument rather than just a library
* name, allowing any file of native code to be loaded.
* <p>
* The method {@link System#load(String)} is the conventional and
* convenient means of invoking this method.
*
* @param filename the file to load.
* @exception SecurityException if a security manager exists and its
* <code>checkLink</code> method doesn't allow
* loading of the specified dynamic library
* @exception UnsatisfiedLinkError if either the filename is not an
* absolute path name, the native library is not statically
* linked with the VM, or the library cannot be mapped to
* a native library image by the host system.
* @exception NullPointerException if <code>filename</code> is
* <code>null</code>
* @see java.lang.Runtime#getRuntime()
* @see java.lang.SecurityException
* @see java.lang.SecurityManager#checkLink(java.lang.String)
*/
@CallerSensitive
public void load(String filename) {
load0(Reflection.getCallerClass(), filename);
} synchronized void load0(Class<?> fromClass, String filename) {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkLink(filename);
}
if (!(new File(filename).isAbsolute())) {
throw new UnsatisfiedLinkError(
"Expecting an absolute path of the library: " + filename);
}
ClassLoader.loadLibrary(fromClass, filename, true);
}
// Invoked in the java.lang.Runtime class to implement load and loadLibrary.
static void loadLibrary(Class<?> fromClass, String name,
boolean isAbsolute) {
ClassLoader loader =
(fromClass == null) ? null : fromClass.getClassLoader();
if (sys_paths == null) {
usr_paths = initializePath("java.library.path");
sys_paths = initializePath("sun.boot.library.path");
}
if (isAbsolute) {
if (loadLibrary0(fromClass, new File(name))) {
return;
}
throw new UnsatisfiedLinkError("Can't load library: " + name);
}
if (loader != null) {
String libfilename = loader.findLibrary(name);
if (libfilename != null) {
File libfile = new File(libfilename);
if (!libfile.isAbsolute()) {
throw new UnsatisfiedLinkError(
"ClassLoader.findLibrary failed to return an absolute path: " + libfilename);
}
if (loadLibrary0(fromClass, libfile)) {
return;
}
throw new UnsatisfiedLinkError("Can't load " + libfilename);
}
}
for (int i = 0 ; i < sys_paths.length ; i++) {
File libfile = new File(sys_paths[i], System.mapLibraryName(name));
if (loadLibrary0(fromClass, libfile)) {
return;
}
libfile = ClassLoaderHelper.mapAlternativeName(libfile);
if (libfile != null && loadLibrary0(fromClass, libfile)) {
return;
}
}
if (loader != null) {
for (int i = 0 ; i < usr_paths.length ; i++) {
File libfile = new File(usr_paths[i],
System.mapLibraryName(name));
if (loadLibrary0(fromClass, libfile)) {
return;
}
libfile = ClassLoaderHelper.mapAlternativeName(libfile);
if (libfile != null && loadLibrary0(fromClass, libfile)) {
return;
}
}
}
// Oops, it failed
throw new UnsatisfiedLinkError("no " + name + " in java.library.path");
}
private static boolean loadLibrary0(Class<?> fromClass, final File file) {
// Check to see if we're attempting to access a static library
String name = findBuiltinLib(file.getName());
boolean isBuiltin = (name != null);
if (!isBuiltin) {
boolean exists = AccessController.doPrivileged(
new PrivilegedAction<Object>() {
public Object run() {
return file.exists() ? Boolean.TRUE : null;
}})
!= null;
if (!exists) {
return false;
}
try {
name = file.getCanonicalPath();
} catch (IOException e) {
return false;
}
}
ClassLoader loader =
(fromClass == null) ? null : fromClass.getClassLoader();
Vector<NativeLibrary> libs =
loader != null ? loader.nativeLibraries : systemNativeLibraries;
synchronized (libs) {
int size = libs.size();
for (int i = 0; i < size; i++) {
NativeLibrary lib = libs.elementAt(i);
if (name.equals(lib.name)) {
return true;
}
} synchronized (loadedLibraryNames) {
if (loadedLibraryNames.contains(name)) {
throw new UnsatisfiedLinkError
("Native Library " +
name +
" already loaded in another classloader");
}
/* If the library is being loaded (must be by the same thread,
* because Runtime.load and Runtime.loadLibrary are
* synchronous). The reason is can occur is that the JNI_OnLoad
* function can cause another loadLibrary invocation.
*
* Thus we can use a static stack to hold the list of libraries
* we are loading.
*
* If there is a pending load operation for the library, we
* immediately return success; otherwise, we raise
* UnsatisfiedLinkError.
*/
int n = nativeLibraryContext.size();
for (int i = 0; i < n; i++) {
NativeLibrary lib = nativeLibraryContext.elementAt(i);
if (name.equals(lib.name)) {
if (loader == lib.fromClass.getClassLoader()) {
return true;
} else {
throw new UnsatisfiedLinkError
("Native Library " +
name +
" is being loaded in another classloader");
}
}
}
NativeLibrary lib = new NativeLibrary(fromClass, name, isBuiltin);
nativeLibraryContext.push(lib);
try {
lib.load(name, isBuiltin);
} finally {
nativeLibraryContext.pop();
}
if (lib.loaded) {
loadedLibraryNames.addElement(name);
libs.addElement(lib);
return true;
}
return false;
}
}
}
这里拿三部曲最后一部举例说明下:参数fromClass就是调用System.load方法所在的类,这里是rocksDB的加载库类org.rocksdb.NativeLibraryLoader,另一个参数File就是C:\Users\Administrator\AppData\Local\Temp\librocksdbjni3696928169151614297.dll,从NativeLibraryLoader类加载librocksdbjni5581206381055061043.dll后,把这个DLL文件放入loadedLibraryNames这个Vector,后续重复加载直接从该Vector取,无需再从rocksdbjni的jar包中复制DLL文件。
跟踪到这里,问题代码已经浮出水面:
lib.load(name, isBuiltin);
这个load方法是ClassLoader类的内部类NativeLibrary的原生方法,动态链接库加载就是从这里进入DLL文件里具体加载方法的
native void load(String name, boolean isBuiltin);
从这个load出来就是UnsatisfiedLinkError。所以问题的焦点转移到了DLL文件本身,用Dependency Walker打开一看,有错误提示:
Error: Modules with different CPU types were found.
继续跟进,发现其中一个文件叫IEShims.dll显示是X86,而我本机是X64的。替换该文件,Dependency Walker不再报错,但跑代码发现依然报错。
问题解决:捕获rockdbs异常,记录日志,跳过,继续启动加载spring容器。该DLL的加载涉及太多因素,无法一一排查,只能吃掉异常来规避,rocksdb加载失败对主业务无太大影响。