分布式锁的几种实现方式
分布式锁的几种实现方式
DB
并发下的问题:
丢失更新:一个事务的更新覆盖了其它事务的更新结果。A把值从6改为2,B把值从6改为3。A的更新结果丢失。
脏读:一个事务读取其它完成一半事务的记录时,就会发生脏读取。A、B读到值都为6,B把值改为2,A认为的值仍为6。
悲观锁
1select * from table where id = 1 for update;//行级锁 要有明确的主键1select * from table for update;//表级锁注:此时只有执行完了for update操作,即该事务commit后,其他select for update、update操作才会执行,但单纯的select操作完全可以执行。
乐观锁
使用版本号或者时间戳。
12select x1,x2 ... ,version from table where x1 = 1;update table set version = version + 1 where x1 = 1 and version = ?乐观锁不能解决脏读的问题。
注:效率低下,只能根据业务场景适量选择。
需要客户端不断重试获取锁。
Redis
4个命令:setnx get getset del
|
|
注:timeout 的值应根据业务来设,因为当业务逻辑执行时间过长,比timeout长时,依然存在并发问题;
这几个命令在redis集群下情况将很复杂,将会有问题;
需要客户端不断重试获取锁。
ZooKeeper
求最小节点
|
|
注:可靠性最好,实现最简单的方式。但是需要额外维护成本,依业务场景选择;
通过服务器端通知客户端锁被释放。
RPC概述
RPC概述
什么是RPC?
Remote Procedure Call 远程过程调用协议
RPC是一种进程间都通信协议,允许程序调用网络上的过程或函数,而不用开发者显示的编写调用细节,使用起来就像是调用本地服务,其中的网络通信对开发者来说是透明的。RPC框架能为我们解决这些通信细节。
“RPC的主要功能是让构建分布式计算(应用)更容易,在提供强大的远程调用能力时不损失本地调用的语义简洁性。”
调用流程
1.服务消费方clinet调用本地服务client stub(存根);
2.client stub封装functions信息(方法名、参数等)用于网络传输(编码、序列化);
3.client stub通过socket找到服务地址,并将消息发给服务端;
4.server stub接收到消息(解码、反序列化);
5.server stub调用本地function(服务);
6.本地服务将执行结果返回给server stub;
7-8.server stub将结果封装成消息(编码、序列化),通过socket 传输消息给client stub;
9-10.client stub解析消息(解码、反序列化)把调用结果返回给client。
RPC调用过程中要面临的问题
- 序列化、反序列化 Hession| JSON|XML|Google Protocol Buffers|Thrift
- Socket 通信 BIO NIO
- 服务寻址 Zookeeper
Java 与 RPC
调用远程服务时使用代理方式封装通信细节,使用起来就像调用本地服务一样。
实现方式:
- JDK动态代理
- 字节码生成技术
对REST的理解
REST
Representational State Transfer (资源的)表现层状态转化
1.资源(Resources)
一个具体URI。
2.表现层(Representation)
通过Http请求,头信息里的Accept和Content-Type字段描述。
3.状态转化(State Transfer)
使用Http协议里的4个动词:GET、POST、PUT、DELETE,来操作资源在服务器端的状态。
RESTful API
1.协议
通过Http(s)协议提供API服务。
2.域名
|
|
3.版本化(Versioning)
版本号放入URL中。
|
|
版本号放入Http头信息中。
|
|
4.路径(Endpoint)
路径又称”终点”(endpoint),表示API的具体网址。
由于每个URL代表一种资源,所以URL中不能有动词,只能有名词,并且是复数形式。
|
|
5.Http动词
|
|
e.g.:
|
|
6.过滤信息(Filtering)
|
|
7.状态码
|
|
详细状态码
8.错误处理
|
|
9.返回结果
Json格式返回符合请求的操作的结果。
动态代理
动态代理
JDK
两个角色:Proxy、InvocationHandler
|
|
CGLIB (Code Generation Library)
|