eucalyptus volume 的一些创建流程以及理解

目前eucalyptus中,数据的共享的逻辑卷采用aoe http://www.txrjy.com/baike/view.asp?ATA%20over%20Ethernet, http://support.coraid.com/support/linux/,
和iscsi, http://baike.baidu.com/view/120148.htm.目前在我们的测试机中使用的是iscsi,进行逻辑卷的共享设置.
在这些逻辑卷的实际测试使用中,在将卷绑定到虚拟机时,有时候会不够稳定,使卷无法绑定到虚拟机,或者是一个卷可以被多个虚拟机绑定,主要有以下三种情况:
1、connect_iscsi_target failed
这是由于iscsi的目标卷处于iactive状态,导致nc端在向目标卷发起连接登录的时候,无法连接,从而导致绑定失败.
但是目前这种错误难以重现.推测是sc服务重启后,卷处于iactive状态,而没有对目标卷进行激活处理.
具体查看目标机上的逻辑卷状态可以通过lvscan http://linux.die.net/man/8/lvscan进行查看,vgscan http://linux.die.net/man/8/vgscan查看逻辑卷组.
clc端的错误日志: 下面日志表明.clc在attachvolume时,收到了结果为空的返回值.

15:57:38 DEBUG [NioResponseHandler:cluster223-Worker-7] :1315900658432:NioResponseHandler:MSG_AWAIT_RESPONSE:MSG_POLL_INTERNAL:100:QueuedEventCallback.waitForResponse.354
15:57:38 DEBUG [NioResponseHandler:cluster223-Worker-7] :1315900658536:NioResponseHandler:MSG_AWAIT_RESPONSE:MSG_POLL_INTERNAL:100:QueuedEventCallback.waitForResponse.354
15:57:38 TRACE [QueuedEventCallback:New I/O client worker #2-12] <?xml version="1.0" encoding="UTF-8"?>
<euca:AttachVolumeResponseType xmlns:euca="http://msgs.eucalyptus.com">
<euca:BlockVolumeMessage>
<euca:EucalyptusMessage>
<euca:userId>admin</euca:userId>
<euca:_return>false</euca:_return>
<euca:statusMessage>ERROR</euca:statusMessage>
</euca:EucalyptusMessage>
</euca:BlockVolumeMessage>
<euca:attachedVolume>
<euca:attachTime>2011-09-13T07:57:38.565Z</euca:attachTime>
</euca:attachedVolume>
</euca:AttachVolumeResponseType>
15:57:38 DEBUG [VolumeAttachCallback:New I/O client worker #2-12]
<?xml version="1.0" encoding="UTF-8"?>
<AttachVolume xmlns="http://eucalyptus.ucsb.edu/">
<correlationId>cda55cc8-197d-4d3c-8382-24e7789930cb</correlationId>
<userId>admin</userId>
<return>true</return>
<volumeId>vol-5DE1063D</volumeId>
<instanceId>i-426E075E</instanceId>
<remoteDev>//,192.168.5.223,iqn.2009-06.com.eucalyptus.cluster223:store3,KiErKVk7UC7vt6ZU12vd5ZUKgZJkZmG5cDZBVcbverPe2Tsp0DxAdWiWdhqhO6orpz36XWN1+/EvBoLzY+pQ0V19cWzBN17WLxOeoLv0zgq4p0hm22zdjJA/kWWD1ME2WnMDTAFe8dbFqyo8DrBO/ywFMBlxmZ7X/hzQb5YdHKAtTe0mOpxNqPgNg8rnrjI/MrQqA7xtUCybEcMlVFekLxwQpR5+UDlilZy2H4V1euzZtgAFkzzVIRsYJ+Hgg3H6f2DfCG+QbblAlLCPjdSi5+oozE/iDrNa+swwazKOXY7/jVCzK5KbM2vnRnuL7GgyHQBxr7KI27Lw/N/HAYLP9w==</remoteDev>
<localDev>/dev/sdb</localDev>
</AttachVolume>

--------------------------------------------------------------------------------
15:57:38 DEBUG [VolumeAttachCallback:New I/O client worker #2-12] com.eucalyptus.util.EucalyptusClusterException: [AttachVolumeResponseType attachedVolume=AttachedVolume null null null null null Tue Sep 13 15:57:38 CST 2011 correlationId=null userId=admin effectiveUserId=null _return=false statusMessage=ERROR]
com.eucalyptus.util.EucalyptusClusterException: [AttachVolumeResponseType attachedVolume=AttachedVolume null null null null null Tue Sep 13 15:57:38 CST 2011 correlationId=null userId=admin effectiveUserId=null _return=false statusMessage=ERROR]

cc端的错误日志: cc端在向nc端发送添加逻辑卷指令时,nc端反馈出了一个错误信息.

[Tue Sep 13 15:59:55 2011][003491][EUCADEBUG ] AttachVolume(): params: userId=admin, volumeId=vol-5DE1063D, instanceId=i-426E075E, remoteDev=//,192.168.5.223,iqn.2009-06.com.eucalyptus.cluster223:store3,KiErKVk7UC7vt6ZU12vd5ZUKgZJkZmG5cDZBVcbverPe2Tsp0DxAdWiWdhqhO6orpz36XWN1+/EvBoLzY+pQ0V19cWzBN17WLxOeoLv0zgq4p0hm22zdjJA/kWWD1ME2WnMDTAFe8dbFqyo8DrBO/ywFMBlxmZ7X/hzQb5YdHKAtTe0mOpxNqPgNg8rnrjI/MrQqA7xtUCybEcMlVFekLxwQpR5+UDlilZy2H4V1euzZtgAFkzzVIRsYJ+Hgg3H6f2DfCG+QbblAlLCPjdSi5+oozE/iDrNa+swwazKOXY7/jVCzK5KbM2vnRnuL7GgyHQBxr7KI27Lw/N/HAYLP9w==, localDev=/dev/sdb
[Tue Sep 13 15:59:55 2011][003491][EUCADEBUG ] find_instanceCache(): found instance in cache 'i-426E075E/192.168.5.245/192.168.138.67'
[Tue Sep 13 15:59:55 2011][003491][EUCADEBUG ] ncClientCall(ncAttachVolume): called ncURL=http://192.168.5.45:8775/axis2/services/EucalyptusNC timeout=20
[Tue Sep 13 15:59:55 2011][007546][EUCADEBUG ] DEBUG: requested URI http://192.168.5.45:8775/axis2/services/EucalyptusNC
[Tue Sep 13 15:59:55 2011][007546][EUCADEBUG ] ncClientCall(ncAttachVolume): ppid=3491 client calling 'ncAttachVolume'
[Tue Sep 13 15:59:56 2011][007546][EUCAERROR ] ERROR: AttachVolume returned an error
nc端的错误日志: nc在向目标卷发起连接时,出现错误,连接失败从而在附加卷时出错.最终错误层层上达到clc端,造成在绑定卷时失败.
[Tue Sep 13 16:06:03 2011][029948][EUCAINFO ] doAttachVolume() invoked (id=i-426E075E vol=vol-5DE1063D remote=//,192.168.5.223,iqn.2009-06.com.eucalyptus.cluster223:store3,KiErKVk7UC7vt6ZU12vd5ZUKgZJkZmG5cDZBVcbverPe2Tsp0DxAdWiWdhqhO6orpz36XWN1+/EvBoLzY+pQ0V19cWzBN17WLxOeoLv0zgq4p0hm22zdjJA/kWWD1ME2WnMDTAFe8dbFqyo8DrBO/ywFMBlxmZ7X/hzQb5YdHKAtTe0mOpxNqPgNg8rnrjI/MrQqA7xtUCybEcMlVFekLxwQpR5+UDlilZy2H4V1euzZtgAFkzzVIRsYJ+Hgg3H6f2DfCG+QbblAlLCPjdSi5+oozE/iDrNa+swwazKOXY7/jVCzK5KbM2vnRnuL7GgyHQBxr7KI27Lw/N/HAYLP9w== local=/dev/sdb)
[Tue Sep 13 16:06:03 2011][029948][EUCAINFO ] connect_iscsi_target invoked (dev_string=//,192.168.5.223,iqn.2009-06.com.eucalyptus.cluster223:store3,KiErKVk7UC7vt6ZU12vd5ZUKgZJkZmG5cDZBVcbverPe2Tsp0DxAdWiWdhqhO6orpz36XWN1+/EvBoLzY+pQ0V19cWzBN17WLxOeoLv0zgq4p0hm22zdjJA/kWWD1ME2WnMDTAFe8dbFqyo8DrBO/ywFMBlxmZ7X/hzQb5YdHKAtTe0mOpxNqPgNg8rnrjI/MrQqA7xtUCybEcMlVFekLxwQpR5+UDlilZy2H4V1euzZtgAFkzzVIRsYJ+Hgg3H6f2DfCG+QbblAlLCPjdSi5+oozE/iDrNa+swwazKOXY7/jVCzK5KbM2vnRnuL7GgyHQBxr7KI27Lw/N/HAYLP9w==)
[Tue Sep 13 16:06:03 2011][029948][EUCADEBUG ] system_output(): [//usr/lib/eucalyptus/euca_rootwrap //usr/share/eucalyptus/connect_iscsitarget.pl //,192.168.5.223,iqn.2009-06.com.eucalyptus.cluster223:store3,KiErKVk7UC7vt6ZU12vd5ZUKgZJkZmG5cDZBVcbverPe2Tsp0DxAdWiWdhqhO6orpz36XWN1+/EvBoLzY+pQ0V19cWzBN17WLxOeoLv0zgq4p0hm22zdjJA/kWWD1ME2WnMDTAFe8dbFqyo8DrBO/ywFMBlxmZ7X/hzQb5YdHKAtTe0mOpxNqPgNg8rnrjI/MrQqA7xtUCybEcMlVFekLxwQpR5+UDlilZy2H4V1euzZtgAFkzzVIRsYJ+Hgg3H6f2DfCG+QbblAlLCPjdSi5+oozE/iDrNa+swwazKOXY7/jVCzK5KbM2vnRnuL7GgyHQBxr7KI27Lw/N/HAYLP9w==]
[Tue Sep 13 16:06:04 2011][029948][EUCAERROR ] ERROR: connect_iscsi_target failed
[Tue Sep 13 16:06:04 2011][029948][EUCAERROR ] AttachVolume(): failed to connect to iscsi target
[Tue Sep 13 16:06:04 2011][029948][EUCAERROR ] ERROR: doAttachVolume() failed error=1



2、 Requested operation is not valid
在nc的日志中有libvirt的错误信息:

libvirt: Requested operation is not valid: Xm driver only supports modifying persistent config (code=55)
AttachVolume() failed (err=-1) XML=<disk type='block'><driver name='phy'/><source dev='/dev/sde'/><target dev='sdq'/></disk>

3、在sc端重启后,逻辑卷显示错误.

在cloud重启后,无法显示卷绑定的实例,尽管这些卷正在被之用着。造成在clc端,卷可以被重复绑定。

因而,针对上述的三个主要问题,讲解一下在解决问题过程中,对eucalyptus中,卷管理的一些理解.


对eucalyptu中卷的管理分析,将从clc端开始,到nc端结束.
卷管理的具体实现 ¶

在clc端,处理volume请求在clc/modules/image-manager/src/main/java/com/eucalyptus/blockstorage/VolumeManager.java中,在这里可以处理volume请求的有:
CreateVolume、DeleteVolume、DescribeVolumes、AttachVolume、detach。对此,将会着重从CreateVolume、DescribeVolumes和AttachVolume作分析,查找AttachVolume失败的原因.
CreateVolume的大概流程:

CreateVolume,接收CreateVolumeType --> 对创建请求作一些预处理和约束,创建卷时必须有快照或是卷大小的参数 --> 获取sc的配置信息,地址 --> 将要创建的卷的信息计入到后台数据库中
--> 将创建卷的请求发送到sc端,
CreateStorageVolumeType req = new CreateStorageVolumeType( newId, request.getSize( ), request.getSnapshotId( ) ); StorageUtil.send( sc.getName( ), req );
--> clc的请求,由clc/modules/storage-controller/src/main/java/edu/ucsb/eucalyptus/cloud/ws/BlockStorage.java中的CreateStorageVolume接收处理,在其中作一些简单预处理,以及数据记录
--> 将创建volume发送到VolumeCreator,进行异步创建 --> VolumeCreator中的run在进行一些基本条件的判断,最终交由LogicalStorageManager的OverlayManager解决卷的创建问题
--> LogicalStorageManager是一个抽象类,在BlockStorageManagerFactory中将其实例化为
clc/modules/storage-controller/src/main/java/com/eucalyptus/storage/OverlayManager.java的OverlayManager,
最终在其中完成卷的创建工作,主要采用java调用一些系统命令完成,详细流程,可以参看具体的代码.

DescribeVolumes的处理流程:

 VolumeManager中的DescribeVolumes接收到查看卷请求 -->从数据库中读取存储的volume卷信息 -->从运行的虚拟机实例列表中读取绑定的卷的信息
-->clc/modules/core/src/main/java/com/eucalyptus/util/BlockStorageUtil.java中的BlockStorageUtil的getVolumeReply从sc中获取卷的信息,其中对数据库中存储的卷和虚拟机已经绑上的卷与
sc上存在的卷进行映射处理 -->最终反馈给了界面显示
从DescribeVolumes的简单流程中,可以看到在对volume的显示时与clc端数据库中存储的volume信息 虚拟机实例绑定的信息 以及具体sc上的卷的信息相关,这样的话,任何一个出问题,都有可能造成显示时的错误.

AttachVolume的处理流程

VolumeManager中的AttachVolume接收到绑定请求 --> 对绑定参数的合法性进行简单判断 --> 检查卷是否被重复绑定 --> 检查卷与实例是否在同一个cc上 -->从数据库中获取要绑定卷的地址信息
--> 从sc中检查卷的的一些基本状况 -->将绑定请求发至cc端new VolumeAttachCallback( request ).dispatch( cluster ); --> cc将绑定请求发送到nc -->
./node/handlers_xen.c中的doAttachVolume对绑定请求进行处理 -->通过./node/handlers.c中的connect_iscsi_target进行与远程卷的连接,至此大概的处理流程也已经结束.
上边的connect_iscsi_target是通过调用一个perl脚本处理的,脚本位置在tools/connect_iscsitarget.pl,安装后该文件在/usr/share/eucalyptus/connect_iscsitarget.pl中.
connect_iscsi_target failed的错误,也正是由于该文件调用失败得来的.

基于对volume卷管理的理解,现对于开头提到的三个bug进行更改:

bug1 connect_iscsi_target failed

从AttachVolume中可以看到,在绑定流程处理中,最终是通过nc的connect_iscsitarget.pl进行卷的绑定处理,从错误日志 也可以看出,要发起的目标地址是iqn.2009-06.com.eucalyptus.cluster223:store3
但是nc在连接该地址时连接不上,连接不上原因有二:一是clc端的volume中的远端地址信息过于陈旧;二是sc端的卷的确无法登录.通过查看sc可以看到,在volume中,卷的空间还在,
说明这些卷并未被删除,因此原因不在于clc,而是在于系统可能处于某个时段,sc的重启或是其他操作,使卷处于iactive状态.使的connect_iscsitarget.pl运行错误.
对connect_iscsitarget.pl的简单分析,可以看到nc登录绑定原端的volume卷时,主要是通过一些iscsiadm基本命令.手工运行这些连接命令,也是无法登录,在sc上查看,卷处于iactive状态.
由于该bug无法重现,因此预防措施是在sc重启时将目标卷重新进行激活,以尽量减少出错概率.
com.eucalyptus.storage.OverlayManager.VolumeEntityWrapperManager.exportVolume(LVMVolumeInfo lvmVolumeInfo) throws EucalyptusCloudException中在lvm卷为ISCSIManager
时,重新激活逻辑卷.exportVolume是sc在重新启动时调用的函数.Bootstrap.load -->BlockStorageBootstrapper.load -->BlockStorage?.ConvertVolumes? -->OverlayManager.checkPreconditions.

bug2 Requested operation is not valid

是传递的逻辑卷的参数不合法,在挂载设备时,设备名字/dev/sd[x][n],中x从a~p,n从0~15,否则就会出错,关于linux的scsi设备命名规范.
可以参加 http://publib.boulder.ibm.com/infocenter/dsichelp/ds6000ic/index.jsp?topic=%2Fcom.ibm.storage.smric.help.doc%2Ff2c_linuxscsilimit_2hsag9.html

bug3 在sc端重启后,逻辑卷显示错误

在eucalyptus-cloud重启后,在describevolume时,volume的显示发生问题,无法显示被绑定到的虚拟机实例。从而造成逻辑卷还没有被绑定的假象,结果使已经被绑定的逻辑卷还可以被重复绑定,造成数据的错误。
从DescribeVolumes的简单流程中,可以看到volume的显示与clc端的数据库信息volume、运行实例绑定的volume、和sc端存在的volume三者有关联。三者中的任何一个出错,都有可能造成volume的显示错误。
因此,在DescribeVolumes中,分别将获取上述三者的信息计入日志文件中。比如:

public DescribeVolumesResponseType DescribeVolumes( DescribeVolumesType request ) throws EucalyptusCloudException {
DescribeVolumesResponseType reply = ( DescribeVolumesResponseType ) request.getReply( );
EntityWrapper<Volume> db = getEntityWrapper( );
try {
String userName = request.isAdministrator( ) ? null : request.getUserId( );
LOG.debug("start describe volume invoke =================");
Map<String, AttachedVolume> attachedVolumes = new HashMap<String, AttachedVolume>( );
for ( VmInstance vm : VmInstances.getInstance( ).listValues( ) ) {
LOG.debug("==try get the instance volume ==hanxiangduo");
LOG.debug( LogUtil.dumpObject(vm) );
for ( AttachedVolume av : vm.getVolumes( ) ) {
LOG.debug("=================attached volume");
attachedVolumes.put( av.getVolumeId( ), av );
LOG.debug( LogUtil.dumpObject(av) );
}
}

List<Volume> volumes = db.query( Volume.ownedBy( userName ) );
List<Volume> describeVolumes = Lists.newArrayList( );
LOG.debug("== try get the volume from db== hanxiangduo");
LOG.debug(LogUtil.dumpObject(volumes));
for ( Volume v : volumes ) {
LOG.debug("==============volume from db");
if ( !State.ANNIHILATED.equals( v.getState( ) ) ) {
LOG.debug("add the avilable volume in describevolume");
LOG.debug( LogUtil.dumpObject(v) );
describeVolumes.add( v );
} else {
db.delete( v );
}
}
try {
ArrayList<edu.ucsb.eucalyptus.msgs.Volume> volumeReplyList = StorageUtil.getVolumeReply( attachedVolumes, describeVolumes );
reply.getVolumeSet( ).addAll( volumeReplyList );
} catch ( Exception e ) {
LOG.warn( "Error getting volume information from the Storage Controller: " + e );
LOG.debug( e, e );
}
db.commit( );
} catch ( Throwable t ) {
db.commit( );
}
return reply;
}

上边分别记录了在eucalyptus-cloud重启后从数据库中读取到的volume和从运行实例中读取到的绑定卷的信息。分析日志发现在重启后运行实例的volume卷信息为空。
但是,重启之后,从clc端的describeinstance日志中可以看到,其中是有实例volume卷的信息的,这说明是在从运行实例中获取绑定卷时出问题。cc端在向clc端返回的数据中,
是有虚拟机实例的volume信息。因此,问题只能出在clc端在获取从cc端instance实例信息赋值记录的过程中。
在clc端向cc请求运行的虚拟机实例信息,对clc端记录的虚拟机列表进行更新的过程大概是:
VmStateHandler.upstreamMessage( ChannelHandlerContext? ctx, MessageEvent e )
--> SystemState.handle( VmDescribeResponseType? request ) --> SystemState.updateVmInstance(final String originCluster, final VmInfo runVm)
-->VmInstance.setVolumes(final List<AttachedVolume?> volList );最终在这里实现对clc的实例列表进行赋值。
下面是原始的赋值代码:

 public void setVolumes( final List<AttachedVolume> newVolumes ) {
for ( AttachedVolume vol : newVolumes ) {
vol.setInstanceId( this.getInstanceId( ) );
vol.setStatus( "attached" );
}
Set<AttachedVolume> oldVolumes = Sets.newHashSet( this.getVolumes( ) );
this.volumes.retainAll( volumes );
this.volumes.addAll( volumes );
for ( AttachedVolume v : oldVolumes ) {
if ( "attaching".equals( v.getStatus( ) ) && !this.volumes.contains( v ) ) {
this.volumes.add( v );
}
}

通过分析上述代码,可以发现,在第一次赋值时,从cc端传递过来的volume信息是根本不能够被设置成功的。因此修改此处的setvolume实现,通过attachvolume的简单流程,已经绑定的卷不可以再被绑定,最终该bug解决。 这个bug已经有人提出,解决方法https://bugs.launchpad.net/eucalyptus/+bug/822505


posted on 2012-01-14 10:44  hanxiangduo  阅读(687)  评论(0编辑  收藏  举报

导航