掌握网络架构核心!了解为什么要分层

简介: 掌握网络架构核心!了解为什么要分层

1 网络是七层、五层还是四层?

常听到三层交换机、七层规则等。网络为什么要分层呢?非分不可?

网络诞生前夜,IP协议、TCP协议都不存在,而你是网络缔造者,你会选择做怎样设计?

大体有两种

1.1 设计方案

1.1.1 应用程序包办一切

程序把应用层的数据,按某种编码转化为二进制数据,然后程序去操控网卡,把二进制数据发送到网络。这期间,通信的连接方式、传输的可靠性、速度和效率的保证等等,都需要这个程序去实现。然后下次开发另外一个应用的时候,就把上面这些活,再干一遍。

大包大揽,实现难度太大、耦合度太高,怎么看都是“反面典型”。

1.1.2 应用程序、os、网络设备等环节各自分工
  • 应用程序只负责实现应用层的业务逻辑
  • Os负责连接建立、处理网络拥塞和丢包乱序、优化网络读写速度等
  • 然后把数据交给网卡,后者和交换机等设备做好联动,负责二进制数据在物理线路上的传送和接收

所以选择第二种,即分层实现。

这思路跟编程思想类似。在编程中,要把一些逻辑抽象为函数或对象,以解耦和复用。网络世界亦如此,每层干好自己的分内事,那么所有的层次配合起来工作的时候,就有条不紊。

1.2 分层模型

OSI的七层模型,和 TCP/IP的四层/五层模型。最大区别:

  • 前者在传输层、应用层之间,还有会话层和表示层
  • 后者没有

哪种用得最多,哪种更合理?不用纠结“谁比谁更好”,如果我们理解每层作用,就不会被表象层级束缚。两种分法都有可取之处。


一般七层模型工作谈论更多。同事会找运维“你帮我建一个七层规则吧”。这七层就指应用层,“七层规则”可能是HTTP路由规则,如把符合某种条件的HTTP请求,分流到某特定后端集群。


还有一些场景适合用七层模型解释。如TLS虽在TCP之上,按TCP/IP模型就要被归入应用层。但HTTPS场景下,HTTP协议就是运行在TLS协议上,是不是把HTTP和TLS分到不同层次更合适?正好七层模型的第5、6层可分别代表TLS的会话保持功能和数据加解密这种表示层的功能。

会话层、表示层协议确实少。控制模型复杂度角度,如把这两层合并到应用层,模型倒更简单,也适合入门。所以从这点,TCP/IP模型也有可取之处。


为何TCP/IP还有四层和五层模型这两种说法呢?其实五层模型就是OSI的前四层,加上一个应用层。这样的话,这个五层模型跟OSI七层模型,差异就比四层模型又缩小了一点。


两种分层模型最大差异,还是在会话层和表示层。1-4层已基本统一。而它们最高层,虽然一个叫第7层,一个叫第4层或第5层,表面虽不一致,但都能用“应用层”代替。既避免可能误解,也更准确表示这层具体用途。

2 啥是TCP流?

Wireshark文档中,“TCP流”很常见,即TCP Stream。Stream“流”意,也有“连续的事件”含义,所以它是有前后、有顺序,正对应TCP特性。

跟Stream相对是Datagram,指没有前后关系的数据单元,如UDP和IP。

Linux网络编程里面:

  • TCP对应socket类型SOCK_STREAM
  • UDP对应的,就是SOCK_DGRAM
  • DGRAM就是Datagram简写

网络报文层面,一个TCP流,对应一个五元组:

  • 传输协议类型
  • 源IP、源端口
  • 目的IP、目的端口
  • 如今天你访问javaedge网站,这次TCP流就可能是这样的五元组:
(TCP, your_ip, your_port, javaedge_ip, 443)

一个IP报文包含所有这五元素,所以Wireshark解析抓包文件时,就能通过五元组知道每个报文所属TCP流。由此,可在Wireshark里,用Follow TCP Stream的方法,找到报文所在TCP流。


不过有时也有四元组,跟五元组大体一致,只是四元组没区分传输层协议类型(TCP或UDP)。但若我们都清楚知道应用类型,如知道应用是HTTP协议,那传输层协议默认就是TCP,这一元是否算进已不重要。

3 报文、帧、分组、段、数据包是一个?

3.1 报文(packet)

一种相对宽泛和通用的说法,基本每层都能用,如:

  • 应用层可说“HTTP报文”
  • 传输层可说“TCP报文”
  • 网络层即“IP报文”。网络层也是“报文”一词被使用最多的场景。

数据包类似,可在很多场景通用。

语法。packet后缀et。et结尾词多表示某个小小东西。如功能完备的一小段代码code snippet,一小段内嵌HTML的Java前端代码applet。packet就是一个小pack(包裹)。

如下就不是通用词,而是特定层专有词汇。

3.2 帧(frame)

二层也就是数据链路层,代表二层报文,包含帧头、载荷、帧尾。

帧有尾部,而其他像IP、TCP、HTTP等层级报文都没尾部。不可以说“TCP帧”或“IP帧”,虽然也许对方也明白你,但也得做得专业点嘛。

HTTP/2实现了多路复用,也有帧概念,不过那帧跟这里网络二层的帧,除了名称相同,就没别的联系。

3.3 分组

IP层报文,即狭义的packet。

3.4 段

特指TCP segment,即TCP报文。既然segment是“部分”意思,那这“整体”又是啥?它就是在应用层交付给传输层的消息(message)。


当message被交付给传输层,如果这个message的原始尺寸,超出传输层数据单元的限制(如超出TCP的MSS),它就会被划分为多个segment。这过程就是 分段(segmentation),也是TCP层重要职责。


说到segmentation,你可能也会想到fragmentation(分片)。这俩是同一个东西吗?这方面的知识点也不少,我在这里就不具体展开了。不过别着急,我会在第8讲里,帮你把这两个东西梳理清楚。


Datagram中文 “数据报”,但不是“数据包”。读音类似,但意思并不完全相同。“数据包”是个通用词,所以“UDP数据包”指代“UDP数据报”没问题。但反过来,非UDP协议的数据包,如TCP段,就不能叫“TCP数据报”,因为TCP不是Datagram。


层级和术语对应关系:

4 网络各层都有哪些排查工具?

4.1 应用层

应用层排查工具太多,选个主要的应用,谈谈 HTTP应用的排查工具

Chrome内置开发者工具,F12启动。可方便地做很多事。

① 找到有问题的服务端IP

如有用户报告死活访问不了你的网站,但你很清楚这网站域名对应很多IP地址,你怎么知道用户连哪个IP?

让客户启用开发者工具,在Network页找到主页对象,在它的Headers部分,就能看到Remote address,这IP就是当前连接的IP,如:

因为DNS解析,可能下次重连就不是这IP,所以每次都应该重新确认下这信息。

这技巧,在 排查公网的访问问题 时特别有用。现在流量大点网站都已上CDN,必然在全国乃至全球各地,有少则数十个、多则数百个CDN终端节点,在给访问者提供就近服务。如有人说他访问不了某站点,一定让他用开发者工具,找到他连的远程IP,再根据这信息排查。

② 辅助排查网页慢

访问页面感觉慢,开发者工具 时间统计功能,找到耗时高的HTTP资源对象,再针对性排查。

如访问 https://github.com 慢,打开开发者工具,然后访问站点,等全部加载完成后,到Network页查看这些HTTP对象的加载时间。

这只能排查哪个资源对象耗时长,但进步排查,如“为啥这对象加载时间比别的对象长”,开发者工具就难答。抓包分析可根本性排查这类问题。

③ 解决失效Cookie带来的问题

有时Cookie过期,导致无法正常登录站点,打开开发者工具,到Application页,找到Storage -> Cookie,把对应条目清除。下次再访问这站点,就已“洗心革面”。对站点来说,你就是一次新访问,可生成一次新Cookie。


通过删除浏览器缓存也可做到。但开发者工具可 细粒度 到这网站级别,而删除缓存就是所有站点Cookie。

4.2 表示层和会话层

表示层和会话层的协议不多,TLS可归入这俩层级。TLS问题排查推荐工具。

基于浏览器

做初步检查,主要围绕证书本身做检查。

浏览器地址栏有按钮,点开查看TLS证书等信息。继续点开【连接是安全的】按钮:

进而点击【证书有效】按钮:

就能查看证书:

使用开发者工具的【安全】菜单,还可查看更为详细的TLS信息,包括协议版本、密钥交换算法、证书有效期等:

tcpdump和Wireshark

TLS握手、密钥交换、密文传输等排查,还是要用专业工具。在Wireshark可更全面查看TLS细节。

如直接看到TLS握手阶段,双方协商 过程中 各自展示的Cipher suite,

而【开发者工具】只能看到协商 完成后 的选择。

4.3 传输层

重中之重,工具很多。按排查场景介绍。

① 路径可达性测试

测试TCP握手,有 telnet、nc 。如telnet:

$ telnet www.baidu.com 443
Trying 180.101.49.12...
Connected to www.a.shifen.com.
Escape character is '^]'.

用nc:

$ nc -w 2 -zv www.baidu.com 443
Connection to www.baidu.com 443 port [tcp/https] succeeded!
② 查看当前连接状况

netstat 获取当前TCP、UDP等连接信息,如:

$ netstat -ant
Active Internet connections (servers and established)
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 127.0.0.53:53           0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN
tcp        0      0 0.0.0.0:80              0.0.0.0:*               LISTEN
tcp        0    280 10.0.2.15:22            10.0.2.2:56669          ESTABLISHED
tcp6       0      0 :::22                   :::*                    LISTEN
③ 查看当前连接的传输速率

有时,你的网络跑得挺繁忙,但你却不知道哪个连接占用大量带宽?用 iftop。这工具不是系统自带,要安装。要有sudo权限,即执行sudo iftop,然后就能看到不同连接的传输速率,把祸害你带宽的连接给找到。如:

④ 查看丢包和乱序等的统计

netstat除了获取实时连接状况,还可获取历史统计信息。

如怀疑一台机器网络不稳定,除了用ping简单测试,还可用

netstat -s

获取更详细的统计信息。如其中的TCP丢包和乱序计数值,就能帮你判断传输层状况。

$ netstat -s
......
Tcp:
    16 active connection openings
    1 passive connection openings
    8 failed connection attempts
    1 connection resets received
    1 connections established
    6254 segments received
    4035 segments sent out
    1 segments retransmitted
    0 bad segments received
    3 resets sent
......
TcpExt:
    1 ICMP packets dropped because socket was locked
    3 TCP sockets finished time wait in fast timer
    8 delayed acks sent
    4674 packet headers predicted
    10 acknowledgments not containing data payload received
    1008 predicted acknowledgments
    TCPTimeouts: 1
    TCPBacklogCoalesce: 140
    1 connections reset due to early user close
    TCPRcvCoalesce: 2187
    TCPAutoCorking: 110
    TCPSynRetrans: 1
    TCPOrigDataSent: 1041
    TCPDelivered: 1049

这些不是静态值吗,我想知道当前情况啊?

watch --diff netstat -s

会把变化数值高亮:

上面这算运维“青铜”版。你也可写个简单脚本,在两次netstat -s之间执行sleep,然后计算两个读数间差值,并除以sleep时间,得到大致变化速度。这就又升级一点。


若你想做得再到位,可将netstat -s输出值写入TSDB,然后用Grafana展示,不仅有视图,也有历史值,运维“王者”!


ss 命令是Iproute2包里的命令,也是netstat“取代者”。提供对socket的丰富统计信息。如下查看当前连接统计信息:

$ ss -s
Total: 164
TCP:   5 (estab 1, closed 0, orphaned 0, timewait 0)
Transport Total     IP        IPv6
RAW   1         0         1
UDP   2         2         0
TCP   5         4         1
INET    8         6         2
FRAG    0         0         0

netstat命令功能被拆分到ss、ip两个命令,并分别得到丰富和加强。

4.4 网络层

在这一层,除了能直接用ping,还应掌握:

  • traceroute
  • mtr
查看网络路径状况

traceroute典型输出:

javaedge@JavaEdgedeMac-mini ~ % traceroute www.baidu.com
traceroute: Warning: www.baidu.com has multiple addresses; using 180.101.50.242
traceroute to www.a.shifen.com (180.101.50.242), 64 hops max, 52 byte packets
 1  * * *
 2  180.156.60.1 (180.156.60.1)  5.187 ms  21.989 ms  35.530 ms
 3  * 61.152.46.197 (61.152.46.197)  5.917 ms  31.525 ms
 4  61.152.25.198 (61.152.25.198)  3.704 ms
    101.95.120.54 (101.95.120.54)  3.566 ms
    61.152.25.198 (61.152.25.198)  3.324 ms
 5  202.97.72.202 (202.97.72.202)  20.957 ms
    202.97.29.126 (202.97.29.126)  8.328 ms
    202.97.66.206 (202.97.66.206)  16.003 ms
 6  58.213.95.174 (58.213.95.174)  8.515 ms
    58.213.94.110 (58.213.94.110)  12.978 ms
    58.213.94.30 (58.213.94.30)  9.487 ms
 7  * * *
 8  58.213.96.66 (58.213.96.66)  9.059 ms  9.095 ms
    58.213.96.50 (58.213.96.50)  9.014 ms
 9  * * *
10  * * *
11  * * *

为何第9跳开始就没IP,只有星号?你是不是也遇到过这情况?稍改命令,加上 -I 参数(I代表ICMP),就能正常跑到底:

$ traceroute  www.baidu.com -I
traceroute to www.a.shifen.com (180.101.49.12), 64 hops max
  1   10.0.2.2  0.099ms  2.363ms  0.078ms
  2   192.168.1.1  3.320ms  1.220ms  1.204ms
  3   100.65.0.1  8.737ms  4.872ms  6.403ms
  4   61.152.54.125  5.035ms  3.397ms  4.288ms
  5   *  61.152.25.110  4.176ms  *
  6   202.97.101.30  7.447ms  6.399ms  5.936ms
  7   58.213.95.110  10.488ms  *  9.014ms
  8   *  58.213.95.134  11.064ms  *
  9   58.213.96.74  10.997ms  10.042ms  10.592ms
 10   *  *  *
 11   *  *  *
 12   *  *  *
 13   180.101.49.12  11.269ms  9.518ms  8.779ms

背后原理,就是traceroute默认用UDP作为探测协议,但很多网络设备不会对UDP回应。所以改成ICMP协议做探测后,网络设备就有回应。

Windows上的tracert,就默认ICMP,和Linux正好反过来。

但traceroute也有明显不足: 它不能对这个路径做连续多次探测。


于是,mtr出现,可算traceroute的超集,除类似traceroute功能,mtr还能实现丰富的探测报告。尤其是它对每一跳的丢包率的百分比,是用来定位路径中节点问题的重要指标。当你遇到 “连接状况时好时坏” ,一次性traceroute难以看清,那就能用mtr获取更全面和动态的链路状态信息。

$ mtr www.baidu.com -r -c 10
Start: 2022-01-07T04:05:02+0000
HOST: victorebpf                  Loss%   Snt   Last   Avg  Best  Wrst StDev
  1.|-- _gateway                   0.0%    10    0.3   0.4   0.2   1.2   0.3
  2.|-- 192.168.1.1                0.0%    10    1.6   1.8   1.4   3.2   0.5
  3.|-- 100.65.0.1                 0.0%    10    3.8   7.0   3.8  10.3   2.0
  4.|-- 61.152.54.125              0.0%    10    4.0   4.3   3.6   5.1   0.5
  5.|-- 61.152.25.110             30.0%    10    5.0   6.8   4.4  18.9   5.4
  6.|-- 202.97.101.30             20.0%    10    7.8   6.6   5.4   7.8   0.8
  7.|-- 58.213.95.110             80.0%    10   10.0   9.8   9.6  10.0   0.3
  8.|-- ???                       100.0    10    0.0   0.0   0.0   0.0   0.0
  9.|-- 58.213.96.74               0.0%    10   10.5  12.7   9.9  24.7   4.9
 10.|-- ???                       100.0    10    0.0   0.0   0.0   0.0   0.0
 11.|-- ???                       100.0    10    0.0   0.0   0.0   0.0   0.0
 12.|-- ???                       100.0    10    0.0   0.0   0.0   0.0   0.0
 13.|-- 180.101.49.12              0.0%    10    9.4   9.1   8.3   9.7   0.5
查看路由

route 能查看路由表,不过这命令较老:

# route -n
Kernel IP routing table
Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
0.0.0.0         10.0.2.2        0.0.0.0         UG    100    0        0 enp0s3
10.0.2.0        0.0.0.0         255.255.255.0   U     0      0        0 enp0s3
10.0.2.2        0.0.0.0         255.255.255.255 UH    100    0        0 enp0s3
172.17.0.0      0.0.0.0         255.255.0.0     U     0      0        0 docker0

传输层工具里介绍的 netstat,其实也能帮我们查看路由,只要加上 -r 参数:

$ netstat -r
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
default         _gateway        0.0.0.0         UG        0 0          0 enp0s3
10.0.2.0        0.0.0.0         255.255.255.0   U         0 0          0 enp0s3
_gateway        0.0.0.0         255.255.255.255 UH        0 0          0 enp0s3
172.17.0.0      0.0.0.0         255.255.0.0     U         0 0          0 docker0

我前面说过,netstat是被ss和ip这两个命令替代了。所以我们同样可以用 ip命令 查看路由。比如这样:

$ ip route
default via 10.0.2.2 dev enp0s3 proto dhcp src 10.0.2.15 metric 100
10.0.2.0/24 dev enp0s3 proto kernel scope link src 10.0.2.15
10.0.2.2 dev enp0s3 proto dhcp scope link src 10.0.2.15 metric 100
172.17.0.0/16 dev docker0 proto kernel scope link src 172.17.0.1 linkdown

4.5 数据链路层和物理层

这一层离应用层已经很远了,一般来说是专职的网络团队在负责。如果这一层有问题,就会直接体现在网络层表现上面,比如IP会有丢包和延迟等现象,然后会引发传输层异常(如丢包、乱序、重传等)。所以, 一个稳定的数据链路层乃至物理层,是网络可靠性的基石。


既然底下这两层稳定性如此重要,那上层TCP不是号称还有传输可靠性保障?

难道这保障形同虚设?

TCP传输可靠性是通过序列号、确认号、重传机制等保证,通过这种机制,TCP可 一定程度 网络不稳定场景下,依然保证传输可靠,但不等于TCP能无限容忍底层的不稳定,因为各种TCP拥塞控制算法都会由于这种问题,而极大降低传输性能。

如你想查看这两层,可用 ethtool

# ethtool -S enp0s3
NIC statistics:
     rx_packets: 45897
     tx_packets: 9457
     rx_bytes: 59125524
     tx_bytes: 834625
     rx_broadcast: 0
     tx_broadcast: 17
     rx_multicast: 0
     tx_multicast: 59
     rx_errors: 0
     tx_errors: 0
     tx_dropped: 0

网卡驱动会到内核中注册ethtool回调函数,然后我们用ethtool命令就能查看这些信息。由于信息由网卡驱动提供,十分“接地气”。

如你在传输层和网络层的排查工具,已看到明确的链路不稳定的信息,那就直接找网络团队吧。

总结

回顾网络分层模型,也了解OSI模型和TCP/IP模型的区别和联系。对分层模型有了更加深入的理解,这个对我们开展网络排查工作,有指导性意义。

  1. 应用层以HTTP为例,可以用 浏览器开发者工具,实现远程IP识别、耗时分析、Cookie删除等需求。
  2. 会话层和表示层以TLS为主,,我们还是用 浏览器开发者工具,可以查看证书细节、协商后使用的Cipher suite等信息,属于静态信息。然后学习了 用tcpdump和Wireshark 查看更详细的TLS握手细节的方法。这些信息是动态的,也只有用抓包分析的手段才能做到。
  3. 在传输层,我们学到了 telnet、nc、netstat、ss 等命令,通过它们,我们可以测试连通性,也可以获取连接状况和统计信息,对于传输问题的排查都很有帮助。
  4. 在网络层及以下的部分,我们学习了 traceroute、mtr、ip 等工具,可以检测网络路径状况。
  1. 在数据链路层和物理层,我们可以做的不多,主要依靠网络层观察到的链路质量来推断这两层的情况。当然,也可以用 ethtool 这个工具查看这两层的详情。

FAQ

traceroute默认是用UDP来做探测的,那这个又是基于啥原理?通和不通,我们会收到怎样的回复?


traceroute使用UDP协议发送探测包,因为UDP协议无需像TCP协议握手和拆除连接,所以traceroute可更快发送探测包,且不对目标主机产生太大负载。


当traceroute发探测包时,每一跳的路由器都会将接收到的探测包的TTL值减1,并将该探测包返回给源主机。当TTL值减为0,路由器会将该探测包丢弃,并向源主机发送一个ICMP超时消息。因此,traceroute可通过TTL值的递减确定每一跳的路由器,并通过接收到的ICMP消息,确定探测包是否到达目标主机。


如果探测包成功到达目标主机,目标主机会向源主机发送一个ICMP端口不可达消息,告诉源主机该端口无法访问。因此,traceroute可以通过接收到的ICMP消息来确定目标主机是否可达,并计算出每一跳的延迟时间。


有时候运行telnet后命令就挂起,没响应了,说明啥问题?


运行telnet后命令挂起可能是因telnet连接已断开或网络连接出现问题。可尝试重新连接并检查您的网络连接是否正常。如果问题仍然存在,可能需要检查您的telnet服务器或客户端的配置是否正确。


目录
相关文章
|
29天前
|
人工智能 前端开发 JavaScript
前端架构思考 :专注于多框架的并存可能并不是唯一的方向 — 探讨大模型时代前端的分层式微前端架构
随着前端技术的发展,微前端架构成为应对复杂大型应用的流行方案,允许多个团队使用不同技术栈并将其模块化集成。然而,这种设计在高交互性需求的应用中存在局限,如音视频处理、AI集成等。本文探讨了传统微前端架构的不足,并提出了一种新的分层式微前端架构,通过展示层与业务层的分离及基于功能的横向拆分,以更好地适应现代前端需求。
|
27天前
|
机器学习/深度学习 计算机视觉 网络架构
【YOLO11改进 - C3k2融合】C3k2融合YOLO-MS的MSBlock : 分层特征融合策略,轻量化网络结构
【YOLO11改进 - C3k2融合】C3k2融合YOLO-MS的MSBlock : 分层特征融合策略,轻量化网络结构
|
1月前
|
JSON 前端开发 Java
Spring Boot框架中的响应与分层解耦架构
在Spring Boot框架中,响应与分层解耦架构是两个核心概念,它们共同促进了应用程序的高效性、可维护性和可扩展性。
53 3
|
1月前
|
存储 前端开发 API
DDD领域驱动设计实战-分层架构
DDD分层架构通过明确各层职责及交互规则,有效降低了层间依赖。其基本原则是每层仅与下方层耦合,分为严格和松散两种形式。架构演进包括传统四层架构与改良版四层架构,后者采用依赖反转设计原则优化基础设施层位置。各层职责分明:用户接口层处理显示与请求;应用层负责服务编排与组合;领域层实现业务逻辑;基础层提供技术基础服务。通过合理设计聚合与依赖关系,DDD支持微服务架构灵活演进,提升系统适应性和可维护性。
|
3月前
|
存储 消息中间件 JSON
|
4月前
|
域名解析 存储 网络协议
一次读懂网络分层:应用层到物理层全解析
**网络五层模型简介:** 探索网络服务的分层结构,从应用层开始,包括HTTP(网页传输)、SMTP(邮件)、DNS(域名解析)和FTP(文件传输)协议。传输层涉及TCP(可靠数据传输)和UDP(高效但不可靠)。网络层由IP(路由数据包)、ICMP(错误报告)和路由器构成。数据链路层处理MAC地址和帧传输,物理层规定了电缆、连接器和信号标准。了解这些基础,有助于深入理解网络运作机制。
355 5
|
5月前
|
网络协议 网络性能优化 数据安全/隐私保护
计算机网络基础知识和术语(二)---分层结构模型
计算机网络基础知识和术语(二)---分层结构模型
79 1
|
4月前
|
运维 Java Docker
业务系统架构实践问题之在某些情况下,将能力代码和业务逻辑严格分层可能是一个挑战问题如何解决
业务系统架构实践问题之在某些情况下,将能力代码和业务逻辑严格分层可能是一个挑战问题如何解决
|
4月前
|
存储 搜索推荐 API
业务系统架构实践问题之分层架构中的四层定位是什么
业务系统架构实践问题之分层架构中的四层定位是什么
131 0
|
4月前
|
缓存 项目管理
项目管理定义问题之DDD架构的分层架构中基础层作用是什么
项目管理定义问题之DDD架构的分层架构中基础层作用是什么

热门文章

最新文章

下一篇
无影云桌面