网络编程-协议
2022-05-17 10:39:15 7 举报
AI智能生成
网络编程相关知识
作者其他创作
大纲/内容
抓包工具
Fiddler
Fiddler是位于客户端和服务器端的HTTP代理,也是目前最常用的http抓包工具之一 。 它能够记录客户端和服务器之间的所有 HTTP请求,可以针对特定的HTTP请求,分析请求数据、设置断点、调试web应用、修改请求的数据,甚至可以修改服务器返回的数据,功能非常强大,是web调试的利器。
特点
1.Fiddler是一个独立的应用,可以调试PC、Mac或Linux系统和移动设备的之间的通信,支持大部分框架如java、.net、java、Ruby,需要设置代理。
2.能够暂停Http通讯,并且允许修改请求和响应方便进行安全测试,也可以设置检查点做功能测试。
3.通过暴露HTTP头,用户可以看见哪些页面被允许在客户端或者是代理端进行缓存。如果要是一个响应没有包含Cache-Control头,那么他就不会被缓存在客户端。
4.可以通过Composer进行接口测试。
Firebug
特点
1、Firebug是firefox下的一个扩展,它除了能进行网络分析还能够调试所有网站语言,如js、Html、Css等,支持各种浏览器如IE、Firefox、Opera,、Safari。
2. Firebug是开源工具,能够将页面中的CSS、javascript以及网页中引用的图片载入所消耗的时间以矩状图呈现出来,方便我们对网页进行调优。
3.Firebug编辑、删改任何网站的CSS、HTML、DOM以及JavaScript代码,可以通过小箭头定位页面元素。
Charles
Charles是mac os和windows下的另外一个抓包软件(均收费,可破解),功能与fiddler类似
优点
可以自定义上下行网速、External Proxy、反向代理配置简单、可解析AMF协议数据
与Firebug相比
1.接口数据呈现方式对比:
Charles树状结构呈现于屏幕,清晰易区分
Fiddler默认按时间倒叙呈现所有接口数据,不易区分
2.针对项目App抓取的接口数据全面性对比:
Charles对于https无法直接获取到,可获取的呈现出来也都是乱码,需要安装ssl证书,后面会写具体设置方法。
Fiddler可以直接抓取所有接口数据,无需设置。
httpwatch
httpwatch与IE和firefox浏览器集成,但不支持chrome;httpwatch界面清晰直观,发送请求后可以快速简单的查看Cookies, Headers, Query Strings and POST data,能够通过页面分组处理多页面场景。
实时分级时间展示图能够展示一个http/https请求的处理过程;通过不同的颜色展示网络请求计时,如DNS查询,tcp连接;以瀑布形式展示浏览器事件,例如从浏览器渲染和页面加载计时就开始了,可以自动检查性能问题。
安装简单,不需要设置代理和证书;提供接口API可以被大部分编程语言自动化调用、录制、保存结果。
只能看不能修改
网络爬虫
网络爬虫是按照一定的规则,自动的抓取万维网信息的程序或者脚本
编程语言分类爬虫
PHP:PHP是世界是最好的语言,但他天生不是做这个的,而且对多线程、异步支持不是很好,并发处理能力弱。爬虫是工具性程序,对速度和效率要求比较高。
Java:生态圈很完善,是Python爬虫最大的竞争对手。但是Java语言本身很笨重,代码量很大。重构成本比较高,任何修改会导致代码大量改动。爬虫经常要修改采集代码
C/C++:运行效率是无敌的。但是学习和开发成本高。写个小爬虫程序可能要大半天时间
Python:语法优美、代码简洁、开发效率高、支持的模块多。相关的HTTP请求模块和HTML解析模块非常丰富。还有Scrapy和Scrapy-redis框架让我们开发爬虫变得异常简单
功能分类
通用爬虫:通用爬虫是搜索引擎抓取系统的重要组成部分,主要是将互联网上的网页下载到本地,形成一个互联网内容的镜像备份。
聚焦爬虫:聚焦爬虫指针对某一领域根据特定要求实现的爬虫程序,抓取需要的数据(垂直领域爬取)
聚焦爬虫设计思路
1,确定爬取的url,模拟浏览器向服务器发起请求;
2,获取响应数据并进行数据解析;
3,将目标数据持久化到本地;
请求
1,请求方法:request method
2,请求网址:request URL
3,请求头:request headers
4,请求体:request
例子
搜索引擎(百度, 谷歌)
多线程
多线程概念问题
内存模型
CAS
内存交换
happen-before
as-if-serial
顺序一致性模型
实践
双重检查锁定的问题
JUC包的实现基石
AQS
非阻塞数据结构
原子变量类
volatile内存语义
synchronized锁的优化
内存屏障
volatile的实现原理
线程基础问题
线程和进程
进程是资源分配的最小单位,线程是CPU调度的最小单位
并行和并发
并行
并行性是指同一时刻内发生两个或多个事件。
并发
并发性是指同一时间间隔内发生两个或多个事件。
线程的生命周期
线程同步
线程不安全
同步方式
使用互斥锁机制
使用互斥锁机制
同步代码块
同步方法
静态同步方法
Lock锁
线程通信
线程通信概念
线程通信指线程之间以什么机制交换信息
有共享内存和消息传递两种方式
线程通信方式
共享变量volatile(共享内存)
synchronized(共享内存)
等待/通知机制(消息传递)
管道输入/输出流(消息传递)
Thread类
Java使用Thread类来表示线程,有两种方式创建线程
继承Thread,重写run方法
实现Runnable接口,重写run方法
一般我们使用实现Runnable接口,可以避免java中的单继承的限制,并发运行任务和运行机制解耦
线程名
主线程叫做main,其他线程是Thread-x
守护线程
守护线程作为一个服务线程,没有服务对象就没有必要继续运行了
使用守护线程需要注意的地方
在线程启动前设置为守护线程,方法是setDaemon(boolean on)
使用守护线程不要访问共享资源(数据库、文件等),因为它可能会在任何时候就挂掉了。
守护线程中产生的新线程也是守护线程
优先级线程
线程优先级高仅仅表示线程获取的CPU时间片的几率高,但这不是一个确定的因素!
线程的优先级是高度依赖于操作系统的
线程的生命周期
sleep方法
调用sleep方法会进入计时等待状态,等时间到了,进入的是就绪状态而并非是运行状态!
不会释放锁
不会释放锁
yield方法
调用yield方法会先让别的线程执行,但是不确保真正让出
不会释放锁
不会释放锁
join方法
调用join方法,会等待该线程执行完毕后才执行别的线程~
会释放锁,底层调用wait()方法
会释放锁,底层调用wait()方法
interrupt方法
interrupt不会真正停止一个线程,它仅仅是给这个线程发了一个信号告诉它,它应该要结束了。是否中断,由被通知线程决定
interrupt方法压根是不会对线程的状态造成影响的,它仅仅设置一个标志位罢了
interrupt方法压根是不会对线程的状态造成影响的,它仅仅设置一个标志位罢了
interrupt线程中断还有另外两个方法(检查该线程是否被中断):
静态方法interrupted()-->会清除中断标志位
实例方法isInterrupted()-->不会清除中断标志位
如果阻塞线程(sleep,wait等)调用了interrupt()方法,
那么会抛出异常,设置标志位为false,同时该线程会退出阻塞的
那么会抛出异常,设置标志位为false,同时该线程会退出阻塞的
Java锁机制
synchronized锁
简介
synchronized是Java的一个关键字,它能够将代码块(方法)锁起来
JVM基于 进入和退出Monitor对象来实现方法同步和代码块同步
每个对象有自己的对象头,存储了很多信息,其中有一个标志位指向 Monitor。
当一个monitor被某一个线程持有后,其标志位 Owner被赋值为该线程唯一标志
当一个monitor被某一个线程持有后,其标志位 Owner被赋值为该线程唯一标志
性质
原子性
可见性
可重入锁
锁的持有者是“线程",而不是”调用“
公平锁与非公平锁
公平锁:线程将按照它们发出请求的顺序来获取锁
非公平锁:线程发出的请求时可以插队获取锁
Lock和synchronized都是默认使用非公平锁的,公平锁会带来一些性能的损耗
类锁与对象锁
静态方法获取的是类锁(类的字节码文件对象)
synchronized修饰普通方法或代码块获取的是对象锁
获取了类锁的线程和获取了对象锁的线程是不冲突的
synchronized锁升级
JDK1.6开始synchronized锁就做了各种优化
优化操作:适应自旋锁,锁消除,锁粗化,轻量级锁,偏向锁
Lock锁
简介
Lock方式来获取锁支持中断、超时不获取、是非阻塞的
支持Condition条件对象
Lock显式锁可以给我们带来很好的灵活性,但同时我们必须手动释放锁
允许多个读线程同时访问共享资源(读写锁)
Lock锁底层原理(AbstractQueuedSynchronizer简称为AQS)
AQS(队列同步器)是一个用来构建锁和其他同步组件的基础框架
内部实现的关键是:
volatile int 的成员变量state表示同步状态
FIFO队列完成线程获取资源的排队工作
一个指向获取当前锁的 线程变量
volatile int 的成员变量state表示同步状态
FIFO队列完成线程获取资源的排队工作
一个指向获取当前锁的 线程变量
拥有两种线程模式
独占模式
共享模式
在LOCK包中的相关锁(常用的有ReentrantLock、 ReadWriteLock)都是基于AQS来构建
细节
修改state状态值时使用CAS算法来实现
等待列被称为:CLH队列(三个名字组成),是一个双向队列
定义了框架,具体实现由子类来做(模板模式)!
ReentrantLock锁
比synchronized更有伸缩性(灵活)
使用时最标准用法是在try之前调用lock方法,在finally代码块释放锁
ReentrantReadWriteLock锁
在读的时候可以共享,在写的时候是互斥的
读锁不能升级为写锁,写锁可以降级为读锁
在内部定义了两个内部类来代表读锁和写锁,本质上还是AQS实现
它使用state的变量高16位是读锁,低16位是写锁
死锁
在死锁时,线程/进程间相互等待资源,而又不释放自身资源,导致无穷无尽的等待,
其结果是任务永远无法执行完成。
其结果是任务永远无法执行完成。
产生死锁的四个必要条件
1. 互斥条件: 一个资源每次只能被一个线程/进程使用
2. 请求与保持条件: 一个线程/进程因请求资源而在阻塞时,对已获得的资源保持不放
3. 不可剥夺条件:线程/进程已获得的资源,在未使用完之前,不能强行剥夺
4. 循环等待条件:若干线程/进程之间形成一种头尾相接的循环等待资源关系
避免死锁
死锁检测和解除
同步工具类
CountDownLatch(闭锁)
某个线程等待其他线程执行完毕后,它才执行(其他线程等待某个线程执行完毕后,它才执行)
CyclicBarrier
一组线程互相等待至某个状态,这组线程再同时执行。
Semaphore
控制同时访问的线程个数
ThreadLocal
ThreadLocal的作用是提供线程内的局部变量,每个线程都可以通过set()和get()来对这个局部变量进行操作,
但不会和其他线程的局部变量进行冲突,实现了线程的数据隔离
但不会和其他线程的局部变量进行冲突,实现了线程的数据隔离
常见的应用
减少同一个线程内多个函数或者组件之间一些公共变量的传递的复杂度。
比如将Connection与当前线程绑定。保证了能进行事务控制。
比如将Connection与当前线程绑定。保证了能进行事务控制。
实现原理
Thread为每个线程维护了ThreadLocalMap这么一个Map,而ThreadLocalMap的key是ThreadLocal对象本身,value则是要存储的对象
想要避免内存泄露就要手动remove()掉!
ThreadLocal设计的目的就是为了能够在当前线程中有属于自己的变量,并不是为了解决并发或者共享变量的问题
Atomic原子类
原子类可分为4种类型:基本数据类型、数组、引用类型、对象的属性
Atomic包里的类基本都是使用Unsafe实现的包装类 (CAS)
解决ABA问题可以使用AtomicStampedReference类(加上了版本号)
LongAdder性能比AtomicLong要好
分段CAS
自动迁移
线程池
线程池的好处
降低资源消耗
通过重复利用已创建的线程降低线程的创建和销毁造成的消耗
提高响应速度
当任务到达时,任务可以不需要等到线程创建就立即执行
提高线程的可管理性
线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性。
使用线程池可以进行统一分配,调优和监控。
使用线程池可以进行统一分配,调优和监控。
线程池框架
线程池生命周期
执行流程
ThreadPoolExecutor详解
变量ctl定义为AtomicInteger,记录了“线程池中的线程数量”和“线程池的状态”两个信息。
高3位表示线程池状态,低29位表示任务线程的数量
线程状态就定义了好几种:
RUNNING:线程池能够接受新任务,以及对新添加的任务进行处理。
SHUTDOWN:线程池不可以接受新任务,但是可以对已添加的任务进行处理。
STOP:线程池不接收新任务,不处理已添加的任务,并且会中断正在处理的任务。
TIDYING:当所有的任务已终止,ctl记录的"任务数量"为0,线程池会变为TIDYING状态。
TERMINATED:线程池彻底终止的状态。
构造函数成员变量详解
线程池有各种的策略:
线程数量策略
如果运行线程的数量少于核心线程数量,则创建新的线程处理请求
如果运行线程的数量大于核心线程数量,小于最大线程数量,则当队列满的时候才创建新的线程
如果核心线程数量等于最大线程数量,那么将创建固定大小的连接池
如果设置了最大线程数量为无穷,那么允许线程池适合任意的并发数量
如果运行线程的数量大于核心线程数量,小于最大线程数量,则当队列满的时候才创建新的线程
如果核心线程数量等于最大线程数量,那么将创建固定大小的连接池
如果设置了最大线程数量为无穷,那么允许线程池适合任意的并发数量
线程空闲时间
当前线程数大于核心线程数,如果空闲时间已经超过了,那该线程会销毁。
排队策略
跟阻塞队列相关
同步移交:不会放到队列中,而是等待线程执行它。如果当前线程没有执行,很可能会新开一个线程执行。
无界限策略:如果核心线程都在工作,该线程会放到队列中。所以线程数不会超过核心线程数
有界限策略:可以避免资源耗尽,但是一定程度上减低了吞吐量
无界限策略:如果核心线程都在工作,该线程会放到队列中。所以线程数不会超过核心线程数
有界限策略:可以避免资源耗尽,但是一定程度上减低了吞吐量
拒绝任务策略
直接抛出异常
使用调用者的线程来处理
直接丢掉这个任务
丢掉最老的任务,并尝试重新执行该任务
使用调用者的线程来处理
直接丢掉这个任务
丢掉最老的任务,并尝试重新执行该任务
Executors中已默认实现的池
newFixedThreadPool
它将返回一个corePoolSize和maximumPoolSize相等的线程池
newCachedThreadPool
非常有弹性的线程池,对于新的任务,如果此时线程池里没有空闲线程,线程池会毫不犹豫的创建一条新的线程去处理这个任务。
SingleThreadExecutor
单个worker线程的Executor
ScheduledThreadPoolExecutor
提供了“延迟”和“周期执行”任务的功能
execute执行方法
如果线程池中运行的线程数量<corePoolSize,则创建新线程来处理请求,即使其他辅助线程是空闲的。
如果线程池中运行的线程数量>=corePoolSize,且线程池处于RUNNING状态,且把提交的任务成功放入阻塞队列中,就再次检查线程池的状态
因为将任务放入阻塞队列过程中线程池可能关闭了,或者说某个线程被回收了。
因为将任务放入阻塞队列过程中线程池可能关闭了,或者说某个线程被回收了。
1.如果线程池不是RUNNING状态,且成功从阻塞队列中删除任务,则该任务由当前 RejectedExecutionHandler 处理。
2.否则如果线程池中运行的线程数量为0,则通过addWorker(null, false)尝试新建一个线程,新建线程对应的任务为null。
如果以上两种case不成立,即没能将任务成功放入阻塞队列中,且addWoker新建线程失败,
说明线程池关闭了,或者队列饱和了 则该任务由当前 RejectedExecutionHandler 处理。
说明线程池关闭了,或者队列饱和了 则该任务由当前 RejectedExecutionHandler 处理。
线程池关闭
调用shutdown()后,线程池状态立刻变为SHUTDOWN,而调用shutdownNow(),线程池状态立刻变为STOP。
shutdown()等待任务执行完才中断线程,而shutdownNow()不等任务执行完就中断了线程
线程数合理配置
如何合理地配置线程池大小
IO密集
CPU密集
线程安全
主要是多个线程对同一变量进行操作时,程序没有按照预期情况执行
解决办法
不可变
在java语言中,不可变的对象一定是线程安全的,无论是对象的方法实现还是方法的调用者,都不需要再采取任何的线程安全保障措施。final关键字修饰的类或数据不可修改,可靠性最高。如 String类,Integer类。
线程封闭
Ad-hoc 线程封闭
Ad-hoc线程封闭是指维护线程封闭性的职责完全由程序实现来承担。Ad-hoc线程封闭是非常脆弱的,因为没有任何一种语言特性,例如可见性修饰符或局部变量,能将对象封闭到目标线程上。事实上,对线程封闭对象(例如,GUI应用程序中的可视化组件或数据模型等)的引用通常保存在公有变量中。
ThreadLocal线程封闭
它是一个特别好的封闭方法,其实ThreadLocal内部维护了一个map,map的key是每个线程的名称,而map的value就是我们要封闭的对象。ThreadLocal提供了get、set、remove方法,每个操作都是基于当前线程的,所以它是线程安全的。
堆栈封闭
堆栈封闭其实就是方法中定义局部变量。不存在并发问题。多个线程访问一个方法的时候,方法中的局部变量都会被拷贝一份到线程的栈中(Java内存模型),所以局部变量是不会被多个线程所共享的。
同步
悲观锁
同步的最常用的方法是使用锁(Lock),它是一种非强制机制,每个线程在访问数据或资源之前首先试图获取锁,并在访问结束之后释放锁;在锁已经被占用的时候试图获取锁时,线程会等待,直到锁重新可用。
实现方式
synchronized
Lock.lock()/Lock.unLock()
乐观锁
先进行操作,如果没有其他线程争用共享数据,那操作就成功了;如果共享数据有争用,产生了冲突,那就再采用其他的补偿措施。这种乐观的并发策略的许多实现都不需要把线程挂起,因此这种同步操作称为非阻塞同步
实现方式
非阻塞的实现CAS(Compare-and-Swap)
为了避免ABA问题,一般增加个版本号进行对比控制
工具类
同步容器的工具有Vector、HashTable、Collections.synchroniedXXX()
并发容器(JUC)
ConcurrentHashMap
CopyOnWriteArrayList
JUC同步器 AQS
AQS是一个同步器,设计模式是模板模式
aqs全称为AbstractQueuedSynchronizer,它提供了一个FIFO队列,可以看成是一个用来实现同步锁以及其他涉及到同步功能的核心组件,常见的有:ReentrantLock、CountDownLatch等。
AQS功能
独占锁,每次只能有一个线程持有锁
共享锁,允许多个线程同时获取锁,并发访问共享资源
AQS的内部实现
AQS的实现依赖内部的同步队列,也就是FIFO的双向队列,如果当前线程竞争锁失败,那么AQS会把当前线程以及等待状态信息构造成一个Node加入到同步队列中,同时再阻塞该线程。当获取锁的线程释放锁以后,会从队列中唤醒一个阻塞的节点(线程)。
GET和POST
get与post为http请求的两种方式
get
从指定的资源请求数据。
GET 请求可被缓存
GET 请求保留在浏览器历史记录中
GET 请求可被收藏为书签
GET 请求不应在处理敏感数据时使用
GET 请求有长度限制
GET 请求只应当用于取回数据
post
向指定的资源提交要被处理的数据。
POST 请求不会被缓存
POST 请求不会保留在浏览器历史记录中
POST 不能被收藏为书签
POST 请求对数据长度没有要求
区别
GET在浏览器回退时是无害的,而POST会再次提交请求。
GET产生的URL地址可以被Bookmark,而POST不可以。
GET请求会被浏览器主动cache,而POST不会,除非手动设置。
GET请求只能进行url编码,而POST支持多种编码方式。
GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
GET请求在URL中传送的参数是有长度限制的,而POST么有。
对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
GET参数通过URL传递,POST放在Request body中。
长连接跟短连接
当网络通信时采用TCP协议时,在真正的读写操作之前,server与client之间必须建立一个连接,当读写操作完成后,双方不再需要这个连接时它们可以释放这个连接,连接的建立是需要三次握手的,而释放则需要4次挥手,所以说每个连接的建立都是需要资源消耗和时间消耗的
长连接
长连接,指在一个TCP连接上可以连续发送多个数据包,在TCP连接保持期间,如果没有数据包发送,需要双方发检测包以维持此连接,一般需要自己做在线维持(不发生RST包和四次挥手)。
短连接
短连接是指通信双方有数据交互时,就建立一个TCP连接,数据发送完成后,则断开此TCP连接(管理起来比较简单,存在的连接都是有用的连接,不需要额外的控制手段);
应用场景
长连接多用于操作频繁(读写),点对点的通讯,而且连接数不能太多情况,。每个TCP连接都需要三步握手,这需要时间,如果每个操作都是先连接,再操作的话那么处理速度会降低很多,所以每个操作完后都不断开,次处理时直接发送数据包就OK了,不用建立TCP连接。例如:数据库的连接用长连接, 如果用短连接频繁的通信会造成socket错误,而且频繁的socket 创建也是对资源的浪费
而像WEB网站的http服务一般都用短链接(http1.0只支持短连接,1.1keep alive 带时间,操作次数限制的长连接),因为长连接对于服务端来说会耗费一定的资源,而像WEB网站这么频繁的成千上万甚至上亿客户端的连接用短连接会更省一些资源,如果用长连接,而且同时有成千上万的用户,如果每个用户都占用一个连接的话,那可想而知吧。所以并发量大,但每个用户无需频繁操作情况下需用短连好;
序列化跟反序列化
简介
序列化:把Java对象转换为字节序列的过程。
主要用途
把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
在网络上传送对象的字节序列。
反序列化:把字节序列恢复为Java对象的过程。
常见的序列化格式
Json
语法
JSON中的元素都是键值对——key:value形式,键值对之间以":"分隔,每个键需用双引号引起来,值的类型为String时也需要双引号。其中value的类型包括:对象,数组,值,每种类型具有不同的语法表示。
基础类型
json数据中地值(value)可以是双引号括起来的字符串(string)、数值(number)、true、false、 null、对象(object)或者数组(array)。这些结构可以嵌套。
字符串(string)是由双引号包围的任意数量Unicode字符的集合,使用反斜线转义。一个字符(character)即一个单独的字符串(character string)。
数值(number)也与C或者Java的数值非常相似。除去未曾使用的八进制与十六进制格式。除去一些编码细节。
对象
对象是一个无序的键值对集合。以"{"开始,以"}"结束, 每个成员以","分隔。
数组
数组是一个有序的集合,以"["开始,以"]"结束,成员之间以","分隔。
Protobuf
Google Protocol Buffer( 简称 Protobuf) 是 Google 公司内部的混合语言数据标准,它是 是一种轻便高效的结构化数据存储格式,可以用于结构化数据串行化,或者说序列化。它很适合做数据存储或 RPC 数据交换格式。可用于通讯协议、数据存储等领域的语言无关、平台无关、可扩展的序列化结构数据格式。
XML
可扩展标记语言(英语:Extensible Markup Language,简称:XML),是一种标记语言。标记指计算机所能理解的信息符号,通过此种标记,计算机之间可以处理包含各种信息的文章等
序列化协议的特性
通用性
技术层面,序列化协议是否支持跨平台、跨语言。如果不支持,在技术层面上的通用性就大大降低了。
流行程度,序列化和反序列化需要多方参与,很少人使用的协议往往意味着昂贵的学习成本;另一方面,流行度低的协议,往往缺乏稳定而成熟的跨语言、跨平台的公共包。
强健性 / 鲁棒性
成熟度不够,一个协议从制定到实施,到最后成熟往往是一个漫长的阶段。协议的强健性依赖于大量而全面的测试,对于致力于提供高质量服务的系统,采用处于测试阶段的序列化协议会带来很高的风险。
语言 / 平台的不公平性。为了支持跨语言、跨平台的功能,序列化协议的制定者需要做大量的工作;但是,当所支持的语言或者平台之间存在难以调和的特性的时候,协议制定者需要做一个艰难的决定 -- 支持更多人使用的语言 / 平台,亦或支持更多的语言 / 平台而放弃某个特性。当协议的制定者决定为某种语言或平台提供更多支持的时候,对于使用者而言,协议的强健性就被牺牲了。
可调试性 / 可读性
支持不到位,跨公司调试在问题出现后可能得不到及时的支持,这大大延长了调试周期
访问限制,调试阶段的查询平台未必对外公开,这增加了读取方的验证难度。
可扩展性 / 兼容性
安全性 / 访问限制
如果使用的序列化协议没有兼容而成熟的 HTTP 传输层框架支持,可能会导致以下三种结果之一
因为访问限制而降低服务可用性;
被迫重新实现安全协议而导致实施成本大大提高;
开放更多的防火墙端口和协议访问,而牺牲安全性。
性能
空间开销(Verbosity), 序列化需要在原有的数据上加上描述字段,以为反序列化解析之用。如果序列化过程引入的额外开销过高,可能会导致过大的网络,磁盘等各方面的压力。对于海量分布式存储系统,数据量往往以 TB 为单位,巨大的的额外空间开销意味着高昂的成本。
时间开销(Complexity),复杂的序列化协议会导致较长的解析时间,这可能会使得序列化和反序列化阶段成为整个系统的瓶颈。
序列化和反序列化协议选择原则
通用性
可调式性/可读性
稳定性
可扩展性
性能
0 条评论
下一页