Coder Social home page Coder Social logo

prontera / spring-cloud-rest-tcc Goto Github PK

View Code? Open in Web Editor NEW
2.6K 2.6K 1.2K 6.84 MB

以Spring Cloud Netflix作为服务治理基础, 展示基于tcc**所实现的分布式事务解决方案

Java 100.00%
c4-diagram c4model distributed-transaction microservice spring-boot spring-cloud spring-cloud-netflix tcc try-confirm-cancel

spring-cloud-rest-tcc's Introduction

Preface

随业务发展、组织架构变动,加上对现有系统进行析构拆分,所带来的一个显著问题是进程间一致性需求增加,是一个协作问题。Atomikos曾撰文介绍使用TCC作为microservice的分布式事务解决方案,这里有一篇简单的译文可作为入门资料。

经文章叙述,Atomikos所设计的TCC交互完全构建在HTTP协议之上,并充分地复用了HTTP语义特性,是一个与应用层协议紧耦合的解决方案。而究其本质,TCC是作为2PC的补充,更是一种设计**。

本文使用Spring Cloud Netflix作为服务治理基础,通篇穿插C4 Model,侧重以最简练的方式,向大家展示如何使用TCC解决分布式事务。

Variants

在microservice兴起的时候,由于对集团内部已有的中间件生态考量与性能的实质需求,更多是以RPC协议进行构建,如gRPC、Dubbo和Thrift等框架。面对TCC设计**,同样应该以更温和的方式落地,而不应受限于应用层协议,我们将以不同的角度阐述这种TCC的"变体"。

在模型上,将原有的HTTP语义下沉到请求体当中,上下游各自定义status code,用于识别不同状态。

在流程上,从Try-Confirm-Cancel演进为Try-Confirm-Diagnose,Try和Confirm保持抽象为API接口。而且在原则上不建议持有长周期的大事务,而小事务可确保预留资源快速回滚,所以不再视Cancel与Try-Confirm平级,建议从API接口转为功能特性融合至Try和Confirm方法当中,并且在非必要场景下不建议提供Cancel接口,避免因拜占庭问题增加轮转至conflict状态的几率。

即便是无可避免地出现conflict状态,也可以通过Diagnose接口作出诊断,追踪坏账以便人工介入处理。

出于对知识的敬重与措辞的严谨性,下文统一使用TCD指代上述理念的TCC变体。

Scenario

假设有以下场景,我们想购入一台PS4,在付款后需要历经生单、扣减余额和扣减库存这三个过程,分别对应服务Order、Account和Product,但每一个过程中都可能会因为网络故障、宕机、网络分区或拜占庭问题,从而暴露出各种矛盾。

System Context Diagram

Coordinator

Atomikos在文章<<TCC for transaction management across microservices>>中提出将TCC Coordinato服务化,Transaction Coordinator delivered as a service,成为一个可重用组件,负责各式各样的异常处理。

但系统的复杂度往往是随着系统内的服务数增加呈正向关系,而且数据包每多跳转一个节点就会有更多的时间耗费在网络I/O上。

在实现形式上,TCC Coordinator基于RESTful所设计的API天生具备易访问的特性,可以较为方便地对单一事务内的打包资源发起协同操作,而RPC的劣势在于序列化协议之间的天然屏障,无法做到如micrometer和service mesh理念中的vendor-neutral,所以TCD Coordinator示例中更倾向于将其概念依附于业务系统中,以白盒的方式管理事务。

纵观整个链路,Customer向Order发起结算请求,Order往往需要通过请求中GUID提供幂等性支持,避免网络故障与应用宕机时,因上游重试从而导致多次生单和重复预留资源的情况,同时重试策略也直接解决了failure recover后的事务恢复问题。

Responsibility

  1. 组织并负责发起TCD事务
  2. 提供诊断conflict事务的Diagnose门面接口
  3. 仅对下游发起Try与Confirm操作,避免出现既Confirm又Cancel的拜占庭问题
  4. 针对下游发起Try操作时,负责计算预留资源时间,并适当考虑下游因GC情况而所需增加的补偿时间
Container Diagram

Lazy Participant

Lazy Participant无需启用调度器自发地将过期的TRYING状态资源轮转至CANCELLED状态,而是将这个功能隐藏在Confirm和Query Transaction接口当中,由TCD Coordinator负责驱动,以减少事务参与者的开发成本,专注于正确的状态轮转和业务逻辑即可。

在本示例当中,Account与Product充当Lazy Participant角色,分别负责余额扣减与库存扣减。

Responsibility

  1. 提供Try操作的预留资源API接口
  2. 提供Confirm操作的确认预留资源API接口,并在内部负责对过期资源的状态轮转
  3. 提供事务状态查询的API接口,并在内部负责对过期资源的状态轮转,并为上游Diagnose操作提供支持
  4. 对Try和Confirm两个接口实现幂等性调用
Component Diagram

Final State Machine

Coordinator

Participant

* Account Transaction与Product Transaction状态机类似,故不赘述

Getting Started

Technology stack

  • Java 8
  • Spring Boot 2.x
  • Spring Cloud Netflix - Hoxton
  • MySQL 8.0

Prerequisites

在开始部署之前,先要确保MySQL有按照预期进行工作,我们有两种方法初始化DDL,根据情况选择其中一种即可。

Docker

在目录assets/docker中存放着所有与Docker相关的内容,我们可以直接找到compose文件夹,通过以下命令启动MySQL镜像。聪明的Docker会根据配置,自动将位于mysql/db/init_mysql_user.sql内的DDL进行初始化。

docker-compose -f database.yml up

Manual

我们亦可根据实际情况,将DDL直接导入至已有的数据源中,相关SQL位于assets/docker/mysql/db目录下的init_mysql_user.sql文件中,但需注意如果当前执行用户缺失GRANT权限,会导致执行失败,按需删减对应SQL即可。

如果一切顺利,我们会有3个账户和3个商品,分别是

Account Product
chris gba
scott ps4
ryan fc

Demonstration

将工程导入IDE后,在目录rest-tcc-projects中按下表顺序依次启动,表中同时也列出了项目的相关URL信息

Name URL
rest-tcc-service-discovery http://localhost:8255/
rest-tcc-account http://localhost:8285/swagger-ui.html
rest-tcc-product http://localhost:8265/swagger-ui.html
rest-tcc-order http://localhost:8295/swagger-ui.html

我们在整个流程中扮演Customer角色,通过Order服务提供的Swagger面板作为操作入口

checkout

在一般情况下,我们发起下单请求,Order服务会根据请求中GUID作幂等性处理,假设检测到GUID已经存在,则会恢复该事务并继续处理后续流程。并通过与上游磋商重试策略,以解决由于network failure或crash后的事务恢复问题。

// request body
{
  "guid": 1,
  "price": 47,
  "productName": "ps4",
  "quantity": 1,
  "username": "chris"
}

// response body
{
  "successful": true,
  "code": 20000,
  "message": "请求成功"
}

Order服务基于TCD Coordinator的理念所设计,在Try阶段需根据Participant响应时间设计资源预留时长,并还需考虑Participant因GC或网络I/O所带来的耗时,适当加上补偿时间。另外为了避免服务间的Clock时钟不一致问题,报文中一律使用相对时间。

reserving_secs_in_participant = reserving_secs_in_coordinator + compensation_secs

但墨菲定律提醒我们partial confirm的情况总是会不经意地产生,在本示例中亦人为地模拟了这一情况。假设我们选择使用账户scott去下单,总会使得confirm阶段操作发生超时而无法正确扣减账户余额;而对于产品,我们选择购买gba的时候,也总是会在confirm阶段因超时而无法扣减产品库存。

/// request body
{
  "guid": 2,     //谨记需要使用不同的guid,否则会根据幂等性操作返回其他订单的状态
  "price": 47,
  "productName": "ps4",
  "quantity": 1,
  "username": "scott"
}

// response body
{
  "successful": false,
  "code": 42003,
  "message": "资源确认存在冲突"
}

我们可以到MySQL account库中的t_account表确认scott账号并没任何余额扣减,但在product库中的t_product表,却发现ps4库存被错误扣减(不要忘了上面chris也买了一台ps4)。此时该订单处于conflict终态,针对坏账diagnose接口可以在有限时间内,在下游Participant未清理事务流水的前提下定位问题。

diagnose

guid 1,chris成功买了一台ps4,除了确认Participant内部的具体扣减情况,我们还可以通过diagnose进行二次确认。

// request body
{
  "guid": 1
}

// response body
{
  "successful": true,
  "code": 20000,
  "message": "请求成功",
  "stateMap": {
    "account": "CONFIRMED",
    "product": "CONFIRMED"
  }
}

guid 2,根据我们的设计,可怜的scott会因为超时买不到任何产品。

// request body
{
  "guid": 2
}

// response body
{
  "successful": true,
  "code": 20000,
  "message": "请求成功",
  "stateMap": {
    "account": "CANCELLED",  //资源预留被取消,所以未能成功扣减账户余额
    "product": "CONFIRMED"
  }
}

至于其他组合情况,就留待大家继续探寻。

End

如果对本人编码风格或设计思路等有更好的想法或建议,欢迎通过GitHub Issue留言,感谢各位耐心阅读!

spring-cloud-rest-tcc's People

Contributors

prontera avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

spring-cloud-rest-tcc's Issues

business服务启动失败

组件部署操作没有问题,eureka都可以看到服务,但是business服务没有在eureka上注册

order-ms的运行报错:
2017-12-19 03:56:53.418 ERROR [order,,,] 1 --- [ main] o.s.boot.SpringApplication : Application startup failed

java.lang.IllegalStateException: Could not locate PropertySource and the fail fast property is set, failing
at org.springframework.cloud.config.client.ConfigServicePropertySourceLocator.locate(ConfigServicePropertySourceLocator.java:130)
at org.springframework.cloud.config.client.ConfigServicePropertySourceLocator$$FastClassBySpringCGLIB$$fa44b2a.invoke()
at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:721)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.retry.interceptor.RetryOperationsInterceptor$1.doWithRetry(RetryOperationsInterceptor.java:74)
at org.springframework.retry.support.RetryTemplate.doExecute(RetryTemplate.java:276)
at org.springframework.retry.support.RetryTemplate.execute(RetryTemplate.java:157)
at org.springframework.retry.interceptor.RetryOperationsInterceptor.invoke(RetryOperationsInterceptor.java:101)
at org.springframework.retry.annotation.AnnotationAwareRetryOperationsInterceptor.invoke(AnnotationAwareRetryOperationsInterceptor.java:119)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:656)
at org.springframework.cloud.config.client.ConfigServicePropertySourceLocator$$EnhancerBySpringCGLIB$$12d13302.locate()
at org.springframework.cloud.bootstrap.config.PropertySourceBootstrapConfiguration.initialize(PropertySourceBootstrapConfiguration.java:89)
at org.springframework.boot.SpringApplication.applyInitializers(SpringApplication.java:636)
at org.springframework.boot.SpringApplication.prepareContext(SpringApplication.java:350)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:314)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1187)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1176)
at com.github.prontera.OrderMsApplication.main(OrderMsApplication.java:14)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:48)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:87)
at org.springframework.boot.loader.Launcher.launch(Launcher.java:50)
at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:51)
Caused by: org.springframework.web.client.ResourceAccessException: I/O error on GET request for "http://localhost:8888/order/default": Connection refused (Connection refused); nested exception is java.net.ConnectException: Connection refused (Connection refused)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:666)
at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:613)
at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:531)
at org.springframework.cloud.config.client.ConfigServicePropertySourceLocator.getRemoteEnvironment(ConfigServicePropertySourceLocator.java:170)
at org.springframework.cloud.config.client.ConfigServicePropertySourceLocator.locate(ConfigServicePropertySourceLocator.java:91)
... 27 common frames omitted
Caused by: java.net.ConnectException: Connection refused (Connection refused)
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at java.net.Socket.connect(Socket.java:538)
at sun.net.NetworkClient.doConnect(NetworkClient.java:180)
at sun.net.www.http.HttpClient.openServer(HttpClient.java:432)
at sun.net.www.http.HttpClient.openServer(HttpClient.java:527)
at sun.net.www.http.HttpClient.(HttpClient.java:211)
at sun.net.www.http.HttpClient.New(HttpClient.java:308)
at sun.net.www.http.HttpClient.New(HttpClient.java:326)
at sun.net.www.protocol.http.HttpURLConnection.getNewHttpClient(HttpURLConnection.java:1202)
at sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1138)
at sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1032)
at sun.net.www.protocol.http.HttpURLConnection.connect(HttpURLConnection.java:966)
at org.springframework.http.client.SimpleBufferingClientHttpRequest.executeInternal(SimpleBufferingClientHttpRequest.java:78)
at org.springframework.http.client.AbstractBufferingClientHttpRequest.executeInternal(AbstractBufferingClientHttpRequest.java:48)
at org.springframework.http.client.AbstractClientHttpRequest.execute(AbstractClientHttpRequest.java:53)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:652)
... 31 common frames omitted

其他服务报错类似
我的操作步骤:
Centos安装java,docker,maven
git clone 源码
运行build.sh脚本
按照顺序docker-compose
另外我用STS打开您的项目,微服务都有报错,我也是初次接触微服务,希望您能多多指点,感谢

mysql无法正常启动

mysql启动错误信息如下(配置文件内只保留了mysql的service):

Creating network "resttcc_default" with the default driver
Creating resttcc_solar_mysql_1 ...  
Creating resttcc_solar_mysql_1 ... done 
Attaching to resttcc_solar_mysql_1 
solar_mysql_1  | Initializing database 
resttcc_solar_mysql_1 exited with code 1 

操作系统:16.04.1-Ubuntu

docker版本信息:17.05.0-ce

docker-compse版本信息:

docker-compose version 1.17.1, build 6d101fb
docker-py version: 2.5.1
CPython version: 2.7.13
OpenSSL version: OpenSSL 1.0.1t  3 May 2016

代码错误

hi,我下载下来,导入工程,发现代码似乎有缺失。
SwaggerApiInfo为什么没有get set方法?
SwaggerConfiguration 23行 SwaggerApiInfo.builder() builder方法找不到?
大神,是不是我这边少了什么东西呢?

启动order报错

我在把您的项目部署到K8S上的时候
infrastructure
basic-ms
monitor-ms
虽然报的一些异常但是还是启动成功能跑起来,spring-boot-admin里有几个是跑起来的但是还是offine
比较棘手的问题就是因为没法用docker-compose部署
所以我准备单个单个服务部署
business启动都报错,部署order的时候报出了如下的错误
Error handling failed (ApplicationEventMulticaster n ot initialized - call 'refresh' before multicasting events via the context: org. springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationCont ext@45ca843: startup date [Thu Jan 01 08:00:00 CST 1970]; parent: org.springfram ework.context.annotation.AnnotationConfigApplicationContext@2ed94a8b)
分配的CPU是0.5核,内存512MB

功能很完善很强大,不过例子工程好像比较复杂,根据例子项目用于自己的项目要做的工作很多,用起来难度很大

例子工程组:
order-ms工程:42个类
product-ms工程:25个类
account-ms工程:31个类
OrderService.java 12个方法,228行
ProductStockTccService.java 8个方法,147行
UserBalanceTccService.java 8个方法,151行
如果能做一个简化版本,例子工程如果能简化抽取部分代码放到一个已有的基础lib工程被引用就能更好的推广应用^_^

能否补全文档及项目

你好,研究了你的库,受益匪浅。是否可以补全详细文档及项目其他模块,如安全模块。谢谢。

楼主项目打包打不了

原因好像就因为你那个common-dps的问题.好多东西在它里面引用完,在其它项目要重新引用!

IncreasePointsEventHandler类中如果消费失败了,没有回执消息,mq中的消息还是会被消费掉

真正的消费业务逻辑在IncreasePointsEventHandler中,如果try中自己的业务抛出了异常,改如何处理?

@OverRide
public void handle(EventSubscriber subscriber) {
Preconditions.checkNotNull(subscriber);
Preconditions.checkNotNull(subscriber.getId());
try {
if (Objects.equal(BUSINESS_TYPE, subscriber.getBusinessType())) {
// 这里取巧,将生产者的报文特地写成PointFlow的格式
final PointFlow request = Jacksons.getMapper().readValue(subscriber.getPayload(), PointFlow.class);
// 简单地增加流水,为了简便就没有模拟任何业务上的校验
pointService.persistFlow(request);
// 增加总数
pointService.increasePoint(request.getPoint(), request.getUserId());
getMapper().updateEventStatusByPrimaryKeyInCasMode(subscriber.getId(), EventStatus.NEW, EventStatus.DONE);
} else {
if (successor != null) {
successor.handle(subscriber);
}
}

    } catch (IOException e) {
        throw new IllegalArgumentException("读取JSON报文至实体时发生异常. payload: " + subscriber.getPayload() + ", entity: PointFlow.class");
    }
}

关于Hystrix Dashboard以及Zipkin的问题

1.Hystrix Dashboard打开请求地址localhost:8193/turbine.stream?cluster=prontera,结果是提示下载一个文件,而不是与README里面的页面
2.Zipkin里面有order,product,account,tcc,但是没有merbership

主事物失败

如果A服务调用B、C服务,用这种要是B、C都确认成功了,要是本地事物失败了怎么办这个好像没有考虑到吧?楼主是不是?

部分Confirm的异常处理

楼主在confirm时,如果其中某项数据库操作(扣除余额或者消费产品) 发生异常,是如何统一全部回滚的???

product启动报错

product_1 | 2017-12-20 16:02:17.714 INFO [product,,,] 1 --- [ main] c.github.prontera.ProductMsApplication : No active profile set, falling back to default profiles: default
检查了下 yml是有的 又谢了个一样的properties加上去也不行
config启动时报错
No active profile set, falling back to default profiles: default
加上启动参数 --spring.profile.active=bootstrap没用

挺强大的

这是我目前在网上看到实现非常好的Spring cloud 事务Tcc demo
不过有几点小建议,是编码规范的
我总觉得在Service层@autowire另外一个service
比如说order-ms中的 orderService 调用orderconflictService 来保存orderconflict model,
在我理解比较规范的方法是orderService调用orderconflict dao层来保存orderconflict对象。

无法启动mysql,错误日志如下

container_linux.go:247: starting container process caused "process_linux.go:359: container init caused "rootfs_linux.go:54: mounting \"/usr/share/zoneinfo/Asia/Shanghai\" to rootfs \"/mnt/sda1/var/lib/docker/aufs/mnt/3a6200731c361eef122ee6ef0deb4eebf0e397597a4a3ebada85d54672360a11\" at \"/mnt/sda1/var/lib/docker/aufs/mnt/3a6200731c361eef122ee6ef0deb4eebf0e397597a4a3ebada85d54672360a11/usr/share/zoneinfo/PRC\" caused \"not a directory\"""

account/product等模块从config-server动态获取配置无效

account/product等模块从config-server动态获取配置无效。
参考启动warning

2019-01-22 14:20:02.102  WARN [tcc,,,] 16988 --- [           main] o.s.c.a.ConfigurationClassPostProcessor  : Cannot enhance @Configuration bean definition 'refreshScope' since its singleton instance has been created too early. The typical cause is a non-static @Bean method with a BeanDefinitionRegistryPostProcessor return type: Consider declaring such methods as 'static'.

为什么一个@EnableEurekaClient注解都没有?

问个比较弱鸡的问题。我仔细看了项目路源码。但是有个让我疑惑地方就是。所有eureka client项目都 没有添加@EnableEurekaClient注解。但是eureka服务端却能获取到。这是为什么?

关于数据校验与CrudMapper的疑问

数据检验,HibernateValidatorAspect是用于数据校验的吗?想跟您学习一下你封装这个完整项目的思路,看你的报错啊,状态什么的都弄的很好.想了解一下...

hystrix-dashboard-ms Exception

ERROR 951 --- [InstanceMonitor] c.n.t.monitor.instance.InstanceMonitor : Could not initiate connection to host, giving up: [{"timestamp":1499224918284,"status":503,"error":"Service Unavailable","message":"MaxConcurrentConnections reached: 5","path":"/78d504ff-82e8-4a87-82e8-724d72d1171b/hystrix.stream"}]

很赞~~

代码写的很赞.... 虽然我的程序还没跑起来...

JSON相关用的是 jackson,我前段时间对 Gson,fastJson 和 Jackson 做了下性能与Json支持度对比,结果是 gson的性能和可靠性在小数据(1kb)下是性能最优的,不知道作者后续有将Jackson换成gson的打算么?

docker-compose启动项目时遇到的问题

按照文档的约定分别启动了
1.basic-ms-compose.yml
2.business-ms-compose.yml

当启动[2]的时候就会抛出异常
2017-06-27 11 29 30
在[1]中,则直接显示docker state:Exit 137
具体日志没有任何提示信息
2017-06-27 11 36 27

启动mysql容器失败

Attaching to springcloudresttcc_jce_java_1, springcloudresttcc_solar_mysql_1, springcloudresttcc_rabbitmq_1
jce_java_1 | jce java
solar_mysql_1 | Initializing database
springcloudresttcc_jce_java_1 exited with code 0
springcloudresttcc_solar_mysql_1 exited with code 1

代码有点小BUG

tcc-coordinator-ms->CoordinateService->66行:
final ResponseEntity response = restTemplate.exchange(participant.getUri(), HttpMethod.PUT, REQUEST_ENTITY, String.class);
此句是否应该先用LoadBalancerClient.choose(serviceId)得出ServiceInstance.getUri() 然后与participant.getUri()拼接,再用restTemplate.exchange(此新的uri).
不然所有的事件资源回调链接都调不通啊.

这个项目里面的对于积分增加的时候

如果说积分汇总和积分明细在入库时报错了new IllegalArgumentException,那么消费者从mq消息队列中取出消息,这个时候消息是被消费了的。 是需要修改t_event_pub中的状态然后重新发送消息到mq队列?

@OverRide
public void handle(EventSubscriber subscriber) {
Preconditions.checkNotNull(subscriber);
Preconditions.checkNotNull(subscriber.getId());
try {
if (Objects.equal(BUSINESS_TYPE, subscriber.getBusinessType())) {
// 这里取巧,将生产者的报文特地写成PointFlow的格式
final PointFlow request = Jacksons.getMapper().readValue(subscriber.getPayload(), PointFlow.class);
// 简单地增加流水,为了简便就没有模拟任何业务上的校验
pointService.persistFlow(request);
// 增加总数
pointService.increasePoint(request.getPoint(), request.getUserId());
getMapper().updateEventStatusByPrimaryKeyInCasMode(subscriber.getId(), EventStatus.NEW, EventStatus.DONE);
} else {
if (successor != null) {
successor.handle(subscriber);
}
}

    } catch (IOException e) {
        throw new IllegalArgumentException("读取JSON报文至实体时发生异常. payload: " + subscriber.getPayload() + ", entity: PointFlow.class");
    }
}

rabbitmq手动确认问题

首先感谢楼主提供很好的代码示例!但是mq那里消费者没有设置手动确认 这样一单程序处理出现异常 消息不就丢失了吗?

[个人建议]为basic和monitor的服务加上hostname,更便于单机部署学习

为basic和monitor的服务加上hostname如:

services:
    jce_java:
        build: ./docker-jce-jre
        image: pronter/jce-java
        read_only: true
        command: echo "jce java"
        environment:
            - TZ=Asia/Shanghai
    gateway:
        hostname: gateway
        build: ./api-gateway-ms
        image: prontera/gateway-ms
        ports:
            - "7291:7291"
            - "10211:10211"
        depends_on:
            - 'jce_java'
        environment:
            - TZ=Asia/Shanghai

然后在主机hosts文件中为所有服务hostname映射:
127.0.0.1 solar_mysql
127.0.0.1 rabbitmq
127.0.0.1 eureka1
127.0.0.1 eureka2
127.0.0.1 config_server
127.0.0.1 zipkin_server
127.0.0.1 gateway
127.0.0.1 hystrix_dashboard
127.0.0.1 spring_boot_admin
127.0.0.1 zipkin_server
127.0.0.1 account
127.0.0.1 membership
127.0.0.1 product
127.0.0.1 tcc_coordinator

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.