云原生训练营模块一go语言特性(代码片段)

果子哥丶 果子哥丶     2022-12-15     735

关键词:

Go语言特性

如何学习云原生技术?

代码驱动

  • 掌握Go语言编程能力

从点到面

  • 学习容器技术
    • cgroup,namespace
    • 网络协议栈
    • 文件系统
  • 抓住核心掌控全局
    • 深入理解Kubernetes
      • API定义
      • 控制器模式
      • 核心组件
      • 二次开发(webhook、鉴权、控制器)
  • 大规模生产化
    • 多集群
    • 服务网格和多网格

构建高可用微服务架构统一思想

1、基准代码
一份基准代码,多份部署

2、依赖
显式声明依赖关系

3、配置
在环境中存储配置

4、后端服务
把后端服务当作附加资源

5、构建、发布、运行
严格分离构建和运行

6、进程
以一个或多个无状态进程运行应用

7、端口绑定
通过端口绑定提供服务

8、并发
通过进程模型进行扩展

9、易处理
快速启动或优雅终止可最大化健壮性

10、开发环境与线上环境等价
尽可能的保持开发,预发布,线上环境相同

11、日志
把日志当作事件流

12、管理进程
后台管理任务当作一次性进程运行

Go语言

Go语言特点

Go支持的特性:
Go语言是一个可以编译高效,支持高并发的,面向垃圾回收的全新语言。

  • 秒级完成大型程序的单节点编译
  • 依赖管理清晰
  • 不支持继承,程序员无需花费精力定义不同类型之间的关系
  • 支持垃圾回收,支持并发执行,支持多线程通讯
  • 对多核计算机支持友好

Go不支持的特性:

  • 不支持函数重载和操作符重载
  • 为了避免在C/C++开发中的一些Bug和混乱,不支持隐式转换
  • 支持接口抽象,不支持继承
  • 不支持动态加载代码
  • 不支持动态链接库
  • 通过recover和panic来替代异常机制
  • 不支持断言
  • 不支持静态变量

Go语言编译环境

  • Go安装文件以及源代码
    https://golang.google.cn/dl
  • 下载对应平台的二进程文件并安装
  • 环境变量
    • GOROOT
      • go的安装目录
    • GOPATH
      • src:存放源代码
      • pkg:存放依赖包
      • bin:存放可执行文件
    • 其他常用变量
      • GOOS、GOARCH、GOPROXY
      • 国内用户建议设置goproxy:export GOPROXY=https://goproxy.cn

IDE设置(VS Code)

  • 下载并安装Visual Studio Code
    https://code.visualstudio.com/download
  • 安装Go语言插件
    https://marketplace.visualstudio.com/items?itemName=golang.go

基本命令

  • bug
  • build 编译可执行文件
  • clean
  • doc
  • env
  • fix
  • fmt go fmt test.go
  • generate
  • get
  • install
  • list
  • mode
  • run 可以编译并运行命令源码文件。
  • test
  • tool
  • version
  • vet
go env用于打印Go语言的环境信息。
go run命令可以编译并运行命令源码文件。
go get可以根据要求和实际情况从互联网上下载或更新指定的代码包及其依赖包,并对它们进行编译和安装。
go build命令用于编译我们指定的源码文件或代码包以及它们的依赖包。
go install用于编译并安装指定的代码包及它们的依赖包。
go clean命令会删除掉执行其它命令时产生的一些文件和目录。
go doc命令可以打印附于Go语言程序实体上的文档。我们可以通过把程序实体的标识符作为该命令的参数来达到查看其文档的目的。
go test命令用于对Go语言编写的程序进行测试。
go list命令的作用是列出指定的代码包的信息。
go fix会把指定代码包的所有Go语言源码文件中的旧版本代码修正为新版本的代码。
go vet是一个用于检查Go语言源码中静态错误的简单工具。
go tool pprof命令来交互式的访问概要文件的内容。

go build

  • Go语言不支持动态链接,因此编译时会把所有依赖编译进同一个二进制文件。
  • 指定输出目录。
    • go build -o bin/mybinary
  • 常用环境设置编译操作系统和CPU架构。
    • GOOS=linux GOARCH=amd64 go build
  • 全支持列表。
    • $GOROOT/src/go/build/syslist.go

go test
Go语言原生自带测试

import "testing"
func TestIncrease(t *testting.T)
  t.Log("Start testing")
  increase(1,2)

go test ./… -v 运行测试
go test命令扫描所有*_test.go为结尾的文件,惯例是将测试代码与正式代码放在同目录,如foo.go的测试代码一般写在foo_test.go

go vet
检查编译器可能发现不出来的错误

代码版本控制

  • 下载并安装 Git command line
    • https://git-scm.com/downloads
  • Github
    • 本课程示例代码均上传在 https://github.com/cncamp/golang
  • 创建代码目录
    • mkdir -p $GOPATH/src/github.com/cncamp
    • cd $GOPATH/src/github.com/cncamp
  • 代码下载
    • git clone https://github.com/cncamp/golang.git
  • 修改代码
  • 上传代码
    git add filename
    git commit -m 'change logs'
    git push
    

在线环境
国内可直接访问的playgroup:https://goplay.tools

控制结构

If条件语句
基本形式:

if condition1 
  // do something
 else if condition2 
  // do something else
 else 
  // catch-all or default

if的简短语句
同for一样,if语句可以在条件表达式前执行一个简单的语句

if v := x - 100; v < 0 
  return v


intVal := 1 相等于:
var intVal int 
intVal =1 

switch分支语句

switch var1 
  case val1: // 空分支
  case val2:
      fallthrough // 执行case3中的f()
  case val3:
      f()
  default: //默认分支
      ...


如果case带有fallthrough,程序会继续执行下一条case,不会再判断下一条case的expr

for循环语句
Go只有一种循环结构:for循环

- 计入计数器的循环
for 初始化语句;条件语句;修饰语句 
for i := 0;i < 10; i++ 
  sum += i


- 初始化语句和后置语句酸可选的,此场景与while等价
for ; sum < 1000; 
  sum += sum


- 无限循环
for 
  if condition1 
      break
  

for-range遍历数组
遍历数组,切片,字符串,Map等

for index,char := range myString 
...


for key,value := range MyMap 
...


for index,value := range MyArray 
...

需要注意:如果for range遍历指针数组,则value取出的指针地址为原指针地址拷贝。

package main

import 
    "flag"
    "fmt"
    "os"


func main() 
  name := flag.String("name", "world", "specify the name you want to say hi")
  flag.Parse()
  fmt.Println("os args is:", os.Args).   // Args是go运行时传入的参数
  fmt.Println("input parameter is", *name)
  fullString := fmt.Sprintf("Hello %s from Go\\n", *name)
  fmt.Println(fullString) 



flag的话是 运行时,带上--参数。  --name jesse ,就会把jesse传进去,参数名与参数值, Hello jesses from Go。 如果不带上参数,按照上面逻辑是 Hello World from Go
go run test.go --name jesse

数据结构

变量与常量

  • 常量:const
  • 变量:var

var a,b,c bool
var i,j int = 1,2
函数内,简洁赋值语句 := 可在类型明确的地方代替var声明
函数外,每个语句都必须以关键字(var, func等等),因此 := 结构不能再函数外使用


类型转换:
var i int = 42
var f float64 = float64(i)

数组

  • 相同类型且长度固定连续内存片段
  • 以编号访问每个元素
  • 定义方法
    • var identifier [len] type
  • myArray := [3]int[1,2,3]

切片

  • 切片是对数据一个连续片段的引用
  • 数组定义中不指定长度的即为切片 var identifier [] type
  • 切片在未初始化之前默认为nil,长度为0
  • 常用方法
package main

import (
	"fmt"
)

func main() 
	myArray := [5]int1, 2, 3, 4, 5
	mySlice := myArray[1:3]
	fmt.Printf("mySlice %+v\\n", mySlice)
	fullSlice := myArray[:]
	remove3rdItem := deleteItem(fullSlice, 2)
	fmt.Printf("remove3rdItem %+v\\n", remove3rdItem)


// 没有原生的删除,通过append的前后组合到一起
func deleteItem(slice []int, index int) []int 
	return append(slice[:index], slice[index+1:]...)

Make和New

  • New返回指针地址
  • Make返回第一个元素,可预设内存空间,避免未来的内存拷贝

Map字典

package main

import (
	"fmt"
)

func main() 
	myMap := make(map[string]string, 10)
	myMap["a"] = "b"
	myFuncMap := map[string]func() int
		"funcA": func() int  return 1 ,
	
	fmt.Println(myFuncMap)
	f := myFuncMap["funcA"]
	fmt.Println(f())
	value, exists := myMap["a"]
	if exists 
		println(value)
	
	for k, v := range myMap 
		println(k, v)
	

关于切片的常见问题
(1)b假设达到空间上限,再新增元素,会导致开辟新的空间,b的地址和新的地址是不一样。 —— 这里需要保证前后的地址一致,即a地址赋值给a,而不是b赋值到a。
(2)假设有个切片是int型,当value*2的时候,这个变动会回去吗? 不会的,是因为把遍历的值临时赋给了value。
(3)通过取下标访问切片,访问的就是指针地址,这时会生效。

结构体和指针

  • 通过type-struct关键字自定义结构体
  • Go语言支持指针,但不支持指针运算
    • 指针变量的值为内存地址
    • 未赋值的指针为nil
  • 结构体里只能包含属性,接口只能定义行为
  • New返回指针地址

结构体标签

  • 结构体中的字段除了有名字和类型外,还可以有一个可选的标签(tag)
  • 使用场景:Kubernetes APIServer
package main

import (
	"encoding/json"
	"fmt"
	"reflect"
)

type MyType struct 
	Name string `json:"name"`
	Address

type Address struct 
	City string `json:"city"`

func main() 
	mt := MyTypeName: "test",Address: AddressCity: "shanghai"
	b, _ := json.Marshal(&mt)
	fmt.Println(string(b))
	
	myType := reflect.TypeOf(mt)
	name := myType.Field(0)
	tag := name.Tag.Get("json")
	println(tag)
	
	tb := TypeBP2: "p2", TypeA: TypeAP1: "p1"
	//可以直接访问 TypeA.P1
	println(tb.P1)


type TypeA struct 
	P1 string


type TypeB struct 
	P2 string
	TypeA

练习:
给定一个字符串数组:[“I”,“am”,“stupid”,“and”,“weak”],用for循环遍历该数组并修改为[“I”,“am”,“smart”,“and”,“strong”]

package main

import (
	"fmt"
)

func main() 
	arr := [5]string"I","am","stupid","and","weak"
        for i,v := range arr 
          switch v 
          case "stupid":
              arr[i] = "smart"
          case "weak":
              arr[i] = "strong"
          default:
              break
          
        
        fmt.Println(arr)

接下来计划:

  • 函数调用
  • 常用语法
  • 多线程
  • 深入理解channel
  • 基于channel编写一个生产者消费者程序



生产者与消费者代码

基于同步锁

import (
	"fmt"
	"sync"
)
var (
	productCount = 5
	mutex sync.Mutex
	cond = sync.NewCond(&mutex)
)
type producer struct 


func (r *producer) produce() 
	for 
		cond.L.Lock()
		if productCount < 10 
			productCount++
			fmt.Printf("生产者生产了一个产品,当前存量%d\\n", productCount)
		 else 
			fmt.Printf("仓库满了,当前容量%d\\n", productCount)
			cond.Wait()
		
		cond.L.Unlock()
		cond.Broadcast()
	

func (r *consumer) consumer() 
	for 
		cond.L.Lock()
		if productCount > 0 
			productCount--
			fmt.Printf("消费者消费了一个产品,当前存量%d\\n", productCount)
		 else 
			fmt.Printf("仓库空了,当前存量%d\\n", productCount)
			cond.Wait()
		
		cond.L.Unlock()
		cond.Broadcast()
	

type consumer struct 


func main() 
	var p = producer
	var c = consumer
	go p.produce()
	go c.consumer()
	time.Sleep(time.Microsecond * 10) //防止因为生产者消费者执行方法时主线程已经结束了,给主线程加个时延

基于通道实现
基于通道实现的这种方式需要注意避免从空通道中取数,否则就会出现死锁

var countChan chan int

type producer struct 


func (r *producer) produce() 
	for i := 0; i < 10; i++ 
		count := <-countChan
		if count < 10 
			count++
			fmt.Printf("生产者生产了一个产品,当前存量%d\\n", count)
		 else 
			fmt.Printf("仓库满了,当前容量%d\\n", count)
		
		countChan <- count
		var t = rand.Intn(100)
		time.Sleep(time.Duration(t))
	


func (r *consumer) consumer() 
	for i := 0; i < 10; i++ 
		count := <-countChan
		if count > 0 
			count--
			fmt.Printf("消费者消费了一个产品,当前存量%d\\n", count)
		 else 
			fmt.Printf("仓库空了,当前存量%d\\n", count)
		
		countChan <- count
		var t = rand.Intn(100)
		time.Sleep(time.Duration(t))
	


type consumer struct 


func main() 
	countChan = make(chan int, 1)
	countChan <- 0
	var p = producer
	var c = consumer
	go p.produce()
	go c.consumer()
	time.Sleep(1000)

基于select解决通道阻塞问题

import (
	"fmt"
	"math/rand"
	"time"
)

var countChan chan int

type producer struct 


func (r *producer) produce() 
	for i := 0; i < 10; i++ 
		select 
		case count := <-countChan:
			if count < 10 
				count++
				fmt.Printf("生产者生产了一个产品,当前存量%d\\n", count)
			 else 
				fmt.Printf("仓库满了,当前容量%d\\n", count)
			
			countChan <- count
			var t = rand.Intn(100)
			time.Sleep(time.Duration(t))
		default:
			fmt.Println("初始化产品池")
			countChan <- 0
		
	


func (r *consumer) consumer() 
	for i := 0; i < 10; i++ 
		select 
		case count := <-countChan:
			if count > 0 
				count--
				fmt.Printf("消费者消费了一个产品,当前存量%d\\n", count)
			 else 
				fmt.Printf("仓库空了,当前存量%d\\n", count)
			
			countChan <- count
			var t = rand.Intn(100)
			time.Sleep(time.Duration(t))
		default:
			fmt.Println("初始化产品池")
			countChan <- 0
		

	


type consumer struct 


func main() 
	countChan = make(chan int, 1)
	var p = producer
	var c = consumer
	go p.produce()
	go c.consumer()
	time.Sleep(10000)

云原生训练营模块二go语言进阶(代码片段)

这里写目录标题函数Main函数init函数传递变长参数内置函数回调函数闭包接口反射机制常用语法错误处理deferPanic和recover多线程channel-多线程通信通道缓冲遍历通道缓冲区关闭通道Select定时器Timer上下文Context如何停止一个子协程线... 查看详情

云原生训练营模块三docker核心技术(代码片段)

Docker核心技术1、系统架构2、DockerDocker概念安装Docker容器操作六大子系统关于namespace的常用操作Cgroups文件系统网络模型理解构建上下文(BuildContext)BuildCacheDockerfile常用指令Docker镜像管理课后练习1、系统架构微服务改造&#... 查看详情

云原生训练营模块六kubernetes控制平面组件:apiserver(代码片段)

APIServer0、APIServer概念1、认证基于webhook的认证服务集成构建符合Kubernetes规范的认证服务1、开发认证服务2、配置apiserver2、鉴权Role与ClusterRole账户/组的管理3、准入准入控制准入控制插件4、限流计数器固定窗口算法漏斗算法... 查看详情

云原生训练营模块五kubernetes控制平面组件:etcd(代码片段)

etcd----------Part1----------etcd概述etcd功能与场景服务注册与发现,消息发布与订阅Etcd的安装etcd工具练习Raft协议❤etcd基于Raft的一致性选举方法日志复制安全性失效处理wal日志----------Part2----------etcdv3存储,Watch以及过期机制... 查看详情

云原生训练营模块五kubernetes控制平面组件:etcd(代码片段)

etcd----------Part1----------etcd概述etcd功能与场景服务注册与发现,消息发布与订阅Etcd的安装etcd工具练习Raft协议❤etcd基于Raft的一致性选举方法日志复制安全性失效处理wal日志----------Part2----------etcdv3存储,Watch以及过期机制... 查看详情

云原生训练营模块四kubernetes架构原则和对象设计(代码片段)

Kubernetes架构原则和对象设计K8s安装K8s概念K8s架构控制器的工作流程了解KubectlKubernetes生态系统常用Kubernetes对象及其分组核心技术概念和API对象TypeMeta核心对象概览课后练习K8s安装CentOS7利用Kubeadm快速部署Kubernetes集群K8s概念Kubernete... 查看详情

云原生训练营模块八kubernetes生命周期管理和服务发现(代码片段)

生命周期管理和服务发现1、深入理解Pod的生命周期管理Pod的生命周期pod创建的时候,经历了哪些过程?initCPod状态计算细节如何确保Pod的高可用基于Taint的Evictions健康探针前置后置Post-start&Pre-stop钩子容器应用可能面临... 查看详情

云原生训练营模块八kubernetes生命周期管理和服务发现(代码片段)

生命周期管理和服务发现1、深入理解Pod的生命周期管理Pod的生命周期pod创建的时候,经历了哪些过程?initCPod状态计算细节如何确保Pod的高可用基于Taint的Evictions健康探针前置后置Post-start&Pre-stop钩子容器应用可能面临... 查看详情

云原生时代崛起的编程语言go基础实战(代码片段)

...用场景、开发环境、基础命令、命名规范,进一步了解其原生标准库的强大,最后通过多个Go代码示例演示了基础语法的使用,从而具备初级编程能力。@目录概述定义使用场景Go安全使用须知搜索工具Go基础命令标准库基础语法Ef... 查看详情

云原生训练营模块六kubernetes控制平面组件:apiserver(代码片段)

APIServer0、APIServer概念1、认证基于webhook的认证服务集成构建符合Kubernetes规范的认证服务1、开发认证服务2、配置apiserver2、鉴权Role与ClusterRole账户/组的管理3、准入准入控制准入控制插件4、限流计数器固定窗口算法漏斗算法... 查看详情

15.go语言“避坑”与技巧(代码片段)

...纳。goroutine(Go语言并发)如何使用才更加高效?Go语言原生支持并发是被众人津津乐道的特性。goroutine早期是Inferno操作系统的一个试验性特性,而现在这个特性与操作系统一起,将开发变得越来越简单。很多刚开始使用Go语言... 查看详情

云原生时代崛起的编程语言go并发编程实战(代码片段)

...o代码示例认识Go的协程、通道、定时器、互斥锁、池化、原生操作等十几个并发编程示例,进一步加深对其并发编程使用场景理解和原理的初步认识。@目录概述基础理论并发原语协程-Goroutine通道-Channel多路复用-Select通道使用超... 查看详情

go语言如何书写测试模块(代码片段)

如何在go语言中使用原生的testing模块书写测试模块1.首先对于test模块如何去命名按照官方的规定在书写test包的时候,应该以源文件名加上_test.go的结尾来书写测试包。如原文件名为`main.go`则测试包按照规定应该写为`main_test.go`。... 查看详情

go语言的特性(代码片段)

一、golang语言特性 1.垃圾回收a、内存自动回收,再也不需要开发人员管理内存 //开发代码中不能存在无引用的变量,不然代码出错b、开发人员专注业务实现,降低了心智负担c、只需要new分配内存,不需要释放2.天然并发... 查看详情

云原生|37docker快速部署编程语言golang(代码片段)

🍁博主简介:        🏅云计算领域优质创作者        🏅新星计划第三季python赛道第一名        🏅阿里云ACE认证高级工程师        🏅阿里云开发者社区专家博主✒️博主微信:1557... 查看详情

03go语言特性(代码片段)

一、基本注意事项  1.转义字符1\t一个制表符,代表一次tab2\n换行符3\\转义代表4\"转义代表"5\r一个回车,从当前行的最前面开始输出,会覆盖以前的内容,常配合\r\n换行使用  2.注释1//行注释2//本行已被注释3/**/块注释4/*本段... 查看详情

不看后悔,一文入门go云原生微服务(代码片段)

...1.先启动服务端2.再启动客户端总结关于专栏一起学习Go云原生开发有着天然的优势,云原生系统需要可扩展、耦合、弹性可管理。Go微服务框架很多,包括:go-micro、go-zero、go-kit、go-kratos、tars-go、dubbo-go、jupiter等等…... 查看详情

不看后悔,一文入门go云原生微服务(代码片段)

...1.先启动服务端2.再启动客户端总结关于专栏一起学习Go云原生开发有着天然的优势,云原生系统需要可扩展、耦合、弹性可管理。Go微服务框架很多,包括:go-micro、go-zero、go-kit、go-kratos、tars-go、dubbo-go、jupiter等等…... 查看详情