rpc im机制和网络优化

什么是rpc?  remote procedure call 远程过程调用 ,简单的来说,我们现在实现了一个计算器的程序,通常我们会把这个计算器封装成一个函数,当我们想要计算的时候只需要把我们的参数传给计算器函数,把我们要处理的两个数据和我们要进行的操作传输过去,之后用一个返回值来把计算的结果返回给我们,但是这一整个流程都是在我们本地计算机上实现的,远程过程调用通俗的来说就是主函数运行在我当前的机器上但是计算器函数则在别人的机器上,我在我当前的机器调用他人机器上边的函数。

rpc和我们之前熟悉的http 的关系?在我想到计算器这个例子的时候就想到了自己之前基于http协议曾经写过了一个代码, 代码是一个客户端一个服务端,通过运行客户端在客户端获取两个数字和操作符传输给服务端,之后服务端进行处理返回给我们对应的结果,这不就是一个简单的rpc吗?那为什么需要rpc而不是像我们之前一样实现一个http接口?这就需要明白这两个的区别rpc是一种概念是一种思想,http也可以是rpc的一种实现方式,但是rpc的核心并不在于使用什么协议,rpc的目的是让你在本地调用远程的方法。我们现在接触到的程序无论是从代码量还是从复杂度上跟公司相比不在同一个数量级上,公司系统都是由上万个大大小小的服务组成的, 各个服务部署在不同的机器上,并且是由不同的团队负责的,比如淘宝里有购物车有收藏有支付系统等等,我们在搭建一个新的服务的时候免不了需要依赖他人的服务,那别人的服务部署在他们那里的远端,我们怎么调用,因为不同的服务在不同的机器,服务之间调用免不了需要通过网路来实现如果说每次调用一个服务都需要程序员像我上边说到的那样调用我编写的计算器那样来重新编写一段代码的话就会有很大个工作量,不仅仅十分复杂还极其容易出错。rpc就是为了解决这个问题。

 rpc调用过程?

1.服务方调用的时候就以本地的调用方式来调用服务

2.client stub接收到调用请求后将方法 参数等组装成一个能够进行网络传输的消息实体,如果大家有印象的话,这里的消息实体就是我们之前计算器中封装的那个结构体。

3.client stub找到对应的服务地址,并将消息发送到对应的服务端,这里还有两步细节,第一步就是client stub来查询我们当前调用的函数在那些机器上,比如淘宝有一百台机器可以处理购物车请求,首先你你要先拿到这一百台机器的地址,其次是从这一百台机器里边选择一个你要请求的ip这里也有一定的负载均衡在里边。

4.server stub收到请求的消息后对其进行解码

5.server stub根据解码结果调用本地的服务

6.本地服务执行并将结果返回给server stub

7.server stub将返回的结果打包成消息并发送至发送方

8.client stub 接受到消息并且进行解码

9.最终请求方的到想要的记过

rpc的目标就是把我们上边说到的2-8之间的步骤都给封装起来。并且用户对这些细节透明,到底是怎么实现透明的,太深奥了我也不懂。

Rpc的框架有很多,这里我要了解的是基于Facebook开源的thrift框架。头条的是在thrift的基础自研了kite框架 kite吸取了大量之前优秀框架的经验集成了微服务架构具备的各项组建和功能比如:

服务注册和发现

统一rpc调用

服务调用跟踪

服务调用容灾

服务动态配置等等  

Im机制和网络优化

im即时通讯系统,例如qq 微信 

网络协议来说

qq默认采用的是udp通讯方式,当udp端口不通的时候会自动切换到tcp也有http 

微信则采用的是 tcp(ssl)+http。

钉钉采用的是tcp(ssl)+http 

同时还有数据通信格式的了解 数据通信格式有json编码 微信和qq中采用了较多的PB,PB是protocol buffers google提出的一种跨平台/多语言支持并且开源的序列化数据格式。他和传统的xml和json相比来说空间更加小,传输速度更加快

Im里离不开的就是消息的同步于存储的架构:传统架构来说 当a给b发送消息的时候,如果b在线那就会直接进行推送,当b不在线的时候会出现消息推送失败,这时候会将消息保存到离线消息数据库里,等c上线之后回去消息数据库里边拉取对应的消息数据。

而现如今的im架构当a给b发送消息的时候如果b在线会直接进行推送通知,如果说b不在线会将消息放到消息同步库中,并且为了消息的持久化会将消息放在消息存储哭中,当b上线之后就从消息同步库中拉取对应的同步消息,并且还可以从消息存储库中拉取到漫游的消息,比如我们经常在手机上登陆微信,当在电脑端登陆微信的时候会有是否漫游消息的选项。存储库全量保存所有的会话消息

每个用户都有一个属于自己的timeline,存储给此用户推送的数据,每个timeline,sid要求都是递增的,sid大的数据是用户的最终状态,也就是说当我我现在给你连续发送了三条消息当你接受到第二条的时候你下线了,那当你再次上线的时候是怎么判断哪些数据是你在下线期间收到的,也就是我们的第三条数据,哪些数据是你之前收到的也就是我们的第一二条数据,这时候就是通过这个timeline来实现的。

我理解的意思通俗来说,每对关系都有一个timeline,也就是说我是a我和b有一个,我和c也有一个同样我和d也有一个,这些都是一个个的list,可以实现连续递增,并且客户端也很容易感知到自己是否缺失消息。

 微信是通过数据版本号来实现终端和后台的数据增量同步机制,来确保发送消息的时候可以把数据可靠的发送到对方的终端上,那这些是怎么来实现的呢,就是微信的服务器端给每一份需要与客户端同步的数据就比如发送的一条消息,一个朋友圈的内容等都会赋予一个唯一的递增的序列号作为这个数据的版本号。比如我现在的序列号是100当我再次申请的时候这个序号就变成了101也就是说如果有用户申请,就在数据库把它对应的序列号加一就可以,这看似很简单的行为,当你有海量访问的时候都会变得不简单,为了保证数据的可靠性,一旦这个加一操作不正确就很有可能引发一系列的事情,想要满足数据的可靠性的话常见的就是把数据持久化到我们的硬盘中,当时微信海量访问通常每秒千万级的访问量,基本没有什么硬盘系统可以扛住。

所以就有了预分配中间层的概念,通过权衡可以发现,我们是要求我们的序列号是递增的却没有要求他是连续的,也就是可以是1,2,3,6,7,99这样的,于是就有了最大序列号的概念,我们有两个数据一个是序列号一个是最大序列号,也就是分配的上限,当分配序列号的时候将我们序列号进行++操作并且和最大序列号进行对比,如果学列好大于我们的最大序列号,那就让最大序列号进行增长。并且持久化也就是写入到硬盘里我们的最大序列号,当重启的时候我门只需要读取出持久化过的最大序列号赋值给我们的序列号就可以了。这样虽然解决了硬盘读取的可靠性问题,但是还是有其他问题,当我们重启机器的时候就要读去大量的序列号到我们的内存中。所以就有了号段的概念,我们某一个区间内的用户用的都是同样的最大序列号,当其中某一个用户达到的时候这个号段内的所有用户的最大序列号都会增长。

移动端如何减少流量?首先移动端为什么会耗费流量,因为在登陆过程中我们会需要拉取很多数据,当我们在手机上推出微信再登陆的时候不能直接使用本地的数据,因为不能保证本地的数据一定是最新的,所以每次登陆都需要进行拉取,所以我们能看到的微信之前的月亮北京,以及qq等转圈登陆操作都是在进行数据拉取,为了保证用户登陆之后的体验,一般都是在登陆过程中进行拉取的。

那怎么减少拉取呢?有两种一种是延时拉取一种是按需拉取,因为在我们用户的使用过程中,通常来说又些数据能够用到,又些数据不一定会用到,所以哪些不一定会用到的数据我们没有必要直接把它拉取下来。比如好友列表我门一定会用到,但是群成员的列表我们不一定会用到。其次可以利用时间戳,我们不能利用本地数据的原因就是因为我们不敢保证本地数据是不是最新的,所以如果我们保证本地数据就是最新的那我们就可以减少数据的拉取,在加入时间戳之后,加入我们有100个好友,之前我们会进行100次拉取,现在我们会先拉取100个好友的时间戳,然后再客户端将这些数据进行一定的比较,找出时间戳不一样的几个用户,然后拉取有变化的用户的数据,这样的好处就是大大减少了数据的传输量,因为了解网络的都知道网络的速度要比我们计算机的速度慢的多得多,但是这样就多进行了一次网络交互,因为以前是直接拉取,现在的话需要先拉取时间戳然后再拉取有差异的数据,那可以不可以减少一次网络交互呢? 答案是可以的。这时候我们反过来执行,我们将客户端的100个用户数据的时间戳上传到对应的服务端,然后再服务端进行时间戳的对比,找出有差异的几个数据,然后直接把有差异的数据进行返回。

已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页