Java转Go日记(三十六):简单的分布式

1.1.1. 简单的分布式server

目前分布式系统已经很流行了,一些开源框架也被广泛应用,如dubbo、Motan等。对于一个分布式服务,最基本的一项功能就是服务的注册和发现,而利用zk的EPHEMERAL节点则可以很方便的实现该功能。EPHEMERAL节点正如其名,是临时性的,其生命周期是和客户端会话绑定的,当会话连接断开时,节点也会被删除。下边我们就来实现一个简单的分布式server:

server:

服务启动时,创建zk连接,并在go_servers节点下创建一个新节点,节点名为"ip:port",完成服务注册 服务结束时,由于连接断开,创建的节点会被删除,这样client就不会连到该节点

client:

先从zk获取go_servers节点下所有子节点,这样就拿到了所有注册的server 从server列表中选中一个节点(这里只是随机选取,实际服务一般会提供多种策略),创建连接进行通信 这里为了演示,我们每次client连接server,获取server发送的时间后就断开。主要代码如下:

server.go

package mainimport ("fmt""net""os""time""github.com/samuel/go-zookeeper/zk"
)func main() {go starServer("127.0.0.1:8897")go starServer("127.0.0.1:8898")go starServer("127.0.0.1:8899")a := make(chan bool, 1)<-a
}func checkError(err error) {if err != nil {fmt.Println(err)}
}func starServer(port string) {tcpAddr, err := net.ResolveTCPAddr("tcp4", port)fmt.Println(tcpAddr)checkError(err)listener, err := net.ListenTCP("tcp", tcpAddr)checkError(err)//注册zk节点q// 链接zkconn, err := GetConnect()if err != nil {fmt.Printf(" connect zk error: %s ", err)}defer conn.Close()// zk节点注册err = RegistServer(conn, port)if err != nil {fmt.Printf(" regist node error: %s ", err)}for {conn, err := listener.Accept()if err != nil {fmt.Fprintf(os.Stderr, "Error: %s", err)continue}go handleCient(conn, port)}fmt.Println("aaaaaa")
}func handleCient(conn net.Conn, port string) {defer conn.Close()daytime := time.Now().String()conn.Write([]byte(port + ": " + daytime))
}
func GetConnect() (conn *zk.Conn, err error) {zkList := []string{"localhost:2181"}conn, _, err = zk.Connect(zkList, 10*time.Second)if err != nil {fmt.Println(err)}return
}func RegistServer(conn *zk.Conn, host string) (err error) {_, err = conn.Create("/go_servers/"+host, nil, zk.FlagEphemeral, zk.WorldACL(zk.PermAll))return
}func GetServerList(conn *zk.Conn) (list []string, err error) {list, _, err = conn.Children("/go_servers")return
}

1.1.2. client.go

package mainimport ("errors""fmt""io/ioutil""math/rand""net""time""github.com/samuel/go-zookeeper/zk"
)func checkError(err error) {if err != nil {fmt.Println(err)}
}
func main() {for i := 0; i < 100; i++ {startClient()time.Sleep(1 * time.Second)}
}func startClient() {// service := "127.0.0.1:8899"//获取地址serverHost, err := getServerHost()if err != nil {fmt.Printf("get server host fail: %s \n", err)return}fmt.Println("connect host: " + serverHost)tcpAddr, err := net.ResolveTCPAddr("tcp4", serverHost)checkError(err)conn, err := net.DialTCP("tcp", nil, tcpAddr)checkError(err)defer conn.Close()_, err = conn.Write([]byte("timestamp"))checkError(err)result, err := ioutil.ReadAll(conn)checkError(err)fmt.Println(string(result))return
}func getServerHost() (host string, err error) {conn, err := GetConnect()if err != nil {fmt.Printf(" connect zk error: %s \n ", err)return}defer conn.Close()serverList, err := GetServerList(conn)if err != nil {fmt.Printf(" get server list error: %s \n", err)return}count := len(serverList)if count == 0 {err = errors.New("server list is empty \n")return}//随机选中一个返回r := rand.New(rand.NewSource(time.Now().UnixNano()))host = serverList[r.Intn(3)]return
}
func GetConnect() (conn *zk.Conn, err error) {zkList := []string{"localhost:2181"}conn, _, err = zk.Connect(zkList, 10*time.Second)if err != nil {fmt.Println(err)}return
}
func GetServerList(conn *zk.Conn) (list []string, err error) {list, _, err = conn.Children("/go_servers")return
}

先启动server,可以看到有三个节点注册到zk:

    127.0.0.1:8897127.0.0.1:8899127.0.0.1:88982018/08/27 14:04:58 Connected to 127.0.0.1:21812018/08/27 14:04:58 Connected to 127.0.0.1:21812018/08/27 14:04:58 Connected to 127.0.0.1:21812018/08/27 14:04:58 Authenticated: id=100619932030205976, timeout=100002018/08/27 14:04:58 Re-submitting `0` credentials after reconnect2018/08/27 14:04:58 Authenticated: id=100619932030205977, timeout=100002018/08/27 14:04:58 Re-submitting `0` credentials after reconnect2018/08/27 14:04:58 Authenticated: id=100619932030205978, timeout=100002018/08/27 14:04:58 Re-submitting `0` credentials after reconnect

启动client,可以看到每次client都会随机连接到一个节点进行通信:

    2018/08/27 14:05:21 Connected to 127.0.0.1:21812018/08/27 14:05:21 Authenticated: id=100619932030205979, timeout=100002018/08/27 14:05:21 Re-submitting `0` credentials after reconnect2018/08/27 14:05:21 Recv loop terminated: err=EOFconnect host: 127.0.0.1:88992018/08/27 14:05:21 Send loop terminated: err=<nil>read tcp 127.0.0.1:54062->127.0.0.1:8899: read: connection reset by peer127.0.0.1:8899: 2018-08-27 14:05:21.291641 +0800 CST m=+22.4801496562018/08/27 14:05:22 Connected to [::1]:21812018/08/27 14:05:22 Authenticated: id=100619932030205980, timeout=100002018/08/27 14:05:22 Re-submitting `0` credentials after reconnect2018/08/27 14:05:22 Recv loop terminated: err=EOF2018/08/27 14:05:22 Send loop terminated: err=<nil>connect host: 127.0.0.1:8897read tcp 127.0.0.1:54064->127.0.0.1:8897: read: connection reset by peer127.0.0.1:8897: 2018-08-27 14:05:22.302322 +0800 CST m=+23.4908013852018/08/27 14:05:23 Connected to 127.0.0.1:21812018/08/27 14:05:23 Authenticated: id=100619932030205981, timeout=100002018/08/27 14:05:23 Re-submitting `0` credentials after reconnect2018/08/27 14:05:23 Recv loop terminated: err=EOF2018/08/27 14:05:23 Send loop terminated: err=<nil>connect host: 127.0.0.1:8897read tcp 127.0.0.1:54070->127.0.0.1:8897: read: connection reset by peer127.0.0.1:8897: 2018-08-27 14:05:23.312873 +0800 CST m=+24.5013242282018/08/27 14:05:24 Connected to 127.0.0.1:21812018/08/27 14:05:24 Authenticated: id=100619932030205982, timeout=100002018/08/27 14:05:24 Re-submitting `0` credentials after reconnect2018/08/27 14:05:24 Recv loop terminated: err=EOFconnect host: 127.0.0.1:88992018/08/27 14:05:24 Send loop terminated: err=<nil>read tcp 127.0.0.1:54072->127.0.0.1:8899: read: connection reset by peer127.0.0.1:8899: 2018-08-27 14:05:24.323668 +0800 CST m=+25.5120901552018/08/27 14:05:25 Connected to 127.0.0.1:21812018/08/27 14:05:25 Authenticated: id=100619932030205983, timeout=100002018/08/27 14:05:25 Re-submitting `0` credentials after reconnect2018/08/27 14:05:25 Recv loop terminated: err=EOF2018/08/27 14:05:25 Send loop terminated: err=<nil>connect host: 127.0.0.1:8897read tcp 127.0.0.1:54074->127.0.0.1:8897: read: connection reset by peer127.0.0.1:8897: 2018-08-27 14:05:25.330257 +0800 CST m=+26.5186505662018/08/27 14:05:26 Connected to [::1]:21812018/08/27 14:05:26 Authenticated: id=100619932030205984, timeout=100002018/08/27 14:05:26 Re-submitting `0` credentials after reconnect2018/08/27 14:05:26 Recv loop terminated: err=EOF2018/08/27 14:05:26 Send loop terminated: err=<nil>connect host: 127.0.0.1:8897read tcp 127.0.0.1:54080->127.0.0.1:8897: read: connection reset by peer127.0.0.1:8897: 2018-08-27 14:05:26.357251 +0800 CST m=+27.5456146162018/08/27 14:05:27 Connected to 127.0.0.1:21812018/08/27 14:05:27 Authenticated: id=100619932030205985, timeout=100002018/08/27 14:05:27 Re-submitting `0` credentials after reconnectconnect host: 127.0.0.1:88992018/08/27 14:05:27 Recv loop terminated: err=EOF2018/08/27 14:05:27 Send loop terminated: err=<nil>read tcp 127.0.0.1:54082->127.0.0.1:8899: read: connection reset by peer127.0.0.1:8899: 2018-08-27 14:05:27.369096 +0800 CST m=+28.5574307642018/08/27 14:05:28 Connected to [::1]:21812018/08/27 14:05:28 Authenticated: id=100619932030205986, timeout=100002018/08/27 14:05:28 Re-submitting `0` credentials after reconnect2018/08/27 14:05:28 Recv loop terminated: err=EOF2018/08/27 14:05:28 Send loop terminated: err=<nil>connect host: 127.0.0.1:8898read tcp 127.0.0.1:54084->127.0.0.1:8898: read: connection reset by peer127.0.0.1:8898: 2018-08-27 14:05:28.380455 +0800 CST m=+29.568760988......

至此,我们的分布式server就实现了

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/pingmian/80989.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

机器学习笔记——特征工程

大家好&#xff0c;这里是好评笔记&#xff0c;公主号&#xff1a;Goodnote&#xff0c;专栏文章私信限时Free。本笔记介绍机器学习中常见的特征工程方法、正则化方法和简要介绍强化学习。 文章目录 特征工程&#xff08;Fzeature Engineering&#xff09;1. 特征提取&#xff…

在 Ubuntu 20.04.6 LTS 中将 SCons 从 3.1.2 升级到 4.9.1

在 Ubuntu 20.04.6 LTS 中将 SCons 从 3.1.2 升级到 4.9.1&#xff0c;可以通过以下步骤完成&#xff1a; 方法 1&#xff1a;使用 pip 安装&#xff08;推荐&#xff09; 步骤 1&#xff1a;卸载旧版本 SCons # 如果通过 apt 安装的旧版本&#xff0c;先卸载 sudo apt remov…

LeetCode热题100--234.回文链表--简单

1. 题目 给你一个单链表的头节点 head &#xff0c;请你判断该链表是否为回文链表。如果是&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,2,1] 输出&#xff1a;true 示例 2&#xff1a; 输入&#xf…

【markdown】介绍如何在markdown中绘制流程图

在 Markdown 中编写流程图主要通过 ​​Mermaid 语法​​实现&#xff08;多数平台如 GitHub、VS Code、Typora 已原生支持&#xff09;。以下是详细方法&#xff1a; 1. 基础流程图​​ 语法结构 用 mermaid 包裹代码块&#xff0c;指定方向后定义节点和连接线&#xff1a…

Java中使用自定义序列化器:自动添加View字段的实现与应用

Java 中 BigDecimal 序列化器:自动添加 View 返回字段的实现与应用 在 Java 开发过程中,数据的序列化与反序列化是非常重要的环节。当我们处理数值类型数据,特别是BigDecimal类型时,有时需要在序列化输出中添加额外的视图字段,以满足前端展示或者特定业务需求。本文将通过…

Java类一文分解:JavaBean,工具类,测试类的深度剖析

解锁Java类的神秘面纱&#xff1a;从JavaBean到测试类的深度剖析 前言一、JavaBean 类&#xff1a;数据的守护者&#xff08;一&#xff09;JavaBean 类是什么&#xff08;二&#xff09;JavaBean 类的特征&#xff08;三&#xff09;JavaBean 类的使用场景&#xff08;四&…

机器学习-- 线性回归、逻辑回归

线性回归 线性回归是一种统计方法,用于发现变量之间的关系。在机器学习背景下,线性回归可找出特征(Feature)与标签(Lable)之间的关系。 例如,假设我们想要根据汽车的重量预测汽车的每加仑汽油行驶里程(mpg),并且我们有以下数据集: 线性回归方程 Linear regressi…

Lua再学习

因为实习的项目用到了Lua&#xff0c;所以再来深入学习一下 函数 函数的的多返回值 Lua中的函数可以实现多返回值&#xff0c;实现方法是再return后列出要返回的值的列表&#xff0c;返回值也可以通过变量接收到&#xff0c;变量不够也不会影响接收对应位置的返回值 Lua中传…

TCP协议十大核心特性深度解析:构建可靠传输的基石

TCP&#xff08;传输控制协议&#xff09;作为互联网的"交通指挥官"&#xff0c;承载着全球80%以上的网络流量。本文将深入解析TCP协议的十大核心特性&#xff0c;通过原理剖析、流程图解和实战案例&#xff0c;揭示其如何实现高效可靠的数据传输。 一、面向连接的可…

基于 Spring Boot 瑞吉外卖系统开发(十三)

基于 Spring Boot 瑞吉外卖系统开发&#xff08;十三&#xff09; 查询套餐 在查询套餐信息时包含套餐的分类名&#xff0c;分类名称在category表中&#xff0c;因此这里需要进行两表关联查询。 自定义SQL如下&#xff1a; select s.* ,c.name as category_name from setmeal…

华为IP(6)

VLAN聚合 VLAN聚合产生的技术背景 在一般是三层交换机中&#xff0c;通常采用一个VLAN接口的方式实现广播域之间的互通&#xff0c;这在某些情况下导致了IP地址的浪费 因为一个VLAN对应的子网中&#xff0c;子网号、子网广播地址、子网网关地址不能用作VLAN内的主机IP地址&a…

深度解析IP静态的工作原理,IP静态的应用场景又哪些?

一、什么是IP静态&#xff1f; 当我们谈到“IP静态”时&#xff0c;大家可能首先想到的是与“动态IP”相对的概念。确实如此&#xff0c;静态IP是一种固定分配的IP地址&#xff0c;也就是说&#xff0c;在特定时间内&#xff0c;分配给你的IP地址不会有所更改——无论你完成多…

docker(四)使用篇一:docker 镜像仓库

前文我们已经介绍了 docker 并安装了 docker&#xff0c;下面我们将正式步入使用环节&#xff0c;本章是第一个使用教学&#xff1a;docker 镜像仓库。 一、什么是镜像仓库 所谓镜像仓库&#xff0c;其实就是负责存储、管理和分发镜像的仓库&#xff0c;并且建立了仓库的索引…

单片机开发软件

目录 纯编码 vscode Ardunio Keil 1. 集成化开发环境&#xff08;IDE&#xff09; 2. 多架构芯片支持 3. 高效的代码生成与优化 4. 强大的调试与仿真功能 5. 丰富的库函数与生态系统 6. 教育与企业级适用性 典型应用场景 半编码半图形化 STM32CUBEIED 1. 图形化配置…

【虚幻引擎】UE5独立游戏开发全流程(商业级架构)

本套课程我将会讲解一下知识 1.虚幻引擎的常用功能节点、模块包含但不限于动画模块、UI模块、AI模块、碰撞模块、伤害模块、背包模块、准心模块、武器模块、可拾取物品模块、死亡等模块。 2.整个游戏的设计思路&#xff08;游戏架构&#xff09;&#xff0c;本套教程讲解了如…

ABP-Book Store Application中文讲解 - Part 2: The Book List Page

本章用于介绍如何创建Book List Page。 TBD 1. 汇总 ABP-Book Store Application中文讲解-汇总-CSDN博客 2. 前一章 ABP-Book Store Application中文讲解 - Part 1: Creating the Server Side 项目之间的引用关系。 目录 1. 多语言配置 1.1 zh-Hans.json 1.2 en.jso…

6、登录功能后端开发

6、登录功能后端开发 https://xiaoxueblog.com/ai/%E7%99%BB%E5%BD%95%E5%8A%9F%E8%83%BD%E5%90%8E%E7%AB%AF%E5%BC%80%E5%8F%91.html 1、新建用户表SQL脚本 -- CREATE DATABASE aicloud CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;-- 创建用户表 drop table if exi…

随机矩阵放大的方式 生成相位数据集,用于相位展开

import os import numpy as np import matplotlib.pyplot as plt from scipy.ndimage import zoom import gc from tqdm import tqdm from zernike import RZerndef wrap_phase(phase):"""将相位包裹到[-π, π]区间"""return np.angle(np.exp(1…

Java面试全记录:Spring Cloud+Kafka+Redis实战解析

Java面试全记录&#xff1a;Spring CloudKafkaRedis实战解析 人物设定 姓名&#xff1a;张伟&#xff08;随机生成唯一姓名&#xff09; 年龄&#xff1a;28岁 学历&#xff1a;硕士 工作年限&#xff1a;5年 工作内容&#xff1a; 基于Spring Cloud搭建微服务架构使用Kafka…

Java Socket编程完全指南:从基础到实战应用

Socket编程是构建网络应用的基石&#xff0c;Java通过java.net包提供了强大的Socket API。本文将深入解析Java Socket类的核心用法&#xff0c;涵盖TCP/UDP协议实现、多线程通信及性能优化技巧&#xff0c;助您快速掌握网络编程精髓。 一、Socket编程核心概念 1.1 网络通信模型…