将eucalyptus数据库更改为Mysql

简介
项目中用到了eucalyptus的东西,在eucalyptus中,数据库采用的是hsqldb,一种轻量级的小型数据库,eucalyptu将其紧密地集成在系统当中。若是从外部访问eucalyptus数据信息,感觉颇为不便。故考虑将eucalyptu的数据库从hsqldb迁移到mysql中。这样的话,从外部可以很方便地访问需要的信息。下面介绍更改的过程,如有需要可以参考。

相关文件介绍
 eucalyptus中,访问数据库的部分采用了hibernate的封装,由hibernate屏蔽了底层数据库的差异性,因而在由hsqldb迁移到mysql中,无需对系统作出大的改动即可迁移成功。
在eucalyptu中,与数据库配置以及初始化相关的文件有:

1 clc/modules/database/conf/scripts/before_database.groovy
2 clc/modules/database/conf/scripts/after_database.groovy
3 clc/modules/database/conf/scripts/pools.groovy
4 clc/modules/database/conf/scripts/caches.groovy

上述的四个groovy文件是关于eucalyptu使用的数据库的初始化脚本,以及关于hibernate的配置,线程池的一些配置优化。
clc/modules/database/src/main/java/com/eucalyptus/bootstrap/LocalDatabaseBootstrapper.java
该文件是Database的的初始化过程,在其中通过调用上述的四个脚本文件完成eucalyptus的数据库的初始化操作,并且启动数据库服务。其服务的基本启动过程与其它eucalyptus服务启动类似,必须实现一些统一的Bootstrapper接口。
clc/modules/database/src/main/java/com/eucalyptus/bootstrap/DatabaseConfig.java
该文件是原始hsqldb数据库服务的基本配置,包括端口、数据库文件等。如果更换成mysql后,该文件没有存在的必要,可以删掉。
clc/modules/hsqldb/src/main/resources/com.eucalyptus.CloudServiceProvider
eucalyptus是以组件的形式,也就是component的方式连接建立起来的,上述文件就是关于db component的配置,其中有component的一些服务port和url等信息。比如此处要修改的数据库服务信息等。
clc/modules/core/src/main/java/com/eucalyptus/bootstrap/RemoteDatabaseBootstrapper.java
该文件不知道要作何用,但是其中有关于数据库密码的一些信息,直接设置到了eucalyptus运行环境的property中。这个property在pools.groovy中有用到,用于设置一些关于hibernate的信息,因而也需要对该文件进行一些简单的处理。

数据库初始化过程
上边是一些要用到可能需要修改的文件,在eucalyptus中,数据库的初始化过程简单介绍如下,基于自己理解,可能会有错误。clc/modules/msgs/src/main/java/com/eucalyptus/bootstrap/Bootstrap.java,这是clc java部分引导启动之后的第一个实例。执行component的初始化过程,初始化过程包括eucalyptus的服务的发现、加载、启动,各个component的初始化,配置文件的加载,其中包括LocalDatabaseBootstrapper服务,也就是在此处,对clc/modules/hsqldb/src/main/resources/com.eucalyptus.CloudServiceProvider的资源文件进行加载处理,并对component db做了初始化处理,其中包括db的url初始化,这是一个比较关键的信息。也只有在该url被完成之后,后续的hibernate对数据库进行初始化才可以进行。
在db component初始化完成后,剩余的将会交给hibernate进行数据库的初始化操作了。对数据库的初始化操作,主要集中在clc/modules/database/src/main/java/com/eucalyptus/bootstrap/LocalDatabaseBootstrapper.java,在bootstrapper中,对数据库的操作主要集中在load中的createDatabase,也就是在其中,执行上述的before_database.groovy、after_database.groovy,在脚本中完成对数据库的操作。

用到的基本原理
基于上述的一些服务启动过程解释,也就是只需要修改上述的一些文件就可以了。这其中需要了解的一些原理包括hibernate的annotation,groovy的lamba表达式,向groovy中变量参数的传递,数据库的连接池配置,hibernate连接数据库的property配置,mysql创建数据库的规则。此处不再赘述。可以通过详细的更改迁移过程了解。

具体改动过程
下面介绍具体实施中的改动过程:
具体的更改详细过程如下:
1、对com.eucalyptus.CloudServiceProvider进行更改配置

name=db 表示对应的component
euca.model.dns=db-model.xml 貌似是mule使用的xml配置文件
euca.model.dns.services=db-services.xml 貌似是mule使用的xml配置文件
euca.url.local=//127.0.0.1:3306/eucalyptus mysql数据库的url配置
euca.url.pattern=//%s:%d/eucalyptus url的匹配模式
euca.url.port=3306 mysql的默认端口
此处更改的文件在clc/modules/hsqldb/src/main/resources/com.eucalyptus.CloudServiceProvider

2、更改LocalDatabaseBootstrapper的实现
修改借口的实现包括start、run。在该类的实现中,主要是删除一些不必要的功能。
修改的文件在clc/modules/database/src/main/java/com/eucalyptus/bootstrap/LocalDatabaseBootstrapper.java

3、修改初始化groovy脚本
有一部分是直接借用于原来的脚本,并对此作出了部分更改。

下面是before_database.groovy脚本,先在mysql中创建好数据库

import com.eucalyptus.system.SubDirectory;
import com.eucalyptus.entities.PersistenceContexts;
import com.eucalyptus.bootstrap.Component;
import com.eucalyptus.util.*;

//init the db setting
//set the mysql char set to utf8
config ="default-character-set=utf8\ndefault-collation=utf8"
//此处是关于mysql的数据库初始化的一些基本配置,此处将其设置为utf8
//此处经过测试汉语不会出现乱码
//create the db file name create the new db file
//through the anonation from the db
Runtime runtime = null;
try
{
runtime = Runtime. getRuntime();
}
catch(Exception e)
{
e.printStackTrace();
System.exit(1)
}
//获取运行时用于更改创建的文件夹权限,以便mysql有权限进行读写操作
//此处采用的是执行linux命令的方式,java内部的api目前无法实现该功能
//此处是hibernate通过java的annotation获取到需要建立的数据库信息以及表的信息
//具体可以参考clc/modules/msgs/arc/main/java/com/eucalyptus/entities中的具体实现文件
PersistenceContexts.list( ).each{ context_name ->
db = new File("${SubDirectory.DB.toString()}/${context_name}");
opt = new File("${SubDirectory.DB.toString()}/${context_name}/db.opt");
//the db not exist create the db
if( !db.exists() ) {
db.mkdir();
//the mysql db.opt conf not exist
if( !opt.exists() ) {
opt.write(config);
}
//在mysql数据库中,创建一个空的数据库的一个简便方法就是在mysql的data文件夹下
//创建对应的数据库名字的文件夹即可,在该文件夹下的db.opt主要是用于配置该数据库的
//一些编码规则,规则比较简单,此处将编码配置为utf8
command = "chmod 777 -R " + "${SubDirectory.DB.toString()}/${context_name}";
try
{
runtime. exec(command);
//change the eucalyptus db file permission to mysql
}
catch(Exception e)
{
e.printStackTrace();
System.exit(1)
}
//在创建完成后,这些文件权限是755,属于eucalyptus用户所有
//mysql根本没有权限进行写入,会造成后期的table创建错误
//因此需要将权限开放给mysql用户
}
}




after_database.groovy脚本,完成对数据库中table表的创建

import com.eucalyptus.entities.PersistenceContexts;
import org.hibernate.ejb.*
import com.eucalyptus.util.*
import edu.ucsb.eucalyptus.cloud.ws.*;
//conf hibernate
//这是hibernate的一些property配置
hiber_config = [
'hibernate.archive.autodetection': 'jar, class, hbm',
'hibernate.show_sql': 'false',
'hibernate.format_sql': 'false',
'hibernate.connection.autocommit': 'true',
'hibernate.hbm2ddl.auto': 'update',
'hibernate.generate_statistics': 'true',
]

contexts = PersistenceContexts.list( );//list the db
//上述的contexts是数据库名列表,在before_database.groovy中已经使用过,
//列出的数据库已经创建完成了
//下面就是创建数据库中表的过程

contexts.each { String ctxName ->
String it = ctxName.replaceAll("eucalyptus_","")
pool_config = new pools(new Binding([context_name:it])).run()
//设置对应的数据库连接池
//正常情况下,每一个数据库对应一个独立的url
//比如eucalyptus_auth和eucalyptus_general分别对应的url是:
////127.0.0.1:3306/eucalyptus_auth”和“//127.0.0.1:3306/eucalyptus_general”
//通过传入pool.groovy中的 context_name进行对应连接池中url的设置

cache_config = new caches(new Binding([context_name:it])).run()
//这是hibernate的缓存设置,没有特别特殊的地方

config = new Ejb3Configuration();
LogUtil.logHeader( "Hibernate for ${ctxName}" ).log(hiber_config.inspect())
hiber_config.each { k, v -> config.setProperty(k, v) }
LogUtil.logHeader( "Pool for ${ctxName}").log( pool_config.inspect() )
pool_config.each { k, v -> config.setProperty(k, v) }
LogUtil.logHeader( "Cache for ${ctxName}").log( cache_config )
cache_config.each { k, v -> config.setProperty(k, v) }
entity_list = PersistenceContexts.listEntities( ctxName )
LogUtil.logHeader("Entities for ${ctxName}")
entity_list.each{ ent ->
LogUtil.log( ent.toString() )
config.addAnnotatedClass( ent )
}
//获取数据库所包含的表,此处通过annotation标记,只需知道对应table的类就可以
try {
PersistenceContexts.registerPersistenceContext("${ctxName}", config)
//注册table,并进行table的创建
} catch( Throwable t ) {
t.printStackTrace();
System.exit(1)
}
}



关于pools.groovy,主要就是上边提到的连接代理的问题,更改后的代码如下:

import com.eucalyptus.bootstrap.Component;
import org.logicalcobwebs.proxool.ProxoolFacade;
import com.eucalyptus.util.LogUtil;
//set hibernate username and passwd

db_pass = System.getProperty("euca.db.password")!=null && System.getProperty("euca.db.password").length()>1 ? System.getProperty("euca.db.password") : "123456";
//此处连接用的用户名暂设为root,密码为“123456”
ClassLoader.getSystemClassLoader().loadClass('org.logicalcobwebs.proxool.ProxoolDriver');
poolProps = [
'proxool.simultaneous-build-throttle': '16',
'proxool.minimum-connection-count': '16',
'proxool.maximum-connection-count': '128',
'proxool.house-keeping-test-sql': 'SELECT * FROM COUNTERS;',
'user': 'root',
'password': db_pass,
]

//set hibernate pool conf
p = new Properties();
p.putAll(poolProps)
String dbDriver = 'com.mysql.jdbc.Driver';

//set the proxool url
//just like mysql url jdbc:mysql://localhost:3306/db_name

String url = "proxool.eucalyptus_${context_name}:${dbDriver}:jdbc:mysql:${Component.db.uri.toASCIIString( )}_${context_name}";

//此处用到了db component的url信息
//context_name pass from after_database
LogUtil.logHeader( "Proxool config for ${context_name}" ).log( url ).log( poolProps )
ProxoolFacade.registerConnectionPool(url, p);

[
'hibernate.bytecode.use_reflection_optimizer': 'true',
'hibernate.cglib.use_reflection_optimizer': 'true',
'hibernate.dialect': 'org.hibernate.dialect.MySQLDialect',
'hibernate.connection.provider_class': 'org.hibernate.connection.ProxoolConnectionProvider',
'hibernate.proxool.pool_alias': "eucalyptus_${context_name}",
'hibernate.proxool.existing_pool': 'true'
]

4、RemoteDatabaseBootstrapper 的修改
在 RemoteDatabaseBootstrapper中,在服务加载的过程中,设置了eucalyptus的"euca.db.password"property,此处设置的password在pool中需要用到,并且为了扩展需要,密码也需要在mysql中进行设置,故没有在此处设置属性,只是在clc/modules/core/src/main/java/com/eucalyptus/bootstrap/RemoteDatabaseBootstrapper.java的81行,去掉了该设置语句。

5、添加必需的mysql jdbc包
由于连接mysql需要的对应的jdbc包,因而在clc的lib下添加了mysql-connector-java-5.1.18-bin.jar包,此包可以在mysql的官网下载.
6、修改eucalyptus中的euca_conf中的一些关于用户id的一些获取方法。也就是通过读数据库而已,比较简单。


 

更改后需要进行的系统配置:
1、首先配置mysql的 datadir和 max_connections
mysql的数据目录配置,在/etc/my.cnf文件中

    [mysqld]
datadir=/$EUCALYPTUS/eucalyptus/db
socket=/var/lib/mysql/mysql.sock
user=mysql
max_connections = 200

在eucalyptus首次安装后,进行自动化配置时,需要将 datadir的目录设置到eucalyptus的db目录下;同时 max_connections也必须设置,默认为101,但是在eucalyptus的连接池中配置为126,如果不进行修改,会造成数据库无法连接读取,出现异常。
2、配置mysql后,重新启动mysql数据库
/etc/init.d/mysqld restart
以将mysql的数据文件定位到设置好的目录下
3、设置mysql的用户名和密码
目前暂时用的是root:123456,密码可以通过 mysqladmin -u root password "123456",将其设置为 123456,当然密码也可以设置为其它,但是应当与/$EUCALYPTUS/etc/eucalyptus/cloud.d/scripts/pools.groovy中的密码相匹配。
但是这仅限于初次mysql的密码设置。
4、mysql重新启动后,修改eucalyptus的db目录权限
chmod 777 /$EUCALYPTUS/eucalyptus/db

 由于mysql服务重新启动后,会将db的权限更改为755,并且db文件夹属于mysql。如果不进行权限设置,在eucalyptus初次启动时没有权限向该文件夹下写数据。
至此eucalyptus的初始化配置已经基本完成,并且mysql或是eucalyptus的重启不会再有文件权限的困扰。当然,这些还需要更多环境的测试。
如果删除了db下的数据库文件,并且mysql重新启动过,则需要进行上述步骤4的操作。
如果eucalyptus进行重装,则基本配置过程同上述类似。


 

经过上边的过程,已经基本算是完结了。由于linux用户权限的问题,在使用的过程中上述的更改可能会造成使用不便。如果需要的话,可以考虑将db数据库目录与eucalyptus单独分开来,这样就不会有用户权限的困扰了。

上述的过程已经经过测试,并且可用。有需要的朋友可以参考下。

posted on 2012-01-13 23:08  hanxiangduo  阅读(590)  评论(1编辑  收藏  举报

导航