tonglin0325的个人主页

go学习笔记——基本语法

1.*和&的区别

& 是取地址符号 , 即取得某个变量的地址 , 如 &a

  • 是指针运算符 , 可以表示一个变量是指针类型 , 也可以表示一个指针变量所指向的存储单元 , 也就是这个地址所存储的值

参考:Go中*和&区别

println打印对象只能打印出其指针,需要使用fmt.Printf,如下

1
2
fmt.Printf("%+v\n", user)

参考:Golang 通过fmt包输出完整struct信息

2.defer

defer是Go语言提供的一种用于注册延迟调用的机制:让函数或语句可以在当前函数执行完毕后(包括通过return正常结束或者panic导致的异常结束)执行。

defer语句通常用于一些成对操作的场景:打开连接/关闭连接;加锁/释放锁;打开文件/关闭文件等。

defer在一些需要回收资源的场景非常有用,可以很方便地在函数结束前做一些清理操作。在打开资源语句的下一行,直接一句defer就可以在函数返回前关闭资源,可谓相当优雅。

1
2
3
f, _ := os.Open("defer.txt")
defer f.Close()

参考:Golang之轻松化解defer的温柔陷阱

3.日志库

1.sirupsen/logrus

1
2
go get -u github.com/sirupsen/logrus

文档

1
2
https://pkg.go.dev/github.com/sirupsen/logrus#section-readme

使用

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

import (
"os"
"github.com/sirupsen/logrus"
)

// Create a new instance of the logger. You can have any number of instances.
var log = logrus.New()

func main() {
// The API for setting attributes is a little different than the package level
// exported logger. See Godoc.
log.Out = os.Stdout

// You could set this to any `io.Writer` such as a file
// file, err := os.OpenFile("logrus.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
// if err == nil {
// log.Out = file
// } else {
// log.Info("Failed to log to file, using default stderr")
// }

log.WithFields(logrus.Fields{
"animal": "walrus",
"size": 10,
}).Info("A group of walrus emerges from the ocean")
}

2.rs/zerolog

1
2
go get -u github.com/rs/zerolog/log

使用

1
2
3
4
5
log.Logger = log.With().Caller().Logger()
log.Info().Msg("hello world")

// Output: {"level": "info", "message": "hello world", "caller": "/go/src/your_project/some_file:21"}

3.uber/zap

1
2
go get -u go.uber.org/zap

文档

1
2
https://pkg.go.dev/go.uber.org/zap

zap提供了2种logger,分别是Logger和SugaredLogger

在性能要求高但是不是很重要的场景下,适合使用SugaredLogger

1
2
3
4
5
6
7
8
9
10
11
logger, _ := zap.NewProduction()
defer logger.Sync() // flushes buffer, if any
sugar := logger.Sugar()
sugar.Infow("failed to fetch URL",
// Structured context as loosely typed key-value pairs.
"url", url,
"attempt", 3,
"backoff", time.Second,
)
sugar.Infof("Failed to fetch URL: %s", url)

输出

1
2
3
{"level":"info","ts":1703922949.209576,"caller":"server/main.go:109","msg":"failed to fetch URL","url":"http://example.com","attempt":3,"backoff":1}
{"level":"info","ts":1703922949.209731,"caller":"server/main.go:115","msg":"Failed to fetch URL: http://example.com"}

在性能要求高且需要类型安全的场景下,适合使用Logger

1
2
3
4
5
6
7
8
9
10
logger, _ := zap.NewProduction()
defer logger.Sync()
url := "http://example.com"
logger.Info("failed to fetch URL",
// Structured context as strongly typed Field values.
zap.String("url", url),
zap.Int("attempt", 3),
zap.Duration("backoff", time.Second),
)

输出

1
2
{"level":"info","ts":1703923022.603034,"caller":"server/main.go:108","msg":"failed to fetch URL","url":"http://example.com","attempt":3,"backoff":1}

NewExample/NewDevelopment/NewProduction区别

NewExample适用于测试代码,它将DebugLevel及以上级别的日志以JSON格式标准输出,但省略了时间戳和调用函数,以保持示例输出简短和确定。

NewDevelopment适用于开发环境,它以人类友好的格式将DebugLevel及以上级别的日志写入标准错误。

NewProduction适用于生产环境,它将info level及以上级别的日志以JSON格式写入标准错误。

其他参考文档:Go 每日一库之 zap

golang常用库包:log日志记录-uber的Go日志库zap使用详解

4.kratos logrus

参考:go各框架的log日志

5.日志文件回滚

日志文件按时间回滚:natefinch/lumberjack

1
2
go get gopkg.in/natefinch/lumberjack.v2

4.strconv包

int转string

1
2
s := strconv.Itoa(i)

int64转string

1
2
s := strconv.FormatInt(i, 10)

string转int

1
2
i, err := strconv.Atoi(s)

string转int64

1
2
i, err := strconv.ParseInt(s, 10, 64)

float转string

1
2
3
4
v := 3.1415926535
s1 := strconv.FormatFloat(v, 'E', -1, 32)//float32
s2 := strconv.FormatFloat(v, 'E', -1, 64)//float64

string转float

1
2
3
4
s := "3.1415926535"
v1, err := strconv.ParseFloat(v, 32)
v2, err := strconv.ParseFloat(v, 64)

参考:Go语言从入门到精通 - 【精华篇】strconv包详解

5.属性复制

可以使用 jinzhu/copier

使用jinzhu/copier

1
2
go get github.com/jinzhu/copier

copy

1
2
copier.Copy(&employee, &user)

deepcopy,区别是deepcopy的时候,对dst的属性进行修改,是肯定不会影响src的

1
2
3
var dst User
copier.CopyWithOption(&dst, src, copier.Option{DeepCopy: true})

如果想在复制的时候,对属性进行修改,可以使用方法赋值,注意需要使用copier.Copy,如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
type User struct {
Name string
Age int
}

func (u *User) DoubleAge() int {
return 2 * u.Age
}

type Employee struct {
Name string
DoubleAge int
Role string
}

func main() {
user := User{Name: "dj", Age: 18}
employee := Employee{}

copier.Copy(&employee, &user)
fmt.Printf("%#v\n", employee)
}

参考:Go 每日一库之 copier

其他类似的库还有ulule/deepcoper,参考:golang struct拷贝工具(类似于java中 BeanUtils.copyProperties())

以及

1
2
3
4
5
6
7
8
9
10
11
12
13
https://github.com/jinzhu/copier
https://github.com/mohae/deepcopy
https://github.com/ulule/deepcopier
https://github.com/mitchellh/copystructure
https://github.com/globusdigital/deep-copy
https://github.com/getlantern/deepcopy
https://github.com/antlabs/deepcopy
https://github.com/go-toolsmith/astcopy
https://github.com/qdm12/reprint
https://github.com/huandu/go-clone
https://github.com/wzshiming/deepclone
https://github.com/davidwalter0/go-clone

6.其他数据结构

golang没有set,priorityqueue这些数据结构,可以使用emirpasic/gods

参考:https://github.com/emirpasic/gods

7.切片处理

可以使用samber/lo来对切片、数组或集合进行处理

1
2
go get github.com/samber/lo@v1

比如filter操作

1
2
3
4
5
even := lo.Filter([]int{1, 2, 3, 4}, func(x int, index int) bool {
return x%2 == 0
})
// []int{2, 4}

map操作

1
2
3
4
5
6
7
import "github.com/samber/lo"

lo.Map([]int64{1, 2, 3, 4}, func(x int64, index int) string {
return strconv.FormatInt(x, 10)
})
// []string{"1", "2", "3", "4"}

去重操作

1
2
3
uniqValues := lo.Uniq([]int{1, 2, 2, 1})
// []int{1, 2}

获得map的key,并转换成数组

不使用lo

1
2
3
4
5
6
7
8
9
m := map[string]int{
"foo": 1,
"bar": 2,
}
keys := make([]string, 0, len(m))
for key := range m {
keys = append(keys, key)
}

使用lo

1
2
3
4
5
6
7
8
9
m := map[string]int{
"foo": 1,
"bar": 2,
}
keys := lo.Keys[string, int](m)
fmt.Println(keys)

// [foo bar]

range操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
result := lo.Range(4)
// [0, 1, 2, 3]

result := lo.Range(-4)
// [0, -1, -2, -3]

result := lo.RangeFrom(1, 5)
// [1, 2, 3, 4, 5]

result := lo.RangeFrom[float64](1.0, 5)
// [1.0, 2.0, 3.0, 4.0, 5.0]

result := lo.RangeWithSteps(0, 20, 5)
// [0, 5, 10, 15]

result := lo.RangeWithSteps[float32](-1.0, -4.0, -1.0)
// [-1.0, -2.0, -3.0]

result := lo.RangeWithSteps(1, 4, -1)
// []

result := lo.Range(0)
// []

8.时间处理

可以使用time或者carbon

1.time

字符串转time.Time

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import (
"fmt"
"time"
)

func main() {
timeStr := "2023-07-21 14:30:00"
// DateTime = "2006-01-02 15:04:05"
// DateOnly = "2006-01-02"
// TimeOnly = "15:04:05"
// RFC3339 = "2006-01-02T15:04:05Z07:00"

parsedTime, err := time.Parse(time.DateTime, timeStr)
if err != nil {
fmt.Println("解析时间字符串时出错:", err)
return
}

fmt.Println("解析后的时间:", parsedTime)
}

time.Time转字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import (
"fmt"
"time"
)

func main() {
// 获取当前时间
currentTime := time.Now()
// DateTime = "2006-01-02 15:04:05"
// DateOnly = "2006-01-02"
// TimeOnly = "15:04:05"
// RFC3339 = "2006-01-02T15:04:05Z07:00"
timeStr := currentTime.Format(time.DateOnly)
// 输出格式化后的时间字符串
fmt.Println("格式化后的时间字符串:", timeStr)
}

2.carbon

1
2
go get -u github.com/golang-module/carbon/v2

文档

1
2
https://pkg.go.dev/github.com/golang-module/carbon/v2

9.断言

可以使用stretchr/testify

1
2
go get -u github.com/stretchr/testify

使用assert

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
import (
"testing"
"github.com/stretchr/testify/assert"
)

func TestSomething(t *testing.T) {

// assert equality
assert.Equal(t, 123, 123, "they should be equal")

// assert inequality
assert.NotEqual(t, 123, 456, "they should not be equal")

// assert for nil (good for errors)
assert.Nil(t, object)

// assert for not nil (good when you expect something)
if assert.NotNil(t, object) {

// now we know that object isn't nil, we are safe to make
// further assertions without causing any errors
assert.Equal(t, "Something", object.Value)

}

}

10.resty

在go中请求接口可以使用go-resty/resty框架

1
2
go get github.com/go-resty/resty/v2

get请求

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Create a Resty Client
client := resty.New()

resp, err := client.R().
SetQueryParams(map[string]string{
"page_no": "1",
"limit": "20",
"sort":"name",
"order": "asc",
"random":strconv.FormatInt(time.Now().Unix(), 10),
}).
SetHeader("Accept", "application/json").
SetResult(&Result{}).
SetAuthToken("BC594900518B4F7EAC75BD37F019E08FBC594900518B4F7EAC75BD37F019E08F").
Get("/search_result")

post请求

1
2
3
4
5
6
7
8
9
10
11
// Create a Resty Client
client := resty.New()

// POST JSON string
// No need to set content type, if you have client level setting
resp, err := client.R().
SetHeader("Content-Type", "application/json").
SetBody(`{"username":"testuser", "password":"testpass"}`).
SetResult(&AuthSuccess{}). // or SetResult(AuthSuccess{}).
Post("https://myapp.com/login")

11.单元测试

使用testing框架进行单元测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package dao

import (
"fmt"
"gin-template/internal/database"
"gin-template/internal/model"
"testing"
)

func Test_userDo_Create(t *testing.T) {
user := model.User{
Username: "test",
Email: "test@test",
}
SetDefault(database.DB)

err := User.Create(&user)
if err != nil {
fmt.Println("creat user")
}
}

如果遇到go testing flag provided but not defined: -test.v的报错,解决方法是添加一个init.go文件

1
2
3
4
5
6
7
8
package test

import "testing"

func init() {
testing.Init()
}

然后在使用了flag的地方添加的import中

1
2
_ "gin-template/internal/test"

参考:问题记录:flag provided but not defined: -test.v 异常处理过程

12.打桩工具——go monkey

go monkey可以用于在单元测试中进行打桩(指补齐未实现的代码)

参考:Go单测从零到溜系列4—使用monkey打桩

全文 >>

Java反射机制

如果要通过一个对象找到一个类的名称,此时就需要用到反射机制(反射技术是用来做框架的,一般情况下Java私有对象不能被访问,但是暴力反射可以访问私有对象)

任何一个类如果没有明确地声明继承自哪个父类的时候,则默认继承Object类,所以getClass()方法是Object类中的。

文件在包java_reflect目录

全文 >>

Airflow分布式部署

airflow分布式部署所依赖的组件有mysql,redis,web-server,scheduler,worker等,可以将这些组件部署在不同的机器上,来减低单台机器的压力

单机安装请参考:Ubuntu16.04安装apache-airflow

然后在不同的机器上启动不同的组件

1
2
3
4
airflow webserver -D
airflow scheduler -D
airflow worker -D

安装airflow其他支持组件,比如airflow-kerberos,参考

1
2
https://awesome.dbyun.net/study/details?mid=160&id=7427

airflow启用kerberos,参考

1
2
https://github.com/astronomer/airflow-guides/blob/main/guides/kerberos.md

MySQL学习笔记——事务和隔离级别

ACID

ACID数据库事务管理的四个关键属性,用于确保数据在并发环境下的可靠性和一致性。

1.Atomicity(原子性)

原子性指的是一个事务中的所有操作要么全部执行成功,要么全部不执行。换句话说,事务是不可分割的最小单位。ACID模型的原子性主要涉及InnoDB事务。

例如,在银行转账操作中,假设从账户 A 转账到账户 B 是一个事务。如果在从 A 扣款后,B 未能成功入账,整个操作就会回滚到初始状态,A 账户的余额也不会减少。

相关的MySQL功能包括:

  • AUTOCOMMIT设置。
  • COMMIT语句。

    全文 >>

hudi-cli使用

在 Amazon EMR 版本 5.28.0 及更高版本中, Amazon EMR 默认情况下会在安装 Spark、Hive 或 Presto 时安装 Hudi 组件。

参考:创建安装了 Hudi 的集群

Amazon EMR的版本和hudi的版本对应可以参考文档:Hudi 发行版历史记录

可以使用下面命令进入hudi-cli

1
2
/usr/lib/hudi/cli/bin/hudi-cli.sh

hudi-cli如下

退出cli,输入exit

我们可以在hive中注册hudi表,然后使用hive,sparkSQL或者presto对其进行查询

参考:Hudi 的工作原理

常用命令:Apache Hudi数据湖hudi-cli客户端使用

官方文档:

1
https://hudi.apache.org/docs/cli#local-set-up

1.连接hudi表

1
2
connect --path s3://bucket_name/path_xxx

2.查看hudi表的属性

1
2
desc

全文 >>

mongo基本操作

1.安装mongo客户端

参考:ubuntu安装mongodb-4.4(通过apt命令)

2.连接mongodb

1
mongo ip:27017/db_name -u user_name -p

3.创建collection

参考:MongoDB 教程

1
2
use xx_db
db.createCollection("xx_collection")

4.插入数据

insert one

1
2
3
4
5
6
7
8
9
10
use xx_db

db.xx_collection.insertOne(
{
"id":"100000",
"time":new Date(),
"abc":"123456"
}
)

insert many

1
2
3
4
5
6
7
8
9
10
11
12
13
db.xx_collection.insertMany(
[
{
"id":"200000",
"time":new Date(),
"token":"1111111"
}, {
"id":"300000",
"time":new Date(),
"token":"2222222"
}
]
)

5.删除数据

delete one

1
2
3
use xx_db
db.xx_collection.deleteOne({'id':'200000'})

delete many

1
2
db.xx_collection.deleteMany({'token':'1111111'})

6.查看Mongo的collection大小

1
2
db.getCollection("your_collection").stats()

参考:获取mongo 数据大小及collection大小

7.查看collection是否是sharded

1
2
db.getCollection("your_collection").stats()

没有sharded字段,或者sharded值为false,都不是sharded collection

全文 >>

Helm基本操作

Helm是k8s的包管理工具,使用helm可以简化k8s应用部署

而使用了helm之后,helm会提供一个模板,将这些yaml文件作为一个整体进行管理,高效复用,同时方便版本管理

全文 >>

Hudi学习笔记——基本操作

1.Hudi概念

参考:

英文官方文档:https://hudi.apache.org/docs/concepts/

中文官方文档:https://hudi.apache.org/cn/docs/0.9.0/concepts/

Apache Hudi架构设计和基本概念

1.Hudi表的存储类型

hudi表的类型有2种,分成cow和mor

cow是Copy On Write的缩写,含义是写入时复制(只有parquet文件)

mor是Merge On Read的缩写,含义是读取时合并(log文件+parquet文件)

2种hudi表类型的对比

适用场景,参考:ByteLake:字节跳动基于Apache Hudi的实时数据湖平台

COW表适用于批量离线更新场景

MOR表适用于实时高频更新场景

1.写时复制

写时复制存储中的文件片仅包含基本/列文件,并且每次提交都会生成新版本的基本文件。 换句话说,我们压缩每个提交,从而所有的数据都是以列数据的形式储存。在这种情况下,写入数据非常昂贵(我们需要重写整个列数据文件,即使只有一个字节的新数据被提交),而读取数据的成本则没有增加。 这种视图有利于读取繁重的分析工作。

cow类型的hudi表文件目录如下,参考:https://jxeditor.github.io/2021/05/07/Hudi初探/#开始文件分析COW

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
.
├── .hoodie
│ ├── .aux
│ │ └── .bootstrap
│ │ ├── .fileids
│ │ └── .partitions
│ ├── .temp
│ ├── 20210511100234.commit
│ ├── 20210511100234.commit.requested
│ ├── 20210511100234.inflight
│ ├── 20210511100304.commit
│ ├── 20210511100304.commit.requested
│ ├── 20210511100304.inflight
│ ├── 20210511100402.commit
│ ├── 20210511100402.commit.requested
│ ├── 20210511100402.inflight
│ ├── 20210511100503.commit.requested
│ ├── 20210511100503.inflight
│ ├── archived
│ └── hoodie.properties
└── par1
├── .hoodie_partition_metadata
├── 48ca22d7-d503-4073-93ec-be7a33e6e8f4_0-1-0_20210511100234.parquet
├── 99aaf2d1-8e82-42d9-a982-65ed8d258f28_0-1-0_20210511100304.parquet
└── 99aaf2d1-8e82-42d9-a982-65ed8d258f28_0-1-0_20210511100402.parquet

使用写时复制的时候,对于update操作,当commit了之后,即使只是update了一行数据的一个字段,hudi会将这行数据所在的文件再copy一遍,然后加个这个更新之后,重新生成一个文件,所以在使用COW表的时候可能会产生写放大的问题,参考:Hudi COW表的数据膨胀(清除历史版本)问题

hudi对于历史数据的保留版本,由hoodie.cleaner.commits.retained参数来控制,默认是24

在查询COW表的时候,可以通过read.start-commit加上read.end-commit参数来按commit时间来控制查询范围,格式为yyyyMMddHHmmss,所有只使用一个参数的话,只有查询最新的一个commit,参考官方配置文档:https://hudi.apache.org/docs/configurations/

2.读时合并

读时合并存储是写时复制的升级版,从某种意义上说,它仍然可以通过读优化表提供数据集的读取优化视图(写时复制的功能)。 此外,它将每个文件组的更新插入存储到基于行的增量日志中,通过文件id,将增量日志和最新版本的基本文件进行合并,从而提供近实时的数据查询。因此,此存储类型智能地平衡了读和写的成本,以提供近乎实时的查询。 这里最重要的一点是压缩器,它现在可以仔细挑选需要压缩到其列式基础文件中的增量日志(根据增量日志的文件大小),以保持查询性能(较大的增量日志将会提升近实时的查询时间,并同时需要更长的合并时间)。

mor类型的hudi表文件目录如下,参考:https://jxeditor.github.io/2021/05/07/Hudi初探/#开始文件分析MOR

可以看到,采用读时合并的目录下除了.parquet文件,还有.log文件,其中.log文件采用的就是avro序列化格式,log文件格式结构可以参考:Hudi Log 文件格式与读写流程

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
.
├── .hoodie
│ ├── .aux
│ │ ├── .bootstrap
│ │ │ ├── .fileids
│ │ │ └── .partitions
│ │ ├── 20210510175131.compaction.requested
│ │ ├── 20210510181521.compaction.requested
│ │ ├── 20210510190422.compaction.requested
│ │ └── 20210511091552.compaction.requested
│ ├── .temp
│ │ ├── 20210510175131
│ │ │ └── par1
│ │ │ ├── 0a0110a8-b26b-4595-b5fb-b2388263ac54_0-1-0_20210510175131.parquet.marker.CREATE
│ │ │ ├── 39798d42-eb9f-46c7-aece-bdbe9fed3c45_0-1-0_20210510175131.parquet.marker.CREATE
│ │ │ └── 75dff8c0-614a-43e9-83c7-452dfa1dc797_0-1-0_20210510175131.parquet.marker.CREATE
│ │ ├── 20210510181521
│ │ │ └── par1
│ │ │ └── 39798d42-eb9f-46c7-aece-bdbe9fed3c45_0-1-0_20210510181521.parquet.marker.MERGE
│ │ └── 20210510190422
│ │ └── par1
│ │ └── 39798d42-eb9f-46c7-aece-bdbe9fed3c45_0-1-0_20210510190422.parquet.marker.MERGE
│ ├── 20210510174713.deltacommit
│ ├── 20210510174713.deltacommit.inflight
│ ├── 20210510174713.deltacommit.requested
......
│ ├── 20210510181212.rollback
│ ├── 20210510181212.rollback.inflight
......
│ ├── 20210510181521.commit
│ ├── 20210510181521.compaction.inflight
│ ├── 20210510181521.compaction.requested
......
│ ├── 20210511090334.clean
│ ├── 20210511090334.clean.inflight
│ ├── 20210511090334.clean.requested
......
│ ├── archived -- 归档目录,操作未达到默认值时,没有产生对应文件
│ └── hoodie.properties
└── par1
├── .39798d42-eb9f-46c7-aece-bdbe9fed3c45_20210510181521.log.1_0-1-0
├── .39798d42-eb9f-46c7-aece-bdbe9fed3c45_20210510190422.log.1_0-1-0
├── .39798d42-eb9f-46c7-aece-bdbe9fed3c45_20210511091552.log.1_0-1-2
├── .hoodie_partition_metadata
├── 0a0110a8-b26b-4595-b5fb-b2388263ac54_0-1-0_20210510175131.parquet
├── 39798d42-eb9f-46c7-aece-bdbe9fed3c45_0-1-0_20210510181521.parquet
├── 39798d42-eb9f-46c7-aece-bdbe9fed3c45_0-1-0_20210510190422.parquet
└── 75dff8c0-614a-43e9-83c7-452dfa1dc797_0-1-0_20210510175131.parquet

parquet文件什么时候合并由参数 compaction.delta_commits 和

全文 >>

java程序内存泄露排查

1.生成内存快照文件(Heap Profile)

1
2
jmap -dump:format=b,file=heap.hprof ${pid}

2.使用Eclipse Memory Analyzer工具对hprof文件进行分析

1.12.0版本需要jdk11,所以下载1.10.0版本

1
2
http://www.eclipse.org/downloads/download.php?file=/mat/1.10.0/rcp/MemoryAnalyzer-1.10.0.20200225-linux.gtk.x86_64.zip

由于堆栈文件可能会很大,所以需要修改 MemoryAnalyzer.ini 文件中的-Xmx1024m,比如改成-Xmx10240m,否则可能会遇到下面报错

1
2
an internal error occurred during parsing heap dump from

3.分析堆栈文件

全文 >>

kudu学习笔记——建表语句

kudu支持的数据类型

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
boolean

8-bit signed integer

16-bit signed integer

32-bit signed integer

64-bit signed integer

date (32-bit days since the Unix epoch)

unixtime_micros (64-bit microseconds since the Unix epoch)

single-precision (32-bit) IEEE-754 floating-point number

double-precision (64-bit) IEEE-754 floating-point number

decimal (see Decimal Type for details)

varchar (see Varchar Type for details)

UTF-8 encoded string (up to 64KB uncompressed)

binary (up to 64KB uncompressed)

参考:Apache Kudu Schema Design

kudu的建表语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CREATE TABLE sales_by_year(					# 列存储
year INT, # 有限固定列,强类型
sale_id INT COLPROPERTIES (encoding=“bitshuffle”), # 每一列均可以设置encoding及压缩方式
amount INT,
PRIMARY KEY (year,sale_id) # 主键索引
)
PARTITION BY HASH (sale_id) PARTITIONS 4,              # 哈希分区
RANGE (year)
(
PARTITION 2014 <= VALUES <= 2016, # 范围分区
PARTITION VALUE = 2017
)
STORED AS KUDU
TBLPROPERTIES (replication=3); # 多副本

或者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
CREATE TABLE xxxx.xxxx(
uuid STRING,
ds string,
`date` string,
`ts` string,
`col1` int,
`col2` bigint,
`col3` int,
PRIMARY KEY (uuid, ds))
PARTITION BY HASH (uuid, ds) PARTITIONS 9,
RANGE(ds) (
PARTITION VALUE="2020-09-05",
PARTITION VALUE="2020-09-06",
PARTITION VALUE="2020-09-07",
PARTITION VALUE="2020-09-08",
PARTITION VALUE="2020-09-09"
)
STORED AS KUDU;

参考:DTCC2017-Kudu介绍-小米张震-final

全文 >>