0%

安装

先安装protobuf的C库

然后安装protoc工具

1
2
3
go get -u github.com/golang/protobuf/proto

go get -u github.com/golang/protobuf/protoc-gen-go

最后安装gRPC-go

阅读全文 »

难点:

最近公司做用户数据迁移,4TB的量,租借了20Gb的带宽,完整迁移需要25天,给的迁移期只有30天,整个迁移过程的容错性和可靠性要非常强

另外由于数据的特殊性,用户数据的错乱比起迁移失败等等无疑是更严重的问题,所以迁移过程要保证强独立性

然而迁移过程的开发时间只有5天,测试时间5天,非常仓促(实际上线后确实遇到不少问题,又花了5天才全部解决)

分析和解决:

阅读全文 »

需求是图片,视频等文件的存储

属于少写多读的场合,修改操作较少。文件粒度是大小文件都有。

fastdfs


先谈谈fastdfs,我在公司已经应用了两年了,对他的基本特性比较熟悉,在这种场合下有这些优缺点

阅读全文 »

golang的http上传文件的实现细节严格遵循了multipart/form-data的RFC1867规范,细节网上已经分析了很多了

本篇只是讨论golang上如何使用官方库实现的框架


客户端上传很简单,利用"mime/multipart"官方库即可完成上传

可以看到这里上传文件时全部加载在内存的bodyBuf字符数组中,所以这里只是上传小文件,大文件这么上传会写爆内存

阅读全文 »

codis在迁移方案上下了不少功夫,我认为codis和twemproxy最大的区别之一是:

codis是面向slot的管理,而twemproxy只是面向redis后端的管理

codis迁移是由Topom结构体的SlotCreateAction方法开始的,这个方法也许叫做SlotMoveToGroupCreateAction更加容易让人理解

这个方法需要两个参数,slot id以及group id,目的是吧这个slot(以及该slot的所有key)迁移到目标group中

SlotCreateAction检测了一些边界条件,例如slot正在被迁移,或者该slot已经存在与目标group

阅读全文 »

记录下踩到的坑

一 接口

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
package main                                                                       

import (
"fmt"
"bytes"
)

type Stringer interface{
String() string
}

type Point struct{X,Y float64}

func (p *Point) String() string{
var buf bytes.Buffer
fmt.Fprintf(&buf, "%f-%f",p.X,p.Y)
return buf.String()
}

func main(){
r1 := Point{1,2}
var r2 Stringer
r2 = &r1
fmt.Println(&r1) //1.000000-2.000000
fmt.Println(r1) //{1 2}
fmt.Println(r1.String()) //1.000000-2.000000
fmt.Println(r2) //1.000000-2.000000
}
```

第一个语句是调用了带指针的String()结果

第二个Print语句输出r1,是Point结构体的,因为没有声明带指针的String方法,因此fmt输出了默认String方法,也就是{1,2}

第三个语句r1.String()为何能正确执行呢,这是因为编译器自动加了&r1.String()

第四个语句r2是接口类型,赋值r1以后检查类型Stringer实现的接口都被Point实现了,因此可以赋值,并且在调用时调用了r2带指针的String方法,而不是默认的那个

这里要注意的是,r2 = &r1是必须的,因为Point没有声明不带指针的String方法,如果要调用带指针的方法,必须对这个结构体取地址

**二 切片**

```go
package main

import "fmt"

func main() {
array1 := [3]int{1,2}
array2 := [5]int{}
array3 := [...]int{}
array4 := []int{1,2,3,4}
array5 := []int{}
fmt.Println(array1) //[1 2 0]
fmt.Println(array2) //[0 0 0 0 0]
fmt.Println(array3) //[]
fmt.Println(array4) //[1 2 3 4]
fmt.Println(array5) //[]
}
```

切片和数组的声明很类似,困扰了我好久

array1,2,3都是数组类型,4,5是切片类型

在类型的[]里,有数字或者...的都是数组,如果什么都没有则是切片

在我的理解看来,切片是对数组的封装,保存了一个数组的指针

1 切片赋值为数组或者切片并且append小于原来的尺寸

```go
//demo1
array1 := [3]int{1,2}
array2 := []int{}
array2 = array1[0:1]
array2 = append(array2, 3, 4)

//demo2
array3 := []int{1,2}
array4 := []int{}
array4 = array3[0:1]
array4 = append(array4, 3)

fmt.Println(array1) //[1 3 4]
fmt.Println(array2) //[1 3 4]
fmt.Println(array3) //[1 3]
fmt.Println(array4) //[1 3]

对于demo1来说数组能够容纳下这一块数据,因此array2依然指向array1,array1被改为[1 3 4]

对于demo2来说array3底层的数组能够容纳下这一块数据,因此array4依然指向array3底层的数组,array3被改为[1,3]

阅读全文 »

codis3.0内置了ha方案(在3.0以前ha是独立项目)

codis HA架构图

本文大致分析一下他的代码,试图找出他这样设计的目的,是否还存在什么缺点以及分析缺点的解决方案

本文的对象是对redis集群有一定经验,基本了解过codis方案的读者


阅读全文 »

最近出现了网络超时的问题要排查,大致按照如图思路去排查

分层图

排除了代码逻辑问题,TCP相关可能的BUG,内核参数等问题后

在排查KVM问题时,在同一个宿主机的不同KVM上,复现了超时问题。

发现大部分异常连接时长都在1s左右,通过抓包分析,可以看到这部分的包被重传了,重传的时间固定为1秒。

阅读全文 »