目录
01-项目简介
# 单体式和微服务 ## 单体式架构服务 —— 过往大家熟悉的服务器。 特性: 1. 复杂性随着开发越来越高, 遇到问题解决困难。 2. 技术债务逐渐上升。 3. 耦合度高,维护成本大! 1. 出现bug, 不容易排查 2. 解决旧bug, 会出新bug 4. 持续交付时间较长。 5. 技术选型成本高,风险大。 6. 扩展性较差 1. 垂直扩展:通过增加单个系统程的负荷来实现扩展。 2. 水平扩展:通过增加更多的系统成员来实现扩展。
02-单体式架构
## 微服务 - 优点: 1. 职责单一 2. 轻量级通信 3. 独立性 4. 迭代开发。 - 缺点: 1. 运维成本高 2. 分部式复杂度 3. 接口成本高 4. 重复性劳动 5. 业务分离困难。
03-微服务优缺点
04-单体式和微服务区别
# RPC 协议 ## 什么是RPC Remote Procedure Call Protocol —— 远程过程调用协议! IPC: 进程间通信 RPC:远程进通信 —— 应用层协议(http协议同层)。底层使用 TCP 实现。 > 回顾: > > OSI 7 层模型架构:物、数、网、传、会、表、应 > > TCP/IP 4 层架构:链路层、网络层、传输层、应用层 - 理解RPC: - **==像调用本地函数一样,去调用远程函数。==** - 通过rpc协议,传递:函数名、函数参数。达到在本地,调用远端函数,得返回值到本地的目标。 - 为什么微服务使用 RPC: 1. 每个服务都被封装成 进程。彼此”独立“。 2. 进程和进程之间,可以使用不同的语言实现。
05-RPC简介
### RPC 入门使用 远程 —— 网络!! > 回顾:Go语言 一般性 网络socket通信 > > server端: > > net.Listen() —— listener 创建监听器 > > listener.Accpet() —— conn 启动监听,建立连接 > > conn.read() > > conn.write() > > defer conn.Close() / listener.Close() > > client端: > > net.Dial() —— conn > > conn.Write() > > conn.Read() > > defer conn.Close()
06-RPC使用步骤
### RPC 使用的步骤 ---- 服务端: 1. 注册 rpc 服务对象。给对象绑定方法( 1. 定义类, 2. 绑定类方法 ) ```go rpc.RegisterName("服务名",回调对象) ``` 2. 创建监听器 ```go listener, err := net.Listen() ``` 3. 建立连接 ```go conn, err := listener.Accept() ``` 4. 将连接 绑定 rpc 服务。 ```go rpc.ServeConn(conn) ```
07-注册RPC服务函数接口
---- 客户端: 1. 用 rpc 连接服务器。 ```go conn, err := rpc.Dial() ``` 2. 调用远程函数。 ```go conn.Call("服务名.方法名", 传入参数, 传出参数) ``` ## RPC 相关函数 1. 注册 rpc 服务 ```go func (server *Server) RegisterName(name string, rcvr interface{}) error 参1:服务名。字符串类型。 参2:对应 rpc 对象。 该对象绑定方法要满足如下条件: 1)方法必须是导出的 —— 包外可见。 首字母大写。 2)方法必须有两个参数, 都是导出类型、內建类型。 3)方法的第二个参数必须是 “指针” (传出参数) 4)方法只有一个 error 接口类型的 返回值。 举例: type World stuct { } func (this *World) HelloWorld (name string, resp *string) error { } rpc.RegisterName("服务名", new(World)) ```
08-绑定服务和调用方法函数接口
2. 绑定 rpc 服务 ```go func (server *Server) ServeConn(conn io.ReadWriteCloser) conn: 成功建立好连接的 socket —— conn ``` 3. 调用远程函数: ```go func (client *Client) Call(serviceMethod string, args interface{}, reply interface{}) error serviceMethod: “服务名.方法名” args:传入参数。 方法需要的数据。 reply:传出参数。定义 var 变量,&变量名 完成传参。
09-rpc服务端和客户端编码实现
## 编码实现 server端 ```go package main import ( "net/rpc" "fmt" "net" ) // 定义类对象 type World struct { } // 绑定类方法 func (this *World) HelloWorld (name string, resp *string) error { *resp = name + " 你好!" return nil } func main() { // 1. 注册RPC服务, 绑定对象方法 err := rpc.RegisterName("hello", new(World)) if err != nil { fmt.Println("注册 rpc 服务失败!", err) return } // 2. 设置监听 listener, err := net.Listen("tcp", "127.0.0.1:8800") if err != nil { fmt.Println("net.Listen err:", err) return } defer listener.Close() fmt.Println("开始监听 ...") // 3. 建立链接 conn, err := listener.Accept() if err != nil { fmt.Println("Accept() err:", err) return } defer conn.Close() fmt.Println("链接成功...") // 4. 绑定服务 rpc.ServeConn(conn) }
10-json的rpc
client端 ```go package main import ( "net/rpc" "fmt" ) func main() { // 1. 用 rpc 链接服务器 --Dial() conn, err := rpc.Dial("tcp", "127.0.0.1:8800") if err != nil { fmt.Println("Dial err:", err) return } defer conn.Close() // 2. 调用远程函数 var reply string // 接受返回值 --- 传出参数 err = conn.Call("hello.HelloWorld", "李白", &reply) if err != nil { fmt.Println("Call:", err) return } fmt.Println(reply) } ```
11-rpc的封装
## json 版 rpc - 使用 nc -l 127.0.0.1 880 充当服务器。 - 02-client.go 充当 客户端。 发起通信。 —— 乱码。 - 因为:RPC 使用了go语言特有的数据序列化 gob。 其他编程语言不能解析。 - 使用 通用的 序列化、反序列化。 —— json、protobuf ### 修改客户端 修改客户端,使用jsonrpc: ```go conn, err := jsonrpc.Dial("tcp", "127.0.0.1:8800") ``` 使用 nc -l 127.0.0.1 880 充当服务器。 看到结果: {"method":"hello.HelloWorld","params":["李白"],"id":0} ### 修改服务器端 修改服务器端,使用 jsonrpc: ```go jsonrpc.ServeConn(conn) ``` 使用 nc 127.0.0.1 880 充当客户端。 看到结果: echo -e '{"method":"hello.HelloWorld","params":["李白"],"id":0}' | nc 127.0.0.1 8800 **如果,绑定方法返回值的 error 不为空? 无论传出参数是否有值,服务端都不会返回数据。**
12-rpc封装小结
## rpc 封装 #### 服务端封装 1. ```go // 定义接口 type xxx interface { 方法名(传入参数,传出参数) error } 例: type MyInterface interface { HelloWorld(string, *string) error } ``` 2. ```go // 封装注册服务方法 func RegisterService (i MyInterface) { rpc.RegisterName("hello", i) } ``` #### 客户端封装 1. ```go // 定义类 type MyClient struct { c *rpc.Client } ``` 2. ```go // 绑定类方法 func (this *MyClient)HelloWorld(a string, b *string) error { return this.c.Call("hello.HelloWorld", a, b) } ``` 3. ```go // 初始客户端 func InitClient(addr string) error { conn, _ := jsonrpc.Dial("tcp", adddr) return MyClient{c:conn} } ``` # protobuf