Facebook路由事故未圆,何以元宇宙?

简介: 笔者并不关心以上这些和技术无关的科技新闻,这里笔者想探讨的话题是不久之前FaceBook发生的那次由于BGP路由协议配置错误造成的史诗级中断事故,在当时故障期间FaceBook所有旗下APP全面对外服务中断,而且故障的时间长达7个小时之久。针对这个话题我也写过一篇博客《一行小错为何产生巨大破坏-Facebook史诗级故障大反思》进行过总结,而如果这次Facebook真的要All In元宇宙,那么有关网络路由协议的问题还需要进一步的优化,不彻底解决网络方面的问题,只是创造一个时常宕机的元宇宙的话,没有任何意义。


最近Facebook创始人马克·扎克伯格正式对外宣布,Facebook将更名为Meta。“Meta”一词来自于最近Facebook火爆全球的概念元宇宙(Metaverse),据说Facebook此举是用改名来彰显公司在元宇宙世界中开拓和创新的愿景。

image.png

据我所知这不是Facebook第一次改名,熟悉Facebook成长纪传题材电影《社交网络》的同学,可能对于其中人物肖恩的经典台词“Drop the ‘The’. Just Facebook. It's cleaner.“印象非常深刻,不得不说当时这一改是神来之笔,Facebook的确是比” The Facebook“更加简洁、响亮,但是这次Facebook丢掉的可不是定惯词The,而是宇宙Verse。按照我的理解这大概可以认为Facebook可以做Meta元的概念,但是不是能做成宇宙就无从知晓了。

这也不是Facebook第一次宣布All In一个概念,2019年他们发布了基于区块链的数字货币-Libra,不过Libra的发展之路却是各种坎坷,有意思的是去年年底Libra也改名为Diem了,而且据说这次Facebook改为Meta之后也会重点与区块链的最新概念NTF相结合,Facebook这种打不过就改名的方式是否值得我们学习,也值得观察。

当然笔者并不关心以上这些和技术无关的科技新闻,这里笔者想探讨的话题是不久之前FaceBook发生的那次由于BGP路由协议配置错误造成的史诗级中断事故,在当时故障期间FaceBook所有旗下APP全面对外服务中断,而且故障的时间长达7个小时之久。针对这个话题我也写过一篇博客《一行小错为何产生巨大破坏-Facebook史诗级故障大反思》进行过总结,而如果这次Facebook真的要All In元宇宙,那么有关网络路由协议的问题还需要进一步的优化,不彻底解决网络方面的问题,只是创造一个时常宕机的元宇宙的话,没有任何意义。

路由协议的核心问题到底是什么?

所谓路由协议,归根结底就是要找到从起始点S出发到目的地点D的最短路径。这其实也就是我们熟知的旅行规划问题,要通过算法回答旅行者从S城市出发如何以最小的代价达到城市D。而针对这个问题早就有经典算法dikjstra解决。

由于网上能搜索到的现成算法大多是根据Leecode等算法网站上的原题给出的答案,运算结果只输出起点和终点的距离和费用,既没有记录具体的行走路径,也没有详细介绍算法的思想,为了说清这个问题下面我们先把dikjstra算法做一下介绍。

再读旅行规划题目

旅行规划的题目可以归结为以下说法,一张自驾旅游路线图显示了城市及公路的数量,高速公路长度、过路费。现在要通过一个算法,找一条出发地和目的地之间的最短路径。如果有若干条路径都是最短的,那么需要输出最便宜的一条路径。

实际在网络路由规划中,城市代表着网络上的节点,调整公路代表网络上的通道,公路长度一般代表网络通道的传输性能,过路费用的数据在实际工程中可能代表着线路质量等参数。

示例代码中的变量说明:N、M、S、D分别代表城市个数、调整公路条数、旅行者起始城市编号、旅行者目的地城市编号,其中N(2≤N≤500)是城市的个数,三维数组g存储高速公路的信息,记录起始城市、终点城市、高速公路长度、收费额,如g[i][j][1]代表编号为i的城市到编号为j的城市之间的距离,g[i][j][2]代表编号为i的城市到编号为j的城市过路的费用,哈希表Path记录由旅行者的起始城市S到编号为i的城市之间的最短路径信息,如起始城市S到i之间经过j、k最短,那么Path[i]的值应该是[j,k],注意j、k对于顺序敏感。Dist数据记录旅行者起始市S到编号为i的城市之间的距离数值,cost数据记录旅行者起始市S到编号为i的城市之间的花费,到Known数组记录城市是否被算法遍历确认,

比如经典路由协议OSPF (Open Shortest Path First)中的SPF最短路径优先其实就非常清楚的表达出了dijkstra算法的精髓,实际上这个算法就是不断找到离起点S最近的未确认城市A,并尝试通过A中转能否优化到S的距离,如下图所示:

image.png

注:绿色代表起点城市

蓝色代表known状态已经迭代的城市

红色代表unknown状态的城市

dijkstra算法首先要做的就是找到所有未知节点中与起始地S最近的城市A,因为经城市A现在离S最近,那么经城市A中转,就有可能会缩短S到其它目的地城市D的距离。比如上图当中S到A的距离是2,截止目前是S到其它城市中距离最短的一条路径,那么经A跳转则有可能获得一个比从S直接到D更短的路径。在上图例中在使用A行过一轮迭代以后,S到D的距离可以由直接访问的距离6,优化为经A中转的距离5。在完成一轮优化后A节点会被记录为known的状态,接下来会用非known状态的节点中找到离起始点最近的那个做下一轮迭代。如下图所示:


image.png

如图所示,这轮迭代中距离起始点D最近的城市是B那么,算法会重复刚刚的步骤,尝试通过B中转去起点S优化到其它unknown状态城市的距离,在这个例子中,可以将由S到C的距离优化到4,迭代完成后b会被标识为known状态,算法持续迭代,直到所有城市全部状态全部都是known为止。

以go语言为例,代码如下:

package main
import (
       "fmt"
       "strconv"
)
const N int = 4
const INF int = 501
var g [N][N][2]int
var dis [N + 1]int
var pay [N]int
var known [N]bool
var n, m, s, d, i, j, t1, t2, v int
var path map[int][]int
func findMinDistance() {
       disMin := INF
       for i := 0; i < n; i++ {
             if !known[i] && dis[i] < disMin {
                    v = i
                    disMin = dis[i]
             }
       }
}
func dijkstra() {
       for k := 1; k < n; k++ {
             findMinDistance()//先把状态为unknown的节点中到起点距离最短的点
//接下来按照之前介绍的算法使用距离最短的节点对其它节点进行优化
             known[v] = true
             for i = 0; i < n; i++ {
                    if !known[i] && g[v][i][0] < INF {
                          if dis[v]+g[v][i][0] < dis[i] {
                                 dis[i] = dis[v] + g[v][i][0]
                                 pay[i] = pay[v] + g[v][i][1]
                                 footPrint := path[v]
                                 path[i] = append(footPrint, v)
                          } else if !known[i] && dis[v]+g[v][i][0] == dis[i] && pay[v]+g[v][i][1] < pay[i] {
                                 pay[i] = pay[v] + g[v][i][1]
                          }
                    }
             }
       }
}
func main() {
//以下是初始化城市个数、高速公路条数、起始城市、终点城市的工作
       path = make(map[int][]int)
       n = 4
       m = 5
       s = 0
       d = 3
       //初始化时先把path对应的路径置为空
       for i := 0; i < n; i++ {
             s1 := make([]int, 0)
             path[i] = s1
       }
       //初始化化时先把g数组对应的路径置为空
       for i = 0; i < n; i++ {
             for j := 0; j < n; j++ {
                    g[i][j][0] = INF
                    g[i][j][1] = INF
             }
       }
       keyInput := [...][5]int{{0, 1, 1, 20}, {1, 2, 3, 30}, {0, 3, 40, 10}, {0, 2, 10, 20}, {2, 3, 2, 20}}
//把道路信息写入g数组
       for ; m > 0; m-- {
             i = keyInput[m-1][0]
             j = keyInput[m-1][1]
             t1 = keyInput[m-1][2]
             t2 = keyInput[m-1][3]
             g[i][j][0] = t1
             g[j][i][0] = t1
             g[i][j][1] = t2
             g[j][i][1] = t2
       }
       //fmt.Println(g)
//初始化known数组全部置为false状态
       for i = 0; i < N; i++ {
             known[i] = false
       }
       //初始化起点到编号为j节点的距离及花费信息
       for j = 0; j < n; j++ {
             dis[j] = g[s][j][0]
             pay[j] = g[s][j][1]
       }
       dis[s] = 0
       pay[s] = 0
       dis[n] = INF
       dijkstra()//调用dijkstra算法
       if dis[d] < INF {
             fmt.Println("Distance is " + strconv.Itoa(dis[d]) + ",The cost is " + strconv.Itoa(pay[d]))
             fmt.Println("Path is", path[d])
       }
}

image.gif

在例程中各城市之间的关系如下,

image.png

从A(0号城市)到D(3号城市)的最短路径需要经B(1号城市)和C(2号城市)中转,路径用红色标出

代码运行结果如下:

Distance is 6,The cost is 70
Path is [1 2]

image.gif

符合预期。

路由协议的核心问题到底是什么?

在聊完经典算法dikjstra之后我们终于可以结合网络当中的实际应用,也就是路由协议的话题了,其实现在各种路由协议的坑本质上都是从dijkstra算法继承而来的,当然这里并不是说dijkstra算法不优秀,而是他与路由算法的角度不同,笔者总结路由协议存在的问题,主要是由以下几方面造成的。

  Dijkstra本质上是旅行者算法而不是网络路由算法

简单来讲dijkstra是为旅行者而设计的,站在旅行者的角度去考虑问题,但是从网络的实际使用情况上看,算法中的旅行者对应应用层的数据包,按照网络结构层的分工界限,应用层只负责提供目的IP地址,具体如何路由到目的IP,完全不是数据包的发送方需要关心的问题。

而站在网络设备的角度上看,假如上面例程中的城市A是上台路由器,那么它上只需要掌握最优路径上下一个城市C的路由信息就可以了,掌握整个路径的全貌,费时费力不说,也没有必要。

image.png


但在实际工程中如果不存整个最优路径的整体路由信息,就可能会成环,

image.png

以上图为例,A节点认为发送给D的包应该经过B,B认为包应该经过C,C的路由表又把包路由给A,也就是数据包会在这个网络环里转圈,永远也出不去,像BGP协议去环的主要方法就是查看路由信息里是否包含了自身的AS编号,如果包含则拒绝接收。但鱼与熊掌不可兼得,要想完全避免环路,就要牺牲一定的效率,在目前djklstra算法框架下建立的路由协议,都要面临这个选择,这可能也是未来路由协议优化的一个重要方向。

Dijkstra算法的时间复杂度决定路由协议要么限制节点数,要么将将网络分区。

熟悉算法的小伙伴肯定一眼就能看出来,Dijkstra算法的时间复杂度接近于O(n*n)。而且我们刚刚也讲了Dijkstra每步迭代的之间是有前后顺序关系的,很难像搜索那样进行分布式并行计算改造。因此这也就使得路由协议必须要限制管理节点的个数,因为如果要给整个互联网上几十亿节点跑一遍Dijkstra算法,显然不是一种可行的计算方案。

而降低管理节点的方式有两种,一种是把网络分区,外部网关协议EGP只处理区和区之间的路由,内部网关协议IGP只处理区域内部的网络关系。这也是为什么路由协议会分为EGP外部网关协议和IGP内部网关协议两大类协议的根本原因。

外部网关协议中的BGP把整个互联网分为几万个自治区(AS),内部网关协议OSPF协议要把网络分为不同AREA本质上都是受Dijkstra算法时间复杂度的影响而做出的妥协。当然也可以直接限制管理的网络节点个数,比如RIP就把路由的步数设置在了16跳以内,这在处理小规模网络区域时也不失一个好的方式。

当然本文只是把问题提出来了,具体怎么优化解决,笔者也正在思考,目前也没有答案,如果各位读者有好的想法欢迎私信或者留言。最后笔者还是要重申一下,如果Facebook对于刚出的史诗级故障都没给出一个靠谱的解决升级建议,就忙着去炒作什么元宇宙,那这样造出来的元宇宙可能稳定性也会堪忧。

相关文章
|
人工智能 数据可视化 物联网
Facebook正式更名为Meta,数字孪生元宇宙落地应用!
如果说近期最火的词,那么元宇宙一定是其中一个。不管是投资、理财、互联网还是关注科技的小伙伴们应该发现,到处都在提到元宇宙。和元宇宙有关的股票、基金都成为了人们的焦点,各路巨头大佬都在布局元宇宙。那么你知道什么是元宇宙吗?
227 0
Facebook正式更名为Meta,数字孪生元宇宙落地应用!
|
机器学习/深度学习 算法 决策智能
【重磅开源】Facebook开源 Nevergrad:一种用于无梯度优化的开源工具
【重磅开源】Facebook开源 Nevergrad:一种用于无梯度优化的开源工具
203 0
|
缓存 数据可视化 测试技术
开源多年后,Facebook这个调试工具,再登Github热门榜
让许多工程师合作开发大型应用大多会面临一个挑战,通常没有一个人知道每个模块是如何工作的,这种技能会让开发新功能、调查Bug或优化性能变得困难,为了解决这个问题,Facebook创建并开源了Flipper,一个可扩展的跨平台的调试工具,用来调试 iOS 和 Android 应用。近日又双叒登上了Github热榜。
|
前端开发 JavaScript 测试技术
Facebook 开源可扩展文本编辑器 Lexical
Meta(原 Facebook)近日开源可扩展文本编辑器 Lexical,源代码托管在 GitHub 上采用 MIT 许可证。
546 0
Facebook 开源可扩展文本编辑器 Lexical
|
XML jenkins Java
Facebook开源静态代码分析工具Infer介绍
Infer是Facebook公司的一个开源的静态分析工具。Infer 可以分析 Objective-C, Java 或者 C 代码,用于发现潜在的问题。其作用类似于sonar和fortify。Infer更倾向于发现代码中的空指针异常、资源泄露以及内存泄漏的问题。
Facebook开源静态代码分析工具Infer介绍
|
机器学习/深度学习 人工智能 文字识别
图神经网络版本的PyTorch来了,Facebook开源GTN框架,还可对图自动微分
近日,Facebook的AI研究院发表了一篇论文「DIFFERENTIABLE WEIGHTED FINITE-STATE TRANSDUCERS」,开源了用于图网络建模的GTN框架,操作类似于PyTorch这种传统的框架,也可以进行自动微分等操作,大大提高了对图模型建模的效率。
345 0
图神经网络版本的PyTorch来了,Facebook开源GTN框架,还可对图自动微分
|
移动开发 Java 程序员
Facebook 将神奇动画引擎 Pop 开源了!
Facebook 2月发布的新闻类应用Paper,因为其灵动的用户界面和交互,成为近来最令人眼前一亮的移动产品之一。 而这个产品的背后是2011年Facebook收购的Push Pop Press,创始人是分别在Apple任设计师和工程师的Mike Matas与Kimon Tsinteris。他们的合作者还有传奇人物Bret Victor。他们为美国前副总统Al Gore开发的电子书Our Choice当时就曾技惊四座。
349 0
Facebook 将神奇动画引擎 Pop 开源了!
|
PHP C语言 开发者
Facebook 发布开源编程语言 Hack
Facebook周四发布一款名为“Hack”的全新编程语言,并声称该语言将能使代码的编写和测试更加高效快速。Facebook已在公司内部使用该语言超过一年时间,现在将以开源的形式将其正式发布。
432 0
Facebook 发布开源编程语言 Hack