權限\其他進程
|
讀(get)n
|
寫(update)n
|
刪(delete)n
|
刪(delete)d
|
AuthPolicy.OP_READ
|
Yes
|
No
|
No
|
No
|
AuthPolicy.OP_READ_WRITE
|
Yes
|
Yes
|
No
|
No
|
AuthPolicy.OP_ALL
|
Yes
|
Yes
|
Yes
|
No
|
</tbody>
</table>
從上表可以發現,當創建進程指定node的權限為AuthPolicy.OP_ALL時,其他使用進程可以刪除該node,但是不能刪除其domain,這是為什么呢?
因為domain下通常還有其他node,它們的權限并不都是AuthPolicy.OP_ALL,比如還有一個n1的node權限為AuthPolicy.OP_READ,按照正常操作,該使用進程無法刪除n1,假設它可以刪除domain,那么它最后間接刪除了n1,于是發生了悖論,因此,為了避免風險,所有的使用進程只能根據權限刪除node,但是無法刪除domain。
不過你允許承擔這樣的刪除風險,也可以在創建進程里強行指定該domain可刪除,通過在domain創建后,調用:
public boolean setDeletable(String domain);
該方法只能被domain的創建進程調用,其他使用進程沒有權限調用。
強行指定可刪除后,其他進程可以直接刪除該domain及所含node并忽略后果。
四、相對于zookeeper的優勢
Zookeeper無疑是一款成功的開源產品,并擁有廣泛的信任者和應用場景,和以往一樣,老外作者在apache網站上發布了一款產品,我們的工程師馬上會虛心的學習和忠心的捍衛,而國產原創的產品往往會遭到百般質疑,因為我們的原創更多是抄襲和粗制濫造,我們的國產更多是框架集成而不是架構設計,所以這種情感上的傾向性不是一天能改變。
做產品對比和列舉優勢往往容易引起激烈爭論,會被認為是在宣傳和引導產品使用,實際上在都能滿足功能需求的情況下,選擇使用哪款產品更多的是個政治問題,而不是技術問題,領導意志及工程師本身的熟悉程度和愛好等等都是決定因素。
這里我們僅僅從技術角度闡述幾點優勢,Zookeeper做為一個chubby和paxos模仿品,缺乏創新型的設計改進,它仍然存在以下缺點:
1、樹型配置節點的繁瑣復雜,性能低下。為了保證這種結構,Zookeeper需要維持一套虛擬文件結構的開銷,對于目錄結構深的樹節點,造成性能影響,而配置信息結構實際上往往不一定需要樹結構。
2、“觀察”(watch)機制的僵化設計:zookeeper沒有獲取最新版本信息的方法支持,它只能粗暴的在每次寫入更新等方法時注冊一個watch,當這些方法被調用后就回調,它不考慮信息內容是否變化,對于沒有使信息內容發生改變的更新,zookeeper仍然會回調,并且zookeeper的回調比較呆板,它只能用一次,如果信息持續變化,必須又重新注冊watch。而fourinone的事件處理則可以自由控制是否持續響應信息變化。
3、領導者選舉機制實現的太過局限,集群只有兩個節點,zookeeper無法進行領導者選舉,zookeeper的領導者選舉必須要奇數節點的奇怪限制。另外,ZooKeeper的領導者選舉實現雖然比原始的Paxos要簡化,但是它仍然存在領導者(Leader)、跟隨者(Follower)、觀察者(observer)、學習者 (Learner)等眾多角色和跟隨狀態(Following)、尋找狀態(Looking)、觀察狀態(Observing)、領導狀態 (Leading)等復雜狀態。相對于fourinone的領導者選舉,zookeeper仍然不夠直觀簡潔,難以用較少配置和代碼演示。
4、Windows系統上幾乎不支持,需要安裝linux殼,并且僅建議用于學習研究。Fourinone支持windows、linux集群混合使用。
Fourinone提出一種新的分布式協同系統設計,在滿足zookeeper所有功能下,并克服了以上缺點,提出了新的配置結構、變化事件機制、簡化的領導者選舉實現,能更好的滿足分布式協調需求。
五、和paxos的區別
paxos在維持領導者選舉或者是變量修改一致性上,采取一種類似議會投票的過半同意機制,比如設定一個領導者,需要將此看為一個議案,征求過半同意,每個節點通過一個議案會有編號記錄,再次收到此領導者的不同人選,發現已經有編號記錄便駁回,最后以多數通過的結果為準。
簡言之,paxos對每個節點的并發修改采取編號記錄的方式保持一致性,對多個節點的并發修改采取少數服從多數的方式保持一致性。paxos有點類似分布式二階段提交方式,但是又不同,二階段提交不能多數節點同意,必須是全部同意。為了遵守過半節點同意的約束,paxos算法往往要求節點總數為奇數。
Fourinone選取領導者采取的是一種謙讓方式,集群中節點會先詢問其他節點是否愿意當領導者,沒人愿意它才擔任;如果已經有了領導了,那它就謙讓;正因為大家都謙讓,不互相爭搶,領導者之間能避免沖突保持一致性。一旦確定了領導者,就只跟該領導者打交道,所有對變量的操作都是通過領導者進行,不會再去操作其他候選節點,操作結果由領導者統一同步到候選節點,跟上面paxos算法保證一致性的方式是不一樣的,paxos算法會去訪問和操作所有節點征求同意,最后以多數節點的結果生效。
六、演示demo
下面是一個操作節點的演示demo,請留意各自節點的權限范圍,程序說明:
1、 ParkServerDemo: 啟動parkserver(它的IP端口已經在配置文件的PARK部分的SERVERS指定
2、 ParkSet:往parkserver里創建了d1n1、d2n2、d3n3、d4n4共4個節點,分別對應只讀、讀寫,所有,所有+強行刪除權限
3、 ParkGet:依次對d1n1、d2n2、d3n3、d4n4進行讀、寫、刪除、刪除domain操作,觀察結果輸出,如果沒有權限操作,parkserver會輸出信息,并且操作返回的結果對象為空
啟動命令和順序:
Javac –classpath fourinone.jar; *.java
Java –classpath fourinone.jar; ParkServerDemo
Java –classpath fourinone.jar; ParkSet
Java –classpath fourinone.jar; ParkGet
如果沒有fourinone.jar,可以到以下地址下載:
http://www.skycn.com/soft/68321.html
下面是demo源碼:
// ParkServerDemo
import com.fourinone.BeanContext;
public class ParkServerDemo{
public static void main(String[] args){
BeanContext.startPark();
}
}
// ParkSet
import com.fourinone.BeanContext;
import com.fourinone.ParkLocal;
import com.fourinone.ObjectBean;
import com.fourinone.AuthPolicy;
public class ParkSet{
public static void main(String[] args){
//獲取parkserver用戶接口
ParkLocal pl = BeanContext.getPark();
//在domain d1下創建節點node n1,指定權限為只讀
ObjectBean d1n1 = pl.create("d1","n1","v1",AuthPolicy.OP_READ);
if(d1n1!=null)
System.out.println("d1n1 with AuthPolicy.OP_READ create success!");
//在domain d2下創建節點node n2,指定權限為讀寫
ObjectBean d2n2 = pl.create("d2","n2","v2",AuthPolicy.OP_READ_WRITE);
if(d2n2!=null)
System.out.println("d2n2 with AuthPolicy.OP_READ_WRITE create success!");
//在domain d3下創建節點node n3,指定權限為所有
ObjectBean d3n3 = pl.create("d3","n3","v3",AuthPolicy.OP_ALL);
if(d3n3!=null)
System.out.println("d3n3 with AuthPolicy.OP_ALL create success!");
//在domain d4下創建節點node n4,指定權限為所有,并且創建完成強行設置為其他進程可刪除
ObjectBean d4n4 = pl.create("d4","n4","v4",AuthPolicy.OP_ALL);
if(d4n4!=null)
System.out.println("d4n4 with AuthPolicy.OP_ALL create success!");
boolean r = pl.setDeletable("d4");
if(r)
System.out.println("set d4 deletable!");
}
}
// ParkGet
import com.fourinone.BeanContext;
import com.fourinone.ParkLocal;
import com.fourinone.ObjectBean;
import java.util.List;
public class ParkGet{
public static void main(String[] args){
//獲取parkserver用戶接口
ParkLocal pl = BeanContext.getPark();
//獲取節點d1n1,節點權限為AuthPolicy.OP_READ
ObjectBean d1n1 = pl.get("d1","n1");//獲取節點
System.out.println("get d1n1:"+(String)d1n1.toObject());
d1n1 = pl.update("d1","n1","v1-update");//更新節點
if(d1n1!=null)
System.out.println("update node d1n1 success!");
else
System.out.println("update node d1n1 failure!");
List<ObjectBean> d1 = pl.delete("d1");//刪除domain
if(d1!=null)
System.out.println("delete domain d1 success!");
else
System.out.println("delete domain d1 failure!");
d1n1 = pl.delete("d1","n1");//刪除節點
if(d1n1!=null)
System.out.println("delete node d1n1 success!");
else
System.out.println("delete node d1n1 failure!");
//獲取節點d2n2,節點權限為AuthPolicy.OP_READ_WRITE
ObjectBean d2n2 = pl.get("d2","n2");
System.out.println("get d2n2:"+(String)d2n2.toObject());
d2n2 = pl.update("d2","n2","v2-update");
if(d2n2!=null)
System.out.println("update node d2n2 success!");
else
System.out.println("update node d2n2 failure!");
List<ObjectBean> d2 = pl.delete("d2");
if(d2!=null)
System.out.println("delete domain d2 success!");
else
System.out.println("delete domain d2 failure!");
d2n2 = pl.delete("d2","n2");
if(d2n2!=null)
System.out.println("delete node d2n2 success!");
else
System.out.println("delete node d2n2 failure!");
//獲取節點d3n3, 節點權限為AuthPolicy.OP_ALL
ObjectBean d3n3 = pl.get("d3","n3");
System.out.println("get d3n3:"+(String)d3n3.toObject());
d3n3 = pl.update("d3","n3","v3-update");
if(d3n3!=null)
System.out.println("update node d3n3 success!");
else
System.out.println("update node d3n3 failure!");
List<ObjectBean> d3 = pl.delete("d3");
if(d3!=null)
System.out.println("delete domain d3 success!");
else
System.out.println("delete domain d3 failure!");
d3n3 = pl.delete("d3","n3");
if(d3n3!=null)
System.out.println("delete node d3n3 success!");
else
System.out.println("delete node d3n3 failure!");
//獲取節點d4n4,節點權限為AuthPolicy.OP_ALL
ObjectBean d4n4 = pl.get("d4","n4");
System.out.println("get d4n4:"+(String)d4n4.toObject());
d4n4 = pl.update("d4","n4","v4-update");
if(d4n4!=null)
System.out.println("update node d4n4 success!");
else
System.out.println("update node d4n4 failure!");
//由于創建進程已經強行指定該domain可刪除setDeletable(d4),因此這里可以刪除掉
List<ObjectBean> d4 = pl.delete("d4");
if(d4!=null)
System.out.println("delete domain d4 success!");
else
System.out.println("delete domain d4 failure!");
d4n4 = pl.delete("d4","n4");//這里刪除節點會失敗,因為上面已經刪除了該domian下所有節點
if(d4n4!=null)
System.out.println("delete node d4n4 success!");
else
System.out.println("delete node d4n4 failure!");
}
}
本文由用戶
fourinone 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!
sesese色