2021/11/12 老男孩带你21周Go语言 (十)

P144 今日内容

在这里插入图片描述

P145 上周作业思路

带参数的GET请求示例

package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
)

func main() {
	apiUrl := "http://127.0.0.1:9090/get"
	// URL param
	data := url.Values{}
	data.Set("name", "小王子")
	data.Set("age", "18")
	u, err := url.ParseRequestURI(apiUrl)
	if err != nil {
		fmt.Printf("parse url requestUrl failed, err:%v\n", err)
	}
	u.RawQuery = data.Encode() // URL encode
	fmt.Println(u.String())
	resp, err := http.Get(u.String())
	if err != nil {
		fmt.Printf("post failed, err:%v\n", err)
		return
	}
	defer resp.Body.Close()
	b, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("get resp failed, err:%v\n", err)
		return
	}
	fmt.Println(string(b))
}

Post请求示例

package main

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"strings"
)

// net/http post demo

func main() {
	url := "http://127.0.0.1:9090/post"
	// 表单数据
	//contentType := "application/x-www-form-urlencoded"
	//data := "name=小王子&age=18"
	// json
	contentType := "application/json"
	data := `{"name":"小王子","age":18}`
	resp, err := http.Post(url, contentType, strings.NewReader(data))
	if err != nil {
		fmt.Printf("post failed, err:%v\n", err)
		return
	}
	defer resp.Body.Close()
	b, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		fmt.Printf("get resp failed, err:%v\n", err)
		return
	}
	fmt.Println(string(b))
}

对应的Server端HandlerFunc如下:

func postHandler(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()
	// 1. 请求类型是application/x-www-form-urlencoded时解析form数据
	r.ParseForm()
	fmt.Println(r.PostForm) // 打印form数据
	fmt.Println(r.PostForm.Get("name"), r.PostForm.Get("age"))
	// 2. 请求类型是application/json时从r.Body读取数据
	b, err := ioutil.ReadAll(r.Body)
	if err != nil {
		fmt.Printf("read request.Body failed, err:%v\n", err)
		return
	}
	fmt.Println(string(b))
	answer := `{"status": "ok"}`
	w.Write([]byte(answer))
}

P146 go module简单介绍

go开发的时候一开始没有考虑依赖,包的管理,现在下载的包都在这里。但是现在还没有一个项目告诉你需要依赖什么包,也不能共存不同版本的包。
一开始使用了一个vender文件夹里,不同项目使用不同的vender

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
开启之后会根据,go.mod里的清单去找依赖。

在这里插入图片描述
可以设置代理去下载go代码

在这里插入图片描述
在这里插入图片描述
类似于webpack
在这里插入图片描述
在这里插入图片描述
replace可以替换,访问代码的原地址访问不到,可以替换地址访问
在这里插入图片描述
在这里插入图片描述
老项目可以在项目目录执行go mod init,会生成一个go.mod文件
在这里插入图片描述
在这里插入图片描述
生成了一个go.mod文件
在这里插入图片描述
会去下载包

在这里插入图片描述

P147 contex初识

在这里插入图片描述
如何优雅控制goroutine的退出,之前是使用wg管理,线程执行完,wg-1,做完了就退出
在这里插入图片描述
现在是一直卡着等待执行完,如何可以通知进行退出

在这里插入图片描述
5秒后告诉你该退出了。
这是第一种用全局变量的方式

在这里插入图片描述
第二种用channel
在这里插入图片描述
break loop相当于指定跳出谁,就跳出谁
在这里插入图片描述
rowloop就是变量名代表冒号后面的缩进都是它的
在这里插入图片描述
这是用之前学的东西,如何让goroutine进行退出。但是这样每个人写的就不标准,就有了context,就是为了解决多个goroutine协同的问题。
多个goroutine嵌套的时候,如何实现后面的goroutine超时通知退出

在这里插入图片描述
如何用context解决之前的问题.
执行的时候把context传进去。
如果ctx.Done就直接退出。

在这里插入图片描述
在这里插入图片描述
这样就退出了
在这里插入图片描述
context可以再启动一个goroutine,现在有两个任务
在这里插入图片描述

package main

import (
	"context"
	"fmt"
	"sync"

	"time"
)

var wg sync.WaitGroup

func worker(ctx context.Context) {
	go worker2(ctx)
LOOP:
	for {
		fmt.Println("worker")
		time.Sleep(time.Second)
		select {
		case <-ctx.Done(): // 等待上级通知
			break LOOP
		default:
		}
	}
	wg.Done()
}

func worker2(ctx context.Context) {
LOOP:
	for {
		fmt.Println("worker2")
		time.Sleep(time.Second)
		select {
		case <-ctx.Done(): // 等待上级通知
			break LOOP
		default:
		}
	}
}
func main() {
	ctx, cancel := context.WithCancel(context.Background())
	wg.Add(1)
	go worker(ctx)
	time.Sleep(time.Second * 3)
	cancel() // 通知子goroutine结束
	wg.Wait()
	fmt.Println("over")
}

通过一个context,让上面起的两个goroutine关闭。等于用一个跟目录写一个ctx,只要一个超时,下面的goroutine所有都超时
在这里插入图片描述
context去遍历子节点,我们传 的时候传父节点
在这里插入图片描述

P148 context内容介绍

在这里插入图片描述
context这个类型其实就是interface,简化处理单个请求的多个goroutine
这两个函数返回的就是context类型在这里插入图片描述

在这里插入图片描述
当时间结束相当于context过期就退出了
在这里插入图片描述
即使超时了也要cancel
在这里插入图片描述

在这里插入图片描述
WithValue
WithValue函数能够将请求作用域的数据与 Context 对象建立关系。声明如下:

func WithValue(parent Context, key, val interface{}) Context

WithValue返回父节点的副本,其中与key关联的值为val。

仅对API和进程间传递请求域的数据使用上下文值,而不是使用它来传递可选参数给函数。

所提供的键必须是可比较的,并且不应该是string类型或任何其他内置类型,以避免使用上下文在包之间发生冲突。WithValue的用户应该为键定义自己的类型。为了避免在分配给interface{}时进行分配,上下文键通常具有具体类型struct{}。或者,导出的上下文关键变量的静态类型应该是指针或接口。

package main

import (
	"context"
	"fmt"
	"sync"

	"time"
)

// context.WithValue

type TraceCode string

var wg sync.WaitGroup

func worker(ctx context.Context) {
	key := TraceCode("TRACE_CODE")
	traceCode, ok := ctx.Value(key).(string) // 在子goroutine中获取trace code
	if !ok {
		fmt.Println("invalid trace code")
	}
LOOP:
	for {
		fmt.Printf("worker, trace code:%s\n", traceCode)
		time.Sleep(time.Millisecond * 10) // 假设正常连接数据库耗时10毫秒
		select {
		case <-ctx.Done(): // 50毫秒后自动调用
			break LOOP
		default:
		}
	}
	fmt.Println("worker done!")
	wg.Done()
}

func main() {
	// 设置一个50毫秒的超时
	ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*50)
	// 在系统的入口中设置trace code传递给后续启动的goroutine实现日志数据聚合
	ctx = context.WithValue(ctx, TraceCode("TRACE_CODE"), "12512312234")
	wg.Add(1)
	go worker(ctx)
	time.Sleep(time.Second * 5)
	cancel() // 通知子goroutine结束
	wg.Wait()
	fmt.Println("over")
}

P149 上午内容复习

go1.11开始才启用go module,需要手动开启,后面1.13就默认启用

在这里插入图片描述
go.mod记录了所有当前项目依赖包的信息和版本信息

在这里插入图片描述
这个是适用新的项目

在这里插入图片描述
导入包的时候,就import hello

在这里插入图片描述
在这里插入图片描述
hello这个包现在并不在gopath下,这样在gomodule使用前是肯定不行的
在这里插入图片描述
在这里插入图片描述
context.Background默认返回父节点,根节点
context.TODO()当不知道传什么的时候,需要接收一个context的变量,就使用TODO,调用别人的包一定要传一个context变量的时候可以用TODO

在这里插入图片描述
withvalue可以给上下文加一下值

在这里插入图片描述

P150 日志收集项目架构

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
logagent具体部署到每台服务器上,根据配置项去收集日志,配置存储到etcd里,etcd用页面管理,logagent从最新的etcd里拿到配置
log transfer把日志取出来发到es和hdaoop里

在这里插入图片描述

在这里插入图片描述

P151 kafika介绍

在这里插入图片描述
同时多个消费者订阅消息

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
**生产者+kafka集群+消费者。
**

在这里插入图片描述
kafka集群的节点称为broker。
topic订阅的主题
partition 分区
分区角色,leader,follower,leader挂了,follower可以升级为leader

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
leader确认发送消息成功,leader告诉follower来拉取新数据,拉取后,follower告诉leader拉取成功。
all代表需要所有follower都要发送成功。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
有三个分区
在这里插入图片描述
每个partition都是一个有序并 且不可变的消息记录集合。当新的数据写入时,就被追加到partition的末
尾。在每个partition中,每条消息都会被分配一个顺序的唯一标识, 这个标识被称为offset,即偏移
量。注意,Kafka只保证在同一个partition内部消息是有序的,在不同partition之间, 并不能保证消息
有序。

Kafka可以配置一个保留期限,用来标识日志会在Kafka集群内保留多长时间。Kafka集 群会保留在保留
期限内所有被发布的消息,不管这些消息是否被消费过。比如保留期限设置为两天,那么数据被发布到
Kafka集群的两天以内,所有的这些数据都可以被消费。当超过两天,这些数据将会被清空,以便为后
续的数据腾出空间。由于Kafka会将数据进行持久化存储(即写入到硬盘上),所以保留的数据大小可
以设置为一个比较大的值。

在这里插入图片描述

Partition在服务器上的表现形式就是一个- 个的文件夹,每个partition的文件夹下面会有多组segment
文件,每组segment文件又包含. index文件、. log文件、。 timeindex文件三个文件,其中.1og文
件就是实际存储message的地方,而. index和.timeindex文件为索引文件,用于检索消息。

在这里插入图片描述
kafka集群里有两台机器,上面各有2个分区。有两个消费者组。
在同一个消费者组中,每个消费者实例可以消费多个分区,但是每个分区最多只能被消费者组中的一个实例消费。
c1如果从p0-p3取了,c2就不能,只能从p1和p2取

在这里插入图片描述
为什么快,每个消息都有文件记录位置

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

P152 kafka启动

安装kafka需要提前安装jdk

在这里插入图片描述
在这里插入图片描述
配置环境变量

在这里插入图片描述
在这里插入图片描述
kafka自带了一个zookeeper,查看配置文件
在这里插入图片描述
在这里插入图片描述
windows执行bat启动脚本
在这里插入图片描述
在本机的2181

在这里插入图片描述

kafka的配置文件

在这里插入图片描述
brokerid。唯一标识

在这里插入图片描述
windows起,需要用管理员

在这里插入图片描述

P153 zookeeper工作机制

在这里插入图片描述
在服务之间调用的时候 ,假如服务后端对应多个节点,就需要有一个登记的地方让调用者知道该如何调用
在这里插入图片描述

P154 tailf模块介绍及使用

在这里插入图片描述
先去下载包
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
发生错误的话还是根据上次的记录位置继续记录,保证连续性
在这里插入图片描述
在这里插入图片描述
一行一行读日志

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

P155 sarama模块及使用

sarama在go1.20之后假如了zstd压缩,需要gcc

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
现在就有版本号了
在这里插入图片描述
在这里插入图片描述
设置代理

在这里插入图片描述
config方式给字段设置值

在这里插入图片描述
日志级别归根到底是传的数字,这个数字和log level绑定在一起

在这里插入图片描述
在这里插入图片描述
指定一个topic

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
现在只有一个分区,里面是真正存数据的log日志文件,索引,时间索引

在这里插入图片描述

P156 logAgent实现

上面kafka和taillog两个实现不通的功能
在这里插入图片描述

kafka初始化成功就相当于全局变量可用
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
发送kafka信息

在这里插入图片描述
写logagent入口

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在main函数里就要做一些操作
在这里插入图片描述
这样写,需要加载多少个组件就加载多少个组件 ,很清晰
在这里插入图片描述
无限循环读日志
在这里插入图片描述
可以把读日志放到一个channel里
在这里插入图片描述
在这里插入图片描述
logagent进行读取日志
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
go build
在这里插入图片描述
go mod init
在这里插入图片描述
在这里插入图片描述
报错,传的类型错误

在这里插入图片描述
在这里插入图片描述
上面是代码依赖和上面的依赖不一样,就使用tidy纠正一下
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
打印日志查看程序执行到哪一步

在这里插入图片描述
现在就等待my.log里面写日志 了
在这里插入图片描述
现在是放到kafka了,可以起一个消费者在这里插入图片描述

在这里插入图片描述
往日志文件里写,taillog模块从文件里读,发到kafka,消费者终端从kafka里读

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

P157 配置文件版LogAgent

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

可以 写个ini配置文件
在这里插入图片描述
在这里插入图片描述
加载配置好的ini文件
在这里插入图片描述
现在信息就出来了
在这里插入图片描述
这样可以转换成string
在这里插入图片描述
可以造一个结构体对应配置
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值