RPC服务和HTTP服务对比

很长时间以来都没有怎么好好搞清楚RPC(即Remote Procedure Call,远程过程调用)和HTTP调用的区别,不都是写一个服务然后在客户端调用么?这里请允许我迷之一笑~Naive!本文简单地介绍一下两种形式的C/S架构,先说一下他们最本质的区别,就是RPC主要是基于TCP/IP协议的,而HTTP服务主要是基于HTTP协议的,我们都知道HTTP协议是在传输层协议TCP之上的,所以效率来看的话,RPC当然是要更胜一筹啦!下面来具体说一说RPC服务和HTTP服务。

OSI网络七层模型

在说RPC和HTTP的区别之前,我觉的有必要了解一下OSI的七层网络结构模型(虽然实际应用中基本上都是五层),它可以分为以下几层: (从上到下)

  • 第一层:应用层。定义了用于在网络中进行通信和传输数据的接口;
  • 第二层:表示层。定义不同的系统中数据的传输格式,编码和解码规范等;
  • 第三层:会话层。管理用户的会话,控制用户间逻辑连接的建立和中断;
  • 第四层:传输层。管理着网络中的端到端的数据传输;
  • 第五层:网络层。定义网络设备间如何传输数据;
  • 第六层:链路层。将上面的网络层的数据包封装成数据帧,便于物理层传输;
  • 第七层:物理层。这一层主要就是传输这些二进制数据。

实际应用过程中,五层协议结构里面是没有表示层和会话层的。应该说它们和应用层合并了。我们应该将重点放在应用层和传输层这两个层面。因为HTTP是应用层协议,而TCP是传输层协议。好,知道了网络的分层模型以后我们可以更好地理解为什么RPC服务相比HTTP服务要Nice一些!

RPC服务

从三个角度来介绍RPC服务:分别是RPC架构,同步异步调用以及流行的RPC框架。

RPC架构

先说说RPC服务的基本架构吧。允许我可耻地盗一幅图哈~我们可以很清楚地看到,一个完整的RPC架构里面包含了四个核心的组件,分别是Client ,Server,Client Stub以及Server Stub,这个Stub大家可以理解为存根。分别说说这几个组件:

  • 客户端(Client),服务的调用方。
  • 服务端(Server),真正的服务提供者。
  • 客户端存根,存放服务端的地址消息,再将客户端的请求参数打包成网络消息,然后通过网络远程发送给服务方。
  • 服务端存根,接收客户端发送过来的消息,将消息解包,并调用本地的方法。

RPC主要是用在大型企业里面,因为大型企业里面系统繁多,业务线复杂,而且效率优势非常重要的一块,这个时候RPC的优势就比较明显了。实际的开发当中是这么做的,项目一般使用maven来管理。比如我们有一个处理订单的系统服务,先声明它的所有的接口(这里就是具体指Java中的interface),然后将整个项目打包为一个jar包,服务端这边引入这个二方库,然后实现相应的功能,客户端这边也只需要引入这个二方库即可调用了。为什么这么做?主要是为了减少客户端这边的jar包大小,因为每一次打包发布的时候,jar包太多总是会影响效率。另外也是将客户端和服务端解耦,提高代码的可移植性。

同步调用与异步调用

什么是同步调用?什么是异步调用?同步调用就是客户端等待调用执行完成并返回结果。异步调用就是客户端不等待调用执行完成返回结果,不过依然可以通过回调函数等接收到返回结果的通知。如果客户端并不关心结果,则可以变成一个单向的调用。这个过程有点类似于Java中的callablerunnable接口,我们进行异步执行的时候,如果需要知道执行的结果,就可以使用callable接口,并且可以通过Future类获取到异步执行的结果信息。如果不关心执行的结果,直接使用runnable接口就可以了,因为它不返回结果,当然啦,callable也是可以的,我们不去获取Future就可以了。

流行的RPC框架

目前流行的开源RPC框架还是比较多的。下面重点介绍三种:

  1. gRPC是Google最近公布的开源软件,基于最新的HTTP2.0协议,并支持常见的众多编程语言。 我们知道HTTP2.0是基于二进制的HTTP协议升级版本,目前各大浏览器都在快马加鞭的加以支持。 这个RPC框架是基于HTTP协议实现的,底层使用到了Netty框架的支持。
  2. Thrift是Facebook的一个开源项目,主要是一个跨语言的服务开发框架。它有一个代码生成器来对它所定义的IDL定义文件自动生成服务代码框架。用户只要在其之前进行二次开发就行,对于底层的RPC通讯等都是透明的。不过这个对于用户来说的话需要学习特定领域语言这个特性,还是有一定成本的。
  3. Dubbo是阿里集团开源的一个极为出名的RPC框架,在很多互联网公司和企业应用中广泛使用。协议和序列化框架都可以插拔是及其鲜明的特色。同样 的远程接口是基于Java Interface,并且依托于spring框架方便开发。可以方便的打包成单一文件,独立进程运行,和现在的微服务概念一致。

偷偷告诉你集团内部已经不怎么使用dubbo啦,现在用的比较多的叫HSF,又名“好舒服”。后面有可能会开源,大家拭目以待。

HTTP服务

其实在很久以前,我对于企业开发的模式一直定性为HTTP接口开发,也就是我们常说的RESTful风格的服务接口。的确,对于在接口不多、系统与系统交互较少的情况下,解决信息孤岛初期常使用的一种通信手段;优点就是简单、直接、开发方便。利用现成的http协议进行传输。我们记得之前本科实习在公司做后台开发的时候,主要就是进行接口的开发,还要写一大份接口文档,严格地标明输入输出是什么?说清楚每一个接口的请求方法,以及请求参数需要注意的事项等。比如下面这个例子:
POST http://www.httpexample.com/restful/buyer/info/share
接口可能返回一个JSON字符串或者是XML文档。然后客户端再去处理这个返回的信息,从而可以比较快速地进行开发。但是对于大型企业来说,内部子系统较多、接口非常多的情况下,RPC框架的好处就显示出来了,首先就是长链接,不必每次通信都要像http一样去3次握手什么的,减少了网络开销;其次就是RPC框架一般都有注册中心,有丰富的监控管理;发布、下线接口、动态扩展等,对调用方来说是无感知、统一化的操作。

总结

RPC服务和HTTP服务还是存在很多的不同点的,一般来说,RPC服务主要是针对大型企业的,而HTTP服务主要是针对小企业的,因为RPC效率更高,而HTTP服务开发迭代会更快。总之,选用什么样的框架不是按照市场上流行什么而决定的,而是要对整个项目进行完整地评估,从而在仔细比较两种开发框架对于整个项目的影响,最后再决定什么才是最适合这个项目的。一定不要为了使用RPC而每个项目都用RPC,而是要因地制宜,具体情况具体分析。

分布式架构的演进

分布式架构的演进

系统架构演化历程-初始阶段架构

初始阶段 的小型系统 应用程序、数据库、文件等所有的资源都在一台服务器上通俗称为LAMP

特征:
应用程序、数据库、文件等所有的资源都在一台服务器上。

描述:
通常服务器操作系统使用linux,应用程序使用PHP开发,然后部署在Apache上,数据库使用Mysql,汇集各种免费开源软件以及一台廉价服务器就可以开始系统的发展之路了。

系统架构演化历程-应用服务和数据服务分离

好景不长,发现随着系统访问量的再度增加,webserver机器的压力在高峰期会上升到比较高,这个时候开始考虑增加一台webserver

特征:
应用程序、数据库、文件分别部署在独立的资源上。

描述:
数据量增加,单台服务器性能及存储空间不足,需要将应用和数据分离,并发处理能力和数据存储空间得到了很大改善。

系统架构演化历程-使用缓存改善性能

特征:
数据库中访问较集中的一小部分数据存储在缓存服务器中,减少数据库的访问次数,降低数据库的访问压力。

描述:
系统访问特点遵循二八定律,即80%的业务访问集中在20%的数据上。
缓存分为本地缓存和远程分布式缓存,本地缓存访问速度更快但缓存数据量有限,同时存在与应用程序争用内存的情况。

系统架构演化历程-使用应用服务器集群

在做完分库分表这些工作后,数据库上的压力已经降到比较低了,又开始过着每天看着访问量暴增的幸福生活了,突然有一天,发现系统的访问又开始有变慢的趋势了,这个时候首先查看数据库,压力一切正常,之后查看webserver,发现apache阻塞了很多的请求,而应用服务器对每个请求也是比较快的,看来 是请求数太高导致需要排队等待,响应速度变慢

特征:
多台服务器通过负载均衡同时向外部提供服务,解决单台服务器处理能力和存储空间上限的问题。

描述:
使用集群是系统解决高并发、海量数据问题的常用手段。通过向集群中追加资源,提升系统的并发处理能力,使得服务器的负载压力不再成为整个系统的瓶颈。

系统架构演化历程-数据库读写分离

享受了一段时间的系统访问量高速增长的幸福后,发现系统又开始变慢了,这次又是什么状况呢,经过查找,发现数据库写入、更新的这些操作的部分数据库连接的资源竞争非常激烈,导致了系统变慢

特征:
多台服务器通过负载均衡同时向外部提供服务,解决单台服务器处理能力和存储空间上限的问题。

描述:
使用集群是系统解决高并发、海量数据问题的常用手段。通过向集群中追加资源,使得服务器的负载压力不在成为整个系统的瓶颈。

系统架构演化历程-反向代理和CDN加速

特征:
采用CDN和反向代理加快系统的 访问速度。

描述:
为了应付复杂的网络环境和不同地区用户的访问,通过CDN和反向代理加快用户访问的速度,同时减轻后端服务器的负载压力。CDN与反向代理的基本原理都是缓存。

系统架构演化历程-分布式文件系统和分布式数据库

随着系统的不断运行,数据量开始大幅度增长,这个时候发现分库后查询仍然会有些慢,于是按照分库的思想开始做分表的工作

特征:
数据库采用分布式数据库,文件系统采用分布式文件系统。

描述:
任何强大的单一服务器都满足不了大型系统持续增长的业务需求,数据库读写分离随着业务的发展最终也将无法满足需求,需要使用分布式数据库及分布式文件系统来支撑。
分布式数据库是系统数据库拆分的最后方法,只有在单表数据规模非常庞大的时候才使用,更常用的数据库拆分手段是业务分库,将不同的业务数据库部署在不同的物理服务器上。

系统架构演化历程-使用NoSQL和搜索引擎

特征:
系统引入NoSQL数据库及搜索引擎。

描述:
随着业务越来越复杂,对数据存储和检索的需求也越来越复杂,系统需要采用一些非关系型数据库如NoSQL和分数据库查询技术如搜索引擎。应用服务器通过统一数据访问模块访问各种数据,减轻应用程序管理诸多数据源的麻烦。

系统架构演化历程-业务拆分

特征:
系统上按照业务进行拆分改造,应用服务器按照业务区分进行分别部署。

描述:
为了应对日益复杂的业务场景,通常使用分而治之的手段将整个系统业务分成不同的产品线,应用之间通过超链接建立关系,也可以通过消息队列进行数据分发,当然更多的还是通过访问同一个数据存储系统来构成一个关联的完整系统。

纵向拆分:
将一个大应用拆分为多个小应用,如果新业务较为独立,那么就直接将其设计部署为一个独立的Web应用系统

纵向拆分相对较为简单,通过梳理业务,将较少相关的业务剥离即可。

横向拆分:将复用的业务拆分出来,独立部署为分布式服务,新增业务只需要调用这些分布式服务

横向拆分需要识别可复用的业务,设计服务接口,规范服务依赖关系。
系统架构演化历程-分布式服务

特征:
公共的应用模块被提取出来,部署在分布式服务器上供应用服务器调用。

描述:
随着业务越拆越小,应用系统整体复杂程度呈指数级上升,由于所有应用要和所有数据库系统连接,最终导致数据库连接资源不足,拒绝服务。

转载:https://www.zhihu.com/question/22764869/answer/31277656

子系统拆分的一点总结

公司系统做了一年多,慢慢也有点规模了。从最初只有一个APP + 一个server的模式,到现在有多个子系统,多个客户端。这个过程中,积累了一些想法,本文简单总结一下

系统拆分的好处

基本上,比较小的系统,单进程集中部署就可以了。集中部署不代表一定不好,在系统规模很小的时候,或许是最适合的,因为调用关系简单,开发也比较容易。但是系统慢慢变大了以后,我认为拆分系统,分布式部署就变得更为合理了。

拆分系统至少有这些我体会到的好处:

1、停掉系统的一个部分,只会影响相关业务,不会造成整体业务中断。特别是一个新的模块上线,尚未稳定的时候,可能会有错误挂掉,或者主动重启维护等,如果是集中部署,就会造成整个系统都不可用。但是分布式部署的情况下,只会中断小范围的业务。当然,就算是集中部署,利用集群,分批重启,也可以实现同样的目的

2、对压力大的节点,可以单独部署集群。比如我们的系统,数据同步模块的负载是最高的,那么就可以针对这个子系统单独部署集群,其他负载低的模块,可以部署在一起,或者单独部署,都比较灵活。当然,要实现水平伸缩,对系统设计本身也有要求,比如至少要实现无状态服务等

3、代码分离,便于权限控制。一般来说,集中部署的代码也是在一起的,如果希望负责子系统A的小组,不需要接触到子系统B的代码,那么分成2个代码库就非常容易实现。相反,如果代码都是在一起的,控制就比较困难。因为不能只开放一部分代码给开发人员,这样不利于在本地搭建开发环境

4、按责任田制度,小团队维护特定模块。跟上面一点比较类似,每个小团队的责任边界比较清晰

按业务垂直拆分系统

拆分系统也要根据实际情况,有不同的选择。我们早期的时候是根据业务,垂直拆分子系统,比如划分成微站,数据同步,连锁等。这样做的好处是,每个子系统都是可以独立跑起来的,比如说把微站子系统运行起来,微站的页面就都能访问了,数据也是该系统自己负责读写的。但是缺点也很明显,就是冗余的代码比较多。比如连锁和微站,2个子系统都需要查询企业信息,那么就各自都写了这部分代码,其实接口几乎是一模一样的,存在很大的复用空间。重复行为基本上都是不好的,这个应该说是开发人员的共识

网状结构

后来做了一点调整,基本上子系统还是按照业务拆分的。但是每个子系统都对外提供服务,比如基础数据查询模块,提供了查询企业信息的接口。连锁和微站子系统,自己就不重复查了,而是以HTTP方式,调用基础数据查询模块的这个接口。这种方式的优缺点和上一种方案大致相反。消除了重复代码,但是模块之间存在依赖关系。如果基础数据查询模块不跑起来,那微站模块虽然能跑起来,但是相关的数据就没有了

而且这样调用关系会比较复杂一点,因为本地调用都变成了HTTP接口调用,意味着业务模块,需要知道去哪里调用所需的服务,可能需要配置很多IP地址(如果依赖很多外部服务的话)。并且这个IP地址是经常需要变化的,不同的开发人员,本地的开发环境地址都不一样;开发环境和生产环境的地址也不一样;生产环境的集群配置变化了,也可能造成地址的变化。系统的复杂性变得比较高

星型结构

再后来为了解决这个调用的问题,TOPO演进为星型结构,有一个中心节点。业务模块把所有的内部请求都发到这个中心节点上,由中心节点负责转发到服务提供者上。这样对于业务模块来说,就不需要知道服务提供方的实际地址,只要把所有请求都发到中心节点上就可以了。映射的工作由中心节点来完成,需要类似这样的映射:

service1       192.168.1.110:8080/svc1

service2       192.168.1.110:8080/svc2

service3       192.168.1.111:8080/svc3

……

这个工作,在服务的数量和复杂度不是太高的时候,只需要一个简单的路由就可以了,不需要专门的服务治理方案。比如我们早期采用的就是nginx,把nginx当做内部的服务中心来使用,借助server_name,proxy_pass,up_stream等特性,已经足以满足需求。但是当服务的数量和复杂度达到一个量级,就需要有专门的方案,来处理服务的注册、发布、寻址、负载均衡、队列、失败重试等需求了

转载:https://blog.csdn.net/kyfxbl/article/details/43506343

sublime text 3 插件安装

第一步:首先打开 sublime text 3 ctrl+` 打开控制台,输入下面的代码:

import urllib.request,os,hashlib; h = '6f4c264a24d933ce70df5dedcf1dcaee' + 'ebe013ee18cced0ef93d5f746d80ef60'; pf = 'Package Control.sublime-package'; ipp = sublime.installed_packages_path(); urllib.request.install_opener( urllib.request.build_opener( urllib.request.ProxyHandler()) ); by = urllib.request.urlopen( 'http://packagecontrol.io/' + pf.replace(' ', '%20')).read(); dh = hashlib.sha256(by).hexdigest(); print('Error validating download (got %s instead of %s), please try manual install' % (dh, h)) if dh != h else open(os.path.join( ipp, pf), 'wb' ).write(by)

第二步:上面的安装完成后,关闭sublime text 3,重新打开。使用

ctrl + shift + p

打开命令面板,在命令面板中输入

Package Control: Install Package

进入下一个命令面板。在命令面板中输入你想安装的插件名称,例如:

sftp

输入之后点击enter等待安装就可以了,安装成功后也需要重启sublime text 3

你可以在 Perferences-> 中看到 Package Settings 下是否有你安装的插件

提示:如果出现安装失败,有可能是网络问题(国内不能访问部分国外网站,下载插件的地址被国内屏蔽了)

前端面试题(整理)

JavaScript:

  1. 原型继承(手写 class B 继承 class A)
  2. call、apply、bind 区别
  3. 解释什么是闭包及其应用
  4. 变量作用域 + 变量提升
  5. 字符串整型数字转数字有多少种实现方法(隐式转换)
  6. 异步编程(回调、promise、async await)(js 单线程 event loop)(手写原生实现简易 promise)
  7. js 事件模型(手写原生实现简易事件监听)
  8. localStorage、cookie(与缓存相关的 cookie 有哪些)
  9. csrf、xss、https(网络安全)
  10. 跨域请求如何实现

ES6:

  1. let、const(for 循环示例)
  2. set、map
  3. 箭头函数 this 的特点
  4. 常用语法有哪些

布局:

  1. 水平垂直居中(定尺寸、不定尺寸)
  2. flex(等高布局、自适应布局、垂直居中)
  3. 自适应正方形(padding、vw)
  4. 移动端屏幕适配(如何实现 rem)(如何实现 1px border)
  5. 清浮动有哪些方法(涉及 BFC)

Vue:

  1. vue 响应式原理
  2. 计算属性、watch 差别
  3. vue 生命周期
  4. 非继承关系组件通讯(vuex、发布订阅)

编程:

  1. 数组去重(数组项类型多样)
  2. 求无序数值数组序列最大值
  3. 常用数组操作有哪些(哪些破坏原结构)
  4. 排序算法(涉及复杂度)
  5. 位运算(两数之和)(成对数值数组寻单)
  6. 斐波那契数列
  7. 阶乘
  8. 反转链表
  9. 遍历 dom 树(广度优先、深度优先)

其它:

  1. html5 新特性有哪些(语义化标签、音视频、缓存…)
  2. hybrid 与 native 通讯方式有哪些(混合开发有什么优势)(如何实现热更新)
  3. 遇到过哪些 ios、android 兼容问题
  4. sass、less、postcss(作用、优点)
  5. 对 webpack 的理解及使用
  6. 开启一 html 经历哪些
  7. 性能优化(图片处理:webp、base64、合并、压缩、延时加载…)(预渲染)(静态资源体积减小)(资源异步加载)(资源缓存)
  8. git 常用命令(git revert、git reset 区别)
  9. 微信授权登录流程(openid、unionid 区别)
  10. AMD、CMD(require()、import、import() 应用场景)

实践:

  1. 富文本混入多种类型卡片的实现
  2. 纯 css 绘制正六边形(一个标签实现)(svg、裁切亦可)
  3. 纯 css 绘制进度圆环(应用于任务中心)(svg、裁切亦可)
  4. 如何实现拖拽