包含标签 Go articles

go实现发送邮件的功能

当然,下面是一个用 Go 语言发送电子邮件的详细示例。我们将使用 gomail 包来实现邮件发送功能。这里的示例展示了如何配置邮件客户端,创建邮件,并发送邮件。

1. 安装 gomail

首先,我们需要安装 gomail 包。打开终端并运行以下命令:

1
go get gopkg.in/gomail.v2

2. 编写邮件发送功能

下面是一个简单的 Go 程序,它演示了如何使用 gomail 发送电子邮件。

……

Continue reading

proxy_pass的末尾带不带/的作用

在 Nginx 的 proxy_pass 指令中,末尾的斜线(/)对代理行为有重要的影响。这主要涉及到请求 URI 的处理方式。

末尾不带斜线

如果你配置 proxy_pass 不带末尾的斜线,Nginx 会将请求的 URI 完整地传递给后端服务器,包括任何路径信息。

例如:

1
2
3
location /somepath/ {  
    proxy_pass http://localhost:8080;  
}

当客户端请求 /somepath/foo 时,Nginx 会将请求代理到 http://localhost:8080/somepath/foo

末尾带斜线 如果你配置 proxy_pass 带有末尾的斜线,Nginx 会修改请求的 URI,移除与 location 块匹配的部分,然后将剩余部分(如果有的话)传递给后端服务器。

……

Continue reading

Protobuf编码原理及优化技巧探讨

https://mp.weixin.qq.com/s/hAfrPlPD2KBCWxpIuGkQTQ

全文复制保存方便自己查看。

1、Protobuf编码原理介绍

序列化算法被广泛应用于各种通信协议中,本文对序列化算法进行狭义定义:

将某个struct或class的内存数据和通信数据链路上的字节流进行互相转化的算法。

基于这个定义序列化算法具有两个行为:

1、序列化:内存数据->通信链路字节流

2、反序列化:通信链路字节流->内存数据

……

Continue reading

如何真正写好Golang代码?

从https://mp.weixin.qq.com/s/OIHqmgK4V7Y26uYoFjsCyA 复制

Golang 实现SOLID 设计原则

本章节按照设计模式中的核心设计原则介绍在Go语言中的实现。

单一职责原则

类的设计尽量做到只有一个原因引起变化。 在交易的场景中,我们需要做一些交易存储、验证,我们可以声明交易的结构体,这个结构体是为了存储每笔交易。但是验证的功能我们可以拆开,这样代码更具有维护性、测试的编写也更简单方便。

……

Continue reading

收藏专题

K8s相关

ovs controller

Istio

可以参考的链接

https://developer.aliyun.com/article/759790

https://zhuanlan.zhihu.com/p/499341027

ovs and iptables

https://www.cnblogs.com/jmilkfan-fanguiju/p/11825035.html

http://www.openvswitch.org/support/dist-docs/ovs-vsctl.8.txt

macVlan

https://icloudnative.io/posts/netwnetwork-virtualization-macvlan/

https://www.cnblogs.com/bakari/p/10893589.html

svc 的不同类型 NodePort等

Go

defer

nil

单例模式

struct 是否可以比较

new和make的区别

内存对齐

……

Continue reading

GMP

非原创

好文:https://yizhi.ren/2019/06/03/goscheduler

参考:https://blog.csdn.net/xmcy001122/article/details/119392934

Go 语言的协程 goroutine

Go 为了提供更容易使用的并发方法,使用了 goroutine 和 channel。goroutine 来自协程的概念,让一组可复用的函数运行在一组线程之上,即使有协程阻塞,该线程的其他协程也可以被 runtime 调度,转移到其他可运行的线程上。最关键的是,程序员看不到这些底层的细节,这就降低了编程的难度,提供了更容易的并发。

……

Continue reading

go server退出

go server以相当优雅的姿势退出(待继续完善)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package main

import (
	"context"
	"fmt"
	"log"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"
)

type H struct{}

func (H) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	time.Sleep(5 * time.Second)
	fmt.Fprintf(w, "Hello, World!") // 向客户端发送响应
}

func initServer() *http.Server {
	s := &http.Server{
		Addr:    ":8080",
		Handler: H{},
	}
	return s
}

type Backend struct {
	Ctx context.Context
	Srv *http.Server

	CancelFunc func()
}

var onlyOneSignalHandler = make(chan struct{})
var shutdownSignals = []os.Signal{os.Interrupt, syscall.SIGTERM}
var shutdownHandler chan os.Signal

// SetupSignalContext is same as SetupSignalHandler, but a context.Context is returned.
// Only one of SetupSignalContext and SetupSignalHandler should be called, and only can
// be called once.
func (b *Backend) SetupSignalContext() context.Context {
	close(onlyOneSignalHandler) // panics when called twice

	shutdownHandler = make(chan os.Signal, 2)

	signal.Notify(shutdownHandler, shutdownSignals...)

	go func() {
		<-shutdownHandler
		b.Clean()
		<-shutdownHandler
		os.Exit(1) // second signal. Exit directly.
	}()

	return b.Ctx
}

// SetupSignalHandler registered for SIGTERM and SIGINT. A stop channel is returned
// which is closed on one of these signals. If a second signal is caught, the program
// is terminated with exit code 1.
// Only one of SetupSignalContext and SetupSignalHandler should be called, and only can
// be called once.
func (b *Backend) SetupSignalHandler() <-chan struct{} {
	return b.SetupSignalContext().Done()
}

func (b *Backend) RunAndServe(stopCh <-chan struct{}) {
	b.Srv.ListenAndServe()
	<-stopCh
	if err := b.Srv.Shutdown(b.Ctx); err != nil {
		log.Fatal("Server Shutdown:", err)
	}
	log.Printf("initServer exiting")
}

func (b *Backend) Clean() {
	fmt.Println("do some clean")
	time.Sleep(time.Second * 10)
	b.CancelFunc()
	fmt.Println("clean over")
	b.Ctx.Done()
}

func main() {
	ctx, cancel := context.WithCancel(context.Background())
	simpleBackend := Backend{
		Ctx:        ctx,
		Srv:        initServer(),
		CancelFunc: cancel,
	}
	simpleBackend.RunAndServe(simpleBackend.SetupSignalHandler())
}
……

Continue reading

go_自旋锁

CAS算法(compare and swap)

CAS算法是一种有名的无锁算法。无锁编程,即不使用锁的情况下实现多线程之间的变量同步,也就是在没有线程被阻塞的情况下实现变量的同步,所以也叫非阻塞同步(Non-blocking Synchronization)。CAS算法涉及到三个操作数:

  • 需要读写的内存值V
  • 进行比较的值A
  • 拟写入的新值B

当且仅当V的值等于A时,CAS通过原子方式用新值B来更新V的值,否则不会执行任何操作(比较和替换是个原子操作).一般情况下是一个自旋操作,即不断的重试.

……

Continue reading

iptables详解

k8siptable 了解

https://blog.csdn.net/qq_36183935/article/details/90734847

iptables工作流程

iptables是采用数据包过滤机制工作的,所以它会对请求的数据包的包头进行分析,并根据我们预先设定的规则进行匹配来决定是否可以进入主机。

① 防火墙是一层一层过滤的。实际是按照配置规则的顺序从上到下,从前到后进行过滤的; ② 如果匹配上规则,即明确表明阻止还是通过,此时数据包就不再向下匹配新规则了; ③ 如果所有规则中没有明确表明是阻止还是通过这个数据包,也就是没有匹配上规则,则按照默认策略进行处理; ④ 防火墙的默认规则是对应的链的所有的规则执行完成后才会执行的;

……

Continue reading

k8s downward API

前面我们从pod的原理到生命周期介绍了pod的一些使用,作为kubernetes中最核心的对象,最基本的调度单元,我们可以发现pod中的属性还是非常繁多的,前面我们使用过一个volumes的属性,表示声明一个数据卷,我们可以通过命令kubectl explain pod.spec.volumes去查看该对象下面的属性非常多,前面我们只是简单的使用了hostpath和empryDir{}这两种模式,其中还有一种叫做downwardAPI这个模式和其他模式不一样的地方在于它不是为了存放容器的数据也不是用来进行容器和宿主机的数据交换的,而是让pod里的容器能够直接获取到这个pod对象本身的一些信息。

……

Continue reading