rpc
RPC 的定义
RPC 的全称是 Remote Procedure Call,即远程过程调用,实现了跨网络调用其他服务就像调用本地服务一样的模式。简单来说 RPC 替我们封装了网络层繁琐的开发开发,通过增强代理的方式嵌入进去,这样我们只需要编写业务逻辑即可调用远程服务。RPC 的使用范围非常广泛,不仅仅约束在接口维度,包括MQ Client 和 MQ Server 间的通信、Redis Client 和 Redis Server 间的通信、JDBC 和 MySQL 间的通信都属于 RPC 通信。
协议
由于跨网络的特性,一次 RPC 调用通常要经过序列化、协议编码、解码、反序列化的过程。当被调用者接收到一堆二进制字节后首先要对这些二进制进行解码和反序列化,这样才能定位到本次调用的具体方法。基于性能的考虑,RPC 调用通常是基于 TCP 层,TCP 接收到的二进制数据是没有分隔的,TCP 窗口可能会对多次调用进行合并,下游必须解析出合并前的数据边界,这就需要指定的协议格式了。也就是说 RPC 协议是为了避免语义不一致的事情发生,需要在发送请求的时候设定一个边界,然后在收到请求的时候按照这个设定的边界进行数据分割。这个边界语义的表达,就是所说的协议。
分布式数据库
选择分布式数据库
以实际使用场景来看,假设有一个广告系统记录了所有用户在任何时刻触发不同广告的消耗明细,每天大约能产生 5000W 条用户消耗数据明细。现在需要实现一个供流量主可以实时查询这些数据的功能,此时应该选用哪种类型的数据库,在这个应用场景下数据库需要满足以下特点:
- 数据量巨大,且面向 C 端用户查询。
- 频繁写入且频繁查询,要支持范围查询,且查询性能需要在毫秒级。
- 数据存在倾斜的可能性。
传统数据库的瓶颈
MySQL 数据库天生是单机数据库,即它只能运行在一台物理机器实例上,我们没有办法把他拆分开让同一个数据库同时运行在多台机器上。因此它的性能和物理机器实例的配置呈正相关,受到机器配置的制约,机器的天花板上限较低。但是它的好处就是架构较为简单,使用起来更加方便。
Redis 应用
http
服务端开发离不开和 http 打交道,无论是 API 请求、RPC 请求,都有可能使用 http 协议。http 太常见了, spring 提供的注解开发可能让我们忽略了协议内不同内容是如何存放,header、body、表单都如何使用。参考极客时间-透视 http 协议,从头到尾梳理一遍 http 的详细知识。
http 是什么
http 全称超文本传输协议,拆分为三个名词详细理解:
- 超文本:普通的文本指的是文字数据,超文本不但包含了文字,它也包括了语音、图片、视频等数据,是一切资源的泛称。同时它含有超链接,可以从一个超文本跳转到另外一个超文本,形成复杂的网状结构。
- 传输:数据在双方的流动叫为传输,http 是一个双向传输协议,一般情况下把发起数据传输的称为请求方,接受数据的称为响应方。
- 协议:首先协议可以分为两个部分,它需要最少两个参与者,参与者要想互相理解对方传输的内容,这离不开规范。简单来说协议就是规定了双方使用同样可以理解的语音进行交流
作为一种协议规范,它本身不是一种程序或软件,HTTP 通常跑在 TCP/IP 协议栈之上,依靠 IP 协议实现寻址和路由、TCP 协议实现可靠数据传输、DNS 协议实现域名查找、SSL/TLS 协议实现安全通信。
OAuth
简单来说,OAuth2.0是一种授权协议,它通过颁发访问令牌的机制而不是使用用户名和密码来请求交互,保证第三方应用只有在成功获取授权之后才可以访问授权者的数据。通过这套协议,用户仅仅通过授权操作就可以免去重复注册的流程,是目前web上重要的安全手段。
OAuth2.0提供了四种许可类型:
- 授权码许可(Authorization Code)
- 隐式许可(Implicit)
- 客户端凭据许可(Client Credentials)
- 资源拥有者凭据许可(Resource Owner Password Credentials)
OAuth2.0的基本流程
OAuth2.0里有4种角色,分别是资源所有者、三方软件、授权服务和受保护资源,授权码许可的流程如下。
Kafka
kafka介绍
Apache Kafka 是消息引擎系统,也是一个分布式事件流处理平台,企业利用它可以在A、B两个系统之间传递消息,实现松耦合的异步数据传输。总的来说,消息引擎具有两个重要能力:
- 消息引擎传输的对象是消息
- 定义了传输消息的规范
消息引擎不在乎A、B两个系统是否相同,它可以在不同系统间传递消息,因此消息的通用格式以及如何传输消息至关重要。kafka的消息格式化使用的是二进制字节序列,消息还是结构化的,只是在使用之前都要将其转换成二进制的字节序列。kafka支持两种常用的消息引擎模型:
- 点对点模型:也叫消息队列模型,消息只能由A系统发出,由B系统接收,其他模型无权生产与消费消息,简单来说是一对一的模型。
- 发布 / 订阅模型:有一个topic的概念,可以有多个生产者向topic中生产消息,同时允许多个消费者订阅topic进行消费,简单来说就是一种多对多的模型。
Netty
Zookeeper
基础
Zookeeper从设计模式角度来理解:是一个基于观察者模式设计的分布式服务管理框架,它负责存储和管理大家都关心的数据,然后接受观察者的注册,一旦这些数据的状态发生变化,Zookeeper就将负责通知已经在Zookeeper上注册的那些观察者做出相应的反应。
特点
- 一个领导者,多个跟随着组成的集群
- 集群中 只要有半数以上节点存活,集群就可以正常提供服务.
- 全局数据一致:每个Server保存一份相同的数据副本,Client无论连接到哪个Server,数据都是一致的
- 更新请求顺序执行,来自同一个Client的更新请求按照发送顺序依次执行
- 数据更新原子性,一次数据更新要么成功,要么失败
- 实时性,在一定时间范围内,Client能读到最新数据
提供的服务包括:统一命名服务、统一配置管理、统一集群管理、服务器节点动态上下线、软负载均衡等。
设计模式
单例模式
一个类只允许创建一个对 象(或者实例),那这个类就是一个单例类,这种设计模式就叫作单例设计模式,简称单例模式。
如何实现一个单例
- 构造函数需要是 private 访问权限的,这样才能避免外部通过 new 创建实例;
- 考虑对象创建时的线程安全问题;
- 考虑是否支持延迟加载;
- 考虑 getInstance() 性能是否高(是否加锁)
- 饿汉式
在类加载的时候,instance 静态实例就已经创建并初始化好了,所以,instance 实例的创建过程是线程安全的。不过,这样的实现方式不支持延迟加载(在真正用到 IdGenerator 的时候,再创建实例)。 - 懒汉式
懒汉式相对于饿汉式的优势是支持延迟加载。这种实现方式会导致频繁加锁、释放锁,以及并发度低等问题,频繁的调用会产生性能瓶颈。 - 双重检测
双重检测实现方式既支持延迟加载、又支持高并发的单例实现方式。只要 instance 被创建 之后,再调用 getInstance() 函数都不会进入到加锁逻辑中。所以,这种实现方式解决了懒汉式并发度低的问题。 - 静态内部类
利用 Java 的静态内部类来实现单例。这种实现方式,既支持延迟加载,也支持高并发,实 现起来也比双重检测简单。 - 枚举
最简单的实现方式,基于枚举类型的单例实现。这种实现方式通过 Java 枚举类型本身的特 性,保证了实例创建的线程安全性和实例的唯一性。