Thriftrouter-简介
- 基于thrift TFramedTransport、TBinaryProtocol的RPC的分发系统
- 采用订阅&主动推送的模式
- 消息订阅基于RPC的名字,即根据RPC的名字决定把一条RPC推送给那些接收方
- 同一条RPC可被多个接收方订阅,同时转发给多个接收方
- thrift router主动连接RPC接收方,主动将RPC推送过去 - 消息是持久化的
- 消息传递是可靠的
- 帮助系统中的多个服务进行消息传递,减少服务间的耦合
- 简化后台服务开发,省去开发者自己实现master-slave模式的开销
- 写单点收敛,单点统一收敛至thrift router
- 协助进行服务跨地域容灾
thrifyrouter概念
endpoint:RPC的接收方,由<IP,PORT>来标识
server:每个server对应一组endpoint,RPC的路由规则对应于server
四种节点(看图完全可以了解)
thriftRouter-数据存储
- GroupFile
将大文件(几百G或者T级别)拆分成多个小文件来存储(大约2G)。比如test.txt,带下为200G,会被拆分为text.txt.0…text.txt.99 - RotateFile
一种日志文件,用来高效的记录不断变化的数据,但是文件不会无限制的增长,最多只会同事存在两个文件,每个文件有一个预设的最大长度。主要用于记录各个endpoijnt转发RPC的状态 - DoubleWriteFile
- 用来可靠的修改一个文件,防止在对一个文件修改的时候,修改在中间的时候,进程异常终止导致文件损坏
- 主动用于修改系统中的配置文件
thrift-Router配置文件
- server_id:由于整个thrift router是一个分布式系统,系统内部有多个节点,server_id是每个内部节点的编号
- server_type:thrift_router节点的类型(MASTER,REPLY,BACKUP三种)
- rpc_cache_size:磁盘上持久化存储的rpc数据的cache大小。减少文件IO
- service:test0
- service:test1
- service:bitmap
service是节点中接入的service名字。
service配置文件
- service_type:service的类型,一般值为comment,或者为2,3,4,对应为MASTER,BACKUP,REPLY
- endpoint:endpoint在service内部的编号,在service内部唯一
- rpc:这个service需要转发和处理的rpc的名字列表
- max_connection:thrift router与endpoint最大连接数
- stop_send:是否暂时停止向这个endpoint发送
- host:endpoint的ip
- port:endpoint的port
消息中转系统-RPC数据存储
全局RPC数据
索引文件
采用GroupFile存储,便于在占用磁盘空间过大的时候,删除较旧的位置
数据文件
采用FroupFile存储,便于删除文件过大的时候,删除较旧的位置
Service RPC数据
为了保证发往每个endpoint上的RPC的seqid都是连续递增的,每个service都记录了自己要转发的RPC。为了节省磁盘空间,只记录全局RPC数据中的rpc的序列号,文件采用GroupFile组织,记录格式为[8字节的global rpc id][4 字节校验和]
存储服务
- key to list
每条数据是一个三元组<key,value_key,value>,<key,value_key>视为系统中数据的唯一逐渐,一个key可以对应一组<value_key,value>对,但其中value_key唯一 - Key to sort list
每条数据是一个四元组<key,value_key,sort_key,value>,<key,value_key>视为系统中数据的唯一主键,一个key可以对应一组(list)<value_key,sort_key,value>但是其中value_key唯一,list中的数据按照sort_key字段排序。
key to [sort] list存储服务-设计思想
- 尽可能节省内存,又有较好的性能
对于list较长的情况,一般只访问其部分区间,因此不必全内存(主要是cache加速访问) - 避免实时写磁盘,优化写操作性能
- 可靠性(不会出现有的成功,有的失败)
- 易维护性(迁移的时候直接迁移整个文件夹)
- 优化get_range操作的性能
实现
- key to list每个key根据list的带下对应一个大小为2的幂的文件块或者一颗特殊的B+树。
- key to sort list:list存储于key to list类似,只不过数据有限按照sort_key排序。sort_key相等的情况下按照value_key排序。所以有一个额外的B+树来保存<key,value_key>对应的sort_key的值。
DoubleWriteBuffer接口
- write: 通过GroupFile的路径的方式提交写操作,如果block_size_bit的值与第一次写操作时指定的值不相等,返回失败
- write:通过group_file_id的方式提交写操作
- read:首先从write buffer中读取,未取到再从read cache中读取,成功读取返回0,否则返回-1
- get_group_file_id:获取group_file_path对应的GroupFile的ID,如果不存在则会分配一个。返回group_file的id
- sync:主动将write buff中的内容同步到磁盘
- notify_sync():通知同步线程进行同步,发完通知立即返回
- set_sync_interval:设置同步间隔
- wait_sync:等待write buffer中的所有内容都同步到磁盘,返回时自动获得doub write buffer的写锁,并且保证write buffer为空
- sync_and_notify:仅由同步线程调用,将work buffer和sync buffer进行切换,并唤醒所有阻塞在等待work buffer可用的线程
其他类
BlockBuffer
BlockCache
buffer向磁盘的同步
- 首先将所有的修改信息写入到一个临时文件,名字为“double_write_prepare”的GroupFile,通过mmap的方式进行,来减少系统调用以及内存拷贝
- 循环对所有被修改的GroupFile进行实际的同步写操作
1. 对修改的块按照block_id进行排序
2. 将整个GroupFile划分成512M大小的块,一次mmap512M的文件内容到共享内存,然后通过memcpy的方式完成文件的修改。 - 删除临时文件
进程启动之后,首先检查是否存在“double_write_prepare”文件,并且查看此文件是否完成,这种情况下意义着在同步的过程中,程序异常终止。没有将所有的修改都写入磁盘,磁盘上的数据处于不一致的状态,需要根据临时文件的内容重写,使数据恢复一致。