Shouly


  • Startseite

  • Archiv

Java NIO Summary

Veröffentlicht am 2016-07-05

Java NIO Summary

分布式锁的几种实现方式

Veröffentlicht am 2016-06-23

分布式锁的几种实现方式

DB

并发下的问题:

​ 丢失更新:一个事务的更新覆盖了其它事务的更新结果。A把值从6改为2,B把值从6改为3。A的更新结果丢失。

​ 脏读:一个事务读取其它完成一半事务的记录时,就会发生脏读取。A、B读到值都为6,B把值改为2,A认为的值仍为6。

  • 悲观锁

    1
    select * from table where id = 1 for update;//行级锁 要有明确的主键
    1
    select * from table for update;//表级锁

    注:此时只有执行完了for update操作,即该事务commit后,其他select for update、update操作才会执行,但单纯的select操作完全可以执行。

  • 乐观锁

    使用版本号或者时间戳。

    1
    2
    select 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
long exsits = setNX(lock.key,System.curtime + timeout);
//获得锁
if(exsits == 1){
//todo business
...
...
//防止死锁,释放锁
if( doBusinessTime < timeout){
del(lock.key);
}
}else{//exsits == 0
long oldExpireTime = get(lock.key);
//锁过期
if(oldExpireTime < System.curtime){
long _oldExpireTime = getset(lock.key, System.curtime + timeout);
//锁没有被其他线程(进程)获取
if(oldExpireTime == _oldExpireTime){
//获得锁
//todo business
...
...
//防止死锁,释放锁
if( doBusinessTime < timeout){
del(lock.key);
}else{
//重试或者阻塞
}
}else{
//重试或者阻塞
}
}
}

​ 注:timeout 的值应根据业务来设,因为当业务逻辑执行时间过长,比timeout长时,依然存在并发问题;

​ 这几个命令在redis集群下情况将很复杂,将会有问题;

​ 需要客户端不断重试获取锁。

ZooKeeper

​ 求最小节点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public void lock(){
path = 在父节点下创建临时顺序节点
while(true){
children = 获取父节点的所有节点
if(path是children中的最小的){
//获取锁
return;
}else{
添加监控前一个节点是否存在的watcher
wait();
}
}
}
watcher中的内容{
notifyAll();
}
//释放锁
删除结点

注:可靠性最好,实现最简单的方式。但是需要额外维护成本,依业务场景选择;

​ 通过服务器端通知客户端锁被释放。

RPC概述

Veröffentlicht am 2016-03-30

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动态代理
  • 字节码生成技术

参考:https://www.cs.rutgers.edu/~pxk/417/notes/03-rpc.html

对REST的理解

Veröffentlicht am 2016-03-27

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.域名

1
2
http://api.example.com 通用API
http://example.com/api/

3.版本化(Versioning)

​ 版本号放入URL中。

1
2
http://api.example.com/v1/
http://api.example.com/v2/

​ 版本号放入Http头信息中。

1
2
3
curl https://api.github.com/users/technoweenie -I
HTTP/1.1 200 OK
X-GitHub-Media-Type: github.v3

4.路径(Endpoint)

​ 路径又称”终点”(endpoint),表示API的具体网址。

​ 由于每个URL代表一种资源,所以URL中不能有动词,只能有名词,并且是复数形式。

1
2
http://api.example.com/v1/books
http://api.example.com/v1/foods/

5.Http动词

1
2
3
4
5
6
7
8
GET: 从服务器取资源(1项或多项)。
POST: 在服务器端新建资源。
PUT: 在服务器端更新资源(客户端提供完整资源)。
PATCH: 在服务器端更新资源(客户端提供改变的字段)。
DELETE: 从服务器端删除资源。
HEAD: 获取资源元数据。
OPTIONS: 获取信息,关于资源的那些属性是客户端可以改变的。

e.g.:

1
2
3
4
5
GET /books /books/ID
POST /books
PUT /books/ID
PATCH /books/ID
DELETE /books/ID

6.过滤信息(Filtering)

1
2
3
4
5
?limit=10
?offset=10
?page=2&per_page=50
?sortby=name&order=desc
?book_id=1

7.状态码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
200 OK GET
201 CREATED POST/PUT/PATCH
202 Accepted *
204 NO CONTENT DELETE 删除数据成功。
400 Invalid Request POST/PUT/PATCH
401 Unauthorized *
403 Forbidden *
404 Not Found *
406 Not Acceptable GET
410 Gone GET
422 Unprocesable Entity POST/PUT/PATCH
500 Internal Server Error *

​ 详细状态码

8.错误处理

1
2
3
{
error:"Invalid API key"
}

9.返回结果

​ Json格式返回符合请求的操作的结果。

参考:http://www.ruanyifeng.com/blog/2014/05/restful_api.html

动态代理

Veröffentlicht am 2016-03-17

动态代理

JDK

​ 两个角色:Proxy、InvocationHandler

1
2
3
4
5
6
7
8
9
10
11
/*
* @param interfaces 注定jdk动态代理只能代理那些有接口的类
*/
Proxy.newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,InvocationHandler h);
/*
* @param proxy 由字节码生成的代理对象
* 命名方式:xxx.xx.$ProxyN N:代表产生的第N个proxy实例
*/
Object invoke(Object proxy,Method method,Object[] args);

CGLIB (Code Generation Library)

1
2

Shouly

5 Artikel
© 2017 Shouly
Erstellt mit Hexo
|
Theme — NexT.Muse v5.1.2