评审社区Neutron代码时遇到的两个很有意思的patch ( by quqi99 )
2013-08-17 16:22
295 查看
作者:张华 发表于:2013-08-17
版权声明:可以任意转载,转载时请务必以超链接形式标明文章原始出处和作者信息及本版权声明
( http://blog.csdn.net/quqi99)
这两天评审了社区的如下两个patch, 值。前一个涉及ML2插件中在一个host中同时为tenant启动GRE和VXLAN遂道的数据隔离性问题(客观上它通过配置SDN的MAC地址学习功能也解决了GRE广播带来的性能问题),后一个patch涉及到OVS插件中一个host启动GRE agent一个host启动VXLAN agent由于使用了同一张表带来的数据库事务问题。这两个patch实际上是关联的,非常地有意思,深入这两个patch背后的讨论我相信能将Neutron中的OVS插件与ML2插件的本质弄得非常清楚。https://review.openstack.org/#/c/41239/
https://review.openstack.org/#/c/27818/
故事由来:
在老的ovs plugin里使用了一张表叫ovs_tunnel_endpoints,它有两个字段:ip_address与id. tunnel_sync方法(在ovs_neutron_plugin.py文件中)会往数据表ovs_tunnel_endpoints中插一条记录,id则由_generate_tunnel_id方法产生。
tunnel_ip = kwargs.get('tunnel_ip')
tunnel = ovs_db_v2.add_tunnel_endpoint(tunnel_ip)
tunnels = ovs_db_v2.get_tunnel_endpoints()
self.notifier.tunnel_update(rpc_context, tunnel.ip_address,
tunnel.id, self.tunnel_type)
def _generate_tunnel_id(session):
max_tunnel_id = session.query(
func.max(ovs_models_v2.TunnelEndpoint.id)).scalar() or 0
return max_tunnel_id + 1
def add_tunnel_endpoint(ip):
session = db.get_session()
try:
tunnel = (session.query(ovs_models_v2.TunnelEndpoint).
filter_by(ip_address=ip).with_lockmode('update').one())
except exc.NoResultFound:
tunnel_id = _generate_tunnel_id(session)
tunnel = ovs_models_v2.TunnelEndpoint(ip, tunnel_id)
session.add(tunnel)
session.flush()
return tunnel
如果一个host运行了gre agent, 同时另一个host也运行了vxlan agent,(老的ovs plugin因为只是一层插件结构在一台host上不能同时运行gre agent与vxlan agent),上述的add_tunnel_endpoint方法可能造成id相同从而抛出主键重复的异常。
正确的做法应该对上述add_tunnel_endpoint方法改造成成乐观锁,添加重试次数。代码见:https://review.openstack.org/#/c/27818/7/neutron/plugins/openvswitch/ovs_db_v2.py
我评审时最初是这样想的:
只有在老的ovs plugin中才会有这个问题,因为gre与vxlan同时共用了一张同名的表ovs_tunnel_endpoints,当在不同的host上同时运行gre与vxlan agent注册遂道端点时就会发生这样的问题。
但是在新的ml2插件中,由于两层插件机制的引入可以在一台host上同时运行gre与vxlan,即使这样也不会出现上的问题,因为它的表名是不同的,一个是ml2_vxlan_endpoints,一个是ml2_gre_endpoints,所以它们都不需要id这个属性。
mysql> desc ml2_vxlan_endpoints;
+------------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+----------------+
| ip_address | varchar(64) | YES | | NULL | |
| udp_port | int(11) | NO | PRI | NULL | auto_increment |
+------------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)
mysql> desc ml2_gre_endpoints;
+------------+-------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------+-------------+------+-----+---------+-------+
| ip_address | varchar(64) | NO | PRI | | |
+------------+-------------+------+-----+---------+-------+
1 row in set (0.00 sec)
所以在对https://review.openstack.org/#/c/27818/6/neutron/plugins/openvswitch/ovs_db_v2.py进行评审的时候,最初我给出的意见是应该对id采用不重复的uuid而不是用乐观锁 ( the incorrect method _generate_tunnel_id should be the root reason for this issue. the id returning by _generate_tunnel_id
will be used to insert the id field of the table ovs_tunnel_endpoints. running the ovs plugin with tunneling in a multi-agent environment. means ovs plugin use only one same table ovs_tunnel_endpoints to store tunnel endpoint info for both GRE and VXLAN, thus
above problem will cause this issue. so I prefer to change the id filed of the table ovs_tunnel_endpoints to use uuid.)
但是这样可能会造成当一个agent重启之后,在数据库又插入一条记录,这样agent在收到通知之后又创建一个重复的port (I dindn't figured out that case before, but you're right, using tunnel_ip in existing installation wouldn't work properly: if an agent gets rebooted, it would properly setup new tunnel ports using
tunnel_ip to name them, but other running agent would recieve a tunnel_update with the ip_address, and set-up a new port to rebooted agent in addition to the existing one...)
所以OVS插件的这个问题最后加乐观锁解决,而对于ML2插件因为表不同永远不会出现此类问题。
相关文章推荐
- 迁移32位下的旧代码到64位sever遇到过的两个很诡异的问题
- 使用Pycharm 社区版配合anaconda进行代码编写遇到的一些小问题汇总
- 【学习随笔】今日项目代码遇到的两个问题
- 求助:两个代码调试遇到一类问题 :有未经处理的异常: 0xC0000005: Access violation
- 调研两个代码评审工具
- [SVN技巧]代码提交中遇到的两个问题及其解决方案
- 最近遇到VS.Net的两个问题--无法调试,未加载符号和后台代码无法调用控件
- 记录安卓遇到的两个小bug,望初学者写代码的时候引以为戒
- Git使用提交代码遇到『Everything up-to-date』
- JAVA基础(31) Java代码计算两个经纬度之间的距离
- 代码人生--前传(一):一台电脑和两个孩子的故事
- 执行CreateObject("Scripting.FileSystemObject")代码遇到"Operation is disallowed in this session"问题
- 两个简单的压力测试代码。
- 升级Android支持库版本遇到的两个问题
- EJB生成代码后遇到transient错误
- 两个非均值滤波算法(NM)代码
- 一些有意思的算法代码[转载]
- [原]jquery第一行代码有意思的两点
- 关于Java异常一段很有意思的代码
- 写JAVA代码时常遇到的一些小问题