Thiết kế Cơ chế Đăng ký Dịch vụ
Thành phần chính của hệ thống đăng ký dịch vụ sử dụng ZooKeeper là lớp CServiceRegistry kế thừa từ NonCopyable. Lớp này đảm nhiệm việc duy trì kết nối với ZooKeeper và xử lý đăng ký, kiểm tra trạng thái dịch vụ.
Lớp Thông tin Dịch vụ
Định nghĩa cấu trúc thông tin dịch vụ với các trường cần thiết:
<span class="keyword">class</span> <span class="class">ServiceInfo</span> {
<span class="keyword">public</span>:
ServiceInfo() { Reset(); }
<span class="keyword">void</span> Reset() {
node_ip = <span class="string">""</span>;
service_port = <span class="string">""</span>;
zk_path = <span class="string">""</span>;
service_name = <span class="string">""</span>;
service_id = <span class="string">""</span>;
instance_index = <span class="string">""</span>;
}
<span class="keyword">std::string</span> ToJsonString() <span class="keyword">const</span> {
<span class="keyword">auto</span> format = [](<span class="keyword">const</span> <span class="keyword">std::string</span>& key, <span class="keyword">const</span> <span class="keyword">std::string</span>& val) {
<span class="keyword">return</span> <span class="string">"\\\"</span> + key + <span class="string">"\\\": \\\"</span> + val + <span class="string">"\\\""</span>;
};
<span class="keyword">return</span> <span class="string">"{"</span> + format(<span class="string">"ip"</span>, node_ip) + <span class="string">", "</span> + format(<span class="string">"port"</span>, service_port) +
<span class="string">", "</span> + format(<span class="string">"zk_path"</span>, zk_path) + <span class="string">", "</span> + format(<span class="string">"service_name"</span>, service_name) +
<span class="string">", "</span> + format(<span class="string">"service_id"</span>, service_id) + <span class="string">", "</span> + format(<span class="string">"instance_idx"</span>, instance_index) + <span class="string">"}"</span>;
}
<span class="keyword">void</span> FromJson(<span class="keyword">const</span> Json::Value& data) {
node_ip = data[<span class="string">"ip"</span>].asString();
service_port = data[<span class="string">"port"</span>].asString();
zk_path = data[<span class="string">"zk_path"</span>].asString();
service_name = data[<span class="string">"service_name"</span>].asString();
service_id = data[<span class="string">"service_id"</span>].asString();
instance_index = data[<span class="string">"instance_idx"</span>].asString();
reg_type = data[<span class="string">"reg_type"</span>].asInt();
}
<span class="keyword">private</span>:
<span class="keyword">std::string</span> node_ip;
<span class="keyword">std::string</span> service_port;
<span class="keyword">std::string</span> zk_path;
<span class="keyword">std::string</span> service_name;
<span class="keyword">std::string</span> service_id;
<span class="keyword">std::string</span> instance_index;
<span class="keyword">int</span> reg_type;
};
Quản lý Đăng ký Dịch vụ
Lớp CServiceRegistry triển khai logic đăng ký và kiểm tra định kỳ:
<span class="keyword">class</span> <span class="class">CServiceRegistry</span> : <span class="keyword">public</span> NonCopyable {
<span class="keyword">public</span>:
<span class="keyword">static</span> CServiceRegistry* GetInstance();
<span class="keyword">int</span> Initialize(<span class="keyword">const</span> ServiceInfo& info);
<span class="keyword">int</span> Register();
<span class="keyword">int</span> Unregister();
<span class="keyword">private</span>:
<span class="keyword">static</span> <span class="keyword">void</span>* RegistrationMonitor(<span class="keyword">void</span>* arg);
<span class="keyword">int</span> AttemptRegistration();
<span class="keyword">int</span> VerifyRegistration();
<span class="keyword">int</span> CleanupRegistration();
<span class="keyword">bool</span> IsRunning() <span class="keyword">const</span>;
<span class="keyword">void</span> SetStatus(<span class="keyword">int</span> status);
<span class="keyword">pthread_t</span> monitor_thread;
<span class="keyword">bool</span> is_active;
ServiceInfo service_info;
<span class="keyword">std::string</span> registered_path;
<span class="keyword">int</span> registration_status;
<span class="keyword">long</span> last_check_time;
};
Quá trình Đăng ký
Quy trình đăng ký bao gồm:
- Tạo nút trên ZooKeeper với đường dẫn
zk_path/service_name_service_id - Xử lý trạng thái
ZNODEEXISTS(nút đã tồn tại) bằng cách thử tạo nút tuần tự - Đảm bảo thông tin nút khớp với thông tin dịch vụ
- Khởi tạo luồng kiểm tra định kỳ để duy trì trạng thái đăng ký
Mã nguồn Minh họa
Phương thức đăng ký thử nghiệm:
<span class="keyword">int</span> CServiceRegistry::AttemptRegistration() {
<span class="keyword">if</span> (registration_status != REG_STATUS_UNREGISTERED) <span class="keyword">return</span> 0;
<span class="keyword">std::string</span> target_path = service_info.zk_path + <span class="string">"/"</span> + service_info.service_name + <span class="string">"_"</span> + service_info.instance_index;
<span class="keyword">bool</span> is_sequence = (service_info.reg_type == REG_TYPE_STANDARD);
<span class="keyword">std::string</span> actual_path;
<span class="keyword">int</span> result = ZooKeeperHandle::GetInstance()->CreateNode(target_path, service_info.ToJsonString(), is_sequence, actual_path);
<span class="keyword">if</span> (result == ZNODEEXISTS) {
<span class="comment">// Xử lý nút đã tồn tại - thử đăng ký tuần tự</span>
result = ZooKeeperHandle::GetInstance()->CreateNode(target_path, service_info.ToJsonString(), <span class="keyword">true</span>, actual_path);
}
<span class="keyword">if</span> (result != ZOK) <span class="keyword">return</span> result;
registered_path = actual_path;
<span class="comment">// Xác minh thông tin nút</span>
<span class="keyword">if</span> (service_info.ToJsonString() == ZooKeeperHandle::GetInstance()->GetNodeData(registered_path)) {
registration_status = REG_STATUS_REGISTERED;
last_check_time = GetCurrentMicroseconds();
}
<span class="keyword">return</span> ZOK;
}