Zookeeper-based Master/Slave switchover
Zookeeper's ZOO_EPHEMERAL node (if ZOO_EPHEMERAL cannot meet the requirements, it can be used with ZOO_SEQUENCE). It is automatically deleted when the session is closed or expired, this feature enables master-slave switchover between two or more nodes.
Implementation Method:
1) Call zookeeper_init () initialization at process startup:
Bool X: init_zookeeper ()
{
// For the first call, _ clientid is always NULL,
// When the status is ZOO_EXPIRED_SESSION_STATE, you must call zookeeper_init again,
// The _ clientid that can be passed in at this time is the _ clientid generated by the previous zookeeper_init ().
// Note that zookeeper_init () is an asynchronous call. returning non-NULL does not indicate that the session is established successfully,
// Only when the type in zk_watcher is ZOO_SESSION_EVENT and the state is ZOO_CONNECTED_STATE,
// Indicates that the session is successfully established.
_ Zhandle = zookeeper_init (zk_hosts, zk_watcher, 5000, _ clientid, this, 0 );
If (NULL = _ zhandle)
{
MYLOG_ERROR ("init zookeeper failed: % s \ n", zerror (errno ));
Return false;
}
MYLOG_INFO ("init zookeeper (% s) successfully \ n", zk_hosts );
Return true;
}
2) before entering the work, first try to switch to the master, only after successfully switching to the master to enter the work
Bool X: run ()
{
While (true)
{
Int num_items = 0;
// The simplest method for the standby machine is to convert it to a master every certain time, for example, one second,
// If no round robin is used, the _ zk_path method can be used.
Mooon: sys: CUtils: millisleep (1000 );
// If it is not the master node, it will be converted to the master node. If the conversion fails, the next attempt will be continued.
If (! Is_master ()&&! Change_to_master ())
Continue;
Do_work ();
}
}
Bool X: is_master () const
{
Return _ is_master;
}
Bool X: change_to_master ()
{
Static uint64_t log_counter = 0; // enter the log counter and log output in the standby status
// ZOO_EPHEMERAL | ZOO_SEQUENCE
// _ Myip is the local IP address, which can be used to determine who is the master
// _ Zk_path value example:/master/test. Ensure that the/master already exists.
Int errcode = zoo_create (_ zhandle, _ zk_path.c_str (), _ myip. c_str (), _ myip. size () + 1, & ZOO_OPEN_ACL_UNSAFE, ZOO_EPHEMERAL, NULL, 0 );
// (-4) connection loss. For example, an invalid hosts is specified for zookeeper_init (). (no valid host exists)
If (errcode! = ZOK)
{
_ Is_master = false;
// Reduce the log output to the STANDBY state
If (0 = log_counter ++ % 600)
{
MYLOG_DEBUG ("become master [% s] failed: (% d) % s \ n", _ zk_path.c_str (), errcode, zerror (errcode ));
}
Return false;
}
Else
{
_ Is_master = true;
Log_counter = 0;
MYLOG_INFO ("becase master [% s] \ n", _ zk_path.c_str ());
// Sleep the job so that the original master is in progress.
Mooon: sys: CUtils: millisleep (2000 );
Return true;
}
}
3) when the zookeeper session is successfully established or expired, zk_watcher is triggered, which can be distinguished by type and state.
Void zk_watcher (zhandle_t * zh, int type, int state, const char * path, void * context)
{
X * x = static_cast <X *> (context );
MYLOG_DEBUG ("zh = % p, type = % d, state = % d, context = % p, path = % s \ n", zh, type, state, context, path );
// When zookeeper_init is successful, the type is ZOO_SESSION_EVENT, and the state is ZOO_CONNECTED_STATE.
If (ZOO_SESSION_EVENT = type) & (ZOO_CONNECTED_STATE = state ))
{
X-> on_zookeeper_connected (path );
}
Else if (ZOO_SESSION_EVENT = type) & (ZOO_EXPIRED_SESSION_STATE = state ))
{
// You need to call zookeeper_init () again. You can simply exit the current process and restart it.
X-> on_zookeeper_expired ();
}
}
Appendix: zookeeper log
By default, zookeeper logs are output to stderr, but can be directed to your own log output through zoo_set_log_stream (). You can also use zoo_set_debug_level () to control the Log Level of zookeeper.