From 7f18d0fb0db72fd3fa9e08b8734c041273c30fc7 Mon Sep 17 00:00:00 2001 From: yedf2 <120050102@qq.com> Date: Tue, 14 Sep 2021 20:15:57 +0800 Subject: [PATCH] add cloud deploy --- Dockerfile | 2 +- README.md | 8 ++++---- common/types.go | 10 +++++++++- dtmsvr/api_http.go | 12 ++++++++++++ dtmsvr/trans.go | 13 +++++++++++++ dtmsvr/utils_test.go | 13 +++++++++++++ helper/compose.cloud.yml | 25 +++++++++++++++++++++++++ test/dtmsvr_test.go | 3 +++ 8 files changed, 80 insertions(+), 6 deletions(-) create mode 100644 helper/compose.cloud.yml diff --git a/Dockerfile b/Dockerfile index eaf5232..6082eb6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM daocloud.io/atsctoo/golang:1.15 +FROM golang:1.15 WORKDIR /app/dtm RUN go env -w GO111MODULE=on RUN go env -w GOPROXY=https://goproxy.io,direct diff --git a/README.md b/README.md index fd3ccd3..d00f7e0 100644 --- a/README.md +++ b/README.md @@ -23,19 +23,19 @@ * 一站式解决分布式事务需求 - 支持TCC、SAGA、XA、事务消息、可靠消息 * 支持跨语言栈事务 - - 适合多语言栈的公司使用。支持Go、Python、PHP、Nodejs、Java、c# 各类语言SDK。 + - 支持多语言栈混合的分布式事务。支持Go、Python、PHP、Nodejs、Java、c# 各类语言SDK。 * 自动处理子事务乱序 - 首创子事务屏障技术,框架层自动处理悬挂、空补偿、幂等网络异常问题 * 支持单服务多数据源访问 - 通过子事务屏障技术,保证单服务多数据源访问的一致性,也能保证本地长事务拆分多个子事务后的一致性 * 开箱即用,提供云上服务 - - 支持通用的HTTP、gRPC协议接入,云原生友好。支持Mysql接入。提供测试版本的云上服务,方便新用户测试 + - 支持通用的HTTP、gRPC协议接入,云原生友好。支持Mysql接入。提供测试版本的云上服务,方便新用户测试接入 ## 与其他框架对比 目前开源的分布式事务框架,暂未看到非Java语言有成熟的框架。而Java语言的较多,其中以seata应用最为广泛。 -下面是dtm和seata的主要特性对比: +下面是DTM和SEATA的主要特性对比: | 特性| DTM | SEATA |备注| |:-----:|:----:|:----:|:----:| @@ -46,7 +46,7 @@ |AT事务|||AT与XA类似,性能更好,但有脏回滚| | SAGA事务 |简单模式 |状态机复杂模式 |dtm的状态机模式在规划中| |事务消息|||dtm提供类似rocketmq的事务消息| -|通信协议|HTTP、GRPC|dubbo等协议,无HTTP|| +|通信协议|HTTP、gRPC|dubbo等协议,无HTTP|| |star数量|github stars|github stars|dtm从20210604发布0.1,发展快| 从上面对比的特性来看,如果您的语言栈包含了Java之外的语言,那么dtm是您的首选。如果您的语言栈是Java,您也可以选择接入dtm,使用子事务屏障技术,简化您的业务编写。 diff --git a/common/types.go b/common/types.go index 6e26204..9dba224 100644 --- a/common/types.go +++ b/common/types.go @@ -125,16 +125,22 @@ func DbGet(conf map[string]string) *DB { type dtmConfigType struct { TransCronInterval int64 `yaml:"TransCronInterval"` // 单位秒 当事务等待这个时间之后,还没有变化,则进行一轮处理,包括prepared中的任务和committed的任务 DB map[string]string `yaml:"DB"` + DisableLocalhost int64 `yaml:"DisableLocalhost"` + RetryLimit int64 `yaml:"RetryLimit"` } // DtmConfig 配置 var DtmConfig = dtmConfigType{} +func getIntEnv(key string, defaultV string) int64 { + return int64(dtmcli.MustAtoi(dtmcli.OrString(os.Getenv(key), defaultV))) +} + func init() { if len(os.Args) == 1 { return } - DtmConfig.TransCronInterval = int64(dtmcli.MustAtoi(dtmcli.OrString(os.Getenv("TRANS_CRON_INTERVAL"), "10"))) + DtmConfig.TransCronInterval = getIntEnv("TRANS_CRON_INTERVAL", "10") DtmConfig.DB = map[string]string{ "driver": dtmcli.OrString(os.Getenv("DB_DRIVER"), "mysql"), "host": os.Getenv("DB_HOST"), @@ -142,6 +148,8 @@ func init() { "user": os.Getenv("DB_USER"), "password": os.Getenv("DB_PASSWORD"), } + DtmConfig.DisableLocalhost = getIntEnv("DISABLE_LOCALHOST", "0") + DtmConfig.RetryLimit = getIntEnv("RETRY_LIMIT", "2000000000") cont := []byte{} for d := MustGetwd(); d != "" && d != "/"; d = filepath.Dir(d) { cont1, err := ioutil.ReadFile(d + "/conf.yml") diff --git a/dtmsvr/api_http.go b/dtmsvr/api_http.go index 81f207d..45f22bf 100644 --- a/dtmsvr/api_http.go +++ b/dtmsvr/api_http.go @@ -16,6 +16,7 @@ func addRoute(engine *gin.Engine) { engine.POST("/api/dtmsvr/registerTccBranch", common.WrapHandler(registerTccBranch)) engine.POST("/api/dtmsvr/abort", common.WrapHandler(abort)) engine.GET("/api/dtmsvr/query", common.WrapHandler(query)) + engine.GET("/api/dtmsvr/all", common.WrapHandler(all)) engine.GET("/api/dtmsvr/newGid", common.WrapHandler(newGid)) } @@ -74,3 +75,14 @@ func query(c *gin.Context) (interface{}, error) { db.Must().Where("gid", gid).Find(&branches) return M{"transaction": trans, "branches": branches}, nil } + +func all(c *gin.Context) (interface{}, error) { + lastId := c.Query("last_id") + if lastId == "" { + lastId = "2000000000" + } + lid := dtmcli.MustAtoi(lastId) + trans := []TransGlobal{} + dbGet().Must().Where("id < ?", lid).Order("id desc").Limit(100).Find(&trans) + return M{"transactions": trans}, nil +} diff --git a/dtmsvr/trans.go b/dtmsvr/trans.go index 29bed06..00926c1 100644 --- a/dtmsvr/trans.go +++ b/dtmsvr/trans.go @@ -2,6 +2,7 @@ package dtmsvr import ( "context" + "errors" "fmt" "strings" "time" @@ -222,6 +223,7 @@ func (t *TransGlobal) saveNew(db *common.DB) { branches := t.getProcessor().GenBranches() if len(branches) > 0 { writeTransLog(t.Gid, "save branches", t.Status, "", dtmcli.MustMarshalString(branches)) + checkLocalhost(branches) db.Must().Clauses(clause.OnConflict{ DoNothing: true, }).Create(&branches) @@ -271,3 +273,14 @@ func TransFromDb(db *common.DB, gid string) *TransGlobal { e2p(dbr.Error) return &m } + +func checkLocalhost(branches []TransBranch) { + if config.DisableLocalhost == 0 { + return + } + for _, branch := range branches { + if strings.HasPrefix(branch.URL, "http://localhost") || strings.HasPrefix(branch.URL, "localhost") { + panic(errors.New("url for localhost is disabled. check for your config")) + } + } +} diff --git a/dtmsvr/utils_test.go b/dtmsvr/utils_test.go index 09576d3..f212a4a 100644 --- a/dtmsvr/utils_test.go +++ b/dtmsvr/utils_test.go @@ -19,3 +19,16 @@ func TestUtils(t *testing.T) { CronExpiredTrans(1) sleepCronTime(10) } + +func TestCheckLocalHost(t *testing.T) { + config.DisableLocalhost = 1 + err := dtmcli.CatchP(func() { + checkLocalhost([]TransBranch{{URL: "http://localhost"}}) + }) + assert.Error(t, err) + config.DisableLocalhost = 0 + err = dtmcli.CatchP(func() { + checkLocalhost([]TransBranch{{URL: "http://localhost"}}) + }) + assert.Nil(t, err) +} diff --git a/helper/compose.cloud.yml b/helper/compose.cloud.yml new file mode 100644 index 0000000..026fedc --- /dev/null +++ b/helper/compose.cloud.yml @@ -0,0 +1,25 @@ +version: '3.3' +services: + api: + build: . + environment: + IS_DOCKER: 1 + DISABLE_LOCALHOST: 1 + RETRY_LIMIT: 6 + ports: + - '9080:8080' + volumes: + - .:/app/dtm + mysql: + image: 'mysql:5.7' + environment: + MYSQL_ALLOW_EMPTY_PASSWORD: 1 + TZ: Asia/shanghai + command: + [ + '--character-set-server=utf8mb4', + '--collation-server=utf8mb4_unicode_ci', + '--default-time-zone=+8:00', + ] + ports: + - '3306:3306' diff --git a/test/dtmsvr_test.go b/test/dtmsvr_test.go index 3577cc8..7da0b73 100644 --- a/test/dtmsvr_test.go +++ b/test/dtmsvr_test.go @@ -105,6 +105,9 @@ func transQuery(t *testing.T, gid string) { dtmcli.MustUnmarshalString(resp.String(), &m) assert.Equal(t, nil, m["transaction"]) assert.Equal(t, 0, len(m["branches"].([]interface{}))) + + resp, err = dtmcli.RestyClient.R().Get(examples.DtmServer + "/all") + assert.Nil(t, err) } func TestSqlDB(t *testing.T) {