A simple Netty Rpc implement tcc
All the examples are implemented in the module badger-example
rpc:
serviceName: badger-example
port: 11311
zk:
address: 127.0.0.1:2181
@RpcProvider
public interface UserInfo {
String echo(String str);
}
zk:
address: 127.0.0.1:2181
@RpcProxy(serviceName = "badger-example")
public interface UserInfo {
String echo(String str);
}
assume you already have a local zookeeper.
start zookeeper
start provider
start consumer
curl http://127.0.0.1:8080/echo?str=abc
then you would get response: echo from server abc
jmeter -n -t rpcTest.jmx -l a -e -o b
- Run badger-tcc-coordinator
- Run badger-example/consumer
create table if not exists `dba`
(
`id` BIGINT unsigned NOT NULL AUTO_INCREMENT,
`cnt` INT NOT NULL,
`reserving` INT NOT NULL,
`version` INT NOT NULL,
`dbctime` DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3),
`dbutime` DATETIME(3) DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3),
PRIMARY KEY (`id`)
) ENGINE = InnoDB
AUTO_INCREMENT = 1
DEFAULT CHARSET = utf8mb4;
INSERT INTO `dba`
SET `id` = 1,
`cnt` = 100,
`reserving` = 0,
`version` = 0;
@Autowired
@RpcProxy(serviceName = "badger-backend", qualifier = "tccBackend")
private TccBackend tccBackend;
@Autowired
@RpcProxy(serviceName = "badger-example", qualifier = "tccProvider")
private TccProvider tccProvider;
@Compensable(identifier = "account", tryMethod = "tryM", confirmMethod = "confirmM", cancelMethod = "cancelM")
public void tryM(int a, int b) {
log.info("tryM {} {}", a, b);
DataA dataA = db.queryForObject("select * from dba where id = :id", ImmutableMap.of("id", a),
(rs, rowNum) -> {
DataA obj = new DataA();
obj.id = rs.getInt("id");
obj.cnt = rs.getInt("cnt");
obj.reserving = rs.getInt("reserving");
obj.version = rs.getInt("version");
return obj;
});
assert dataA != null;
if ((dataA.cnt - dataA.reserving) < b) {
throw new RuntimeException("DataA.cnt < b" + dataA + " " + b);
}
tccProvider.tryProvider(a, b);
tccBackend.tryBackend(a, b);
int res = db.update("update dba set reserving = reserving + :b,`version` = `version` + 1 where id = :id and `version` = :version", ImmutableMap.of("id", a, "b", b, "version", dataA.version));
if (res == 0) {
throw new RuntimeException("not change success" + dataA + " " + b);
}
}
@Compensable(identifier = "account", tryMethod = "tryM", confirmMethod = "confirmM", cancelMethod = "cancelM")
public void confirmM(int a, int b) {
log.info("confirmM {} {}", a, b);
db.update("update dba set cnt = cnt - :b, reserving = reserving - :b,`version` = `version` + 1 where id = :id", ImmutableMap.of("id", a, "b", b));
}
@Compensable(identifier = "account", tryMethod = "tryM", confirmMethod = "confirmM", cancelMethod = "cancelM")
public void cancelM(int a, int b) {
log.info("cancelM {} {}", a, b);
db.update("update dba set reserving = reserving - :b,`version` = `version` + 1 where id = :id", ImmutableMap.of("id", a, "b", b));
}
- Run badger-example/provider
- Run badger-example/backend
then execute the shell below two times
curl http://127.0.0.1:8080/try?a=1&b=50
first time will execute success,second execute failed.
assume you already install docker and kind.
# create a cluster with local registry
sh kind-with-registry.sh
sh deploy.sh
kubectl port-forward service/consumer 8080:8080
curl http://127.0.0.1:8080/echo?str=abc
- trace
- transaction