image frame

数据链路层

1、概述

     数据链路层是TCP/IP协议栈的第二层!数据链路层的传输单元:帧(也就是传输单位)。

数据链路层

     帧的结构如下:

  • 帧结构的构成:MAC子层 + 上三层数据 + FCS

帧结构

  • 比喻:一个帧我们可以理解为一辆火车,MAC子层是火车头,上三层数据为乘客,FCS为火车尾巴
  • MAC子层头部包含(也叫帧头):目标MAC地址(6字节) 源MAC地址(6字节) 类型(2字节)
  • MAC地址:也称为物理地址,是被固化到网卡的全球唯一标识,如下图:

Mac 地址结构

     注释:MAC地址=厂家标识+内部编号====实现了全球唯一!怎么查看自己的MAC地址?开始运行–cmd–ipconfig /all

  • 类型字段的作用:区分上层协议,0806代表上层协议是ARP协议,0800代表上层是IP协议
  • 上三层数据:也就是3层包头+4层包头+5层数据。其中一个帧是有最大承载能力限制的。也就是一个帧中的上三层数据就是乘客,而一辆火车中的乘客是又上限的,一个帧的最大承受能力叫MTU值,目前国际标准为1500字节
  • MTU:(最大传输单元)1500字节
  • 帧尾:FCS=帧校验,长度4个字节,作用是校验整个帧在传输过程中是否发生传输错误。

     帧结构最终效果图如下:

帧结构效果图

     经典问题:请描述一下帧结构?

     答:帧是由帧头+上三层数据+帧尾,帧头包含目MAC,源MAC,类型,帧尾是FCS,MTU:1500

2、本层设备

     工作在2层的设备:交换机/网桥

3、交换机的工作原理

     经典问题:请描述一下交换机的工作原理。

     答:

     1)当收到一个帧,首先学习帧中的MAC地址来形成自己的MAC地址表!

     2)然后检查帧中的目标MAC地址,并匹配MAC地址表。

        如表中匹配成功,则单播转发!

        如表中无匹配项,则广播转发!

     3)MAC地址表的老化时间是?300秒!

     效果图如下:

交换机的工作原理

4、如何配置交换机

     傻瓜式交换机一般是不支持管理和配置的!企业级交换机支持配置高级功能及高级配置,价格要高,一般称为管理型交换机!如购买一台华为或者思科交换机,看下图:

交换机

     一般会自带一根console线!看下图:

console线

     建议再买一根com口转USB线,看下图:

com口转USB线

     使用console线+转换usb线,来连接交换机的console口与电脑的USB接口,如下图:

交换机接线

     然后再电脑上打开超级终端(xp上自带,win7另行下载即可),即可看到配置界面。当然我们可以使用思科的模拟软件来做实验,如cisco packettracer

谈谈云原生

     之前关于云计算技术底座的部门会谈,我本着程序员实事求是的态度,表示自己其实并不懂云原生。前段时间云技术底座的模型验证,遇到一个测试案例叫做“白屏纳管”,意思是指 CAAS 平台能够对包括云下硬件负载 F5、A10,云上 SLB 等设备进行管理。云原生技术有着太多的这种花里胡哨的名词,将本来很简单的一件事情包装出个能吓住人的词,来提高理解的门槛。作为一个一线开发,我有一种很深切的感受:很多优秀的设计,都是有着简洁优雅的设计原理或者说思想蕴含其中。这种没什么太多内涵的毫无意义的造词运动,对于工程实践,没有任何好处。我们不应该人云亦云盲目从众,也不应该以偏概全一叶障目。

     以下是阿里云公众号某产品经理关于云原生的解释,我截了图如下:

阿里云云原生公众号某文章

     这段话讲得没有问题,但是似乎又什么都没讲,对于云原生的定义,这种似是而非的说法显然不是一线开发人员想要的答案。

     我们在说云原生的时候,其实是在说“云原生计算”,云原生这个词其实可以拆为“云”和”原生“两个词,这其中其实隐藏了一个词——“云计算”。云原生一定是云计算, 这就要求我们事先已经对云计算的发展历史有所了解。云原生与云计算的区别便在“原生”二字上,那么理解云原生,重点就在理解其为何为“原生”。我这里用一句话来总结云原生:云原生是为了发挥出云计算所有优势的最短路径(这句精辟的提炼摘自《阿里云云原生架构实践》一书)。

     这些想法和做法归纳为三个方面:应用架构、计算模型、代表技术。

  • 代表技术 是最容易理解的。代表技术可以是一些狭义上的云原生基础设施,包含了相关的软件或硬件技术,例如裸金属、docker、K8S;也可以是泛化的一些工程技术体系,比如 Spring Cloud,DevOps,DDD ——它们与云基础设施不一样,很多并非为了云原生而生的,但是在云上环境表现活跃,也可以归纳到云原生代表技术中来。有些人说,使用了容器技术,就是云原生,这肯定是不准确的。容器其实只是改变了我们应用的部署方式,应用运行时的形态,以此来定义云原生是非常片面的。

  • 计算模型, 既然这个行业这么喜欢遣词造句,那我也造几个词(切,谁还不会啊!!!)。计算模型可以从两个方面来看:

     计算的服务模型: 计算的服务模型是从商业的角度看的。我们从传统的购买硬件送软件,到购买软件和维护再到如今购买云服务,云计算平台将计算、存储、网络像煤电一样卖给我们。需要指出,计算资源的这种服务模型并不是在云原生中才强调的,而是从云计算提出的时候,就已经强调了的。

     服务的计算模型: 这个语境中,“服务”不再是商业上的“服务”,而是指“应用服务”。应用服务的计算模型,强调了应用程序的可伸缩性、弹性、自动化和可维护性,以适应现代云环境中的需求。当然,应用的可伸缩、弹性自动化运维这些并不是应用自身具备的能力,而是在云上环境被赋予的,但是需要从应用侧做一定的改造工作,“以适应现代云环境中的需求”,比如下面要说的——应用架构。

  • 应用架构 为了最大化发挥云原生的计算优势,应用侧应该也要做架构升级——例如微服务化,在弹性扩缩的时候以更细的粒度进行算力分配,更精确的分配云计算底座资源(计算、存储、网络)——当然,这只是我简单作示意的一种说法。这种说法换个侧面来看,单体应用就不能上云计算么?当然可以,但是那就不叫云原生了,因为单体无法发挥出云计算的最大优势。

     所以从我自己目前的工作经历总结如下: 云原生一定是云计算,特别的,云原生是有效发挥出云计算所有优势的最短路径。理解云原生,可以从代表技术、云原生计算模型、云原生应用架构三方面着手理解。

简述Oauth2的工作原理

简述互联网的工作原理

深入 OGNL 与 Mybatis 源代码分析一次 Mybatis 升级引发的线上事故

     项目中对 Mybatis 做了一次升级。前后版本如下,3.2.5 -> 3.4.4:

mybatis前后版本升级

     结果第二天巡检发现如下报错,过了两个小时业务高峰期,前台业务人员不断反馈某最核心的业务无法进行:

报错信息

     我们当时定位到错误的地方,根据经验修改之后验证通过,重新上线之后得以解决。可能涉及敏感数据,所以不展示实际的报错与弥补方案。

     以下是我在本地的问题复现。在本地的一个标准的 SSM 工程中分别引入以下两个版本的 Mybatis 依赖:

分别引入两个版本的依赖

     编写如下数据库脚本:

数据库脚本

     dao 层调用方法如下:

dao层方法调用

     当 Mybatis 依赖为 3.2.5 的较低版本时,不会报错;当 Mybatis 依赖版本为 3.4.4 的较高版本时,则会报出上面的错误:

1
invalid comparision:  java.util.HashMap and java.lang.String

     在本地问题得到复现。问题的关键在于数据库脚本中的 if 条件编译语句的这一个子句 _parameter!=’’ 将_parameter 与 ‘’ 做比较,_parameter 是 Mybatis 的一个内置对象,你不需要知道它的作用,只需要知道他是 Map 类型的就行了,显然 ‘’ 是 String 类型的。到这里我们其实已经猜出来了,正是因为这种不规范的比较导致数据库脚本执行失败(实际上是 Mybatis 编译 SQL 失败)。

     但是问题又来了,为什么 Mybatis 较低版本的时候没有问题,而较高版本则暴露出这个问题了? 我们深入源码分析一下。因为我对 Mybatis 源码比较熟悉,加上实际生产中报错的堆栈信息也很全,所以直接定位到了 Mybatis 的这个类型:

ifnode

     上述代码的作用:在我们上述 SQL 脚本中,根据 if 子句的测试语句(就是 … && _parameter!=’’ 那一坨)判断,当前 if 子句所包裹的 sql 是否需要动态编译进最终的执行sql中。当我们进一步追踪,就进入到了 OGNL 的源码中,OGNL 是一套表达式解析引擎,一直定位下去就到了具体报错的方法。到这里我们补充一下版本依赖关系:

1
2
mybatis-3.2.5  ->  ognl-2.6.9
mybatis-3.4.4 -> ognl-3.1.14

     高版本 OGNL 源码如下:

高版本 OGNL 代码

     低版本 OGNL 源码如下:

低版本 OGNL 代码

     类型标识相关的源码如下:

类型标记

     case 为 NONUMBERIC 的含义是当比较的值是非数值类型,所以 _parameter!=’’ 子句的判断自然是走该分支语句的代码。t1、t2,v1、v2 的含义是两个待比值( _parameter 和 ‘’)的类型和 value,在这个场景中分别是如下调试面板所示的(不明白的请观察为了复现问题所编写的 SQL 脚本和 dao 层语句):

调试信息如下

     解释一下:t1 = t2 = 10,表示 _parameter 与 ‘’ 都是非数值类型。v1 表明了 _parameter 是个 HashMap 类型的变量,有一个 (blurname,cat) 的键值对,v2 = ‘’。另外,类的 Class 实例中有一个 isAssignableFrom 方法,这个方法是用来判断两个类的之间的关联关系,也可以说是一个类是否可以被强制转换为另外一个实例对象。

     至此所需信息全部已经准备完毕,我们可以来分析高低版本 OGNL 的源码了。高版本 OGNL 中,我们直接看 case:NONUMBERIC 的分支子句。代码含义为:

     如果 V1 是 Comparable 类型的并且 V1 可以强转为 V2 的类型,则进入 if 分支,否则进入 else 分支,而 else 分支直接报错,而且报错信息是我们实际生产环境中遇到的。显然,V1 既不是 Comparable 类型,也无法转换为 V2 的类型(HashMap -> String),所以进入了 else 分支,mybatis 升级之后携带 OGNL 的升级,数据库不规范的写法导致 mybatis 编译 sql 语句报错,阻塞了业务

     低版本的 OGNL 的 case:NONUMBERIC 的分支子句的代码逻辑说实话非常拧巴,含义是:

     如果 v1、v2 任一变量为 null,则进入 if 分支,显然不会进入。else 先判断v1、v2 是否能互转,显然不能,直接跳过。接下来是重中之重:如果 equals 为 true ,跳出 case,否则报错。我们根据结果看,equals 必定为 true,因为我们那种不规范的 mybatis 在这个地方,它每没报错——事实上是应该将该问题抛出来的,从而引导开发者更正 mybatis 脚本。接下来我们看方法外面这个 equals 的来源:

equals

     我惊呆了,直接写死传经来的,至于这个 equals 意欲何为,当初作者为什么这么写,也许只有作者自己知道。反正高版本的 OGNL 已经将这部分的代码逻辑全部重构了。

     我们可以得到如下结论: _低版本的 mybatis 依赖了低版本的 OGNL ,低版本的 OGNL 在上述分析的函数中存在一定缺陷,这个缺陷会导致我们在编写 Mybatis 脚本的时候类似于 parameter!=’’ 的不规范写法不被发现。当我们升级了 Mybatis 之后,这种不规范的写法反而兜不住暴露出来了,加上组件升级测试不充分,直接上到了生产环境。

     反思:

  • 日常开发要严格要求自己,追求正规、大气的编程素养,每一行代码,每一个字符,都要过大脑,不要太随便,不要随便复制粘贴能跑就行。
  • 组件升级要慎之又慎,测试要充分。
  • Copyrights © 2017 - 2026 杨海波
  • 访问人数: | 浏览次数:

请我喝杯咖啡吧~

支付宝
微信