1. Basic Introduction
Distributed locks are a way to control shared resources between distributed systems, and they need to be mutually exclusive to prevent mutual interference to ensure consistency.
The lock service can be completed with the strong consistency of zookeeper. The official document of zookeeper is to enumerate the two types of locks. Exclusive locks and shared locks.
Exclusive locks guarantee that there is only one process or resource read-write permission at any time. A shared lock can have multiple reads at the same time, but at most one write at a time, read and write are mutually exclusive.
2. Scenario Analysis
We are ready to implement mutually exclusive lock, according to the official website of the idea, given a lock path, such as/lock, all the process to apply for this lock in the/lock folder to create a/lock/lock-temporary sequence node, and monitor the/lock child node change events. When a child node sends a change with Get_children () gets a list of child nodes, assuming the discovery process finds itself having the smallest ordinal number, the lock is obtained.
When the processing business is completed, the lock needs to be released and only the temporary node needs to be deleted. Simply put, the process that has the smallest sequence number always gets the lock.
3. Scene Practice
Using a lock has two main functions, which is lock
or unlock
. Defined as
Lock *lock(zhandle_t *zkhandle,const char *path)
The lock function has two parameters, one is the handle returned by Zookeeper_init Zkhandle, and the other is the path to the lock, assuming that success returns a lock's struct pointer. And get the lock at the same time, otherwise null is returned.
int unlock(zhandle_t *zkhandle,Lock * *lock)
The unlock function also has two parameters. One is the handle returned by Zookeeper_init Zkhandle, and the other is a pointer to the struct pointer returned by the lock function.
The next step is to look at the detailed implementation.
Lock *lock (zhandle_t *zkhandle,const char *path) { Lock *lock = Create_lock (Zkhandle,path); if (lock! = NULL) { while (Try_lock (zkhandle,lock) = = 0) { sleep (1); } } else{ fprintf (stderr, "error when create lock%s.\n", path); } return lock;}
lock
After the function initializes the lock, it continues to attempt to lock until it succeeds. Though I have done so. But too simple and rude (haha). Suppose you can't get a lock. Persistent will clog up in the lock
function.
int unlock (zhandle_t *zkhandle,lock * *lock) { if (*lock) { int ret = Zoo_delete (Zkhandle, (*lock)->selfpath,- 1); if (ret! = Zok) { fprintf (stderr, "error when release lock%s.\n", (*lock)->selfpath); } Free (*lock); *lock = NULL; return ret; } return Zok;}
unlock
The function is easy. is create_lock
to delete the temporary sequence nodes that were created in.
Next look at the function of the simulation program.
>./mylock-husage: [Mylock] [-h] [-P path][-s Ip:port]- h Show help- P lock Path- s zookeeper server ip:portfor Example: mylock-s 172.17.0.36:2181-p/lock
The simulation program has 3 options.
Of
-s
: The ip:port of the server for zookeeper.
-p
: The path to the lock.
By executing multiple mylock programs at the same time, you can see how the locks are acquired between each program.
The final is the complete code:
#include <stdio.h> #include <string.h> #include <unistd.h> #include "zookeeper.h" #include "zookeeper _log.h "Char g_host[512]=" 172.17.0.36:2181 "; Char g_path[512]= "/lock"; typedef struct lock{char lockpath[1024]; Char selfpath[1024];} Lock;void print_usage (); void get_option (int argc,const char* argv[]);/**********unitl*********************/void Print_usage () {printf ("Usage: [Mylock] [-h] [-P path][-s Ip:port] \ n"); printf ("-H Show help\n"); printf ("-P lock path\n"); printf ("-S zookeeper Server ip:port\n"); printf ("for example:\n"); printf ("Mylock-s172.17.0.36:2181-p/lock\n");} void get_option (int argc,const char* argv[]) {extern char *optarg; int optch; int dem = 1; const char optstring[] = "hp:s:"; while ((Optch = Getopt (argc, (char * const *) argv, optstring))! =-1) {switch (optch) {case ' H ': Print_usage (); Exit (-1); Case '? ': Print_usage (); printf ("Unknown parameter:%c\n", optopt); Exit (-1); Case ': ': print_usage (); printf ("Need parameter:%c\n", optopt); Exit (-1); Case ' s ': strncpy (g_host,optarg,sizeof (g_host)); Break Case ' P ': strncpy (g_path,optarg,sizeof (G_path)); Break Default:break; }}} Lock *create_lock (zhandle_t *zkhandle,const char *path) {char path_buffer[512]={0}; int bufferlen = sizeof (Path_buffer); Lock * lock = NULL; int ret = zoo_exists (zkhandle,path,0,null); if (ret! = Zok) {ret = Zoo_create (Zkhandle,path, "1.0", strlen ("1.0"), &zoo_open_acl_un safe,0, Path_buffer,bufferlen); if (ret! = Zok) {fprintf (stderr, "failed to create the path%s!\n", path); }else{printf ("Create path%s successfully!\n", path); }} if (ret = = Zok) {char child_path[512]; sprintf (Child_path, "%s/lock-", Path); ret = Zoo_create (Zkhandle,child_path, "1.0", strlen ("1.0"), &zoo_open_acl_unsafe,zoo_sequence | Zoo_ephemeral, Path_buffer,bufferlen); if (ret! = Zok) {fprintf (stderr, "failed to create the path%s!\n", path); }else{printf ("Create path%s successfully!\n", path); }} if (ret = = Zok) {lock = (lock *) malloc (sizeof (lock)); strcpy (Lock->lockpath,path); strcpy (Lock->selfpath,path_buffer); } return lock;} int Try_lock (zhandle_t *zkhandle,lock *lock) {struct string_vector children; int i = 0; int ret = Zoo_get_children (Zkhandle,lock->lockpath,0,&children); if (ret! = Zok) {fprintf (stderr, "error when get children of path%s\n", Lock->lockpath); ret =-1; }else{char *myseq = Rindex (Lock->selfpath, '/'); if (myseq! = NULL) Myseq + = 1; ret = 1; for (i = 0; i < Children.Count; ++i) {if (strcmp (CHILDREN.DATA[I],MYSEQ) < 0) {ret = 0; Break }} for (i = 0; i < Children.Count; ++i) {free (children.data[i]); Children.data[i] = NULL; }} return ret;} Lock *lock (zhandle_t *zkhandle,const char *path) {Lock *lock = Create_lock (Zkhandle,path); if (lock! = NULL) {while (Try_lock (zkhandle,lock) = = 0) {sleep (1); }}else{fprintf (stderr, "error when create lock%s.\n", path); } return lock;} int unlock (zhandle_t *zkhandle,lock * *lock) {if (*lock) {int ret = Zoo_delete (Zkhandle, (*lock)->selfpath,-1); if (ret! = Zok) {fprintf (stderr, "error when release lock%s.\n", (*lock)->selfpath); } free (*lock); *lock = NULL; return ret; } return Zok;} int main (int argc, const cHar *argv[]) {int timeout = 30000; Char path_buffer[512]; int bufferlen=sizeof (path_buffer); Zoo_set_debug_level (Zoo_log_level_warn); Set the log level to avoid some other information get_option (ARGC,ARGV); zhandle_t* Zkhandle = zookeeper_init (g_host,null, timeout, 0, (char *) "lock Test", 0); if (Zkhandle ==null) {fprintf (stderr, "Error when connecting to Zookeeper servers...\n"); Exit (Exit_failure); } int ret = zoo_exists (zkhandle,g_path,0,null); if (ret! = Zok) {ret = Zoo_create (Zkhandle,g_path, "1.0", strlen ("1.0"), &zoo_open_acl_ unsafe,0, Path_buffer,bufferlen); if (ret! = Zok) {fprintf (stderr, "failed to create the path%s!\n", G_path); }else{printf ("Create path%s successfully!\n", G_path); }} if (ret = = Zok) {Lock *mylock = lock (Zkhandle,g_path); if (mylock) {printf ("Get Lock of%s.\n", G_path); printf ("Self path is%s.\n", Mylock->selfpath); printf ("Do something....\n"); GetChar (); Unlock (Zkhandle,&mylock); }} zookeeper_close (Zkhandle); return 0;}
Copyright notice: This article blog original articles, blogs, without consent, may not be reproduced.
Zookeeper Practical Solution: (7) distributed lock