ovn 常規使用場景以及優化過程

1. ovn trunk port

image.png

vm1 bound to worker1
vm2 bound to worker2
child1 (VLAN 30) inside vm1
child2 (VLAN 50) inside vm2

image.png

ovn nb 以及 sb db存儲的網絡資源


[root@central vagrant]# ovn-nbctl show
switch db4e7781-370c-4439-becd-35803c0e3f12 (network1)
    port vm1
        addresses: ["40:44:00:00:00:01 192.168.0.11"]
    port vm2
        addresses: ["40:44:00:00:00:02 192.168.0.12"]
switch 40ac144b-a32a-4202-bce2-3329f8f3e98f (network2)
    port child1
        parent: vm1
        tag: 30 # vlan
        addresses: ["40:44:00:00:00:03 192.168.1.13"]
    port child2
        parent: vm2
        tag: 50  # vlan
        addresses: ["40:44:00:00:00:04 192.168.1.14"]

[root@central vagrant]# ovn-sbctl show
Chassis worker2
    hostname: worker2
    Encap geneve
        ip: "192.168.50.101"
[root@central vagrant]# ovn-sbctl show
Chassis worker2
    hostname: worker2
    Encap geneve
        ip: "192.168.50.101"
        options: {csum="true"}
    Port_Binding child2
    Port_Binding vm2
Chassis worker1
    hostname: worker1
    Encap geneve
        ip: "192.168.50.100"
        options: {csum="true"}
    Port_Binding child1
    Port_Binding vm1

虛擬機內部的vlan配置


[root@worker1 vagrant]# ip netns exec vm1 ip -d link show
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 promiscuity 0 addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
2: child1@vm1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 40:44:00:00:00:03 brd ff:ff:ff:ff:ff:ff promiscuity 0
    vlan protocol 802.1Q id 30 <REORDER_HDR> addrgenmode eui64 
# vlan 30
numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
24: vm1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/ether 40:44:00:00:00:01 brd ff:ff:ff:ff:ff:ff promiscuity 2
    openvswitch addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535


[root@worker2 vagrant]# ip netns exec vm2 ip -d link show
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 promiscuity 0 addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
2: child2@vm2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
    link/ether 40:44:00:00:00:04 brd ff:ff:ff:ff:ff:ff promiscuity 0
    vlan protocol 802.1Q id 50 <REORDER_HDR> addrgenmode eui64  
# vlan 50
numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535
15: vm2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
    link/ether 40:44:00:00:00:02 brd ff:ff:ff:ff:ff:ff promiscuity 2
    openvswitch addrgenmode eui64 numtxqueues 1 numrxqueues 1 gso_max_size 65536 gso_max_segs 65535

2. 優化neutron 內存占用

RSS - Resident Set Size 實際使用物理內存(包含共享庫占用的內存)

image.png

可以看到在優化之前,neutron-server實際使用物理內存高達73.5Gib。
經過定位分析發現,ovn sb db存在將近上百萬調MAC_Binding 記錄(也就是arp相關的ip和mac的對應記錄)。 MAC_Binding 是由ovn-controller維護和傳播的。一旦學習到一個新的MAC地址,ovn就會為每一個連接到外部的軟路由添加一個MAC_Binding。

在這個場景中,連接到外部網絡的軟路由只有16個,并且有觀察到近1M條記錄。 這個不進會導致內存問題,也會對ovn sbbound server造成大量的流量和壓力,ovn-controller會向ovn sbbound發起大量的事務請求,并且還要響應回復。

為什么neutron要關注MAC_Binding, 為了復用fip。但是內網ip和mac都在不斷的發生切換。為了刪除過期的MAC_Binding 記錄,在neutron中維護了MAC_Binding 的全量copy,因為copy中的MAC_Binding沒有過期機制,所以最終肯定會觸發OOM。

為了解決該問題,ovn提供了一種機制用于在某個時間點清理過期的MAC_Binding 記錄。 比如在綁定和取消綁定fip的時候。
為了讓neutron觸發清理,特別提供了一個ovsdb-client 工具。

該機制合入后,RSS從75GB 收斂到 7.5GB。

image.png

3. 定位ovn的擴展性問題

ovn 支持fip(dnat_and_snat) 在hypervisor本地直接進行南北向路由決策。而不必將流量轉發到一個中心式的網絡節點。

當出去的流量到達ovn網橋時,會對源ip進行snat,經過br-int到br-external 的patch port 經專用公網網卡直接轉發出去。

該特性叫做DVR,路由階段不需要轉發到網關節點,直接經本地計算節點出去,沒有下一跳,overlay 流量,以及分布式路由處理。

主要優勢就是,只要伸縮計算節點即可,唯一的成本是公網ip。

但是在fip的使用場景中,我們留意到 fip相關的 邏輯流表非常巨大。這會導致客戶端(ovn-controller)以及服務端ovsdb-server cpu和內存消耗非常高。

我想繼續弄清楚流表是如何分發的,以及什么材質導致該泄漏的主要原因。我只是簡單計算了一下每一個階段的流表數量并對他們進行了排序。如下的數據中心展示了93%的邏輯流表都處于兩個階段中。

$ head -n 6 logical_flows_distribution_sorted.txt
lr_out_egr_loop: 423414  62.24%
lr_in_ip_routing: 212199  31.19%
lr_in_ip_input: 10831  1.59%
ls_out_acl: 4831  0.71%
ls_in_port_sec_ip: 3471  0.51%
ls_in_l2_lkup: 2360  0.34%

以下是對應的工具

# ovn-sbctl list Logical_Flow > logical_flows.txt

# Retrieve all the stages in the current pipeline
$ grep ^external_ids logical_flows.txt | sed 's/.*stage-name=//' | tr -d '}' | sort | uniq

# Count how many flows on each stage
$ while read stage; do echo $stage: $(grep $stage logical_flows.txt -c); done < stage_names.txt  > logical_flows_distribution.txt

$ sort  -k 2 -g -r logical_flows_distribution.txt  > logical_flows_distribution_sorted.txt

下一步就是弄清楚這兩張表的內容
(lr_out_egr_loop & lr_in_ip_routing)


_uuid               : e1cc600a-fb9c-4968-a124-b0f78ed8139f
actions             : "next;"
external_ids        : {source="ovn-northd.c:8958", stage-name=lr_out_egr_loop}
logical_datapath    : 9cd315f4-1033-4f71-a26e-045a379aebe8
match               : "ip4.src == 172.24.4.10 &amp;&amp; ip4.dst == 172.24.4.209"
pipeline            : egress
priority            : 200
table_id            : 2
hash                : 0

_uuid               : c8d8400a-590e-4b7e-b433-7a1491d31488
actions             : "inport = outport; outport = \"\"; flags = 0; flags.loopback = 1; reg9[1] = 1; next(pipeline=ingress, table=0); "
external_ids        : {source="ovn-northd.c:8950", stage-name=lr_out_egr_loop}
logical_datapath    : 9cd315f4-1033-4f71-a26e-045a379aebe8
match               : "is_chassis_resident(\"vm1\") &amp;&amp; ip4.src == 172.24.4.218 &amp;&amp; ip4.dst == 172.24.4.220"
pipeline            : egress
priority            : 300
table_id            : 2
hash                : 0


_uuid               : 0777b005-0ff0-40cb-8532-f7e2261dae06
actions             : "outport = \"router1-public\"; eth.src = 40:44:00:00:00:06; eth.dst = 40:44:00:00:00:07; reg0 = ip4.dst; reg1 = 172.24.4.218; reg9[2] = 1; reg9[0] = 0; ne
xt;"
external_ids        : {source="ovn-northd.c:6945", stage-name=lr_in_ip_routing}
logical_datapath    : 9cd315f4-1033-4f71-a26e-045a379aebe8
match               : "inport == \"router1-net1\" &amp;&amp; ip4.src == 192.168.0.11 &amp;&amp; ip4.dst == 172.24.4.226"
pipeline            : ingress
priority            : 400
table_id            : 9
hash                : 0

可以看出來,這些流表用于處理fip之間的包。
基本上是,對于每一個可能的fip對都存在這些流表,以便為了這些fip間的流量不會流經過geneve隧道。

然而fip到fip的流量流經兩個ovn 端口,這個場景并不是最常用的用例。這些流表就先存在著以便保證dvr,并且不經過overlay 網絡。

目前該問題已解決,200fip情況的邏輯流表的梳理已經從127K下降為2.7k, 并且能夠保證線性增長。


image.png
image.png

4. 關于geneve的封裝

http://dani.foroselectronica.es/wp-content/uploads/2019/02/icmp-geneve-decoding

image.png
  1. Logical Datapath (switch/router) identifier (24 bits) - Geneve VNI
  2. Ingress and Egress port identifiers - Option with class 0x0102 and type 0x80 with 32 bits of data:

關于vni id 實際上是邏輯交換機和邏輯路由器的標識符。

進出 端口標識符

# 查看ls lr的vni id

[root@pc-node-1 master]# k ko sbctl list Datapath_Binding
_uuid               : af422fb1-f006-40a0-a347-aebfb6d686e3
external_ids        : {logical-switch="9fc30bf4-a27f-4e43-900c-bc346d09e4b6", name=external204}
load_balancers      : []
tunnel_key          : 4

_uuid               : 65d9b655-bbd7-45a5-b382-430668803c36
external_ids        : {logical-switch="76f17a8b-6458-4edc-b886-89497c1e3347", name=vpc1-subnet1}
load_balancers      : []
tunnel_key          : 6

_uuid               : c81d45b5-a362-4ce7-bc3a-f6fc81cb45bf
external_ids        : {logical-switch="f451ee57-2ccd-47e5-956b-cbb78c7e69a0", name=join}
load_balancers      : []
tunnel_key          : 2

_uuid               : b154d04e-4a14-4a9d-b171-b952de1eea7a
external_ids        : {logical-switch="015926e7-4e12-464c-859b-ad309ec4904d", name=ovn-default}
load_balancers      : []
tunnel_key          : 3

_uuid               : a6cf5a4f-3ddb-4d2f-a293-235aa1d8d553
external_ids        : {logical-router="e3e5e1ea-5193-4c80-9b91-3046f229bcfb", name=vpc1}
load_balancers      : []
tunnel_key          : 5

_uuid               : f234ef33-0a32-46d2-a065-2caa1f4cec59
external_ids        : {logical-router="dcd93f0a-0706-4e6d-9e8b-17ee3de2e17b", name=ovn-cluster}
load_balancers      : []
tunnel_key          : 1

參考: http://dani.foroselectronica.es/category/uncategorized/

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • kubernetes各版本離線安裝包 諸如calico flannel等CNI實現,通過犧牲一些功能讓網絡復雜度得...
    sealyun閱讀 955評論 0 1
  • 拓撲 配置一個簡單的L2 和 L3 Network 測試拓撲,包含兩個L2 Network(logic switc...
    蘇蘇林閱讀 2,810評論 0 1
  • 本文將針對ovn實現安全組進行技術總結,分為ovn插件安全組實現,ovn邏輯流表,openflow流表三部分進行介...
    劉力思閱讀 3,626評論 0 1
  • 環境路由和floatingip均為分布式的 東西向二層流量 vlan網絡net1下的云主機vm1訪問vm3(上圖標...
    Shawn_Lu_0127閱讀 1,895評論 0 1
  • 在部署openstack的官方文檔(最近幾個版本)中的neutron組件默認使用的是linux bridge來做網...
    cjzhao閱讀 18,677評論 3 15