微服务开发实战

微服务之协议概述

2018-06-02  本文已影响9人  老瓦在霸都

微服务协议

互联网协议很多,TCP IP 是基础协议,在它之上有众多应用层协议,这里关注的微服务以什么协议向外提供服务, 即以什么方式, 或者说以什么手段, 通过什么媒介来提供面向用户或者其他服务提供他们所需要的服务。传统的单体服务对外一般提供RPC (远程方法调用)的接口, 对内的组件之间通过方法调用或者线程/进程间通信就行了.

而微服务一般所提供的服务都是节点与节点之间的远程分布式调用, 使用基于流式的TCP 连接或基于数据包的UDP 连接之上的应用层协议

协议都是分层的, OSI的七层网络模型中, 我们关心的是传输层以上, 主要是应用层的协议

协议分类

按照它所针对的语义可以分为

面向资源

比如 REST, 主要是对于资源的存取和修改

面向命令

比如SOAP, RMI,RPC , 主要是指对于方法, 命令及过程的远程调用

面向事件

比如 XMPP, JMS,AMQP, 主要是对于消息的传递和转发

按照远程调用协议的编码可以分为

文本协议

例如 HTTP + JSON/XML, SIP

二进制协议

例如 WebSocket + BSon/Protobuf

按照协议的用途可以分为

信令及控制协议

例如 SIP, SDP, Jingle, ROAP

媒体传输协议

例如 HTTP, RTP, RTMP

安全相关协议

例如 TLS, DTLS, oAuth2

按交互方式分类

基本上是 Request 请求/ Response 响应 方式, 这其中的响应有所区别, 主要就是看是不是最终响应

请求/搞定

client->server: POST /calls
server-->client: 201 created

或者

client->server: send request PDU
server-->client: send response PDU

请求/收到

这时候, 一般客户端只是收到一个接受的响应, 最终结果需要客户端轮询和给一个回调的地址

client->server: POST /orders (including callbackUrl)
server-->client: 202 accepted
client->server: GET /orders/tasks/taskid
server->client: 200 OK (state: doing)
server->client: POST /callbackurl
client->server: 200 OK (state:finished)

如果是基于长连接的协议, 比如 WebSocket, 应用层的TCP协议包, 这种方式用得最多

client->server: send PDU(request)
server-->client: reply PDU(ack)
server->client: send PDU (result)
server->client: reply PDU (ack)

请求/协商/确认

典型的 SIP 会话搭建流程

client->server: SIP Invite
server-->client: SIP 200 OK
server->client: SIP Ack

Pub/sub 发布/订阅

image.png
client1->broker: subscribe
broker->client1: ok
client2->broker: publish event
broker-->client2: ok
broker->client1: event
client1-->broker: ok

按数据传输格式分类

任何一个服务会使用一个协议栈, 从下到上采用相应的协议, 上层服务应用协议所使用的数据传输格式很多,但无非表示为文本和二进制格式

HTTP 是互联网的最主要的协议, 也是微服务中最流行的协议, 在它之上, 又有 RPC (Remote Procedure Call 远程过程调用) 和 REST (Representational state transfer 表述性状态转移) 两种风格.
前者多使用 HTTP + XML(SOAP), 后者多使用 HTTP + JSON(REST)

WebSocket + Protobuf 也是一个比较流行的做法, 发挥了长连接双向通讯的优势, 并且编解码速度比较快

文本格式

常用的有

二进制格式

常用的有

基于 TCP 的流式传输, 在数据包之间必需有易于识别的分隔符, 文本格式中用得最多的就是 \r\n, 或者类似于 xml/json 之类的 tag, 成对的 {} 或 []. 二进制格式中一般会在包头指定长度, 以便分割, 例如 SMTP 和 HTTP 协议,

$ curl https://tools.ietf.org/rfc/rfc768.txt -vvv

*   Trying 4.31.198.61...
* TCP_NODELAY set
* Connected to tools.ietf.org (4.31.198.61) port 443 (#0)
* TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
* Server certificate: *.tools.ietf.org
* Server certificate: Starfield Secure Certificate Authority - G2
* Server certificate: Starfield Root Certificate Authority - G2
> GET /rfc/rfc768.txt HTTP/1.1
> Host: tools.ietf.org
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Date: Sun, 20 May 2018 02:29:29 GMT
< Server: Apache/2.2.22 (Debian)
< Last-Modified: Thu, 15 Oct 1992 21:56:01 GMT
< ETag: "108828d-1708-28e1893a75e40"
< Accept-Ranges: bytes
< Content-Length: 5896
< Vary: Accept-Encoding
< Strict-Transport-Security: max-age=3600
< X-Frame-Options: SAMEORIGIN
< X-Xss-Protection: 1; mode=block
< X-Content-Type-Options: nosniff
< X-Clacks-Overhead: GNU Terry Pratchett
< Content-Type: text/plain; charset=UTF-8
<


RFC 768                                                        J. Postel
...

UDP 本身就是以数据包为单位的, 一个一个包收就好了, 不过一般在包中会承载序号信息, 以便对丢包或乱序进行处理, 之后我们来详细分析下文本协议的代表 HTTP, 以及二进制协议的代表 RTP

协议分析

协议标准理解

分析协议的第一步是阅读相应的协议标准 RFC(Request for Comments), 互联网的核心是 TCP/IP 协议簇

packet header + payload 是基本格式,

IP packet 的包头为20个字节, IP 包头中包含 IP源地址, 目的地址, TTL 存活时间 (所经过路由器的跳数)

上层协议不必关心下层协议, 但是是知道IP是3层协议, 2层所使用的数据链路协议如果是以太网, 以最大传输单元(MTU)为 1500 字节, 如果你的包的长度超过这个长度, 网络设备会将这个IP数据包分片传输, 划分成多个 IP packet

TCP 包头中包含源端口, 目的端口, 序列号, 确认号, 类型标记, 窗口大小, 校验和等.
TCP是一个很复杂和强大的协议

UDP 包头包含源端口, 目的端口, 内容长度, 校验和, 它非常简单, 所以你可以发现基于它之上的众多协议会建立许多类似于TCP的序号, 标记等机制

协议包分析

第二步就是抓包, 最常用的是 tcpdump 和 wireshark, 通常在服务器端用 tcpdump 抓完包后, 用 wireshark 打开抓包文件 *. pcap 进行详细分析

这里还推荐一个 python 工具 scapy , 它是一个功能强大的基于Python的交互式数据包操作程序和库。
可以从 https://github.com/secdev/scapy 下载, 或者直接用 pip 安装

pip install scapy
pip install matplotlib
pip install pyx

它能够伪造或解码大量协议的数据包,在线上发送它们,捕获它们,使用pcap文件存储或读取它们,匹配请求和回复等等。 它旨在通过使用默认值来实现快速数据包原型设计。

简单用它来看来 IP 和 TCP 的包头

$ scapy

>>> pkt =IP(ttl=10, dst="192.168.1.1")/TCP(flags="SF")
>>> pkt.summary()
'IP / TCP 10.79.102.90:ftp_data > 192.168.1.1:http FS'
>>> pkt.show()
###[ IP ]###
  version= 4
  ihl= None
  tos= 0x0
  len= None
  id= 1
  flags=
  frag= 0
  ttl= 10
  proto= tcp
  chksum= None
  src= 10.79.102.90
  dst= 192.168.1.1
  \options\
###[ TCP ]###
     sport= ftp_data
     dport= http
     seq= 0
     ack= 0
     dataofs= None
     reserved= 0
     flags= FS
     window= 8192
     chksum= None
     urgptr= 0
     options= {}

上一篇下一篇

猜你喜欢

热点阅读