This reverts commit 250d9723a3
.
This commit is contained in:
parent
250d9723a3
commit
303106e1a5
|
@ -3,4 +3,10 @@ node_modules/
|
|||
.DS_Store
|
||||
npm-debug.log
|
||||
*.orig
|
||||
*.iml
|
||||
package-lock.json
|
||||
/en-us/
|
||||
/zh-cn/
|
||||
/index.html
|
||||
md_json/
|
||||
log
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1 +0,0 @@
|
|||
F15FA76EB8413EC9
|
|
@ -1,334 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Seata, Downloads, Version" />
|
||||
<meta name="description" content="This article will introduce you how to understand the details of each version and upgrade matters needing attention." />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>Downloads</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/blogDetail.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="blog-detail-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/developers/developers_dev.html" target="_self">DEVELOPERS</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><section class="blog-content markdown-body"><h1>Downloads</h1>
|
||||
<h1>Seata</h1>
|
||||
<blockquote>
|
||||
<p>GitHub: <a href="https://github.com/seata/seata">https://github.com/seata/seata</a> <br>
|
||||
Release Notes: <a href="https://github.com/seata/seata/releases">https://github.com/seata/seata/releases</a></p>
|
||||
</blockquote>
|
||||
<h2>0.9.0 (2019-10-16)</h2>
|
||||
<p><a href="https://github.com/seata/seata/archive/v0.8.1.zip">source</a> |
|
||||
<a href="https://github.com/seata/seata/releases/download/v0.8.1/seata-server-0.8.1.zip">binary</a></p>
|
||||
<details>
|
||||
<summary><mark>Release notes</mark></summary>
|
||||
<h3>Seata 0.9.0</h3>
|
||||
<p>Seata 0.9.0 Released.</p>
|
||||
<p>Seata is an easy-to-use, high-performance, open source distributed transaction solution.</p>
|
||||
<p>The version is updated as follows:</p>
|
||||
<h4>feature:</h4>
|
||||
<ul>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1608">#1608</a>] Saga implementation base on state machine</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1625">#1625</a>] support custom config and registry type</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1656">#1656</a>] support spring cloud config</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1689">#1689</a>] support -e startup parameter for specifying the environment name</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1739">#1739</a>] support retry when tm commit or rollback failed</li>
|
||||
</ul>
|
||||
<h4>bugfix:</h4>
|
||||
<ul>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1605">#1605</a>] fix deadlocks that can be caused by object locks and global locks and optimize the granularity of locks</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1685">#1685</a>] fix pk too long in lock table on db mode and optimize error log</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1691">#1691</a>] fix can't access private member of DruidDataSourceWrapper</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1699">#1699</a>] fix use 'in' and 'between' in where condition for Oracle and Mysql</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1713">#1713</a>] fix LockManagerTest.concurrentUseAbilityTest assertion condition</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1720">#1720</a>] fix can't refresh table meta data for oracle</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1729">#1729</a>] fix oracle batch insert error</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1735">#1735</a>] clean xid when tm commit or rollback failed</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1749">#1749</a>] fix undo support oracle table meta cache</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1751">#1751</a>] fix memory lock is not released due to hash conflict</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1761">#1761</a>] fix oracle rollback failed when the table has null Blob Clob value</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1759">#1759</a>] fix saga service method not support interface type parameter</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1401">#1401</a>] fix the first registration resource is null when RM starts</li>
|
||||
</ul>
|
||||
<p></p>
|
||||
<h4>optimize:</h4>
|
||||
<ul>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1701">#1701</a>] remove unused imports</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1705">#1705</a>] Based on Java5 optimization</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1706">#1706</a>] optimize inner class to static class</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1707">#1707</a>] default charset use StandardCharsets.UTF_8 instead</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1712">#1712</a>] abstract undolog manager class</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1722">#1722</a>] simplify to make codes more readable</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1726">#1726</a>] format log messages</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1738">#1738</a>] add server's jvm parameters</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1743">#1743</a>] improve the efficiency of the batch log</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1747">#1747</a>] use raw types instead of boxing types</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1750">#1750</a>] abstract tableMeta cache class</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1755">#1755</a>] enhance test coverage of seata-common module</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1756">#1756</a>] security: upgrade jackson to avoid security vulnerabilities</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1657">#1657</a>] optimize the problem of large direct buffer when file rolling in file storage mode</li>
|
||||
</ul>
|
||||
<p><br>
|
||||
Thanks to these contributors for their code commits. Please report an unintended omission.<br>
|
||||
</p>
|
||||
<ul>
|
||||
<li><a href="https://github.com/slievrly">slievrly</a></li>
|
||||
<li><a href="https://github.com/long187">long187</a></li>
|
||||
<li><a href="https://github.com/ggndnn">ggndnn</a></li>
|
||||
<li><a href="https://github.com/xingfudeshi">xingfudeshi</a></li>
|
||||
<li><a href="https://github.com/BeiKeJieDeLiuLangMao">BeiKeJieDeLiuLangMao</a></li>
|
||||
<li><a href="https://github.com/zjinlei">zjinlei</a></li>
|
||||
<li><a href="https://github.com/cmonkey">cmonkey</a></li>
|
||||
<li><a href="https://github.com/jsbxyyx">jsbxyyx</a></li>
|
||||
<li><a href="https://github.com/zaqweb">zaqweb</a></li>
|
||||
<li><a href="https://github.com/tjnettech">tjnettech</a></li>
|
||||
<li><a href="https://github.com/l81893521">l81893521</a></li>
|
||||
<li><a href="https://github.com/abel533">abel533</a></li>
|
||||
<li><a href="https://github.com/suhli">suhli</a></li>
|
||||
<li><a href="https://github.com/github-ygy">github-ygy</a></li>
|
||||
<li><a href="https://github.com/worstenemy">worstenemy</a></li>
|
||||
<li><a href="https://github.com/caioguedes">caioguedes</a></li>
|
||||
</ul>
|
||||
<p>Also, we receive many valuable issues, questions and advices from our community. Thanks for you all.</p>
|
||||
<h4>Link</h4>
|
||||
<ul>
|
||||
<li><strong>Seata:</strong> <a href="https://github.com/seata/seata">https://github.com/seata/seata</a></li>
|
||||
<li><strong>Seata-Samples:</strong> <a href="https://github.com/seata/seata-samples">https://github.com/seata/seata-samples</a></li>
|
||||
<li><strong>Release:</strong> <a href="https://github.com/seata/seata/releases">https://github.com/seata/seata/releases</a></li>
|
||||
</ul>
|
||||
</details>
|
||||
<h3>0.8.1 (2019-09-18)</h3>
|
||||
<p><a href="https://github.com/seata/seata/archive/v0.8.1.zip">source</a> |
|
||||
<a href="https://github.com/seata/seata/releases/download/v0.8.1/seata-server-0.8.1.zip">binary</a></p>
|
||||
<details>
|
||||
<summary><mark>Release notes</mark></summary>
|
||||
<h3>Seata 0.8.1</h3>
|
||||
<p>Seata 0.8.1 Released.</p>
|
||||
<p>Seata is an easy-to-use, high-performance, open source distributed transaction solution.</p>
|
||||
<p>The version is updated as follows:</p>
|
||||
<h4>feature:</h4>
|
||||
<ul>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1598">#1598</a>] support profile to use absolute path</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1617">#1617</a>] support profile’s(registry.conf) name configurable</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1418">#1418</a>] support undo_log kryo serializer</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1489">#1489</a>] support protobuf maven plugin</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1437">#1437</a>] support kryo codec</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1478">#1478</a>] support db mock</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1512">#1512</a>] extended support for mysql and oracle multiple insert batch syntax</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1496">#1496</a>] support auto proxy of DataSource</li>
|
||||
</ul>
|
||||
<h4>bugfix:</h4>
|
||||
<ul>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1646">#1646</a>] fix selectForUpdate lockQuery exception in file mode</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1572">#1572</a>] fix get tablemeta fail in oracle when table name was lower case</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1663">#1663</a>] fix get tablemeta fail when table name was keyword</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1666">#1666</a>] fix restore connection's autocommit</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1643">#1643</a>] fix serialize and deserialize in java.sql.Blob, java.sql.Clob</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1628">#1628</a>] fix oracle support ROWNUM query</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1552">#1552</a>] fix BufferOverflow when BranchSession size too large</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1609">#1609</a>] fix thread unsafe of oracle keyword checker</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1599">#1599</a>] fix thread unsafe of mysql keyword checker</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1607">#1607</a>] fix NoSuchMethodError when the version of druid used < 1.1.3</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1581">#1581</a>] fix missing some length in GlobalSession and FileTransactionStoreManager</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1594">#1594</a>] fix nacos's default namespace</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1550">#1550</a>] fix calculate BranchSession size missing xidBytes.length</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1558">#1558</a>] fix NPE when the rpcMessage's body is null</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1505">#1505</a>] fix bind public network address listen failed</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1539">#1539</a>] fix nacos namespace setting does not take effect</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1537">#1537</a>] fix nacos-config.txt missing store.db.driver-class-name property</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1522">#1522</a>] fix ProtocolV1CodecTest testAll may be appears test not pass</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1525">#1525</a>] fix when getAfterImage error, trx autocommit</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1518">#1518</a>] fix EnhancedServiceLoader may be appears load class error</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1514">#1514</a>] fix when lack serialization dependence can't generate undolog and report true</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1445">#1445</a>] fix DefaultCoordinatorMetricsTest UT failed</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1481">#1481</a>] fix TableMetaCache refresh problem in multiple datasource</li>
|
||||
</ul>
|
||||
<h4>optimize:</h4>
|
||||
<ul>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1629">#1629</a>] optimize the watcher efficiency of etcd3</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1661">#1661</a>] optimize global_table insert transaction_name size</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1633">#1633</a>] optimize branch transaction repeated reporting false</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1654">#1654</a>] optimize wrong usage of slf4j</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1593">#1593</a>] optimize and standardize server log</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1648">#1648</a>] optimize transaction_name length when building the table</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1576">#1576</a>] eliminate the impact of instructions reordering on session async committing task</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1618">#1618</a>] optimize undolog manager and fix delete undolog support oracle</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1469">#1469</a>] reduce the number of lock conflict exception</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1416">#1619</a>] replace StringBuffer with StringBuilder</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1580">#1580</a>] optimize LockKeyConflictException and change register method</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1574">#1574</a>] optimize once delete GlobalSession locks for db mode when commit success</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1601">#1601</a>] optimize typo</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1602">#1602</a>] upgrade fastjson version to 1.2.60 for security issue</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1583">#1583</a>] optimize get oracle primary index</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1575">#1575</a>] add UT for RegisterTMRequest</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1559">#1559</a>] optimize delay to delete the expired undo log</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1547">#1547</a>] TableRecords delete jackson annotation</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1542">#1542</a>] optimize AbstractSessionManager debug log</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1535">#1535</a>] remove H2 and pgsql get primary index code and close resultSet</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1541">#1541</a>] code clean</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1544">#1544</a>] remove Chinese comment</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1533">#1533</a>] refactor of the logics of Multi-configuration Isolation</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1493">#1493</a>] add table meta checker switch</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1530">#1530</a>] throw Exception when no index in the table</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1444">#1444</a>] simplify operation of map</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1497">#1497</a>] add seata-all dependencies</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1490">#1490</a>] remove unnecessary code</li>
|
||||
</ul>
|
||||
<p>Thanks to these contributors for their code commits. Please report an unintended omission.</p>
|
||||
<ul>
|
||||
<li><a href="https://github.com/slievrly">slievrly</a></li>
|
||||
<li><a href="https://github.com/BeiKeJieDeLiuLangMao">BeiKeJieDeLiuLangMao</a></li>
|
||||
<li><a href="https://github.com/jsbxyyx">jsbxyyx</a></li>
|
||||
<li><a href="https://github.com/ldcsaa">ldcsaa</a></li>
|
||||
<li><a href="https://github.com/zjinlei">zjinlei</a></li>
|
||||
<li><a href="https://github.com/l81893521">l81893521</a></li>
|
||||
<li><a href="https://github.com/ggndnn">ggndnn</a></li>
|
||||
<li><a href="https://github.com/github-ygy">github-ygy</a></li>
|
||||
<li><a href="https://github.com/chenxi-null">chenxi-null</a></li>
|
||||
<li><a href="https://github.com/tq02ksu">tq02ksu</a></li>
|
||||
<li><a href="https://github.com/AjaxXu">AjaxXu</a></li>
|
||||
<li><a href="https://github.com/finalcola">finalcola</a></li>
|
||||
<li><a href="https://github.com/lovepoem">lovepoem</a></li>
|
||||
<li><a href="https://github.com/cmonkey">cmonkey</a></li>
|
||||
<li><a href="https://github.com/xingfudeshi">xingfudeshi</a></li>
|
||||
<li><a href="https://github.com/andyqian">andyqian</a></li>
|
||||
<li><a href="https://github.com/tswstarplanet">tswstarplanet</a></li>
|
||||
<li><a href="https://github.com/zhengyangyong">zhengyangyong</a></li>
|
||||
</ul>
|
||||
<p>Also, we receive many valuable issues, questions and advices from our community. Thanks for you all.</p>
|
||||
<h4>Link</h4>
|
||||
<ul>
|
||||
<li><strong>Seata:</strong> <a href="https://github.com/seata/seata">https://github.com/seata/seata</a></li>
|
||||
<li><strong>Seata-Samples:</strong> <a href="https://github.com/seata/seata-samples">https://github.com/seata/seata-samples</a></li>
|
||||
<li><strong>Release:</strong> <a href="https://github.com/seata/seata/releases">https://github.com/seata/seata/releases</a></li>
|
||||
</ul>
|
||||
</details>
|
||||
<h3>0.8.0 (2019-08-16)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.8.0.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.8.0/seata-server-0.8.0.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.7.1 (2019-07-15)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.7.1.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.7.1/seata-server-0.7.1.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.7.0 (2019-07-12)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.7.0.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.7.0/seata-server-0.7.0.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.6.1 (2019-05-31)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.6.1.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.6.1/seata-server-0.6.1.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.6.0 (2019-05-24)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.6.0.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.6.0/seata-server-0.6.0.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.5.2 (2019-05-17)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.5.2.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.5.2/seata-server-0.5.2.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.5.1 (2019-04-30)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.5.1.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.5.1/seata-server-0.5.1.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.5.0 (2019-04-19)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/0.5.0.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/0.5.0/seata-server-0.5.0.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.4.2 (2019-04-12)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.4.2.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.4.2/fescar-server-0.4.2.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.4.1 (2019-03-29)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.4.1.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.4.1/fescar-server-0.4.1.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.4.0 (2019-03-19)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.4.0.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.4.0/fescar-server-0.4.0.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.3.1 (2019-03-15)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.3.1.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.3.1/fescar-server-0.3.1.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.3.0 (2019-03-08)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.3.0.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.3.0/fescar-server-0.3.0.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.2.3 (2019-03-02)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.2.3.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.2.3/fescar-server-0.2.3.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.2.2 (2019-02-22)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.2.2.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.2.2/fescar-server-0.2.2.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.2.1 (2019-02-18)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.2.1.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.2.1/fescar-server-0.2.1.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.2.0 (2019-02-14)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.2.0.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.2.0/fescar-server-0.2.0.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.1.4 (2019-02-11)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.1.4.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.1.4/fescar-server-0.1.4.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.1.3 (2019-01-29)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.1.3.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.1.3/fescar-server-0.1.3.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.1.2 (2019-01-25)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/V0.1.2.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/V0.1.2/fescar-server-0.1.2.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.1.1 (2019-01-18)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.1.1.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.1.1/fescar-server-0.1.1.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.1.0 (2019-01-09)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.1.0.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.1.0/fescar-server-0.1.0.zip">binary</a></li>
|
||||
</ul>
|
||||
</section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is an Alibaba open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/blogDetail.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
|
@ -1,205 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Dubbo,Seata,Consistency" />
|
||||
<meta name="description" content="This article will introduce you how to use Seata to ensure consistency between Dubbo Microservices." />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>How to use Seata to ensure consistency between Dubbo Microservices</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/blogDetail.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="blog-detail-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/overview/what_is_seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li></ul></div></div></header><section class="blog-content markdown-body"><h1>How to use Seata to ensure consistency between Dubbo Microservices</h1>
|
||||
<h2>Use case</h2>
|
||||
<p>A business logic for user purchasing commodities. The whole business logic is powered by 3 microservices:</p>
|
||||
<ul>
|
||||
<li>Storage service: deduct storage count on given commodity.</li>
|
||||
<li>Order service: create order according to purchase request.</li>
|
||||
<li>Account service: debit the balance of user's account.</li>
|
||||
</ul>
|
||||
<h3>Architecture</h3>
|
||||
<p><img src="/img/blog/seata/seata-1.png" alt="Architecture"></p>
|
||||
<h3>StorageService</h3>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">StorageService</span> </span>{
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* deduct storage count
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">deduct</span><span class="hljs-params">(String commodityCode, <span class="hljs-keyword">int</span> count)</span></span>;
|
||||
}
|
||||
</code></pre>
|
||||
<h3>OrderService</h3>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">OrderService</span> </span>{
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* create order
|
||||
*/</span>
|
||||
<span class="hljs-function">Order <span class="hljs-title">create</span><span class="hljs-params">(String userId, String commodityCode, <span class="hljs-keyword">int</span> orderCount)</span></span>;
|
||||
}
|
||||
</code></pre>
|
||||
<h3>AccountService</h3>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">AccountService</span> </span>{
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* debit balance of user's account
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">debit</span><span class="hljs-params">(String userId, <span class="hljs-keyword">int</span> money)</span></span>;
|
||||
}
|
||||
</code></pre>
|
||||
<h3>Main business logic</h3>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BusinessServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">BusinessService</span> </span>{
|
||||
|
||||
<span class="hljs-keyword">private</span> StorageService storageService;
|
||||
|
||||
<span class="hljs-keyword">private</span> OrderService orderService;
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* purchase
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">purchase</span><span class="hljs-params">(String userId, String commodityCode, <span class="hljs-keyword">int</span> orderCount)</span> </span>{
|
||||
|
||||
storageService.deduct(commodityCode, orderCount);
|
||||
|
||||
orderService.create(userId, commodityCode, orderCount);
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StorageServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">StorageService</span> </span>{
|
||||
|
||||
<span class="hljs-keyword">private</span> StorageDAO storageDAO;
|
||||
|
||||
<span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deduct</span><span class="hljs-params">(String commodityCode, <span class="hljs-keyword">int</span> count)</span> </span>{
|
||||
Storage storage = <span class="hljs-keyword">new</span> Storage();
|
||||
storage.setCount(count);
|
||||
storage.setCommodityCode(commodityCode);
|
||||
storageDAO.update(storage);
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">OrderServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">OrderService</span> </span>{
|
||||
|
||||
<span class="hljs-keyword">private</span> OrderDAO orderDAO;
|
||||
|
||||
<span class="hljs-keyword">private</span> AccountService accountService;
|
||||
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> Order <span class="hljs-title">create</span><span class="hljs-params">(String userId, String commodityCode, <span class="hljs-keyword">int</span> orderCount)</span> </span>{
|
||||
|
||||
<span class="hljs-keyword">int</span> orderMoney = calculate(commodityCode, orderCount);
|
||||
|
||||
accountService.debit(userId, orderMoney);
|
||||
|
||||
Order order = <span class="hljs-keyword">new</span> Order();
|
||||
order.userId = userId;
|
||||
order.commodityCode = commodityCode;
|
||||
order.count = orderCount;
|
||||
order.money = orderMoney;
|
||||
|
||||
<span class="hljs-keyword">return</span> orderDAO.insert(order);
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<h2>Distributed Transaction Solution with Seata</h2>
|
||||
<p><img src="/img/blog/seata/seata-2.png" alt="undefined"></p>
|
||||
<p>We just need an annotation <code>@GlobalTransactional</code> on business method:</p>
|
||||
<pre><code class="language-java">
|
||||
<span class="hljs-meta">@GlobalTransactional</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">purchase</span><span class="hljs-params">(String userId, String commodityCode, <span class="hljs-keyword">int</span> orderCount)</span> </span>{
|
||||
......
|
||||
}
|
||||
</code></pre>
|
||||
<h2>Example powered by Dubbo + Seata</h2>
|
||||
<h3>Step 1: Setup database</h3>
|
||||
<ul>
|
||||
<li>Requirement: MySQL with InnoDB engine.</li>
|
||||
</ul>
|
||||
<p><strong>Note:</strong> In fact, there should be 3 database for the 3 services in the example use case. However, we can just create one database and configure 3 data sources for simple.</p>
|
||||
<p>Modify Spring XML with the database URL/username/password you just created.</p>
|
||||
<p>dubbo-account-service.xml
|
||||
dubbo-order-service.xml
|
||||
dubbo-storage-service.xml</p>
|
||||
<pre><code class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"url"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"jdbc:mysql://x.x.x.x:3306/xxx"</span> /></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"username"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"xxx"</span> /></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"xxx"</span> /></span>
|
||||
</code></pre>
|
||||
<h3>Step 2: Create UNDO_LOG table for Seata</h3>
|
||||
<p><code>UNDO_LOG</code> table is required by Seata AT mode.</p>
|
||||
<pre><code class="language-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`undo_log`</span> (
|
||||
<span class="hljs-string">`id`</span> <span class="hljs-built_in">bigint</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> AUTO_INCREMENT,
|
||||
<span class="hljs-string">`branch_id`</span> <span class="hljs-built_in">bigint</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`xid`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`rollback_info`</span> longblob <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`log_status`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`log_created`</span> datetime <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`log_modified`</span> datetime <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`ext`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
|
||||
PRIMARY <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`id`</span>),
|
||||
<span class="hljs-keyword">KEY</span> <span class="hljs-string">`idx_unionkey`</span> (<span class="hljs-string">`xid`</span>,<span class="hljs-string">`branch_id`</span>)
|
||||
) <span class="hljs-keyword">ENGINE</span>=<span class="hljs-keyword">InnoDB</span> AUTO_INCREMENT=<span class="hljs-number">159</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CHARSET</span>=utf8
|
||||
</code></pre>
|
||||
<h3>Step 3: Create tables for example business</h3>
|
||||
<pre><code class="language-sql">
|
||||
<span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">IF</span> <span class="hljs-keyword">EXISTS</span> <span class="hljs-string">`storage_tbl`</span>;
|
||||
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`storage_tbl`</span> (
|
||||
<span class="hljs-string">`id`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> AUTO_INCREMENT,
|
||||
<span class="hljs-string">`commodity_code`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`count`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span>,
|
||||
PRIMARY <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`id`</span>),
|
||||
<span class="hljs-keyword">UNIQUE</span> <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`commodity_code`</span>)
|
||||
) <span class="hljs-keyword">ENGINE</span>=<span class="hljs-keyword">InnoDB</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CHARSET</span>=utf8;
|
||||
|
||||
|
||||
<span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">IF</span> <span class="hljs-keyword">EXISTS</span> <span class="hljs-string">`order_tbl`</span>;
|
||||
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`order_tbl`</span> (
|
||||
<span class="hljs-string">`id`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> AUTO_INCREMENT,
|
||||
<span class="hljs-string">`user_id`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`commodity_code`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`count`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span>,
|
||||
<span class="hljs-string">`money`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span>,
|
||||
PRIMARY <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`id`</span>)
|
||||
) <span class="hljs-keyword">ENGINE</span>=<span class="hljs-keyword">InnoDB</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CHARSET</span>=utf8;
|
||||
|
||||
|
||||
<span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">IF</span> <span class="hljs-keyword">EXISTS</span> <span class="hljs-string">`account_tbl`</span>;
|
||||
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`account_tbl`</span> (
|
||||
<span class="hljs-string">`id`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> AUTO_INCREMENT,
|
||||
<span class="hljs-string">`user_id`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`money`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span>,
|
||||
PRIMARY <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`id`</span>)
|
||||
) <span class="hljs-keyword">ENGINE</span>=<span class="hljs-keyword">InnoDB</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CHARSET</span>=utf8;
|
||||
</code></pre>
|
||||
<h3>Step 4: Start Seata-Server</h3>
|
||||
<ul>
|
||||
<li>Download server <a href="https://github.com/seata/seata/releases">package</a>, unzip it.</li>
|
||||
<li>Start Seata-Server</li>
|
||||
</ul>
|
||||
<pre><code class="language-shell">sh seata-server.sh $LISTEN_PORT $PATH_FOR_PERSISTENT_DATA
|
||||
|
||||
e.g.
|
||||
|
||||
sh seata-server.sh 8091 /home/admin/seata/data/
|
||||
</code></pre>
|
||||
<h3>Step 5: Run example</h3>
|
||||
<ul>
|
||||
<li>Start AccountService (<a href="https://github.com/seata/seata-samples/blob/master/dubbo/src/main/java/com/seata/seata/samples/dubbo/starter/DubboAccountServiceStarter.java">DubboAccountServiceStarter</a>).</li>
|
||||
<li>Start StorageService (<a href="https://github.com/seata/seata-samples/blob/master/dubbo/src/main/java/com/seata/seata/samples/dubbo/starter/DubboStorageServiceStarter.java">DubboStorageServiceStarter</a>).</li>
|
||||
<li>Start OrderService (<a href="https://github.com/seata/seata-samples/blob/master/dubbo/src/main/java/com/seata/seata/samples/dubbo/starter/DubboOrderServiceStarter.java">DubboOrderServiceStarter</a>).</li>
|
||||
<li>Run BusinessService for test (<a href="https://github.com/seata/seata-samples/blob/master/dubbo/src/main/java/com/seata/seata/samples/dubbo/starter/DubboBusinessTester.java">DubboBusinessTester</a>).</li>
|
||||
</ul>
|
||||
<h3>Related projects</h3>
|
||||
<ul>
|
||||
<li>seata: <a href="https://github.com/seata/seata/">https://github.com/seata/seata/</a></li>
|
||||
<li>seata-samples : <a href="https://github.com/seata/seata-samples">https://github.com/seata/seata-samples</a></li>
|
||||
</ul>
|
||||
</section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_white.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is dedicated to improving the efficiency of large-scale file distribution, building the go-to solution and standards of container image distribution, and providing you with file and image distribution service which is efficient, easy-to-use, and of high availability.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what_is_seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/blogDetail.js"></script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
|
@ -1,32 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Seata,Blog" />
|
||||
<meta name="description" content="Seata Blog" />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>Blog</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/blog.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="blog-list-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/developers/developers_dev.html" target="_self">DEVELOPERS</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><div class="bar"><div class="bar-body"><img src="https://img.alicdn.com/tfs/TB1gQ8uJyrpK1RjSZFhXXXSdXXa-160-160.png" class="front-img"/><span>Blog</span><img src="https://img.alicdn.com/tfs/TB1gQ8uJyrpK1RjSZFhXXXSdXXa-160-160.png" class="back-img"/></div></div><section class="blog-container"><div class="col col-18 left-part"><div class="page-slider"><div class="slider-list" style="transform:translateX(-0px);transition:transform 500ms ease;width:0"><div class="slider-page" style="width:0"><div class="slider-item"><a href="/en-us/blog/quick-start-use-seata-and-dubbo-services.html" target="_self" class="blog-item"><div class="title"><img src="https://img.alicdn.com/tfs/TB1OkBRukzoK1RjSZFlXXai4VXa-32-40.png"/><span>How to use Seata to ensure consistency between Dubbo Microservices</span></div><div class="brief-info"><span class="author">slievrly</span><span class="date">2019-03-07</span></div><p>This article will introduce you how to use Seata to ensure consistency between Dubbo Microservices.</p></a></div><div class="slider-item"><a href="/en-us/blog/manual-transaction-mode.html" target="_self" class="blog-item"><div class="title"><img src="https://img.alicdn.com/tfs/TB1OkBRukzoK1RjSZFlXXai4VXa-32-40.png"/><span>MT mode</span></div><div class="brief-info"><span class="author">kmmshmily</span><span class="date">2019-02-13</span></div><p>introduce MT mode</p></a></div></div></div><div class="slider-control"><img class="slider-control-prev slider-control-prev-hidden" src="/img/system/prev.png"/><img class="slider-control-next slider-control-next-hidden" src="/img/system/next.png"/></div></div></div><div class="col col-6 right-part"><h4>All posts</h4><ul><li><a href="/en-us/blog/quick-start-use-seata-and-dubbo-services.html" target="_self"><span>2019-03-07<!-- --> </span><span>How to use Seata to ensure consistency between Dubbo Microservices</span></a></li><li><a href="/en-us/blog/manual-transaction-mode.html" target="_self"><span>2019-02-13<!-- --> </span><span>MT mode</span></a></li></ul></div></section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is an Alibaba open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/blog.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,53 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="MT mode" />
|
||||
<meta name="description" content="introduce MT mode" />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>MT mode</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/blogDetail.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="blog-detail-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/developers/developers_dev.html" target="_self">DEVELOPERS</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><section class="blog-content markdown-body"><h1>Manual Transaction Mode</h1>
|
||||
<p>Review the description in the overview: a distributed global transaction, the whole is a model of <strong>the two-phase commit</strong>. A global transaction consists of several branch transactions that meet the model requirements of <strong>the two-phase commit</strong>, which requires each branch transaction to have its own:</p>
|
||||
<ul>
|
||||
<li>One phase prepare behavior</li>
|
||||
<li>Two phase commit or rollback behavior</li>
|
||||
</ul>
|
||||
<p><img src="https://upload-images.jianshu.io/upload_images/4420767-e48f0284a037d1df.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="Overview of a global transaction"></p>
|
||||
<p>According to the two phase behavior pattern,We divide the branch transaction into <strong>Automatic (Branch) Transaction Mode</strong> and <strong>Manual (Branch) Transaction Mode</strong>.</p>
|
||||
<p>The AT mode(<a href="">Reference Link TBD</a>)is based on the <strong>Relational Database</strong> that <strong>supports local ACID transactions</strong>:</p>
|
||||
<ul>
|
||||
<li>One phase prepare behavior: In the local transaction, the business data update and the corresponding rollback log record are submitted together.</li>
|
||||
<li>Two phase commit behavior: Immediately ended successfully, <strong>Auto</strong> asynchronous batch cleanup of the rollback log.</li>
|
||||
<li>Two phase rollback behavior: By rolling back the log, <strong>automatic</strong> generates a compensation operation to complete the data rollback.</li>
|
||||
</ul>
|
||||
<p>Accordingly, the MT mode does not rely on transaction support for the underlying data resources:</p>
|
||||
<ul>
|
||||
<li>One phase prepare behavior: Call the prepare logic of <strong>custom</strong> .</li>
|
||||
<li>Two phase commit behavior:Call the commit logic of <strong>custom</strong> .</li>
|
||||
<li>Two phase rollback behavior:Call the rollback logic of <strong>custom</strong> .</li>
|
||||
</ul>
|
||||
<p>The so-called MT mode refers to the support of the branch transaction of <strong>custom</strong> into the management of global transactions.</p>
|
||||
</section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is an Alibaba open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/blogDetail.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"filename": "manual-transaction-mode.md",
|
||||
"__html": "<h1>Manual Transaction Mode</h1>\n<p>Review the description in the overview: a distributed global transaction, the whole is a model of <strong>the two-phase commit</strong>. A global transaction consists of several branch transactions that meet the model requirements of <strong>the two-phase commit</strong>, which requires each branch transaction to have its own:</p>\n<ul>\n<li>One phase prepare behavior</li>\n<li>Two phase commit or rollback behavior</li>\n</ul>\n<p><img src=\"https://upload-images.jianshu.io/upload_images/4420767-e48f0284a037d1df.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240\" alt=\"Overview of a global transaction\"></p>\n<p>According to the two phase behavior pattern,We divide the branch transaction into <strong>Automatic (Branch) Transaction Mode</strong> and <strong>Manual (Branch) Transaction Mode</strong>.</p>\n<p>The AT mode(<a href=\"\">Reference Link TBD</a>)is based on the <strong>Relational Database</strong> that <strong>supports local ACID transactions</strong>:</p>\n<ul>\n<li>One phase prepare behavior: In the local transaction, the business data update and the corresponding rollback log record are submitted together.</li>\n<li>Two phase commit behavior: Immediately ended successfully, <strong>Auto</strong> asynchronous batch cleanup of the rollback log.</li>\n<li>Two phase rollback behavior: By rolling back the log, <strong>automatic</strong> generates a compensation operation to complete the data rollback.</li>\n</ul>\n<p>Accordingly, the MT mode does not rely on transaction support for the underlying data resources:</p>\n<ul>\n<li>One phase prepare behavior: Call the prepare logic of <strong>custom</strong> .</li>\n<li>Two phase commit behavior:Call the commit logic of <strong>custom</strong> .</li>\n<li>Two phase rollback behavior:Call the rollback logic of <strong>custom</strong> .</li>\n</ul>\n<p>The so-called MT mode refers to the support of the branch transaction of <strong>custom</strong> into the management of global transactions.</p>\n",
|
||||
"link": "/en-us/blog/manual-transaction-mode.html",
|
||||
"meta": {
|
||||
"title": "MT mode",
|
||||
"keywords": "MT mode",
|
||||
"description": "introduce MT mode",
|
||||
"author": "kmmshmily",
|
||||
"date": "2019-02-13"
|
||||
}
|
||||
}
|
|
@ -1,214 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Dubbo,Seata,Consistency" />
|
||||
<meta name="description" content="This article will introduce you how to use Seata to ensure consistency between Dubbo Microservices." />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>How to use Seata to ensure consistency between Dubbo Microservices</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/blogDetail.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="blog-detail-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/developers/developers_dev.html" target="_self">DEVELOPERS</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><section class="blog-content markdown-body"><h1>How to use Seata to ensure consistency between Dubbo Microservices</h1>
|
||||
<h2>Use case</h2>
|
||||
<p>A business logic for user purchasing commodities. The whole business logic is powered by 3 microservices:</p>
|
||||
<ul>
|
||||
<li>Storage service: deduct storage count on given commodity.</li>
|
||||
<li>Order service: create order according to purchase request.</li>
|
||||
<li>Account service: debit the balance of user's account.</li>
|
||||
</ul>
|
||||
<h3>Architecture</h3>
|
||||
<p><img src="/img/blog/seata/seata-1.png" alt="Architecture"></p>
|
||||
<h3>StorageService</h3>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">StorageService</span> </span>{
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* deduct storage count
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">deduct</span><span class="hljs-params">(String commodityCode, <span class="hljs-keyword">int</span> count)</span></span>;
|
||||
}
|
||||
</code></pre>
|
||||
<h3>OrderService</h3>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">OrderService</span> </span>{
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* create order
|
||||
*/</span>
|
||||
<span class="hljs-function">Order <span class="hljs-title">create</span><span class="hljs-params">(String userId, String commodityCode, <span class="hljs-keyword">int</span> orderCount)</span></span>;
|
||||
}
|
||||
</code></pre>
|
||||
<h3>AccountService</h3>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">AccountService</span> </span>{
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* debit balance of user's account
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">debit</span><span class="hljs-params">(String userId, <span class="hljs-keyword">int</span> money)</span></span>;
|
||||
}
|
||||
</code></pre>
|
||||
<h3>Main business logic</h3>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BusinessServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">BusinessService</span> </span>{
|
||||
|
||||
<span class="hljs-keyword">private</span> StorageService storageService;
|
||||
|
||||
<span class="hljs-keyword">private</span> OrderService orderService;
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* purchase
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">purchase</span><span class="hljs-params">(String userId, String commodityCode, <span class="hljs-keyword">int</span> orderCount)</span> </span>{
|
||||
|
||||
storageService.deduct(commodityCode, orderCount);
|
||||
|
||||
orderService.create(userId, commodityCode, orderCount);
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StorageServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">StorageService</span> </span>{
|
||||
|
||||
<span class="hljs-keyword">private</span> StorageDAO storageDAO;
|
||||
|
||||
<span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deduct</span><span class="hljs-params">(String commodityCode, <span class="hljs-keyword">int</span> count)</span> </span>{
|
||||
Storage storage = <span class="hljs-keyword">new</span> Storage();
|
||||
storage.setCount(count);
|
||||
storage.setCommodityCode(commodityCode);
|
||||
storageDAO.update(storage);
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">OrderServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">OrderService</span> </span>{
|
||||
|
||||
<span class="hljs-keyword">private</span> OrderDAO orderDAO;
|
||||
|
||||
<span class="hljs-keyword">private</span> AccountService accountService;
|
||||
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> Order <span class="hljs-title">create</span><span class="hljs-params">(String userId, String commodityCode, <span class="hljs-keyword">int</span> orderCount)</span> </span>{
|
||||
|
||||
<span class="hljs-keyword">int</span> orderMoney = calculate(commodityCode, orderCount);
|
||||
|
||||
accountService.debit(userId, orderMoney);
|
||||
|
||||
Order order = <span class="hljs-keyword">new</span> Order();
|
||||
order.userId = userId;
|
||||
order.commodityCode = commodityCode;
|
||||
order.count = orderCount;
|
||||
order.money = orderMoney;
|
||||
|
||||
<span class="hljs-keyword">return</span> orderDAO.insert(order);
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<h2>Distributed Transaction Solution with Seata</h2>
|
||||
<p><img src="/img/blog/seata/seata-2.png" alt="undefined"></p>
|
||||
<p>We just need an annotation <code>@GlobalTransactional</code> on business method:</p>
|
||||
<pre><code class="language-java">
|
||||
<span class="hljs-meta">@GlobalTransactional</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">purchase</span><span class="hljs-params">(String userId, String commodityCode, <span class="hljs-keyword">int</span> orderCount)</span> </span>{
|
||||
......
|
||||
}
|
||||
</code></pre>
|
||||
<h2>Example powered by Dubbo + Seata</h2>
|
||||
<h3>Step 1: Setup database</h3>
|
||||
<ul>
|
||||
<li>Requirement: MySQL with InnoDB engine.</li>
|
||||
</ul>
|
||||
<p><strong>Note:</strong> In fact, there should be 3 database for the 3 services in the example use case. However, we can just create one database and configure 3 data sources for simple.</p>
|
||||
<p>Modify Spring XML with the database URL/username/password you just created.</p>
|
||||
<p>dubbo-account-service.xml
|
||||
dubbo-order-service.xml
|
||||
dubbo-storage-service.xml</p>
|
||||
<pre><code class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"url"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"jdbc:mysql://x.x.x.x:3306/xxx"</span> /></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"username"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"xxx"</span> /></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"xxx"</span> /></span>
|
||||
</code></pre>
|
||||
<h3>Step 2: Create UNDO_LOG table for Seata</h3>
|
||||
<p><code>UNDO_LOG</code> table is required by Seata AT mode.</p>
|
||||
<pre><code class="language-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`undo_log`</span> (
|
||||
<span class="hljs-string">`id`</span> <span class="hljs-built_in">bigint</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> AUTO_INCREMENT,
|
||||
<span class="hljs-string">`branch_id`</span> <span class="hljs-built_in">bigint</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`xid`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`rollback_info`</span> longblob <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`log_status`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`log_created`</span> datetime <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`log_modified`</span> datetime <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`ext`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
|
||||
PRIMARY <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`id`</span>),
|
||||
<span class="hljs-keyword">KEY</span> <span class="hljs-string">`idx_unionkey`</span> (<span class="hljs-string">`xid`</span>,<span class="hljs-string">`branch_id`</span>)
|
||||
) <span class="hljs-keyword">ENGINE</span>=<span class="hljs-keyword">InnoDB</span> AUTO_INCREMENT=<span class="hljs-number">159</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CHARSET</span>=utf8
|
||||
</code></pre>
|
||||
<h3>Step 3: Create tables for example business</h3>
|
||||
<pre><code class="language-sql">
|
||||
<span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">IF</span> <span class="hljs-keyword">EXISTS</span> <span class="hljs-string">`storage_tbl`</span>;
|
||||
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`storage_tbl`</span> (
|
||||
<span class="hljs-string">`id`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> AUTO_INCREMENT,
|
||||
<span class="hljs-string">`commodity_code`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`count`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span>,
|
||||
PRIMARY <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`id`</span>),
|
||||
<span class="hljs-keyword">UNIQUE</span> <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`commodity_code`</span>)
|
||||
) <span class="hljs-keyword">ENGINE</span>=<span class="hljs-keyword">InnoDB</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CHARSET</span>=utf8;
|
||||
|
||||
|
||||
<span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">IF</span> <span class="hljs-keyword">EXISTS</span> <span class="hljs-string">`order_tbl`</span>;
|
||||
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`order_tbl`</span> (
|
||||
<span class="hljs-string">`id`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> AUTO_INCREMENT,
|
||||
<span class="hljs-string">`user_id`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`commodity_code`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`count`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span>,
|
||||
<span class="hljs-string">`money`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span>,
|
||||
PRIMARY <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`id`</span>)
|
||||
) <span class="hljs-keyword">ENGINE</span>=<span class="hljs-keyword">InnoDB</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CHARSET</span>=utf8;
|
||||
|
||||
|
||||
<span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">IF</span> <span class="hljs-keyword">EXISTS</span> <span class="hljs-string">`account_tbl`</span>;
|
||||
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`account_tbl`</span> (
|
||||
<span class="hljs-string">`id`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> AUTO_INCREMENT,
|
||||
<span class="hljs-string">`user_id`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`money`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span>,
|
||||
PRIMARY <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`id`</span>)
|
||||
) <span class="hljs-keyword">ENGINE</span>=<span class="hljs-keyword">InnoDB</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CHARSET</span>=utf8;
|
||||
</code></pre>
|
||||
<h3>Step 4: Start Seata-Server</h3>
|
||||
<ul>
|
||||
<li>Download server <a href="https://github.com/seata/seata/releases">package</a>, unzip it.</li>
|
||||
<li>Start Seata-Server</li>
|
||||
</ul>
|
||||
<pre><code class="language-shell">sh seata-server.sh $LISTEN_PORT $PATH_FOR_PERSISTENT_DATA
|
||||
|
||||
e.g.
|
||||
|
||||
sh seata-server.sh 8091 /home/admin/seata/data/
|
||||
</code></pre>
|
||||
<h3>Step 5: Run example</h3>
|
||||
<ul>
|
||||
<li>Start AccountService (<a href="https://github.com/seata/seata-samples/blob/master/dubbo/src/main/java/com/seata/seata/samples/dubbo/starter/DubboAccountServiceStarter.java">DubboAccountServiceStarter</a>).</li>
|
||||
<li>Start StorageService (<a href="https://github.com/seata/seata-samples/blob/master/dubbo/src/main/java/com/seata/seata/samples/dubbo/starter/DubboStorageServiceStarter.java">DubboStorageServiceStarter</a>).</li>
|
||||
<li>Start OrderService (<a href="https://github.com/seata/seata-samples/blob/master/dubbo/src/main/java/com/seata/seata/samples/dubbo/starter/DubboOrderServiceStarter.java">DubboOrderServiceStarter</a>).</li>
|
||||
<li>Run BusinessService for test (<a href="https://github.com/seata/seata-samples/blob/master/dubbo/src/main/java/com/seata/seata/samples/dubbo/starter/DubboBusinessTester.java">DubboBusinessTester</a>).</li>
|
||||
</ul>
|
||||
<h3>Related projects</h3>
|
||||
<ul>
|
||||
<li>seata: <a href="https://github.com/seata/seata/">https://github.com/seata/seata/</a></li>
|
||||
<li>seata-samples : <a href="https://github.com/seata/seata-samples">https://github.com/seata/seata-samples</a></li>
|
||||
</ul>
|
||||
</section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is an Alibaba open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/blogDetail.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
|
@ -1,32 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Seata,Community" />
|
||||
<meta name="description" content="Seata Community" />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>Community</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/community.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="community-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/developers/developers_dev.html" target="_self">DEVELOPERS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><div class="bar"><div class="bar-body"><img src="https://img.alicdn.com/tfs/TB115XwJzTpK1RjSZKPXXa3UpXa-160-160.png" class="front-img"/><span>Community</span><img src="https://img.alicdn.com/tfs/TB115XwJzTpK1RjSZKPXXa3UpXa-160-160.png" class="back-img"/></div></div><section class="events-section"><h3>Events & News</h3><div class="slider"><div class="slider-list" style="transform:translateX(-0px);transition:transform 500ms ease;width:0"><div class="slider-screen" style="width:0"><div class="slider-item"><div class="event-card"><a href="/en-us/blog/blog1.html"><img src="/img/brhtqqzh.jpeg"/></a><div class="event-introduction"><h4>title</h4><p>seata</p><a href="/en-us/blog/blog1.html">May 12nd,2018<img class="arrow" src="/img/arrow_right.png"/></a></div></div></div></div></div><div class="slider-control"><span class="slider-control-item slider-control-item-active"></span></div></div></section><section class="contact-section"><h3>Talk To Us</h3><p>Feel free to contact us via the following channel.</p><div class="contact-list"><a class="contact-item" href="mailto:dev-seata+subscribe@googlegroups.com" rel="noopener noreferrer" target="_blank"><img src="/img/mailinglist.png"/><div>Mailing List</div></a><a class="contact-item" href="https://twitter.com/seataio" rel="noopener noreferrer" target="_blank"><img src="/img/twitter.png"/><div>@Seata</div></a></div></section><section class="contributor-section"><h3>Contributor Guide</h3><p>You can always contribute to Seata.</p><div class="contributor-list"><div class="contributor-item"><img src="/img/channels/email_gray.svg"/><div>Mailing List</div><p><span>Join our mailing list.</span></p></div><div class="contributor-item"><img src="/img/channels/github_gray.svg"/><div>Issue</div><p><span>Submit a <a href="https://github.com/seata/seata/issues/new">new issue</a>.</span></p></div><div class="contributor-item"><img src="/img/documents.png"/><div>Documents</div><p><span>Improve the <a href="https://github.com/seata/seata.github.io">documentation</a>.</span></p></div><div class="contributor-item"><img src="/img/pullrequest.png"/><div>Pull Request</div><p><span>Create a brilliant <a href="https://github.com/seata/seata/pulls">pull request</a>. </span></p></div></div></section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is an Alibaba open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/community.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,277 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Seata, AT mode" />
|
||||
<meta name="description" content="Seata AT mode." />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>Seata AT Mode</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/documentation.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="documentation-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/developers/developers_dev.html" target="_self">DEVELOPERS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><div class="bar"><div class="bar-body"><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="front-img"/><span>Documentation</span><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="back-img"/></div></div><section class="content-section"><div class="sidemenu"><div class="sidemenu-toggle"><img src="https://img.alicdn.com/tfs/TB1E6apXHGYBuNjy0FoXXciBFXa-200-200.png"/></div><ul><li class="menu-item menu-item-level-1"><span>Overview</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/terminology.html" target="_self">Terminology</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/faq.html" target="_self">FAQ</a></li></ul></li><li class="menu-item menu-item-level-1"><span>User Doc</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/api.html" target="_self">API Guide</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/microservice.html" target="_self">Microservices Framework Supports</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Developer Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Transaction Mode<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/at-mode.html" target="_self">Seata AT mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/tcc-mode.html" target="_self">Seata TCC mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/saga-mode.html" target="_self">Seata Saga mode</a></li></ul></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/dev/seata-mertics.html" target="_self">Metrics design</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Ops Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/ops/multi-configuration-isolation.html" target="_self">Configuration Isolation</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Deploy<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-server.html" target="_self">Deploy Directly</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-docker.html" target="_self">Deploy by Docker</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-kubernetes.html" target="_self">Deploy by Kubernetes</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-helm.html" target="_self">Deploy by Helm</a></li></ul></li></ul></li></ul></div><div class="doc-content markdown-body"><h1>Seata AT mode</h1>
|
||||
<h1>The basic idea</h1>
|
||||
<h2>Prerequisite</h2>
|
||||
<ul>
|
||||
<li>Relational databases that support local ACID transaction.</li>
|
||||
<li>Java applications that access database via JDBC.</li>
|
||||
</ul>
|
||||
<h2>Overall mechanism</h2>
|
||||
<p>Evolution from the two phases commit protocol:</p>
|
||||
<ul>
|
||||
<li>Phase 1:commit business data and rollback log in the same local transaction, then release local lock and connection resources.</li>
|
||||
<li>Phase 2:
|
||||
<ul>
|
||||
<li>for commit case, do the work asynchronously and quickly.</li>
|
||||
<li>for rollback case, do compensation, base on the rollback log created in the phase 1.</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h1>Write isolation</h1>
|
||||
<ul>
|
||||
<li>The <strong>global lock</strong> must be acquired before committing the local transaction of phase 1.</li>
|
||||
<li>If the <strong>global lock</strong> is not acquired, the local transaction should not be committed.</li>
|
||||
<li>One transaction will try to acquire the <strong>global lock</strong> many times if it fails to, but there is a timeout, if it's timeout, rollback local transaction and release local lock as well.</li>
|
||||
</ul>
|
||||
<p>For example:</p>
|
||||
<p>Two transactions tx1 and tx2 are trying to update field m of table a. The original value of m is 1000.</p>
|
||||
<p>tx1 starts first, begins a local transaction, acquires the local lock, do the update operation: m = 1000 - 100 = 900. tx1 must acquire the <strong>global lock</strong> before committing the local transaction, after that, commit local transaction and release local lock.</p>
|
||||
<p>next, tx2 begins local transaction, acquires local lock, do the update operation: m = 900 - 100 = 800. Before tx2 can commit local transaction, it must acquire the <strong>global lock</strong>, but the <strong>global lock</strong> may be hold by tx1, so tx2 will do retry. After tx1 does the global commit and releases the <strong>global lock</strong>, tx2 can acquire the <strong>global lock</strong>, then it can commit local transaction and release local lock.</p>
|
||||
<p><img src="/img/seata_at-1.png" alt="Write-Isolation: Commit"></p>
|
||||
<p>See the figure above, tx1 does the global commit in phase 2 and release the <strong>global lock</strong>, tx2 acquires the <strong>global lock</strong> and commits local transaction.</p>
|
||||
<p><img src="/img/seata_at-2.png" alt="Write-Isolation: Rollback"></p>
|
||||
<p>See the figure above, if tx1 wants to do the global rollback, it must acquire local lock to revert the update operation of phase 1.</p>
|
||||
<p>However, now the local lock is held by tx2 which hopes to acquire the <strong>global lock</strong>, so tx1 fails to rollback, but it would try it many times until it's timeout for tx2 to acquire the <strong>global lock</strong>, then tx2 rollbacks local transaction and releases local lock, after that, tx1 can acquire the local lock, and do the branch rollback successfully.</p>
|
||||
<p>Because the <strong>global lock</strong> is held by tx1 during the whole process, there isn't no problem of <strong>dirty write</strong>.</p>
|
||||
<h1>Read isolation</h1>
|
||||
<p>The isolation level of local database is <strong>read committed</strong> or above, so the default isolation level of the global transaction is <strong>read uncommitted</strong>.</p>
|
||||
<p>If it needs the isolation level of the global transaction is <strong>read committed</strong>, currently, Fescar implements it via SELECT FOR UPDATE statement.</p>
|
||||
<p><img src="/img/seata_at-3.png" alt="Read Isolation: SELECT FOR UPDATE"></p>
|
||||
<p>The <strong>global lock</strong> is be applied during the execution of SELECT FOR UPDATE statement, if the <strong>global lock</strong> is held by other transactions, the transaction will release local lock retry execute the SELECT FOR UPDATE statement. During the whole process, the query is blocked until the <strong>global lock</strong> is acquired, if the lock is acquired, it means the other global transaction has committed, so the isolation level of global transaction is <strong>read committed</strong>.</p>
|
||||
<p>For the performance consideration, Fescar only does proxy work for SELECT FOR UPDATE. For the general SELECT statement, do nothing.</p>
|
||||
<h1>Work process</h1>
|
||||
<p>Take an example to illustrate it.</p>
|
||||
<p>A business table:<code>product</code></p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Type</th>
|
||||
<th>Key</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>id</td>
|
||||
<td>bigint(20)</td>
|
||||
<td>PRI</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>name</td>
|
||||
<td>varchar(100)</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>since</td>
|
||||
<td>varchar(100)</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>The sql of branch transaction in AT mode:</p>
|
||||
<pre><code class="language-sql"><span class="hljs-keyword">update</span> product <span class="hljs-keyword">set</span> <span class="hljs-keyword">name</span> = <span class="hljs-string">'GTS'</span> <span class="hljs-keyword">where</span> <span class="hljs-keyword">name</span> = <span class="hljs-string">'TXC'</span>;
|
||||
</code></pre>
|
||||
<h2>Phase 1</h2>
|
||||
<p>Process:</p>
|
||||
<ol>
|
||||
<li>Parse sql: know the sql type is update operation, table name is product, the where condition is name = 'TXC' and so on.</li>
|
||||
<li>Query the data before update(Named before image): In order to locate the data that will be updated, generate a query statement by the where condition above.</li>
|
||||
</ol>
|
||||
<pre><code class="language-sql"><span class="hljs-keyword">select</span> <span class="hljs-keyword">id</span>, <span class="hljs-keyword">name</span>, since <span class="hljs-keyword">from</span> product <span class="hljs-keyword">where</span> <span class="hljs-keyword">name</span> = <span class="hljs-string">'TXC'</span>;
|
||||
</code></pre>
|
||||
<p>Got the "before image":</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>id</th>
|
||||
<th>name</th>
|
||||
<th>since</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>TXC</td>
|
||||
<td>2014</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<ol start="3">
|
||||
<li>Execute the update sql: update the record of name equals 'GTS'.</li>
|
||||
<li>Query the data after update(Named after image): locate the record by the <strong>primary key</strong> of image data before update.</li>
|
||||
</ol>
|
||||
<pre><code class="language-sql"><span class="hljs-keyword">select</span> <span class="hljs-keyword">id</span>, <span class="hljs-keyword">name</span>, since <span class="hljs-keyword">from</span> product <span class="hljs-keyword">where</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">1</span>;
|
||||
</code></pre>
|
||||
<p>Got the after image:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>id</th>
|
||||
<th>name</th>
|
||||
<th>since</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>GTS</td>
|
||||
<td>2014</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<ol start="5">
|
||||
<li>Insert a rollback log: build the rollback log with image before and after, as well as SQL statement relelated information, then insert into table <code>UNDO_LOG</code> .</li>
|
||||
</ol>
|
||||
<pre><code class="language-json">{
|
||||
<span class="hljs-attr">"branchId"</span>: <span class="hljs-number">641789253</span>,
|
||||
<span class="hljs-attr">"undoItems"</span>: [{
|
||||
<span class="hljs-attr">"afterImage"</span>: {
|
||||
<span class="hljs-attr">"rows"</span>: [{
|
||||
<span class="hljs-attr">"fields"</span>: [{
|
||||
<span class="hljs-attr">"name"</span>: <span class="hljs-string">"id"</span>,
|
||||
<span class="hljs-attr">"type"</span>: <span class="hljs-number">4</span>,
|
||||
<span class="hljs-attr">"value"</span>: <span class="hljs-number">1</span>
|
||||
}, {
|
||||
<span class="hljs-attr">"name"</span>: <span class="hljs-string">"name"</span>,
|
||||
<span class="hljs-attr">"type"</span>: <span class="hljs-number">12</span>,
|
||||
<span class="hljs-attr">"value"</span>: <span class="hljs-string">"GTS"</span>
|
||||
}, {
|
||||
<span class="hljs-attr">"name"</span>: <span class="hljs-string">"since"</span>,
|
||||
<span class="hljs-attr">"type"</span>: <span class="hljs-number">12</span>,
|
||||
<span class="hljs-attr">"value"</span>: <span class="hljs-string">"2014"</span>
|
||||
}]
|
||||
}],
|
||||
<span class="hljs-attr">"tableName"</span>: <span class="hljs-string">"product"</span>
|
||||
},
|
||||
<span class="hljs-attr">"beforeImage"</span>: {
|
||||
<span class="hljs-attr">"rows"</span>: [{
|
||||
<span class="hljs-attr">"fields"</span>: [{
|
||||
<span class="hljs-attr">"name"</span>: <span class="hljs-string">"id"</span>,
|
||||
<span class="hljs-attr">"type"</span>: <span class="hljs-number">4</span>,
|
||||
<span class="hljs-attr">"value"</span>: <span class="hljs-number">1</span>
|
||||
}, {
|
||||
<span class="hljs-attr">"name"</span>: <span class="hljs-string">"name"</span>,
|
||||
<span class="hljs-attr">"type"</span>: <span class="hljs-number">12</span>,
|
||||
<span class="hljs-attr">"value"</span>: <span class="hljs-string">"TXC"</span>
|
||||
}, {
|
||||
<span class="hljs-attr">"name"</span>: <span class="hljs-string">"since"</span>,
|
||||
<span class="hljs-attr">"type"</span>: <span class="hljs-number">12</span>,
|
||||
<span class="hljs-attr">"value"</span>: <span class="hljs-string">"2014"</span>
|
||||
}]
|
||||
}],
|
||||
<span class="hljs-attr">"tableName"</span>: <span class="hljs-string">"product"</span>
|
||||
},
|
||||
<span class="hljs-attr">"sqlType"</span>: <span class="hljs-string">"UPDATE"</span>
|
||||
}],
|
||||
<span class="hljs-attr">"xid"</span>: <span class="hljs-string">"xid:xxx"</span>
|
||||
}
|
||||
</code></pre>
|
||||
<ol start="6">
|
||||
<li>Before local commit, the transaction submmit an application to TC to acquire a <strong>global lock</strong> for the record whose primary key equals 1 in the table product.</li>
|
||||
<li>Commit local transaction: commit the update of PRODUCT table and the insert of UNDO_LOG table in the same local transaction.</li>
|
||||
<li>Report the result of step 7 to TC.</li>
|
||||
</ol>
|
||||
<h2>Phase 2 - Rollback case</h2>
|
||||
<ol>
|
||||
<li>After receive the rollback request from TC, begin a local transaction, execute operation as following.</li>
|
||||
<li>Retrieve the UNDO LOG by XID and Branch ID.</li>
|
||||
<li>Validate data: Compare the image data after update in UNDO LOG with current data, if there is difference, it means the data has been changed by operation out of current transaction, it should be handled in different policy, we will describe it detailedly in other document.</li>
|
||||
<li>Generate rollback SQL statement base on before image in UNDO LOG and related information of the business SQL.</li>
|
||||
</ol>
|
||||
<pre><code class="language-sql"><span class="hljs-keyword">update</span> product <span class="hljs-keyword">set</span> <span class="hljs-keyword">name</span> = <span class="hljs-string">'TXC'</span> <span class="hljs-keyword">where</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">1</span>;
|
||||
</code></pre>
|
||||
<ol start="5">
|
||||
<li>Commit local transaction, report the result of execution of local transaction(The rollback result of the Branch transaction) to TC.</li>
|
||||
</ol>
|
||||
<h2>Phase 2 - Commit case</h2>
|
||||
<ol>
|
||||
<li>After receive the commit request from TC, put the request into a work queue, return success to TC immediately.</li>
|
||||
<li>During the phase of doing the asynchronous work in the queue, the UNDO LOGs are deleted in batch way.</li>
|
||||
</ol>
|
||||
<h1>Appendix</h1>
|
||||
<h2>Undo log table</h2>
|
||||
<p>UNDO_LOG Table:there is a little bit difference on the data type for different databases.</p>
|
||||
<p>For MySQL example:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Type</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>branch_id</td>
|
||||
<td>bigint PK</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>xid</td>
|
||||
<td>varchar(100)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>rollback_info</td>
|
||||
<td>longblob</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>log_status</td>
|
||||
<td>tinyint</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>log_created</td>
|
||||
<td>datetime</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>log_modified</td>
|
||||
<td>datetime</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>ext</td>
|
||||
<td>varchar(100)</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<pre><code class="language-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`undo_log`</span> (
|
||||
<span class="hljs-string">`id`</span> <span class="hljs-built_in">bigint</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> AUTO_INCREMENT <span class="hljs-keyword">COMMENT</span> <span class="hljs-string">'increment id'</span>,
|
||||
<span class="hljs-string">`branch_id`</span> <span class="hljs-built_in">bigint</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> <span class="hljs-keyword">COMMENT</span> <span class="hljs-string">'branch transaction id'</span>,
|
||||
<span class="hljs-string">`xid`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> <span class="hljs-keyword">COMMENT</span> <span class="hljs-string">'global transaction id'</span>,
|
||||
<span class="hljs-string">`context`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">128</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> <span class="hljs-keyword">COMMENT</span> <span class="hljs-string">'undo_log context,such as serialization'</span>,
|
||||
<span class="hljs-string">`rollback_info`</span> longblob <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> <span class="hljs-keyword">COMMENT</span> <span class="hljs-string">'rollback info'</span>,
|
||||
<span class="hljs-string">`log_status`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> <span class="hljs-keyword">COMMENT</span> <span class="hljs-string">'0:normal status,1:defense status'</span>,
|
||||
<span class="hljs-string">`log_created`</span> datetime <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> <span class="hljs-keyword">COMMENT</span> <span class="hljs-string">'create datetime'</span>,
|
||||
<span class="hljs-string">`log_modified`</span> datetime <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> <span class="hljs-keyword">COMMENT</span> <span class="hljs-string">'modify datetime'</span>,
|
||||
<span class="hljs-string">`ext`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span> <span class="hljs-keyword">COMMENT</span> <span class="hljs-string">'reserved field'</span>,
|
||||
PRIMARY <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`id`</span>),
|
||||
<span class="hljs-keyword">UNIQUE</span> <span class="hljs-keyword">KEY</span> <span class="hljs-string">`ux_undo_log`</span> (<span class="hljs-string">`xid`</span>,<span class="hljs-string">`branch_id`</span>)
|
||||
) <span class="hljs-keyword">ENGINE</span>=<span class="hljs-keyword">InnoDB</span> AUTO_INCREMENT=<span class="hljs-number">1</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CHARSET</span>=utf8 <span class="hljs-keyword">COMMENT</span>=<span class="hljs-string">'AT transaction mode undo table'</span>;
|
||||
</code></pre>
|
||||
</div></section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is an Alibaba open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/documentation.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
|
@ -1,33 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Seata, Saga mode" />
|
||||
<meta name="description" content="Seata Saga mode." />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>Seata Saga Mode</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/documentation.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="documentation-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/developers/developers_dev.html" target="_self">DEVELOPERS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><div class="bar"><div class="bar-body"><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="front-img"/><span>Documentation</span><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="back-img"/></div></div><section class="content-section"><div class="sidemenu"><div class="sidemenu-toggle"><img src="https://img.alicdn.com/tfs/TB1E6apXHGYBuNjy0FoXXciBFXa-200-200.png"/></div><ul><li class="menu-item menu-item-level-1"><span>Overview</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/terminology.html" target="_self">Terminology</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/faq.html" target="_self">FAQ</a></li></ul></li><li class="menu-item menu-item-level-1"><span>User Doc</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/api.html" target="_self">API Guide</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/microservice.html" target="_self">Microservices Framework Supports</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Developer Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Transaction Mode<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/at-mode.html" target="_self">Seata AT mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/tcc-mode.html" target="_self">Seata TCC mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/saga-mode.html" target="_self">Seata Saga mode</a></li></ul></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/dev/seata-mertics.html" target="_self">Metrics design</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Ops Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/ops/multi-configuration-isolation.html" target="_self">Configuration Isolation</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Deploy<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-server.html" target="_self">Deploy Directly</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-docker.html" target="_self">Deploy by Docker</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-kubernetes.html" target="_self">Deploy by Kubernetes</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-helm.html" target="_self">Deploy by Helm</a></li></ul></li></ul></li></ul></div><div class="doc-content markdown-body"><p>TODO : Should be translated from docs/zh-cn/dev/mode/saga-mode.md</p>
|
||||
</div></section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is an Alibaba open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/documentation.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"filename": "saga-mode.md",
|
||||
"__html": "<p>TODO : Should be translated from docs/zh-cn/dev/mode/saga-mode.md</p>\n",
|
||||
"link": "/en-us/docs/dev/mode/saga-mode.html",
|
||||
"meta": {
|
||||
"title": "Seata Saga Mode",
|
||||
"keywords": "Seata, Saga mode",
|
||||
"description": "Seata Saga mode."
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Seata, TCC Mode" />
|
||||
<meta name="description" content="Seata TCC mode." />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>Seata TCC Mode</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/documentation.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="documentation-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/developers/developers_dev.html" target="_self">DEVELOPERS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><div class="bar"><div class="bar-body"><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="front-img"/><span>Documentation</span><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="back-img"/></div></div><section class="content-section"><div class="sidemenu"><div class="sidemenu-toggle"><img src="https://img.alicdn.com/tfs/TB1E6apXHGYBuNjy0FoXXciBFXa-200-200.png"/></div><ul><li class="menu-item menu-item-level-1"><span>Overview</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/terminology.html" target="_self">Terminology</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/faq.html" target="_self">FAQ</a></li></ul></li><li class="menu-item menu-item-level-1"><span>User Doc</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/api.html" target="_self">API Guide</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/microservice.html" target="_self">Microservices Framework Supports</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Developer Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Transaction Mode<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/at-mode.html" target="_self">Seata AT mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/tcc-mode.html" target="_self">Seata TCC mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/saga-mode.html" target="_self">Seata Saga mode</a></li></ul></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/dev/seata-mertics.html" target="_self">Metrics design</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Ops Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/ops/multi-configuration-isolation.html" target="_self">Configuration Isolation</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Deploy<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-server.html" target="_self">Deploy Directly</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-docker.html" target="_self">Deploy by Docker</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-kubernetes.html" target="_self">Deploy by Kubernetes</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-helm.html" target="_self">Deploy by Helm</a></li></ul></li></ul></li></ul></div><div class="doc-content markdown-body"><h1>Seata TCC Mode</h1>
|
||||
<p>Review the description in the overview: A distributed global transaction, the whole is a <strong>two-phase commit</strong> model. The global transaction is composed of several branch transactions. The branch transaction must meet the requirements of the <strong>two-phase commit</strong> model, that is, each branch transaction must have its own:</p>
|
||||
<ul>
|
||||
<li>One-stage prepare behavior</li>
|
||||
<li>Two-phase commit or rollback behavior</li>
|
||||
</ul>
|
||||
<p><img src="/img/seata_tcc-1.png" alt="Overview of a global transaction"></p>
|
||||
<p>According to the two-phase behavior mode, we divide branch transactions into <strong>Automatic (Branch) Transaction Mode</strong> and <strong>TCC (Branch) Transaction Mode</strong>.</p>
|
||||
<p>The AT mode (<a href="">Reference Link TBD</a>) is based on a <strong>relational database</strong> that <strong>supports local ACID transactions</strong>:</p>
|
||||
<ul>
|
||||
<li>One-stage prepare behavior: In local transactions, business data updates and corresponding rollback log records are submitted together.</li>
|
||||
<li>Two-phase commit behavior: Immediately completed successfully, <strong>automatically</strong> asynchronously clean up the rollback log.</li>
|
||||
<li>Two-phase rollback behavior: Through the rollback log, <strong>automatically</strong> generates compensation operations to complete data rollback.</li>
|
||||
</ul>
|
||||
<p>Correspondingly, the TCC mode does not rely on transaction support of the underlying data resources:</p>
|
||||
<ul>
|
||||
<li>One-stage prepare behavior: Call the <strong>custom</strong> prepare logic.</li>
|
||||
<li>Two-phase commit behavior: Call <strong>custom</strong> commit logic.</li>
|
||||
<li>Two-phase rollback behavior: Call the <strong>custom</strong> rollback logic.</li>
|
||||
</ul>
|
||||
<p>The so-called TCC mode refers to the support of putting <strong>customized's</strong> branch transactions into the management of global transactions.</p>
|
||||
</div></section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is an Alibaba open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/documentation.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"filename": "tcc-mode.md",
|
||||
"__html": "<h1>Seata TCC Mode</h1>\n<p>Review the description in the overview: A distributed global transaction, the whole is a <strong>two-phase commit</strong> model. The global transaction is composed of several branch transactions. The branch transaction must meet the requirements of the <strong>two-phase commit</strong> model, that is, each branch transaction must have its own:</p>\n<ul>\n<li>One-stage prepare behavior</li>\n<li>Two-phase commit or rollback behavior</li>\n</ul>\n<p><img src=\"/img/seata_tcc-1.png\" alt=\"Overview of a global transaction\"></p>\n<p>According to the two-phase behavior mode, we divide branch transactions into <strong>Automatic (Branch) Transaction Mode</strong> and <strong>TCC (Branch) Transaction Mode</strong>.</p>\n<p>The AT mode (<a href=\"\">Reference Link TBD</a>) is based on a <strong>relational database</strong> that <strong>supports local ACID transactions</strong>:</p>\n<ul>\n<li>One-stage prepare behavior: In local transactions, business data updates and corresponding rollback log records are submitted together.</li>\n<li>Two-phase commit behavior: Immediately completed successfully, <strong>automatically</strong> asynchronously clean up the rollback log.</li>\n<li>Two-phase rollback behavior: Through the rollback log, <strong>automatically</strong> generates compensation operations to complete data rollback.</li>\n</ul>\n<p>Correspondingly, the TCC mode does not rely on transaction support of the underlying data resources:</p>\n<ul>\n<li>One-stage prepare behavior: Call the <strong>custom</strong> prepare logic.</li>\n<li>Two-phase commit behavior: Call <strong>custom</strong> commit logic.</li>\n<li>Two-phase rollback behavior: Call the <strong>custom</strong> rollback logic.</li>\n</ul>\n<p>The so-called TCC mode refers to the support of putting <strong>customized's</strong> branch transactions into the management of global transactions.</p>\n",
|
||||
"link": "/en-us/docs/dev/mode/tcc-mode.html",
|
||||
"meta": {
|
||||
"title": "Seata TCC Mode",
|
||||
"keywords": "Seata, TCC Mode",
|
||||
"description": "Seata TCC mode."
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Seata, Metrics" />
|
||||
<meta name="description" content="Seata Metrics." />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>Seata Metrics</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/documentation.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="documentation-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/developers/developers_dev.html" target="_self">DEVELOPERS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><div class="bar"><div class="bar-body"><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="front-img"/><span>Documentation</span><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="back-img"/></div></div><section class="content-section"><div class="sidemenu"><div class="sidemenu-toggle"><img src="https://img.alicdn.com/tfs/TB1E6apXHGYBuNjy0FoXXciBFXa-200-200.png"/></div><ul><li class="menu-item menu-item-level-1"><span>Overview</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/terminology.html" target="_self">Terminology</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/faq.html" target="_self">FAQ</a></li></ul></li><li class="menu-item menu-item-level-1"><span>User Doc</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/api.html" target="_self">API Guide</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/microservice.html" target="_self">Microservices Framework Supports</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Developer Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Transaction Mode<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/at-mode.html" target="_self">Seata AT mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/tcc-mode.html" target="_self">Seata TCC mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/saga-mode.html" target="_self">Seata Saga mode</a></li></ul></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/dev/seata-mertics.html" target="_self">Metrics design</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Ops Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/ops/multi-configuration-isolation.html" target="_self">Configuration Isolation</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Deploy<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-server.html" target="_self">Deploy Directly</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-docker.html" target="_self">Deploy by Docker</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-kubernetes.html" target="_self">Deploy by Kubernetes</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-helm.html" target="_self">Deploy by Helm</a></li></ul></li></ul></li></ul></div><div class="doc-content markdown-body"><p>TODO : Should be translated from docs/zh-cn/dev/architecture/seata_mertics.md</p>
|
||||
</div></section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is an Alibaba open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/documentation.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"filename": "seata-mertics.md",
|
||||
"__html": "<p>TODO : Should be translated from docs/zh-cn/dev/architecture/seata_mertics.md</p>\n",
|
||||
"link": "/en-us/docs/dev/seata-mertics.html",
|
||||
"meta": {
|
||||
"title": "Seata Metrics",
|
||||
"keywords": "Seata, Metrics",
|
||||
"description": "Seata Metrics."
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Seata" />
|
||||
<meta name="description" content="Label an Issue." />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>Label an Issue</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/documentation.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="documentation-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/developers/developers_dev.html" target="_self">DEVELOPERS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><div class="bar"><div class="bar-body"><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="front-img"/><span>Documentation</span><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="back-img"/></div></div><section class="content-section"><div class="sidemenu"><div class="sidemenu-toggle"><img src="https://img.alicdn.com/tfs/TB1E6apXHGYBuNjy0FoXXciBFXa-200-200.png"/></div><ul><li class="menu-item menu-item-level-1"><span>Overview</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/terminology.html" target="_self">Terminology</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/faq.html" target="_self">FAQ</a></li></ul></li><li class="menu-item menu-item-level-1"><span>User Doc</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/api.html" target="_self">API Guide</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/microservice.html" target="_self">Microservices Framework Supports</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Developer Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Transaction Mode<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/at-mode.html" target="_self">Seata AT mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/tcc-mode.html" target="_self">Seata TCC mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/saga-mode.html" target="_self">Seata Saga mode</a></li></ul></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/dev/seata-mertics.html" target="_self">Metrics design</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Ops Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/ops/multi-configuration-isolation.html" target="_self">Configuration Isolation</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Deploy<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-server.html" target="_self">Deploy Directly</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-docker.html" target="_self">Deploy by Docker</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-kubernetes.html" target="_self">Deploy by Kubernetes</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-helm.html" target="_self">Deploy by Helm</a></li></ul></li></ul></li></ul></div><div class="doc-content markdown-body"><h1>Label an Issue</h1>
|
||||
<p>If you are handling an issue, remember to <strong>mark the issue cearly with one or more labels</strong> whenever you think it's meaningful. With labels on, other developers can easily recognize problems, classify them or track progress.</p>
|
||||
<p>For issues or pull requests that need coding and further version release to fix, you should always <strong>mark it with a <a href="https://github.com/seata/seata/milestones">milestone</a></strong>.</p>
|
||||
<p>Some frequently used labels:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p>Help Wanted</p>
|
||||
<ul>
|
||||
<li>help wanted</li>
|
||||
<li>good first issue</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p>Prority</p>
|
||||
<ul>
|
||||
<li>priority/blocker</li>
|
||||
<li>priority/high</li>
|
||||
<li>priority/low</li>
|
||||
<li>priority/normal</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p>Status</p>
|
||||
<ul>
|
||||
<li>status/need-triage</li>
|
||||
<li>status/DO-NOT-MERGE</li>
|
||||
<li>status/READY-TO-MERGE</li>
|
||||
<li>status/invalid</li>
|
||||
<li>status/wontfix</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p>Type</p>
|
||||
<ul>
|
||||
<li>type/bug</li>
|
||||
<li>type/documentation</li>
|
||||
<li>type/enhancement</li>
|
||||
<li>type/feature</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div></section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is an Alibaba open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/documentation.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"filename": "label-an-issue-guide_dev.md",
|
||||
"__html": "<h1>Label an Issue</h1>\n<p>If you are handling an issue, remember to <strong>mark the issue cearly with one or more labels</strong> whenever you think it's meaningful. With labels on, other developers can easily recognize problems, classify them or track progress.</p>\n<p>For issues or pull requests that need coding and further version release to fix, you should always <strong>mark it with a <a href=\"https://github.com/seata/seata/milestones\">milestone</a></strong>.</p>\n<p>Some frequently used labels:</p>\n<ul>\n<li>\n<p>Help Wanted</p>\n<ul>\n<li>help wanted</li>\n<li>good first issue</li>\n</ul>\n</li>\n<li>\n<p>Prority</p>\n<ul>\n<li>priority/blocker</li>\n<li>priority/high</li>\n<li>priority/low</li>\n<li>priority/normal</li>\n</ul>\n</li>\n<li>\n<p>Status</p>\n<ul>\n<li>status/need-triage</li>\n<li>status/DO-NOT-MERGE</li>\n<li>status/READY-TO-MERGE</li>\n<li>status/invalid</li>\n<li>status/wontfix</li>\n</ul>\n</li>\n<li>\n<p>Type</p>\n<ul>\n<li>type/bug</li>\n<li>type/documentation</li>\n<li>type/enhancement</li>\n<li>type/feature</li>\n</ul>\n</li>\n</ul>\n",
|
||||
"link": "/en-us/docs/developers/committer-guide/label-an-issue-guide_dev.html",
|
||||
"meta": {
|
||||
"title": "Label an Issue",
|
||||
"keywords": "Seata",
|
||||
"description": "Label an Issue."
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="release-guide_dev" />
|
||||
<meta name="description" content="release-guide_dev" />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>release-guide_dev</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/documentation.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="documentation-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/developers/developers_dev.html" target="_self">DEVELOPERS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><div class="bar"><div class="bar-body"><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="front-img"/><span>Documentation</span><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="back-img"/></div></div><section class="content-section"><div class="sidemenu"><div class="sidemenu-toggle"><img src="https://img.alicdn.com/tfs/TB1E6apXHGYBuNjy0FoXXciBFXa-200-200.png"/></div><ul><li class="menu-item menu-item-level-1"><span>Overview</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/terminology.html" target="_self">Terminology</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/faq.html" target="_self">FAQ</a></li></ul></li><li class="menu-item menu-item-level-1"><span>User Doc</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/api.html" target="_self">API Guide</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/microservice.html" target="_self">Microservices Framework Supports</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Developer Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Transaction Mode<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/at-mode.html" target="_self">Seata AT mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/tcc-mode.html" target="_self">Seata TCC mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/saga-mode.html" target="_self">Seata Saga mode</a></li></ul></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/dev/seata-mertics.html" target="_self">Metrics design</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Ops Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/ops/multi-configuration-isolation.html" target="_self">Configuration Isolation</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Deploy<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-server.html" target="_self">Deploy Directly</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-docker.html" target="_self">Deploy by Docker</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-kubernetes.html" target="_self">Deploy by Kubernetes</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-helm.html" target="_self">Deploy by Helm</a></li></ul></li></ul></li></ul></div><div class="doc-content markdown-body"><p>TBD</p>
|
||||
</div></section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is an Alibaba open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/documentation.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"filename": "release-guide_dev.md",
|
||||
"__html": "<p>TBD</p>\n",
|
||||
"link": "/en-us/docs/developers/committer-guide/release-guide_dev.html",
|
||||
"meta": {}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Seata" />
|
||||
<meta name="description" content="Website Guide." />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>Website Guide</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/documentation.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="documentation-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/developers/developers_dev.html" target="_self">DEVELOPERS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><div class="bar"><div class="bar-body"><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="front-img"/><span>Documentation</span><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="back-img"/></div></div><section class="content-section"><div class="sidemenu"><div class="sidemenu-toggle"><img src="https://img.alicdn.com/tfs/TB1E6apXHGYBuNjy0FoXXciBFXa-200-200.png"/></div><ul><li class="menu-item menu-item-level-1"><span>Overview</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/terminology.html" target="_self">Terminology</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/faq.html" target="_self">FAQ</a></li></ul></li><li class="menu-item menu-item-level-1"><span>User Doc</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/api.html" target="_self">API Guide</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/microservice.html" target="_self">Microservices Framework Supports</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Developer Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Transaction Mode<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/at-mode.html" target="_self">Seata AT mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/tcc-mode.html" target="_self">Seata TCC mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/saga-mode.html" target="_self">Seata Saga mode</a></li></ul></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/dev/seata-mertics.html" target="_self">Metrics design</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Ops Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/ops/multi-configuration-isolation.html" target="_self">Configuration Isolation</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Deploy<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-server.html" target="_self">Deploy Directly</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-docker.html" target="_self">Deploy by Docker</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-kubernetes.html" target="_self">Deploy by Kubernetes</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-helm.html" target="_self">Deploy by Helm</a></li></ul></li></ul></li></ul></div><div class="doc-content markdown-body"><h1>Website Guide</h1>
|
||||
<ol>
|
||||
<li>The website repository of Seata is <a href="https://github.com/seata/seata.github.io">https://github.com/seata/seata.github.io</a>.</li>
|
||||
<li>After building the website, it'll be published to <a href="http://seata.io">seata.io</a> automatically.</li>
|
||||
</ol>
|
||||
</div></section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is an Alibaba open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/documentation.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"filename": "website-guide_dev.md",
|
||||
"__html": "<h1>Website Guide</h1>\n<ol>\n<li>The website repository of Seata is <a href=\"https://github.com/seata/seata.github.io\">https://github.com/seata/seata.github.io</a>.</li>\n<li>After building the website, it'll be published to <a href=\"http://seata.io\">seata.io</a> automatically.</li>\n</ol>\n",
|
||||
"link": "/en-us/docs/developers/committer-guide/website-guide_dev.html",
|
||||
"meta": {
|
||||
"title": "Website Guide",
|
||||
"keywords": "Seata",
|
||||
"description": "Website Guide."
|
||||
}
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Seata, contributor" />
|
||||
<meta name="description" content="This is a guide for new comers who wants to contribute to Seata." />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>New contributor guide</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/documentation.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="documentation-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/developers/developers_dev.html" target="_self">DEVELOPERS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><div class="bar"><div class="bar-body"><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="front-img"/><span>Documentation</span><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="back-img"/></div></div><section class="content-section"><div class="sidemenu"><div class="sidemenu-toggle"><img src="https://img.alicdn.com/tfs/TB1E6apXHGYBuNjy0FoXXciBFXa-200-200.png"/></div><ul><li class="menu-item menu-item-level-1"><span>Overview</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/terminology.html" target="_self">Terminology</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/faq.html" target="_self">FAQ</a></li></ul></li><li class="menu-item menu-item-level-1"><span>User Doc</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/api.html" target="_self">API Guide</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/microservice.html" target="_self">Microservices Framework Supports</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Developer Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Transaction Mode<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/at-mode.html" target="_self">Seata AT mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/tcc-mode.html" target="_self">Seata TCC mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/saga-mode.html" target="_self">Seata Saga mode</a></li></ul></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/dev/seata-mertics.html" target="_self">Metrics design</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Ops Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/ops/multi-configuration-isolation.html" target="_self">Configuration Isolation</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Deploy<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-server.html" target="_self">Deploy Directly</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-docker.html" target="_self">Deploy by Docker</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-kubernetes.html" target="_self">Deploy by Kubernetes</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-helm.html" target="_self">Deploy by Helm</a></li></ul></li></ul></li></ul></div><div class="doc-content markdown-body"><h1>New contributor guide</h1>
|
||||
<p>This is a guide for new comers who wants to contribute to Seata.</p>
|
||||
<h3>Subscribe to the mailing list</h3>
|
||||
<p>TBD</p>
|
||||
<h3>Reporting issue</h3>
|
||||
<p>You can always reporting an issue to Seata via Github <a href="https://github.com/seata/seata/issues">Issues</a>.</p>
|
||||
<p>If you are reporting bugs, please refer to the issue report <a href="https://github.com/seata/seata/issues/new?template=BUG_REPORT.md">template</a>.</p>
|
||||
<p>If you are reporting feature, please refer to the issue report <a href="https://github.com/seata/seata/issues/new?template=FEATURE_REQUEST.md">template</a>.</p>
|
||||
<p>If you are reporting regular issues, like raise an question, you can open an <a href="https://github.com/seata/seata/issues/new">regular issue</a>.</p>
|
||||
<h3>Sending pull request</h3>
|
||||
<ul>
|
||||
<li>Follow the checklist in the <a href="https://github.com/seata/seata/blob/develop/.github/PULL_REQUEST_TEMPLATE.md">pull request template</a></li>
|
||||
<li>Before you sending out the pull request, please sync your forked repository with remote repository, this will make your pull request simple and clear. See guide below:</li>
|
||||
</ul>
|
||||
<pre><code class="language-sh">git remote add upstream git@github.com:seata/seata.git
|
||||
git fetch upstream
|
||||
git rebase upstream/master
|
||||
git checkout -b your_awesome_patch
|
||||
... add some work
|
||||
git push origin your_awesome_patch
|
||||
</code></pre>
|
||||
<h3>Code convention</h3>
|
||||
<p>Please check the <a href="https://github.com/seata/seata/blob/develop/CONTRIBUTING.md">CONTRIBUTING.md</a> for code convention.</p>
|
||||
</div></section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is an Alibaba open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/documentation.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"filename": "new-contributor-guide_dev.md",
|
||||
"__html": "<h1>New contributor guide</h1>\n<p>This is a guide for new comers who wants to contribute to Seata.</p>\n<h3>Subscribe to the mailing list</h3>\n<p>TBD</p>\n<h3>Reporting issue</h3>\n<p>You can always reporting an issue to Seata via Github <a href=\"https://github.com/seata/seata/issues\">Issues</a>.</p>\n<p>If you are reporting bugs, please refer to the issue report <a href=\"https://github.com/seata/seata/issues/new?template=BUG_REPORT.md\">template</a>.</p>\n<p>If you are reporting feature, please refer to the issue report <a href=\"https://github.com/seata/seata/issues/new?template=FEATURE_REQUEST.md\">template</a>.</p>\n<p>If you are reporting regular issues, like raise an question, you can open an <a href=\"https://github.com/seata/seata/issues/new\">regular issue</a>.</p>\n<h3>Sending pull request</h3>\n<ul>\n<li>Follow the checklist in the <a href=\"https://github.com/seata/seata/blob/develop/.github/PULL_REQUEST_TEMPLATE.md\">pull request template</a></li>\n<li>Before you sending out the pull request, please sync your forked repository with remote repository, this will make your pull request simple and clear. See guide below:</li>\n</ul>\n<pre><code class=\"language-sh\">git remote add upstream git@github.com:seata/seata.git\ngit fetch upstream\ngit rebase upstream/master\ngit checkout -b your_awesome_patch\n... add some work\ngit push origin your_awesome_patch\n</code></pre>\n<h3>Code convention</h3>\n<p>Please check the <a href=\"https://github.com/seata/seata/blob/develop/CONTRIBUTING.md\">CONTRIBUTING.md</a> for code convention.</p>\n",
|
||||
"link": "/en-us/docs/developers/contributor-guide/new-contributor-guide_dev.html",
|
||||
"meta": {
|
||||
"title": "New contributor guide",
|
||||
"keywords": "Seata, contributor",
|
||||
"description": "This is a guide for new comers who wants to contribute to Seata."
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Seata, contributor" />
|
||||
<meta name="description" content="This is a guide for new comers who wants to contribute to Seata." />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>New contributor guide</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/documentation.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="documentation-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/developers/developers_dev.html" target="_self">DEVELOPERS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><div class="bar"><div class="bar-body"><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="front-img"/><span>Documentation</span><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="back-img"/></div></div><section class="content-section"><div class="sidemenu"><div class="sidemenu-toggle"><img src="https://img.alicdn.com/tfs/TB1E6apXHGYBuNjy0FoXXciBFXa-200-200.png"/></div><ul><li class="menu-item menu-item-level-1"><span>Overview</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/terminology.html" target="_self">Terminology</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/faq.html" target="_self">FAQ</a></li></ul></li><li class="menu-item menu-item-level-1"><span>User Doc</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/api.html" target="_self">API Guide</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/microservice.html" target="_self">Microservices Framework Supports</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Developer Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Transaction Mode<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/at-mode.html" target="_self">Seata AT mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/tcc-mode.html" target="_self">Seata TCC mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/saga-mode.html" target="_self">Seata Saga mode</a></li></ul></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/dev/seata-mertics.html" target="_self">Metrics design</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Ops Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/ops/multi-configuration-isolation.html" target="_self">Configuration Isolation</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Deploy<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-server.html" target="_self">Deploy Directly</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-docker.html" target="_self">Deploy by Docker</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-kubernetes.html" target="_self">Deploy by Kubernetes</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-helm.html" target="_self">Deploy by Helm</a></li></ul></li></ul></li></ul></div><div class="doc-content markdown-body"><h1>Reporting Security Issues</h1>
|
||||
<p>The Seata Group takes a rigorous standpoint in annihilating the security issues in its software projects. Seata is highly sensitive and forthcoming to issues pertaining to its features and functionality.</p>
|
||||
<h2>REPORTING VULNERABILITY</h2>
|
||||
<p>If you have apprehensions regarding Seata's security or you discover vulnerability or potential threat, don’t hesitate to get in touch with the Seata Security Team by dropping a mail at <a href="mailto:dev-seata@googlegroups.com">dev-seata@googlegroups.com</a>. In the mail, specify the description of the issue or potential threat. You are also urged to recommend the way to reproduce and replicate the issue. The Seata community will get back to you after assessing and analysing the findings.</p>
|
||||
<p>PLEASE PAY ATTENTION to report the security issue on the security email before disclosing it on public domain.</p>
|
||||
<h2>VULNERABILITY HANDLING</h2>
|
||||
<p>An overview of the vulnerability handling process is:</p>
|
||||
<ul>
|
||||
<li>The reporter reports the vulnerability privately to Apache.</li>
|
||||
<li>The appropriate project's security team works privately with the reporter to resolve the vulnerability.</li>
|
||||
<li>A new release of the Apache product concerned is made that includes the fix.</li>
|
||||
<li>The vulnerability is publically announced.</li>
|
||||
</ul>
|
||||
</div></section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is an Alibaba open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/documentation.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"filename": "reporting-security-issues_dev.md",
|
||||
"__html": "<h1>Reporting Security Issues</h1>\n<p>The Seata Group takes a rigorous standpoint in annihilating the security issues in its software projects. Seata is highly sensitive and forthcoming to issues pertaining to its features and functionality.</p>\n<h2>REPORTING VULNERABILITY</h2>\n<p>If you have apprehensions regarding Seata's security or you discover vulnerability or potential threat, don’t hesitate to get in touch with the Seata Security Team by dropping a mail at <a href=\"mailto:dev-seata@googlegroups.com\">dev-seata@googlegroups.com</a>. In the mail, specify the description of the issue or potential threat. You are also urged to recommend the way to reproduce and replicate the issue. The Seata community will get back to you after assessing and analysing the findings.</p>\n<p>PLEASE PAY ATTENTION to report the security issue on the security email before disclosing it on public domain.</p>\n<h2>VULNERABILITY HANDLING</h2>\n<p>An overview of the vulnerability handling process is:</p>\n<ul>\n<li>The reporter reports the vulnerability privately to Apache.</li>\n<li>The appropriate project's security team works privately with the reporter to resolve the vulnerability.</li>\n<li>A new release of the Apache product concerned is made that includes the fix.</li>\n<li>The vulnerability is publically announced.</li>\n</ul>\n",
|
||||
"link": "/en-us/docs/developers/contributor-guide/reporting-security-issues_dev.html",
|
||||
"meta": {
|
||||
"title": "New contributor guide",
|
||||
"keywords": "Seata, contributor",
|
||||
"description": "This is a guide for new comers who wants to contribute to Seata."
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Seata, coverage" />
|
||||
<meta name="description" content="Test coverage guide." />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>Test coverage guide</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/documentation.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="documentation-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/developers/developers_dev.html" target="_self">DEVELOPERS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><div class="bar"><div class="bar-body"><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="front-img"/><span>Documentation</span><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="back-img"/></div></div><section class="content-section"><div class="sidemenu"><div class="sidemenu-toggle"><img src="https://img.alicdn.com/tfs/TB1E6apXHGYBuNjy0FoXXciBFXa-200-200.png"/></div><ul><li class="menu-item menu-item-level-1"><span>Overview</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/terminology.html" target="_self">Terminology</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/faq.html" target="_self">FAQ</a></li></ul></li><li class="menu-item menu-item-level-1"><span>User Doc</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/api.html" target="_self">API Guide</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/microservice.html" target="_self">Microservices Framework Supports</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Developer Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Transaction Mode<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/at-mode.html" target="_self">Seata AT mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/tcc-mode.html" target="_self">Seata TCC mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/saga-mode.html" target="_self">Seata Saga mode</a></li></ul></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/dev/seata-mertics.html" target="_self">Metrics design</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Ops Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/ops/multi-configuration-isolation.html" target="_self">Configuration Isolation</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Deploy<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-server.html" target="_self">Deploy Directly</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-docker.html" target="_self">Deploy by Docker</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-kubernetes.html" target="_self">Deploy by Kubernetes</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-helm.html" target="_self">Deploy by Helm</a></li></ul></li></ul></li></ul></div><div class="doc-content markdown-body"><h1>Test coverage guide</h1>
|
||||
<h3>1.The benefits of unit testing</h3>
|
||||
<ul>
|
||||
<li>Unit test code can help everyone to go into details and understand the function of the code.</li>
|
||||
<li>We can find bugs by test case, and then enhance the robustness of the code.</li>
|
||||
<li>Test case code is also the demo usage of the core code.</li>
|
||||
</ul>
|
||||
<h3>2.Some design principle of unit test case</h3>
|
||||
<ul>
|
||||
<li>Steps, fine-grained and combination conditions should be well designed.</li>
|
||||
<li>Attention to boundary condition test</li>
|
||||
<li>Test code should also be designed without writing useless code.</li>
|
||||
<li>When you find a <code>method</code> that is hard to write unit test, if you can be sure the <code>method</code> is "smelly code", then refactor it with the committer.</li>
|
||||
<li>The mock framework in seata is: <a href="http://site.mockito.org/">mockito</a>. Some tutorials:<a href="http://www.baeldung.com/bdd-mockito">mockito tutorial</a>,<a href="https://dzone.com/refcardz/mockito">mockito refcard</a></li>
|
||||
<li>TDD(optional):When you start a new issue, you can try to write test case at first</li>
|
||||
</ul>
|
||||
<h3>3.The specified value of the test coverage</h3>
|
||||
<ul>
|
||||
<li>In the stage, the test coverage specified value of delta changed codes is :>=80%. The higher, the better.</li>
|
||||
<li>We can see the coverage report in this page: <a href="https://codecov.io/gh/seata/seata">https://codecov.io/gh/seata/seata</a></li>
|
||||
</ul>
|
||||
</div></section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is an Alibaba open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/documentation.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"filename": "test-coverage-guide_dev.md",
|
||||
"__html": "<h1>Test coverage guide</h1>\n<h3>1.The benefits of unit testing</h3>\n<ul>\n<li>Unit test code can help everyone to go into details and understand the function of the code.</li>\n<li>We can find bugs by test case, and then enhance the robustness of the code.</li>\n<li>Test case code is also the demo usage of the core code.</li>\n</ul>\n<h3>2.Some design principle of unit test case</h3>\n<ul>\n<li>Steps, fine-grained and combination conditions should be well designed.</li>\n<li>Attention to boundary condition test</li>\n<li>Test code should also be designed without writing useless code.</li>\n<li>When you find a <code>method</code> that is hard to write unit test, if you can be sure the <code>method</code> is "smelly code", then refactor it with the committer.</li>\n<li>The mock framework in seata is: <a href=\"http://site.mockito.org/\">mockito</a>. Some tutorials:<a href=\"http://www.baeldung.com/bdd-mockito\">mockito tutorial</a>,<a href=\"https://dzone.com/refcardz/mockito\">mockito refcard</a></li>\n<li>TDD(optional):When you start a new issue, you can try to write test case at first</li>\n</ul>\n<h3>3.The specified value of the test coverage</h3>\n<ul>\n<li>In the stage, the test coverage specified value of delta changed codes is :>=80%. The higher, the better.</li>\n<li>We can see the coverage report in this page: <a href=\"https://codecov.io/gh/seata/seata\">https://codecov.io/gh/seata/seata</a></li>\n</ul>\n",
|
||||
"link": "/en-us/docs/developers/contributor-guide/test-coverage-guide_dev.html",
|
||||
"meta": {
|
||||
"title": "Test coverage guide",
|
||||
"keywords": "Seata, coverage",
|
||||
"description": "Test coverage guide."
|
||||
}
|
||||
}
|
|
@ -1,188 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Seata, Developers" />
|
||||
<meta name="description" content="Seata Team." />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>Developers</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/documentation.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="documentation-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/developers/developers_dev.html" target="_self">DEVELOPERS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><div class="bar"><div class="bar-body"><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="front-img"/><span>Documentation</span><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="back-img"/></div></div><section class="content-section"><div class="sidemenu"><div class="sidemenu-toggle"><img src="https://img.alicdn.com/tfs/TB1E6apXHGYBuNjy0FoXXciBFXa-200-200.png"/></div><ul><li class="menu-item menu-item-level-1"><span>Overview</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/terminology.html" target="_self">Terminology</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/faq.html" target="_self">FAQ</a></li></ul></li><li class="menu-item menu-item-level-1"><span>User Doc</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/api.html" target="_self">API Guide</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/microservice.html" target="_self">Microservices Framework Supports</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Developer Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Transaction Mode<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/at-mode.html" target="_self">Seata AT mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/tcc-mode.html" target="_self">Seata TCC mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/saga-mode.html" target="_self">Seata Saga mode</a></li></ul></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/dev/seata-mertics.html" target="_self">Metrics design</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Ops Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/ops/multi-configuration-isolation.html" target="_self">Configuration Isolation</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Deploy<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-server.html" target="_self">Deploy Directly</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-docker.html" target="_self">Deploy by Docker</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-kubernetes.html" target="_self">Deploy by Kubernetes</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-helm.html" target="_self">Deploy by Helm</a></li></ul></li></ul></li></ul></div><div class="doc-content markdown-body"><h2>Seata Team</h2>
|
||||
<p>This page shows Seata developers and continues to expand. The list is not prioritized.</p>
|
||||
<h1>Seata Committer List</h1>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>姓名</th>
|
||||
<th>github</th>
|
||||
<th>公司</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Min Ji</td>
|
||||
<td><a href="https://github.com/slievrly">slievrly</a></td>
|
||||
<td>Alibabba</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Haiqiang Shen</td>
|
||||
<td><a href="https://github.com/sharajava">sharajava</a></td>
|
||||
<td>Alibabba</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Qipeng Li</td>
|
||||
<td><a href="https://github.com/wlliqipeng">wlliqipeng</a></td>
|
||||
<td>Alibabba</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Liandong Chen</td>
|
||||
<td><a href="https://github.com/purple-force">purple-force</a></td>
|
||||
<td>Alibabba</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Jiang Yu</td>
|
||||
<td><a href="https://github.com/jiangyu-gts">jiangyu-gts</a></td>
|
||||
<td>Alibabba</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Wei Zhang</td>
|
||||
<td><a href="https://github.com/jezhang2014">jezhang2014</a></td>
|
||||
<td>Alibabba</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Sen Zhang</td>
|
||||
<td><a href="https://github.com/zhangthen">zhangthen</a></td>
|
||||
<td>Antfin</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Guangshu Wang</td>
|
||||
<td><a href="https://github.com/wgs13579">wgs13579</a></td>
|
||||
<td>Antfin</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Geng Zhang</td>
|
||||
<td><a href="https://github.com/ujjboy">ujjboy</a></td>
|
||||
<td>Antfin</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Zhiyuan Lei</td>
|
||||
<td><a href="https://github.com/leizhiyuan">leizhiyuan</a></td>
|
||||
<td>Antfin</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Qing Wang</td>
|
||||
<td><a href="https://github.com/jovany-wang">jovany-wang</a></td>
|
||||
<td>Antfin</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Jiangke Wu</td>
|
||||
<td><a href="https://github.com/xingfudeshi">xingfudeshi</a></td>
|
||||
<td>Truthai</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Zhao Li</td>
|
||||
<td><a href="https://github.com/CoffeeLatte007">CoffeeLatte007</a></td>
|
||||
<td>YuanFuDao</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Xin Wang</td>
|
||||
<td><a href="https://github.com/lovepoem">lovepoem</a></td>
|
||||
<td>WeiDian</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Guoyao Yuan</td>
|
||||
<td><a href="https://github.com/github-ygy">github-ygy</a></td>
|
||||
<td>Tuya</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Xu Zhang</td>
|
||||
<td><a href="https://github.com/zhangxu19830126">zhangxu19830126</a></td>
|
||||
<td>InfiniVision</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Shuaipeng Ren</td>
|
||||
<td><a href="https://github.com/niaoshuai">niaoshuai</a></td>
|
||||
<td>HuanQiuYouLu</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Donglin Zhai</td>
|
||||
<td><a href="https://github.com/tony-zdl">tony-zdl</a></td>
|
||||
<td>Springs Capital</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Xugang Shen</td>
|
||||
<td><a href="https://github.com/xuririse">xuririse</a></td>
|
||||
<td>CNIC</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Deyou Xu</td>
|
||||
<td><a href="https://github.com/skyesx">skyesx</a></td>
|
||||
<td>WeBank</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Jinlei Zhuang</td>
|
||||
<td><a href="https://github.com/zjinlei">zjinlei</a></td>
|
||||
<td>Helios</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Jiawei Zhang</td>
|
||||
<td><a href="https://github.com/l81893521">l81893521</a></td>
|
||||
<td>Locals</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Zhengtao Zhong</td>
|
||||
<td><a href="https://github.com/jsbxyyx">jsbxyyx</a></td>
|
||||
<td>Shenzhen arts</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Long Chen</td>
|
||||
<td><a href="https://github.com/long187">long187</a></td>
|
||||
<td>Antfin</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<h2>Seata Developer Roles</h2>
|
||||
<p>Seata developers include three roles: Maintainer, Committer, and Contributor. The standard definitions for each role are as follows.</p>
|
||||
<h3>Maintainer</h3>
|
||||
<p>Maintainer is an individual who has made a significant contribution to the evolution and development of the Seata project, including projects under the seata group. Specifically includes the following criteria:</p>
|
||||
<ul>
|
||||
<li>Completing the design and development of multiple key modules or projects, is an core developer of the project.</li>
|
||||
<li>Continuous investment and passion, can actively participate in the maintenance of related matters such as community, official website, issue, PR, etc.</li>
|
||||
<li>Has a visible influence in the community and is able to represent Seata in important community meetings and events.</li>
|
||||
<li>Have the consciousness and ability to cultivate Committer and Contributor.</li>
|
||||
</ul>
|
||||
<h3>Committer</h3>
|
||||
<p>Committer is an individual with write access to the Seata repository and includes the following criteria:</p>
|
||||
<ul>
|
||||
<li>An individual who can contribute to the issue and PR continuously for a long time.</li>
|
||||
<li>Participate in the maintenance of the issue list and discussion of important features.</li>
|
||||
<li>Participate in code review.</li>
|
||||
</ul>
|
||||
<h3>Contributor</h3>
|
||||
<p>Contributor is an individual who contributes to the Seata project. The standard is:</p>
|
||||
<ul>
|
||||
<li>Submitted a PR that is merged.</li>
|
||||
</ul>
|
||||
</div></section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is an Alibaba open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/documentation.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"filename": "developers_dev.md",
|
||||
"__html": "<h2>Seata Team</h2>\n<p>This page shows Seata developers and continues to expand. The list is not prioritized.</p>\n<h1>Seata Committer List</h1>\n<table>\n<thead>\n<tr>\n<th>姓名</th>\n<th>github</th>\n<th>公司</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>Min Ji</td>\n<td><a href=\"https://github.com/slievrly\">slievrly</a></td>\n<td>Alibabba</td>\n</tr>\n<tr>\n<td>Haiqiang Shen</td>\n<td><a href=\"https://github.com/sharajava\">sharajava</a></td>\n<td>Alibabba</td>\n</tr>\n<tr>\n<td>Qipeng Li</td>\n<td><a href=\"https://github.com/wlliqipeng\">wlliqipeng</a></td>\n<td>Alibabba</td>\n</tr>\n<tr>\n<td>Liandong Chen</td>\n<td><a href=\"https://github.com/purple-force\">purple-force</a></td>\n<td>Alibabba</td>\n</tr>\n<tr>\n<td>Jiang Yu</td>\n<td><a href=\"https://github.com/jiangyu-gts\">jiangyu-gts</a></td>\n<td>Alibabba</td>\n</tr>\n<tr>\n<td>Wei Zhang</td>\n<td><a href=\"https://github.com/jezhang2014\">jezhang2014</a></td>\n<td>Alibabba</td>\n</tr>\n<tr>\n<td>Sen Zhang</td>\n<td><a href=\"https://github.com/zhangthen\">zhangthen</a></td>\n<td>Antfin</td>\n</tr>\n<tr>\n<td>Guangshu Wang</td>\n<td><a href=\"https://github.com/wgs13579\">wgs13579</a></td>\n<td>Antfin</td>\n</tr>\n<tr>\n<td>Geng Zhang</td>\n<td><a href=\"https://github.com/ujjboy\">ujjboy</a></td>\n<td>Antfin</td>\n</tr>\n<tr>\n<td>Zhiyuan Lei</td>\n<td><a href=\"https://github.com/leizhiyuan\">leizhiyuan</a></td>\n<td>Antfin</td>\n</tr>\n<tr>\n<td>Qing Wang</td>\n<td><a href=\"https://github.com/jovany-wang\">jovany-wang</a></td>\n<td>Antfin</td>\n</tr>\n<tr>\n<td>Jiangke Wu</td>\n<td><a href=\"https://github.com/xingfudeshi\">xingfudeshi</a></td>\n<td>Truthai</td>\n</tr>\n<tr>\n<td>Zhao Li</td>\n<td><a href=\"https://github.com/CoffeeLatte007\">CoffeeLatte007</a></td>\n<td>YuanFuDao</td>\n</tr>\n<tr>\n<td>Xin Wang</td>\n<td><a href=\"https://github.com/lovepoem\">lovepoem</a></td>\n<td>WeiDian</td>\n</tr>\n<tr>\n<td>Guoyao Yuan</td>\n<td><a href=\"https://github.com/github-ygy\">github-ygy</a></td>\n<td>Tuya</td>\n</tr>\n<tr>\n<td>Xu Zhang</td>\n<td><a href=\"https://github.com/zhangxu19830126\">zhangxu19830126</a></td>\n<td>InfiniVision</td>\n</tr>\n<tr>\n<td>Shuaipeng Ren</td>\n<td><a href=\"https://github.com/niaoshuai\">niaoshuai</a></td>\n<td>HuanQiuYouLu</td>\n</tr>\n<tr>\n<td>Donglin Zhai</td>\n<td><a href=\"https://github.com/tony-zdl\">tony-zdl</a></td>\n<td>Springs Capital</td>\n</tr>\n<tr>\n<td>Xugang Shen</td>\n<td><a href=\"https://github.com/xuririse\">xuririse</a></td>\n<td>CNIC</td>\n</tr>\n<tr>\n<td>Deyou Xu</td>\n<td><a href=\"https://github.com/skyesx\">skyesx</a></td>\n<td>WeBank</td>\n</tr>\n<tr>\n<td>Jinlei Zhuang</td>\n<td><a href=\"https://github.com/zjinlei\">zjinlei</a></td>\n<td>Helios</td>\n</tr>\n<tr>\n<td>Jiawei Zhang</td>\n<td><a href=\"https://github.com/l81893521\">l81893521</a></td>\n<td>Locals</td>\n</tr>\n<tr>\n<td>Zhengtao Zhong</td>\n<td><a href=\"https://github.com/jsbxyyx\">jsbxyyx</a></td>\n<td>Shenzhen arts</td>\n</tr>\n<tr>\n<td>Long Chen</td>\n<td><a href=\"https://github.com/long187\">long187</a></td>\n<td>Antfin</td>\n</tr>\n</tbody>\n</table>\n<h2>Seata Developer Roles</h2>\n<p>Seata developers include three roles: Maintainer, Committer, and Contributor. The standard definitions for each role are as follows.</p>\n<h3>Maintainer</h3>\n<p>Maintainer is an individual who has made a significant contribution to the evolution and development of the Seata project, including projects under the seata group. Specifically includes the following criteria:</p>\n<ul>\n<li>Completing the design and development of multiple key modules or projects, is an core developer of the project.</li>\n<li>Continuous investment and passion, can actively participate in the maintenance of related matters such as community, official website, issue, PR, etc.</li>\n<li>Has a visible influence in the community and is able to represent Seata in important community meetings and events.</li>\n<li>Have the consciousness and ability to cultivate Committer and Contributor.</li>\n</ul>\n<h3>Committer</h3>\n<p>Committer is an individual with write access to the Seata repository and includes the following criteria:</p>\n<ul>\n<li>An individual who can contribute to the issue and PR continuously for a long time.</li>\n<li>Participate in the maintenance of the issue list and discussion of important features.</li>\n<li>Participate in code review.</li>\n</ul>\n<h3>Contributor</h3>\n<p>Contributor is an individual who contributes to the Seata project. The standard is:</p>\n<ul>\n<li>Submitted a PR that is merged.</li>\n</ul>\n",
|
||||
"link": "/en-us/docs/developers/developers_dev.html",
|
||||
"meta": {
|
||||
"title": "Developers",
|
||||
"keywords": "Seata, Developers",
|
||||
"description": "Seata Team."
|
||||
}
|
||||
}
|
|
@ -1,185 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Seata" />
|
||||
<meta name="description" content="It is warmly welcomed if you have interest to hack on Seata. First, we encourage this kind of willing very much. And here is a list of contributing guide for you." />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>Contributing to Seata</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/documentation.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="documentation-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/developers/developers_dev.html" target="_self">DEVELOPERS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><div class="bar"><div class="bar-body"><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="front-img"/><span>Documentation</span><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="back-img"/></div></div><section class="content-section"><div class="sidemenu"><div class="sidemenu-toggle"><img src="https://img.alicdn.com/tfs/TB1E6apXHGYBuNjy0FoXXciBFXa-200-200.png"/></div><ul><li class="menu-item menu-item-level-1"><span>Overview</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/terminology.html" target="_self">Terminology</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/faq.html" target="_self">FAQ</a></li></ul></li><li class="menu-item menu-item-level-1"><span>User Doc</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/api.html" target="_self">API Guide</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/microservice.html" target="_self">Microservices Framework Supports</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Developer Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Transaction Mode<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/at-mode.html" target="_self">Seata AT mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/tcc-mode.html" target="_self">Seata TCC mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/saga-mode.html" target="_self">Seata Saga mode</a></li></ul></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/dev/seata-mertics.html" target="_self">Metrics design</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Ops Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/ops/multi-configuration-isolation.html" target="_self">Configuration Isolation</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Deploy<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-server.html" target="_self">Deploy Directly</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-docker.html" target="_self">Deploy by Docker</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-kubernetes.html" target="_self">Deploy by Kubernetes</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-helm.html" target="_self">Deploy by Helm</a></li></ul></li></ul></li></ul></div><div class="doc-content markdown-body"><h1>Contributing to Seata</h1>
|
||||
<p>It is warmly welcomed if you have interest to hack on Seata. First, we encourage this kind of willing very much. And here is a list of contributing guide for you.</p>
|
||||
<h2>Topics</h2>
|
||||
<ul>
|
||||
<li><a href="#reporting-security-issues">Reporting security issues</a></li>
|
||||
<li><a href="#reporting-general-issues">Reporting general issues</a></li>
|
||||
<li><a href="#code-and-doc-contribution">Code and doc contribution</a></li>
|
||||
<li><a href="#test-case-contribution">Test case contribution</a></li>
|
||||
<li><a href="#engage-to-help-anything">Engage to help anything</a></li>
|
||||
<li><a href="#code-style">Code Style</a></li>
|
||||
</ul>
|
||||
<h2>Reporting security issues</h2>
|
||||
<p>Security issues are always treated seriously. As our usual principle, we discourage anyone to spread security issues. If you find a security issue of Seata, please do not discuss it in public and even do not open a public issue. Instead we encourage you to send us a private email to <a href="mailto:dev-seata@googlegroups.com">dev-seata@googlegroups.com</a> to report this.</p>
|
||||
<h2>Reporting general issues</h2>
|
||||
<p>To be honest, we regard every user of Seata as a very kind contributor. After experiencing Seata, you may have some feedback for the project. Then feel free to open an issue via <a href="https://github.com/seata/seata/issues/new/choose">NEW ISSUE</a>.</p>
|
||||
<p>Since we collaborate project Seata in a distributed way, we appreciate <strong>WELL-WRITTEN</strong>, <strong>DETAILED</strong>, <strong>EXPLICIT</strong> issue reports. To make the communication more efficient, we wish everyone could search if your issue is an existing one in the searching list. If you find it existing, please add your details in comments under the existing issue instead of opening a brand new one.</p>
|
||||
<p>To make the issue details as standard as possible, we setup an <a href="https://github.com/seata/seata/blob/develop/.github/ISSUE_TEMPLATE">ISSUE TEMPLATE</a> for issue reporters. Please <strong>BE SURE</strong> to follow the instructions to fill fields in template.</p>
|
||||
<p>There are a lot of cases when you could open an issue:</p>
|
||||
<ul>
|
||||
<li>bug report</li>
|
||||
<li>feature request</li>
|
||||
<li>performance issues</li>
|
||||
<li>feature proposal</li>
|
||||
<li>feature design</li>
|
||||
<li>help wanted</li>
|
||||
<li>doc incomplete</li>
|
||||
<li>test improvement</li>
|
||||
<li>any questions on project</li>
|
||||
<li>and so on</li>
|
||||
</ul>
|
||||
<p>Also we must remind that when filling a new issue, please remember to remove the sensitive data from your post. Sensitive data could be password, secret key, network locations, private business data and so on.</p>
|
||||
<h2>Code and doc contribution</h2>
|
||||
<p>Every action to make project Seata better is encouraged. On GitHub, every improvement for Seata could be via a PR (short for pull request).</p>
|
||||
<ul>
|
||||
<li>If you find a typo, try to fix it!</li>
|
||||
<li>If you find a bug, try to fix it!</li>
|
||||
<li>If you find some redundant codes, try to remove them!</li>
|
||||
<li>If you find some test cases missing, try to add them!</li>
|
||||
<li>If you could enhance a feature, please <strong>DO NOT</strong> hesitate!</li>
|
||||
<li>If you find code implicit, try to add comments to make it clear!</li>
|
||||
<li>If you find code ugly, try to refactor that!</li>
|
||||
<li>If you can help to improve documents, it could not be better!</li>
|
||||
<li>If you find document incorrect, just do it and fix that!</li>
|
||||
<li>...</li>
|
||||
</ul>
|
||||
<p>Actually it is impossible to list them completely. Just remember one principle:</p>
|
||||
<blockquote>
|
||||
<p>WE ARE LOOKING FORWARD TO ANY PR FROM YOU.</p>
|
||||
</blockquote>
|
||||
<p>Since you are ready to improve Seata with a PR, we suggest you could take a look at the PR rules here.</p>
|
||||
<ul>
|
||||
<li><a href="#workspace-preparation">Workspace Preparation</a></li>
|
||||
<li><a href="#branch-definition">Branch Definition</a></li>
|
||||
<li><a href="#commit-rules">Commit Rules</a></li>
|
||||
<li><a href="#pr-description">PR Description</a></li>
|
||||
</ul>
|
||||
<h3>Workspace Preparation</h3>
|
||||
<p>To put forward a PR, we assume you have registered a GitHub ID. Then you could finish the preparation in the following steps:</p>
|
||||
<ol>
|
||||
<li>
|
||||
<p><strong>FORK</strong> Seata to your repository. To make this work, you just need to click the button Fork in right-left of <a href="https://github.com/seata/seata">seata/seata</a> main page. Then you will end up with your repository in <code>https://github.com/<your-username>/seata</code>, in which <code>your-username</code> is your GitHub username.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>CLONE</strong> your own repository to develop locally. Use <code>git clone git@github.com:<your-username>/seata.git</code> to clone repository to your local machine. Then you can create new branches to finish the change you wish to make.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p><strong>Set Remote</strong> upstream to be <code>git@github.com:seata/seata.git</code> using the following two commands:</p>
|
||||
</li>
|
||||
</ol>
|
||||
<pre><code>git remote add upstream git@github.com:seata/seata.git
|
||||
git remote set-url --push upstream no-pushing
|
||||
</code></pre>
|
||||
<p>With this remote setting, you can check your git remote configuration like this:</p>
|
||||
<pre><code>$ git remote -v
|
||||
origin git@github.com:<your-username>/seata.git (fetch)
|
||||
origin git@github.com:<your-username>/seata.git (push)
|
||||
upstream git@github.com:seata/seata.git (fetch)
|
||||
upstream no-pushing (push)
|
||||
</code></pre>
|
||||
<p>Adding this, we can easily synchronize local branches with upstream branches.</p>
|
||||
<h3>Branch Definition</h3>
|
||||
<p>Right now we assume every contribution via pull request is for <a href="https://github.com/seata/seata/tree/develop">branch develop</a> in Seata. Before contributing, be aware of branch definition would help a lot.</p>
|
||||
<p>As a contributor, keep in mind again that every contribution via pull request is for branch develop. While in project Seata, there are several other branches, we generally call them release branches(such as 0.6.0,0.6.1), feature branches, hotfix branches and master branch.</p>
|
||||
<p>When officially releasing a version, there will be a release branch and named with the version number.</p>
|
||||
<p>After the release, we will merge the commit of the release branch into the master branch.</p>
|
||||
<p>When we find that there is a bug in a certain version, we will decide to fix it in a later version or fix it in a specific hotfix version. When we decide to fix the hotfix version, we will checkout the hotfix branch based on the corresponding release branch, perform code repair and verification, and merge it into the develop branch and the master branch.</p>
|
||||
<p>For larger features, we will pull out the feature branch for development and verification.</p>
|
||||
<h3>Commit Rules</h3>
|
||||
<p>Actually in Seata, we take two rules serious when committing:</p>
|
||||
<ul>
|
||||
<li><a href="#commit-message">Commit Message</a></li>
|
||||
<li><a href="#commit-content">Commit Content</a></li>
|
||||
</ul>
|
||||
<h4>Commit Message</h4>
|
||||
<p>Commit message could help reviewers better understand what is the purpose of submitted PR. It could help accelerate the code review procedure as well. We encourage contributors to use <strong>EXPLICIT</strong> commit message rather than ambiguous message. In general, we advocate the following commit message type:</p>
|
||||
<ul>
|
||||
<li>docs: xxxx. For example, "docs: add docs about Seata cluster installation".</li>
|
||||
<li>feature: xxxx.For example, "feature: support oracle in AT mode".</li>
|
||||
<li>bugfix: xxxx. For example, "bugfix: fix panic when input nil parameter".</li>
|
||||
<li>refactor: xxxx. For example, "refactor: simplify to make codes more readable".</li>
|
||||
<li>test: xxx. For example, "test: add unit test case for func InsertIntoArray".</li>
|
||||
<li>other readable and explicit expression ways.</li>
|
||||
</ul>
|
||||
<p>On the other side, we discourage contributors from committing message like the following ways:</p>
|
||||
<ul>
|
||||
<li><s>fix bug</s></li>
|
||||
<li><s>update</s></li>
|
||||
<li><s>add doc</s></li>
|
||||
</ul>
|
||||
<p>If you get lost, please see <a href="http://chris.beams.io/posts/git-commit/">How to Write a Git Commit Message</a> for a start.</p>
|
||||
<h4>Commit Content</h4>
|
||||
<p>Commit content represents all content changes included in one commit. We had better include things in one single commit which could support reviewer's complete review without any other commits' help. In another word, contents in one single commit can pass the CI to avoid code mess. In brief, there are three minor rules for us to keep in mind:</p>
|
||||
<ul>
|
||||
<li>avoid very large change in a commit;</li>
|
||||
<li>complete and reviewable for each commit.</li>
|
||||
<li>check git config(<code>user.name</code>, <code>user.email</code>) when committing to ensure that it is associated with your github ID.</li>
|
||||
</ul>
|
||||
<p>In addition, in the code change part, we suggest that all contributors should read the <a href="#code-style">code style of Seata</a>.</p>
|
||||
<p>No matter commit message, or commit content, we do take more emphasis on code review.</p>
|
||||
<h3>PR Description</h3>
|
||||
<p>PR is the only way to make change to Seata project files. To help reviewers better get your purpose, PR description could not be too detailed. We encourage contributors to follow the <a href="./.github/PULL_REQUEST_TEMPLATE.md">PR template</a> to finish the pull request.</p>
|
||||
<h2>Test case contribution</h2>
|
||||
<p>Any test case would be welcomed. Currently, Seata function test cases are high priority.</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p>For unit test, you need to create a test file named <code>xxxTest.java</code> in the test directory of the same module. Recommend you to use the junit5 UT framework</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>For integration test, you can put the integration test in the test directory or the seata-test module. It is recommended to use the mockito test framework.</p>
|
||||
</li>
|
||||
</ul>
|
||||
<h2>Engage to help anything</h2>
|
||||
<p>We choose GitHub as the primary place for Seata to collaborate. So the latest updates of Seata are always here. Although contributions via PR is an explicit way to help, we still call for any other ways.</p>
|
||||
<ul>
|
||||
<li>reply to other's issues if you could;</li>
|
||||
<li>help solve other user's problems;</li>
|
||||
<li>help review other's PR design;</li>
|
||||
<li>help review other's codes in PR;</li>
|
||||
<li>discuss about Seata to make things clearer;</li>
|
||||
<li>advocate Seata technology beyond GitHub;</li>
|
||||
<li>write blogs on Seata and so on.</li>
|
||||
</ul>
|
||||
<h2>Code Style</h2>
|
||||
<p>Seata code style Comply with Alibaba Java Coding Guidelines.</p>
|
||||
<h3>Guidelines</h3>
|
||||
<p><a href="https://alibaba.github.io/Alibaba-Java-Coding-Guidelines/">Alibaba-Java-Coding-Guidelines</a></p>
|
||||
<h3>IDE Plugin Install(not necessary)</h3>
|
||||
<p><em>It is not necessary to install, if you want to find a problem when you are coding.</em></p>
|
||||
<h4>idea IDE</h4>
|
||||
<p><a href="https://github.com/alibaba/p3c/blob/master/idea-plugin/README.md">p3c-idea-plugin-install</a></p>
|
||||
<h4>eclipse IDE</h4>
|
||||
<p><a href="https://github.com/alibaba/p3c/blob/master/eclipse-plugin/README.md">p3c-eclipse-plugin-install</a></p>
|
||||
<p>In a word, <strong>ANY HELP IS CONTRIBUTION.</strong></p>
|
||||
</div></section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is an Alibaba open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/documentation.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
|
@ -1,72 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Seata, Maintainers" />
|
||||
<meta name="description" content="A list of Seata maintainers" />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>Seata Maintainers</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/documentation.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="documentation-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><div class="bar"><div class="bar-body"><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="front-img"/><span>Documentation</span><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="back-img"/></div></div><section class="content-section"><div class="sidemenu"><div class="sidemenu-toggle"><img src="https://img.alicdn.com/tfs/TB1E6apXHGYBuNjy0FoXXciBFXa-200-200.png"/></div><ul><li class="menu-item menu-item-level-1"><span>Overview</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/terminology.html" target="_self">Terminology</a></li></ul></li><li class="menu-item menu-item-level-1"><span>User Doc</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/api.html" target="_self">API Guide</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/microservice.html" target="_self">Microservices Framework Supports</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Developer Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Transaction Mode<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/at-mode.html" target="_self">Seata AT mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/tcc-mode.html" target="_self">Seata TCC mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/saga-mode.html" target="_self">Seata Saga mode</a></li></ul></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/dev/seata-mertics.html" target="_self">Metrics</a></li></ul></li><li class="menu-item menu-item-level-1"><span>FAQ</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/faq/faq.html" target="_self">FAQ</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Ops Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/ops/multi-configuration-isolation.html" target="_self">Metrics配置</a></li></ul></li></ul></div><div class="doc-content markdown-body"><h1>Seata Maintainers</h1>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="text-align:center">GitHub ID</th>
|
||||
<th style="text-align:center">Name</th>
|
||||
<th style="text-align:center">Email</th>
|
||||
<th style="text-align:center">Company</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="text-align:center"><a href="https://github.com/allencloud">allencloud</a></td>
|
||||
<td style="text-align:center">Allen Sun</td>
|
||||
<td style="text-align:center"><a href="mailto:allensun.shl@alibaba-inc.com">allensun.shl@alibaba-inc.com</a></td>
|
||||
<td style="text-align:center">Alibaba Group</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:center"><a href="https://github.com/chenchaobing">chenchaobing</a></td>
|
||||
<td style="text-align:center">Chaobing Chen</td>
|
||||
<td style="text-align:center"><a href="mailto:chenchaobing@126.com">chenchaobing@126.com</a></td>
|
||||
<td style="text-align:center">Meitu</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:center"><a href="https://github.com/garfield009">garfield009</a></td>
|
||||
<td style="text-align:center">Zuozheng Hu</td>
|
||||
<td style="text-align:center"><a href="mailto:zuozheng.hzz@alibaba-inc.com">zuozheng.hzz@alibaba-inc.com</a></td>
|
||||
<td style="text-align:center">Alibaba Group</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:center"><a href="https://github.com/lowzj">lowzj</a></td>
|
||||
<td style="text-align:center">Jin Zhang</td>
|
||||
<td style="text-align:center"><a href="mailto:zj3142063@gmail.com">zj3142063@gmail.com</a></td>
|
||||
<td style="text-align:center">Alibaba Group</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:center"><a href="https://github.com/wangj998">wangj998</a></td>
|
||||
<td style="text-align:center">Jian Wang</td>
|
||||
<td style="text-align:center"><a href="mailto:mingzhi.wj@alibaba-inc.com">mingzhi.wj@alibaba-inc.com</a></td>
|
||||
<td style="text-align:center">Alibaba Group</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:center"><a href="https://github.com/zhouhaibing089">zhouhaibing089</a></td>
|
||||
<td style="text-align:center">Haibing Zhou</td>
|
||||
<td style="text-align:center"><a href="mailto:zhouhaibing089@gmail.com">zhouhaibing089@gmail.com</a></td>
|
||||
<td style="text-align:center">eBay</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div></section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is dedicated to improving the efficiency of large-scale file distribution, building the go-to solution and standards of container image distribution, and providing you with file and image distribution service which is efficient, easy-to-use, and of high availability.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/documentation.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"filename": "maintainers.md",
|
||||
"__html": "<h1>Seata Maintainers</h1>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:center\">GitHub ID</th>\n<th style=\"text-align:center\">Name</th>\n<th style=\"text-align:center\">Email</th>\n<th style=\"text-align:center\">Company</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:center\"><a href=\"https://github.com/allencloud\">allencloud</a></td>\n<td style=\"text-align:center\">Allen Sun</td>\n<td style=\"text-align:center\"><a href=\"mailto:allensun.shl@alibaba-inc.com\">allensun.shl@alibaba-inc.com</a></td>\n<td style=\"text-align:center\">Alibaba Group</td>\n</tr>\n<tr>\n<td style=\"text-align:center\"><a href=\"https://github.com/chenchaobing\">chenchaobing</a></td>\n<td style=\"text-align:center\">Chaobing Chen</td>\n<td style=\"text-align:center\"><a href=\"mailto:chenchaobing@126.com\">chenchaobing@126.com</a></td>\n<td style=\"text-align:center\">Meitu</td>\n</tr>\n<tr>\n<td style=\"text-align:center\"><a href=\"https://github.com/garfield009\">garfield009</a></td>\n<td style=\"text-align:center\">Zuozheng Hu</td>\n<td style=\"text-align:center\"><a href=\"mailto:zuozheng.hzz@alibaba-inc.com\">zuozheng.hzz@alibaba-inc.com</a></td>\n<td style=\"text-align:center\">Alibaba Group</td>\n</tr>\n<tr>\n<td style=\"text-align:center\"><a href=\"https://github.com/lowzj\">lowzj</a></td>\n<td style=\"text-align:center\">Jin Zhang</td>\n<td style=\"text-align:center\"><a href=\"mailto:zj3142063@gmail.com\">zj3142063@gmail.com</a></td>\n<td style=\"text-align:center\">Alibaba Group</td>\n</tr>\n<tr>\n<td style=\"text-align:center\"><a href=\"https://github.com/wangj998\">wangj998</a></td>\n<td style=\"text-align:center\">Jian Wang</td>\n<td style=\"text-align:center\"><a href=\"mailto:mingzhi.wj@alibaba-inc.com\">mingzhi.wj@alibaba-inc.com</a></td>\n<td style=\"text-align:center\">Alibaba Group</td>\n</tr>\n<tr>\n<td style=\"text-align:center\"><a href=\"https://github.com/zhouhaibing089\">zhouhaibing089</a></td>\n<td style=\"text-align:center\">Haibing Zhou</td>\n<td style=\"text-align:center\"><a href=\"mailto:zhouhaibing089@gmail.com\">zhouhaibing089@gmail.com</a></td>\n<td style=\"text-align:center\">eBay</td>\n</tr>\n</tbody>\n</table>\n",
|
||||
"link": "/en-us/docs/developers/maintainers.html",
|
||||
"meta": {
|
||||
"title": "Seata Maintainers",
|
||||
"keywords": "Seata, Maintainers",
|
||||
"description": "A list of Seata maintainers"
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="faq" />
|
||||
<meta name="description" content="faq" />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>faq</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/documentation.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="documentation-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/docs/overview/what_is_seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li></ul></div></div></header><div class="bar"><div class="bar-body"><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="front-img"/><span>Documentation</span><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="back-img"/></div></div><section class="content-section"><div class="sidemenu"><div class="sidemenu-toggle"><img src="https://img.alicdn.com/tfs/TB1E6apXHGYBuNjy0FoXXciBFXa-200-200.png"/></div><ul><li class="menu-item menu-item-level-1"><span>Overview</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/what_is_seata.html" target="_self">What is Seata?</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/terminology.html" target="_self">Terminology</a></li></ul></li><li class="menu-item menu-item-level-1"><span>User Doc</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/api.html" target="_self">API Guide</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/microservice.html" target="_self">Microservices Framework Supports</a></li></ul></li><li class="menu-item menu-item-level-1"><span>FAQ</span><ul></ul></li></ul></div><div class="doc-content markdown-body"><h1>FAQ</h1>
|
||||
<p>TBD</p>
|
||||
</div></section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_white.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is dedicated to improving the efficiency of large-scale file distribution, building the go-to solution and standards of container image distribution, and providing you with file and image distribution service which is efficient, easy-to-use, and of high availability.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what_is_seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/documentation.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"filename": "faq.md",
|
||||
"__html": "<h1>FAQ</h1>\n<p>TBD</p>\n",
|
||||
"link": "/en-us/docs/faq.html",
|
||||
"meta": {}
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="faq" />
|
||||
<meta name="description" content="faq" />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>faq</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/documentation.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="documentation-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/developers/developers_dev.html" target="_self">DEVELOPERS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><div class="bar"><div class="bar-body"><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="front-img"/><span>Documentation</span><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="back-img"/></div></div><section class="content-section"><div class="sidemenu"><div class="sidemenu-toggle"><img src="https://img.alicdn.com/tfs/TB1E6apXHGYBuNjy0FoXXciBFXa-200-200.png"/></div><ul><li class="menu-item menu-item-level-1"><span>Overview</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/terminology.html" target="_self">Terminology</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/faq/faq.html" target="_self">FAQ</a></li></ul></li><li class="menu-item menu-item-level-1"><span>User Doc</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/api.html" target="_self">API Guide</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/microservice.html" target="_self">Microservices Framework Supports</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Developer Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Transaction Mode<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/at-mode.html" target="_self">Seata AT mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/tcc-mode.html" target="_self">Seata TCC mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/saga-mode.html" target="_self">Seata Saga mode</a></li></ul></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/dev/seata-mertics.html" target="_self">Metrics design</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Ops Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/ops/multi-configuration-isolation.html" target="_self">Configuration Isolation</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Deploy<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-server.html" target="_self">Deploy Directly</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-docker.html" target="_self">Deploy by Docker</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-kubernetes.html" target="_self">Deploy by Kubernetes</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-helm.html" target="_self">Deploy by Helm</a></li></ul></li></ul></li></ul></div><div class="doc-content markdown-body"><h1>FAQ</h1>
|
||||
<h2>java.lang.NoSuchMethodError: com.fasterxml.jackson.databind.jsontype.TypeSerializer.typeId(Ljava/lang/Object;Lcom/fasterxml/jackson/core/JsonToken;)</h2>
|
||||
<pre><code>undolog序列化配置为jackson时,jackson版本需要为2.9.9+
|
||||
</code></pre>
|
||||
</div></section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is an Alibaba open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/documentation.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"filename": "faq.md",
|
||||
"__html": "<h1>FAQ</h1>\n<h2>java.lang.NoSuchMethodError: com.fasterxml.jackson.databind.jsontype.TypeSerializer.typeId(Ljava/lang/Object;Lcom/fasterxml/jackson/core/JsonToken;)</h2>\n<pre><code>undolog序列化配置为jackson时,jackson版本需要为2.9.9+\n</code></pre>\n",
|
||||
"link": "/en-us/docs/faq/faq.html",
|
||||
"meta": {}
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="docker" />
|
||||
<meta name="description" content="Deploy Seata Server By Docker" />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>Deploy Seata Server By Docker</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/documentation.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="documentation-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/developers/developers_dev.html" target="_self">DEVELOPERS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><div class="bar"><div class="bar-body"><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="front-img"/><span>Documentation</span><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="back-img"/></div></div><section class="content-section"><div class="sidemenu"><div class="sidemenu-toggle"><img src="https://img.alicdn.com/tfs/TB1E6apXHGYBuNjy0FoXXciBFXa-200-200.png"/></div><ul><li class="menu-item menu-item-level-1"><span>Overview</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/terminology.html" target="_self">Terminology</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/faq.html" target="_self">FAQ</a></li></ul></li><li class="menu-item menu-item-level-1"><span>User Doc</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/api.html" target="_self">API Guide</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/microservice.html" target="_self">Microservices Framework Supports</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Developer Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Transaction Mode<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/at-mode.html" target="_self">Seata AT mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/tcc-mode.html" target="_self">Seata TCC mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/saga-mode.html" target="_self">Seata Saga mode</a></li></ul></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/dev/seata-mertics.html" target="_self">Metrics design</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Ops Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/ops/multi-configuration-isolation.html" target="_self">Configuration Isolation</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Deploy<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-server.html" target="_self">Deploy Directly</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-docker.html" target="_self">Deploy by Docker</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-kubernetes.html" target="_self">Deploy by Kubernetes</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-helm.html" target="_self">Deploy by Helm</a></li></ul></li></ul></li></ul></div><div class="doc-content markdown-body"><h1>Deploy Seata Server By Docker</h1>
|
||||
<h2>Quick Start</h2>
|
||||
<h4>Start a seata-server instance</h4>
|
||||
<pre><code class="language-bash">$ docker run --name seata-server -p 8091:8091 seataio/seata-server:latest
|
||||
</code></pre>
|
||||
<h4>Use custom configuration file</h4>
|
||||
<pre><code class="language-bash">$ docker run --name seata-server \
|
||||
-p 8091:8091 \
|
||||
-e SEATA_CONFIG_NAME=file:/root/seata-config/registry \
|
||||
-v /PATH/TO/CONFIG_FILE:/root/seata-config \
|
||||
seataio/seata-server
|
||||
</code></pre>
|
||||
<h4>Specify server IP</h4>
|
||||
<pre><code class="language-bash">$ docker run --name seata-server \
|
||||
-p 8091:8091 \
|
||||
-e SEATA_IP=192.168.1.1 \
|
||||
seataio/seata-server
|
||||
</code></pre>
|
||||
<h4>Docker compose</h4>
|
||||
<p>Example of <code>docker-conmpose.yaml</code></p>
|
||||
<pre><code class="language-yaml"><span class="hljs-attr">version:</span> <span class="hljs-string">"3"</span>
|
||||
<span class="hljs-attr">services:</span>
|
||||
<span class="hljs-attr">seata-server:</span>
|
||||
<span class="hljs-attr">image:</span> <span class="hljs-string">seataio/seata-server</span>
|
||||
<span class="hljs-attr">hostname:</span> <span class="hljs-string">seata-server</span>
|
||||
<span class="hljs-attr">ports:</span>
|
||||
<span class="hljs-bullet">-</span> <span class="hljs-string">"8091:8091"</span>
|
||||
<span class="hljs-attr">environment:</span>
|
||||
<span class="hljs-bullet">-</span> <span class="hljs-string">SEATA_PORT=8091</span>
|
||||
<span class="hljs-bullet">-</span> <span class="hljs-string">STORE_MODE=file</span>
|
||||
</code></pre>
|
||||
<h2>Container shell access and viewing logs</h2>
|
||||
<pre><code class="language-bash">$ docker <span class="hljs-built_in">exec</span> -it seata-server sh
|
||||
</code></pre>
|
||||
<pre><code class="language-bash">$ tail -f /root/logs/seata/seata-server.log
|
||||
</code></pre>
|
||||
<h2>Using custom configuration file</h2>
|
||||
<p>The default configuration could be found under path <code>/seata-server/resources</code>, suggest that put your custom configuration under other directories. And the environment variable<code>SEATA_CONFIG_NAME</code> is required when use custom configuration, and the value must be started with <code>file:</code> like <code>file:/root/seata-config/registry</code>:</p>
|
||||
<pre><code class="language-bash">$ docker run --name seata-server \
|
||||
-p 8091:8091 \
|
||||
-e SEATA_CONFIG_NAME=file:/root/seata-config/registry \
|
||||
-v /PATH/TO/CONFIG_FILE:/root/seata-config \
|
||||
seataio/seata-server
|
||||
</code></pre>
|
||||
<h2>Environment Variables</h2>
|
||||
<p>You can modify configuration of seata-server by the environment variables like this:</p>
|
||||
<ul>
|
||||
<li><strong>SEATA_IP</strong></li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<p>The variable is optional, specifies registry IP instead of the container IP in registry center like eureka or others.</p>
|
||||
</blockquote>
|
||||
<ul>
|
||||
<li><strong>SEATA_PORT</strong></li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<p>The variable is optional, specifies seata-server port, default is <code>8091</code></p>
|
||||
</blockquote>
|
||||
<ul>
|
||||
<li><strong>STORE_MODE</strong></li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<p>The variable is optional, specifies the log store mode of seata-server, support <code>db</code> and <code>file</code>, default is <code>file</code>.</p>
|
||||
</blockquote>
|
||||
<ul>
|
||||
<li><strong>SERVER_NODE</strong></li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<p>The variable is optional, specifies the seata-server node ID, like <code>1</code>,<code>2</code>,<code>3</code>..., default is <code>1</code></p>
|
||||
</blockquote>
|
||||
<ul>
|
||||
<li><strong>SEATA_ENV</strong></li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<p>The variable is optional, specifies the seata-server environment, like <code>dev</code>, <code>test</code> etc. Then server will find file like <code>registry-dev.conf</code> under the configuration path when start.</p>
|
||||
</blockquote>
|
||||
<ul>
|
||||
<li><strong>SEATA_CONFIG_NAME</strong></li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<p>The variable is optional, specifies the configuration file path, like the <code>file:/root/registry</code>, will load file<code>/root/registry.conf</code> as configuration.</p>
|
||||
</blockquote>
|
||||
</div></section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is an Alibaba open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/documentation.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"filename": "deploy-by-docker.md",
|
||||
"__html": "<h1>Deploy Seata Server By Docker</h1>\n<h2>Quick Start</h2>\n<h4>Start a seata-server instance</h4>\n<pre><code class=\"language-bash\">$ docker run --name seata-server -p 8091:8091 seataio/seata-server:latest\n</code></pre>\n<h4>Use custom configuration file</h4>\n<pre><code class=\"language-bash\">$ docker run --name seata-server \\\n -p 8091:8091 \\\n -e SEATA_CONFIG_NAME=file:/root/seata-config/registry \\\n -v /PATH/TO/CONFIG_FILE:/root/seata-config \\\n seataio/seata-server\n</code></pre>\n<h4>Specify server IP</h4>\n<pre><code class=\"language-bash\">$ docker run --name seata-server \\\n -p 8091:8091 \\\n -e SEATA_IP=192.168.1.1 \\\n seataio/seata-server\n</code></pre>\n<h4>Docker compose</h4>\n<p>Example of <code>docker-conmpose.yaml</code></p>\n<pre><code class=\"language-yaml\"><span class=\"hljs-attr\">version:</span> <span class=\"hljs-string\">\"3\"</span>\n<span class=\"hljs-attr\">services:</span>\n <span class=\"hljs-attr\">seata-server:</span>\n <span class=\"hljs-attr\">image:</span> <span class=\"hljs-string\">seataio/seata-server</span>\n <span class=\"hljs-attr\">hostname:</span> <span class=\"hljs-string\">seata-server</span>\n <span class=\"hljs-attr\">ports:</span>\n <span class=\"hljs-bullet\">-</span> <span class=\"hljs-string\">\"8091:8091\"</span>\n <span class=\"hljs-attr\">environment:</span>\n <span class=\"hljs-bullet\">-</span> <span class=\"hljs-string\">SEATA_PORT=8091</span>\n <span class=\"hljs-bullet\">-</span> <span class=\"hljs-string\">STORE_MODE=file</span>\n</code></pre>\n<h2>Container shell access and viewing logs</h2>\n<pre><code class=\"language-bash\">$ docker <span class=\"hljs-built_in\">exec</span> -it seata-server sh\n</code></pre>\n<pre><code class=\"language-bash\">$ tail -f /root/logs/seata/seata-server.log\n</code></pre>\n<h2>Using custom configuration file</h2>\n<p>The default configuration could be found under path <code>/seata-server/resources</code>, suggest that put your custom configuration under other directories. And the environment variable<code>SEATA_CONFIG_NAME</code> is required when use custom configuration, and the value must be started with <code>file:</code> like <code>file:/root/seata-config/registry</code>:</p>\n<pre><code class=\"language-bash\">$ docker run --name seata-server \\\n -p 8091:8091 \\\n -e SEATA_CONFIG_NAME=file:/root/seata-config/registry \\\n -v /PATH/TO/CONFIG_FILE:/root/seata-config \\\n seataio/seata-server\n</code></pre>\n<h2>Environment Variables</h2>\n<p>You can modify configuration of seata-server by the environment variables like this:</p>\n<ul>\n<li><strong>SEATA_IP</strong></li>\n</ul>\n<blockquote>\n<p>The variable is optional, specifies registry IP instead of the container IP in registry center like eureka or others.</p>\n</blockquote>\n<ul>\n<li><strong>SEATA_PORT</strong></li>\n</ul>\n<blockquote>\n<p>The variable is optional, specifies seata-server port, default is <code>8091</code></p>\n</blockquote>\n<ul>\n<li><strong>STORE_MODE</strong></li>\n</ul>\n<blockquote>\n<p>The variable is optional, specifies the log store mode of seata-server, support <code>db</code> and <code>file</code>, default is <code>file</code>.</p>\n</blockquote>\n<ul>\n<li><strong>SERVER_NODE</strong></li>\n</ul>\n<blockquote>\n<p>The variable is optional, specifies the seata-server node ID, like <code>1</code>,<code>2</code>,<code>3</code>..., default is <code>1</code></p>\n</blockquote>\n<ul>\n<li><strong>SEATA_ENV</strong></li>\n</ul>\n<blockquote>\n<p>The variable is optional, specifies the seata-server environment, like <code>dev</code>, <code>test</code> etc. Then server will find file like <code>registry-dev.conf</code> under the configuration path when start.</p>\n</blockquote>\n<ul>\n<li><strong>SEATA_CONFIG_NAME</strong></li>\n</ul>\n<blockquote>\n<p>The variable is optional, specifies the configuration file path, like the <code>file:/root/registry</code>, will load file<code>/root/registry.conf</code> as configuration.</p>\n</blockquote>\n",
|
||||
"link": "/en-us/docs/ops/deploy-by-docker.html",
|
||||
"meta": {
|
||||
"hidden": "true",
|
||||
"title": "Deploy Seata Server By Docker",
|
||||
"keywords": "docker",
|
||||
"description": "Deploy Seata Server By Docker",
|
||||
"author": "helloworlde",
|
||||
"date": "2019-11-25"
|
||||
}
|
||||
}
|
|
@ -1,69 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="kubernetes,helm,ops" />
|
||||
<meta name="description" content="Deploy Seata Server By Helm" />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>Deploy Seata Server By Helm</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/documentation.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="documentation-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/developers/developers_dev.html" target="_self">DEVELOPERS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><div class="bar"><div class="bar-body"><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="front-img"/><span>Documentation</span><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="back-img"/></div></div><section class="content-section"><div class="sidemenu"><div class="sidemenu-toggle"><img src="https://img.alicdn.com/tfs/TB1E6apXHGYBuNjy0FoXXciBFXa-200-200.png"/></div><ul><li class="menu-item menu-item-level-1"><span>Overview</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/terminology.html" target="_self">Terminology</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/faq.html" target="_self">FAQ</a></li></ul></li><li class="menu-item menu-item-level-1"><span>User Doc</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/api.html" target="_self">API Guide</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/microservice.html" target="_self">Microservices Framework Supports</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Developer Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Transaction Mode<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/at-mode.html" target="_self">Seata AT mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/tcc-mode.html" target="_self">Seata TCC mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/saga-mode.html" target="_self">Seata Saga mode</a></li></ul></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/dev/seata-mertics.html" target="_self">Metrics design</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Ops Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/ops/multi-configuration-isolation.html" target="_self">Configuration Isolation</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Deploy<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-server.html" target="_self">Deploy Directly</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-docker.html" target="_self">Deploy by Docker</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-kubernetes.html" target="_self">Deploy by Kubernetes</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-helm.html" target="_self">Deploy by Helm</a></li></ul></li></ul></li></ul></div><div class="doc-content markdown-body"><h1>Deploy Seata Server By Helm</h1>
|
||||
<h3>Quick start</h3>
|
||||
<pre><code class="language-bash">$ <span class="hljs-built_in">cd</span> ./script/server/helm/seata-server
|
||||
$ helm install seata-server ./seata-server
|
||||
</code></pre>
|
||||
<h2>Custom configuration</h2>
|
||||
<h3>Environment</h3>
|
||||
<p>The environment is same with Docker, can reference <a href="./deploy-by-docker.md">Deploy Seata Server By Docker</a></p>
|
||||
<h3>Use specify configuration file</h3>
|
||||
<p>Can specify configuration file by mount files, like mount files under <code>/root/workspace/seata/seata-config/file</code> to pod. And need specify environment <code>SEATA_CONFIG_NAME</code> also, the value need start with <code>file:</code>, like <code>file:/root/seata-config/registry</code></p>
|
||||
<ul>
|
||||
<li>Values.yaml</li>
|
||||
</ul>
|
||||
<pre><code class="language-yaml"><span class="hljs-attr">replicaCount:</span> <span class="hljs-number">1</span>
|
||||
|
||||
<span class="hljs-attr">namespace:</span> <span class="hljs-string">default</span>
|
||||
|
||||
<span class="hljs-attr">image:</span>
|
||||
<span class="hljs-attr">repository:</span> <span class="hljs-string">seataio/seata-server</span>
|
||||
<span class="hljs-attr">tag:</span> <span class="hljs-string">latest</span>
|
||||
<span class="hljs-attr">pullPolicy:</span> <span class="hljs-string">IfNotPresent</span>
|
||||
|
||||
<span class="hljs-attr">service:</span>
|
||||
<span class="hljs-attr">type:</span> <span class="hljs-string">NodePort</span>
|
||||
<span class="hljs-attr">port:</span> <span class="hljs-number">30091</span>
|
||||
|
||||
<span class="hljs-attr">env:</span>
|
||||
<span class="hljs-attr">seataPort:</span> <span class="hljs-string">"8091"</span>
|
||||
<span class="hljs-attr">storeMode:</span> <span class="hljs-string">"file"</span>
|
||||
<span class="hljs-attr">seataIp:</span> <span class="hljs-string">"127.0.0.1"</span>
|
||||
<span class="hljs-attr">seataConfigName:</span> <span class="hljs-string">"file:/root/seata-config/registry"</span>
|
||||
|
||||
<span class="hljs-attr">volume:</span>
|
||||
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">seata-config</span>
|
||||
<span class="hljs-attr">mountPath:</span> <span class="hljs-string">/root/seata-config</span>
|
||||
<span class="hljs-attr">hostPath:</span> <span class="hljs-string">/root/workspace/seata/seata-config/file</span>
|
||||
</code></pre>
|
||||
</div></section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is an Alibaba open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/documentation.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,13 +0,0 @@
|
|||
{
|
||||
"filename": "deploy-by-helm.md",
|
||||
"__html": "<h1>Deploy Seata Server By Helm</h1>\n<h3>Quick start</h3>\n<pre><code class=\"language-bash\">$ <span class=\"hljs-built_in\">cd</span> ./script/server/helm/seata-server\n$ helm install seata-server ./seata-server\n</code></pre>\n<h2>Custom configuration</h2>\n<h3>Environment</h3>\n<p>The environment is same with Docker, can reference <a href=\"./deploy-by-docker.md\">Deploy Seata Server By Docker</a></p>\n<h3>Use specify configuration file</h3>\n<p>Can specify configuration file by mount files, like mount files under <code>/root/workspace/seata/seata-config/file</code> to pod. And need specify environment <code>SEATA_CONFIG_NAME</code> also, the value need start with <code>file:</code>, like <code>file:/root/seata-config/registry</code></p>\n<ul>\n<li>Values.yaml</li>\n</ul>\n<pre><code class=\"language-yaml\"><span class=\"hljs-attr\">replicaCount:</span> <span class=\"hljs-number\">1</span>\n\n<span class=\"hljs-attr\">namespace:</span> <span class=\"hljs-string\">default</span>\n\n<span class=\"hljs-attr\">image:</span>\n <span class=\"hljs-attr\">repository:</span> <span class=\"hljs-string\">seataio/seata-server</span>\n <span class=\"hljs-attr\">tag:</span> <span class=\"hljs-string\">latest</span>\n <span class=\"hljs-attr\">pullPolicy:</span> <span class=\"hljs-string\">IfNotPresent</span>\n\n<span class=\"hljs-attr\">service:</span>\n <span class=\"hljs-attr\">type:</span> <span class=\"hljs-string\">NodePort</span>\n <span class=\"hljs-attr\">port:</span> <span class=\"hljs-number\">30091</span>\n\n<span class=\"hljs-attr\">env:</span>\n <span class=\"hljs-attr\">seataPort:</span> <span class=\"hljs-string\">\"8091\"</span>\n <span class=\"hljs-attr\">storeMode:</span> <span class=\"hljs-string\">\"file\"</span>\n <span class=\"hljs-attr\">seataIp:</span> <span class=\"hljs-string\">\"127.0.0.1\"</span>\n <span class=\"hljs-attr\">seataConfigName:</span> <span class=\"hljs-string\">\"file:/root/seata-config/registry\"</span>\n\n<span class=\"hljs-attr\">volume:</span>\n <span class=\"hljs-bullet\">-</span> <span class=\"hljs-attr\">name:</span> <span class=\"hljs-string\">seata-config</span>\n <span class=\"hljs-attr\">mountPath:</span> <span class=\"hljs-string\">/root/seata-config</span>\n <span class=\"hljs-attr\">hostPath:</span> <span class=\"hljs-string\">/root/workspace/seata/seata-config/file</span>\n</code></pre>\n",
|
||||
"link": "/en-us/docs/ops/deploy-by-helm.html",
|
||||
"meta": {
|
||||
"hidden": "true",
|
||||
"title": "Deploy Seata Server By Helm",
|
||||
"keywords": "kubernetes,helm,ops",
|
||||
"description": "Deploy Seata Server By Helm",
|
||||
"author": "helloworlde",
|
||||
"date": "2019-12-01"
|
||||
}
|
||||
}
|
|
@ -1,135 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="kubernetes,ops" />
|
||||
<meta name="description" content="Deploy Seata Server By Kubernetes" />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>Deploy Seata Server By Kubernetes</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/documentation.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="documentation-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/developers/developers_dev.html" target="_self">DEVELOPERS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><div class="bar"><div class="bar-body"><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="front-img"/><span>Documentation</span><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="back-img"/></div></div><section class="content-section"><div class="sidemenu"><div class="sidemenu-toggle"><img src="https://img.alicdn.com/tfs/TB1E6apXHGYBuNjy0FoXXciBFXa-200-200.png"/></div><ul><li class="menu-item menu-item-level-1"><span>Overview</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/terminology.html" target="_self">Terminology</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/faq.html" target="_self">FAQ</a></li></ul></li><li class="menu-item menu-item-level-1"><span>User Doc</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/api.html" target="_self">API Guide</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/microservice.html" target="_self">Microservices Framework Supports</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Developer Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Transaction Mode<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/at-mode.html" target="_self">Seata AT mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/tcc-mode.html" target="_self">Seata TCC mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/saga-mode.html" target="_self">Seata Saga mode</a></li></ul></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/dev/seata-mertics.html" target="_self">Metrics design</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Ops Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/ops/multi-configuration-isolation.html" target="_self">Configuration Isolation</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Deploy<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-server.html" target="_self">Deploy Directly</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-docker.html" target="_self">Deploy by Docker</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-kubernetes.html" target="_self">Deploy by Kubernetes</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-helm.html" target="_self">Deploy by Helm</a></li></ul></li></ul></li></ul></div><div class="doc-content markdown-body"><h1>Deploy Seata Server By Kubernetes</h1>
|
||||
<h3>Quick Start</h3>
|
||||
<p>Create file <code>seata-server.yaml</code></p>
|
||||
<pre><code class="language-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">v1</span>
|
||||
<span class="hljs-attr">kind:</span> <span class="hljs-string">Service</span>
|
||||
<span class="hljs-attr">metadata:</span>
|
||||
<span class="hljs-attr">name:</span> <span class="hljs-string">seata-server</span>
|
||||
<span class="hljs-attr">namespace:</span> <span class="hljs-string">default</span>
|
||||
<span class="hljs-attr">labels:</span>
|
||||
<span class="hljs-attr">k8s-app:</span> <span class="hljs-string">seata-server</span>
|
||||
<span class="hljs-attr">spec:</span>
|
||||
<span class="hljs-attr">type:</span> <span class="hljs-string">NodePort</span>
|
||||
<span class="hljs-attr">ports:</span>
|
||||
<span class="hljs-bullet">-</span> <span class="hljs-attr">port:</span> <span class="hljs-number">8091</span>
|
||||
<span class="hljs-attr">nodePort:</span> <span class="hljs-number">30091</span>
|
||||
<span class="hljs-attr">protocol:</span> <span class="hljs-string">TCP</span>
|
||||
<span class="hljs-attr">name:</span> <span class="hljs-string">http</span>
|
||||
<span class="hljs-attr">selector:</span>
|
||||
<span class="hljs-attr">k8s-app:</span> <span class="hljs-string">seata-server</span>
|
||||
|
||||
<span class="hljs-meta">---</span>
|
||||
|
||||
<span class="hljs-attr">apiVersion:</span> <span class="hljs-string">apps/v1</span>
|
||||
<span class="hljs-attr">kind:</span> <span class="hljs-string">Deployment</span>
|
||||
<span class="hljs-attr">metadata:</span>
|
||||
<span class="hljs-attr">name:</span> <span class="hljs-string">seata-server</span>
|
||||
<span class="hljs-attr">namespace:</span> <span class="hljs-string">default</span>
|
||||
<span class="hljs-attr">labels:</span>
|
||||
<span class="hljs-attr">k8s-app:</span> <span class="hljs-string">seata-server</span>
|
||||
<span class="hljs-attr">spec:</span>
|
||||
<span class="hljs-attr">replicas:</span> <span class="hljs-number">1</span>
|
||||
<span class="hljs-attr">selector:</span>
|
||||
<span class="hljs-attr">matchLabels:</span>
|
||||
<span class="hljs-attr">k8s-app:</span> <span class="hljs-string">seata-server</span>
|
||||
<span class="hljs-attr">template:</span>
|
||||
<span class="hljs-attr">metadata:</span>
|
||||
<span class="hljs-attr">labels:</span>
|
||||
<span class="hljs-attr">k8s-app:</span> <span class="hljs-string">seata-server</span>
|
||||
<span class="hljs-attr">spec:</span>
|
||||
<span class="hljs-attr">containers:</span>
|
||||
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">seata-server</span>
|
||||
<span class="hljs-attr">image:</span> <span class="hljs-string">docker.io/seataio/seata-server:latest</span>
|
||||
<span class="hljs-attr">imagePullPolicy:</span> <span class="hljs-string">IfNotPresent</span>
|
||||
<span class="hljs-attr">env:</span>
|
||||
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">SEATA_PORT</span>
|
||||
<span class="hljs-attr">value:</span> <span class="hljs-string">"8091"</span>
|
||||
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">STORE_MODE</span>
|
||||
<span class="hljs-attr">value:</span> <span class="hljs-string">file</span>
|
||||
<span class="hljs-attr">ports:</span>
|
||||
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">http</span>
|
||||
<span class="hljs-attr">containerPort:</span> <span class="hljs-number">8091</span>
|
||||
<span class="hljs-attr">protocol:</span> <span class="hljs-string">TCP</span>
|
||||
</code></pre>
|
||||
<pre><code class="language-bash">$ kubectl apply -f seata-server.yaml
|
||||
</code></pre>
|
||||
<h2>Custom configuration</h2>
|
||||
<h3>Environment</h3>
|
||||
<p>The environment is same with Docker, can reference <a href="./deploy-by-docker.md">Deploy Seata Server By Docker</a></p>
|
||||
<h3>Use specify configuration file</h3>
|
||||
<p>Can specify configuration file by mount files, like mount files under <code>/root/workspace/seata/seata-config/file</code> to pod. And need specify environment <code>SEATA_CONFIG_NAME</code> also, the value need start with <code>file:</code>, like <code>file:/root/seata-config/registry</code></p>
|
||||
<ul>
|
||||
<li>Deployment</li>
|
||||
</ul>
|
||||
<pre><code class="language-yaml"><span class="hljs-attr">apiVersion:</span> <span class="hljs-string">apps/v1</span>
|
||||
<span class="hljs-attr">kind:</span> <span class="hljs-string">Deployment</span>
|
||||
<span class="hljs-attr">metadata:</span>
|
||||
<span class="hljs-attr">name:</span> <span class="hljs-string">seata-server</span>
|
||||
<span class="hljs-attr">namespace:</span> <span class="hljs-string">default</span>
|
||||
<span class="hljs-attr">labels:</span>
|
||||
<span class="hljs-attr">k8s-app:</span> <span class="hljs-string">seata-server</span>
|
||||
<span class="hljs-attr">spec:</span>
|
||||
<span class="hljs-attr">replicas:</span> <span class="hljs-number">1</span>
|
||||
<span class="hljs-attr">selector:</span>
|
||||
<span class="hljs-attr">matchLabels:</span>
|
||||
<span class="hljs-attr">k8s-app:</span> <span class="hljs-string">seata-server</span>
|
||||
<span class="hljs-attr">template:</span>
|
||||
<span class="hljs-attr">metadata:</span>
|
||||
<span class="hljs-attr">labels:</span>
|
||||
<span class="hljs-attr">k8s-app:</span> <span class="hljs-string">seata-server</span>
|
||||
<span class="hljs-attr">spec:</span>
|
||||
<span class="hljs-attr">containers:</span>
|
||||
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">seata-server</span>
|
||||
<span class="hljs-attr">image:</span> <span class="hljs-string">docker.io/seataio/seata-server:latest</span>
|
||||
<span class="hljs-attr">imagePullPolicy:</span> <span class="hljs-string">IfNotPresent</span>
|
||||
<span class="hljs-attr">env:</span>
|
||||
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">SEATA_PORT</span>
|
||||
<span class="hljs-attr">value:</span> <span class="hljs-string">"8091"</span>
|
||||
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">STORE_MODE</span>
|
||||
<span class="hljs-attr">value:</span> <span class="hljs-string">file</span>
|
||||
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">SEATA_CONFIG_NAME</span>
|
||||
<span class="hljs-attr">value:</span> <span class="hljs-string">file:/root/seata-config/registry</span>
|
||||
<span class="hljs-attr">ports:</span>
|
||||
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">http</span>
|
||||
<span class="hljs-attr">containerPort:</span> <span class="hljs-number">8091</span>
|
||||
<span class="hljs-attr">protocol:</span> <span class="hljs-string">TCP</span>
|
||||
<span class="hljs-attr">volumeMounts:</span>
|
||||
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">seata-config</span>
|
||||
<span class="hljs-attr">mountPath:</span> <span class="hljs-string">/root/seata-config</span>
|
||||
<span class="hljs-attr">volumes:</span>
|
||||
<span class="hljs-bullet">-</span> <span class="hljs-attr">name:</span> <span class="hljs-string">seata-config</span>
|
||||
<span class="hljs-attr">hostPath:</span>
|
||||
<span class="hljs-attr">path:</span> <span class="hljs-string">/root/workspace/seata/seata-config/file</span>
|
||||
</code></pre>
|
||||
</div></section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is an Alibaba open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/documentation.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
|
@ -1,108 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Seata" />
|
||||
<meta name="description" content="The server can deploy by multiple method: Directly, Docker, Docker-Compose, Kubernetes, Helm." />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>Deploy Server</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/documentation.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="documentation-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/developers/developers_dev.html" target="_self">DEVELOPERS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><div class="bar"><div class="bar-body"><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="front-img"/><span>Documentation</span><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="back-img"/></div></div><section class="content-section"><div class="sidemenu"><div class="sidemenu-toggle"><img src="https://img.alicdn.com/tfs/TB1E6apXHGYBuNjy0FoXXciBFXa-200-200.png"/></div><ul><li class="menu-item menu-item-level-1"><span>Overview</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/terminology.html" target="_self">Terminology</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/faq.html" target="_self">FAQ</a></li></ul></li><li class="menu-item menu-item-level-1"><span>User Doc</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/api.html" target="_self">API Guide</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/microservice.html" target="_self">Microservices Framework Supports</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Developer Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Transaction Mode<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/at-mode.html" target="_self">Seata AT mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/tcc-mode.html" target="_self">Seata TCC mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/saga-mode.html" target="_self">Seata Saga mode</a></li></ul></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/dev/seata-mertics.html" target="_self">Metrics design</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Ops Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/ops/multi-configuration-isolation.html" target="_self">Configuration Isolation</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Deploy<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-server.html" target="_self">Deploy Directly</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-docker.html" target="_self">Deploy by Docker</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-kubernetes.html" target="_self">Deploy by Kubernetes</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-helm.html" target="_self">Deploy by Helm</a></li></ul></li></ul></li></ul></div><div class="doc-content markdown-body"><h1>Deploy Server</h1>
|
||||
<p>The server can deploy by multiple method: Directly, Docker, Docker-Compose, Kubernetes, Helm.</p>
|
||||
<h2>Directly</h2>
|
||||
<ol>
|
||||
<li>
|
||||
<p>Download the server application from <a href="https://github.com/seata/seata/releases">RELEASE</a> and unzip.</p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Startup</p>
|
||||
</li>
|
||||
</ol>
|
||||
<p>On Linux/Mac</p>
|
||||
<pre><code class="language-bash">$ sh ./bin/seata-server.sh
|
||||
</code></pre>
|
||||
<p>On Windows</p>
|
||||
<pre><code class="language-cmd">bin\seata-server.bat
|
||||
</code></pre>
|
||||
<h3>Arguments</h3>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="text-align:left">Argument</th>
|
||||
<th style="text-align:left">Fullname</th>
|
||||
<th style="text-align:left">Effect</th>
|
||||
<th style="text-align:left">Comment</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td style="text-align:left">-h</td>
|
||||
<td style="text-align:left">--host</td>
|
||||
<td style="text-align:left">Specify IP in registry center</td>
|
||||
<td style="text-align:left">Suggest to specify Virtural machine or cloud server, or will use internal IP</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">-p</td>
|
||||
<td style="text-align:left">--port</td>
|
||||
<td style="text-align:left">Specify startup port</td>
|
||||
<td style="text-align:left">default is 8091</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">-m</td>
|
||||
<td style="text-align:left">--storeMode</td>
|
||||
<td style="text-align:left">The way to save transaction log</td>
|
||||
<td style="text-align:left">Support <code>file</code> and <code>db</code>default is <code>file</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">-n</td>
|
||||
<td style="text-align:left">--serverNode</td>
|
||||
<td style="text-align:left">Specify the seata-server node ID</td>
|
||||
<td style="text-align:left">Like <code>1</code>,<code>2</code>,<code>3</code>..., default is <code>1</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="text-align:left">-e</td>
|
||||
<td style="text-align:left">--seataEnv</td>
|
||||
<td style="text-align:left">Specify the environment of seata-server</td>
|
||||
<td style="text-align:left">Like <code>dev</code>, <code>test</code> etc. Then will use file like <code>registry-dev.conf</code> as configuraiton</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>For example:</p>
|
||||
<pre><code class="language-bash">$ sh ./bin/seata-server.sh -p 8091 -h 127.0.0.1 -m file
|
||||
</code></pre>
|
||||
<h2>Deploy in container</h2>
|
||||
<p>Now support these method:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p><a href="./deploy-by-docker.md">Deploy Seata Server By Docker</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="./deploy-by-kubernetes.md">Deploy Seata Server By Kubernetes</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p><a href="./deploy-by-helm.md">Deploy Seata Server By Helm</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
</div></section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is an Alibaba open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/documentation.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"filename": "deploy-server.md",
|
||||
"__html": "<h1>Deploy Server</h1>\n<p>The server can deploy by multiple method: Directly, Docker, Docker-Compose, Kubernetes, Helm.</p>\n<h2>Directly</h2>\n<ol>\n<li>\n<p>Download the server application from <a href=\"https://github.com/seata/seata/releases\">RELEASE</a> and unzip.</p>\n</li>\n<li>\n<p>Startup</p>\n</li>\n</ol>\n<p>On Linux/Mac</p>\n<pre><code class=\"language-bash\">$ sh ./bin/seata-server.sh\n</code></pre>\n<p>On Windows</p>\n<pre><code class=\"language-cmd\">bin\\seata-server.bat\n</code></pre>\n<h3>Arguments</h3>\n<table>\n<thead>\n<tr>\n<th style=\"text-align:left\">Argument</th>\n<th style=\"text-align:left\">Fullname</th>\n<th style=\"text-align:left\">Effect</th>\n<th style=\"text-align:left\">Comment</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td style=\"text-align:left\">-h</td>\n<td style=\"text-align:left\">--host</td>\n<td style=\"text-align:left\">Specify IP in registry center</td>\n<td style=\"text-align:left\">Suggest to specify Virtural machine or cloud server, or will use internal IP</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">-p</td>\n<td style=\"text-align:left\">--port</td>\n<td style=\"text-align:left\">Specify startup port</td>\n<td style=\"text-align:left\">default is 8091</td>\n</tr>\n<tr>\n<td style=\"text-align:left\">-m</td>\n<td style=\"text-align:left\">--storeMode</td>\n<td style=\"text-align:left\">The way to save transaction log</td>\n<td style=\"text-align:left\">Support <code>file</code> and <code>db</code>default is <code>file</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\">-n</td>\n<td style=\"text-align:left\">--serverNode</td>\n<td style=\"text-align:left\">Specify the seata-server node ID</td>\n<td style=\"text-align:left\">Like <code>1</code>,<code>2</code>,<code>3</code>..., default is <code>1</code></td>\n</tr>\n<tr>\n<td style=\"text-align:left\">-e</td>\n<td style=\"text-align:left\">--seataEnv</td>\n<td style=\"text-align:left\">Specify the environment of seata-server</td>\n<td style=\"text-align:left\">Like <code>dev</code>, <code>test</code> etc. Then will use file like <code>registry-dev.conf</code> as configuraiton</td>\n</tr>\n</tbody>\n</table>\n<p>For example:</p>\n<pre><code class=\"language-bash\">$ sh ./bin/seata-server.sh -p 8091 -h 127.0.0.1 -m file\n</code></pre>\n<h2>Deploy in container</h2>\n<p>Now support these method:</p>\n<ul>\n<li>\n<p><a href=\"./deploy-by-docker.md\">Deploy Seata Server By Docker</a></p>\n</li>\n<li>\n<p><a href=\"./deploy-by-kubernetes.md\">Deploy Seata Server By Kubernetes</a></p>\n</li>\n<li>\n<p><a href=\"./deploy-by-helm.md\">Deploy Seata Server By Helm</a></p>\n</li>\n</ul>\n",
|
||||
"link": "/en-us/docs/ops/deploy-server.html",
|
||||
"meta": {
|
||||
"title": "Deploy Server",
|
||||
"keywords": "Seata",
|
||||
"description": "The server can deploy by multiple method: Directly, Docker, Docker-Compose, Kubernetes, Helm."
|
||||
}
|
||||
}
|
|
@ -1,66 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Seata" />
|
||||
<meta name="description" content="Seata supports Multi-configuration Isolation since 0.6.1,You can configure it in the following steps." />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>Multi-configuration Isolation</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/documentation.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="documentation-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/developers/developers_dev.html" target="_self">DEVELOPERS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><div class="bar"><div class="bar-body"><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="front-img"/><span>Documentation</span><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="back-img"/></div></div><section class="content-section"><div class="sidemenu"><div class="sidemenu-toggle"><img src="https://img.alicdn.com/tfs/TB1E6apXHGYBuNjy0FoXXciBFXa-200-200.png"/></div><ul><li class="menu-item menu-item-level-1"><span>Overview</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/terminology.html" target="_self">Terminology</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/faq.html" target="_self">FAQ</a></li></ul></li><li class="menu-item menu-item-level-1"><span>User Doc</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/api.html" target="_self">API Guide</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/microservice.html" target="_self">Microservices Framework Supports</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Developer Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Transaction Mode<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/at-mode.html" target="_self">Seata AT mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/tcc-mode.html" target="_self">Seata TCC mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/saga-mode.html" target="_self">Seata Saga mode</a></li></ul></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/dev/seata-mertics.html" target="_self">Metrics design</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Ops Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/ops/multi-configuration-isolation.html" target="_self">Configuration Isolation</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Deploy<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-server.html" target="_self">Deploy Directly</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-docker.html" target="_self">Deploy by Docker</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-kubernetes.html" target="_self">Deploy by Kubernetes</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-helm.html" target="_self">Deploy by Helm</a></li></ul></li></ul></li></ul></div><div class="doc-content markdown-body"><h1>Multi-configuration Isolation</h1>
|
||||
<p>Seata supports Multi-configuration Isolation since 0.6.1,You can configure it in the following steps.</p>
|
||||
<h2>use case</h2>
|
||||
<p>Suppose we now have a test environment in which we want to read only the configuration items corresponding to the test environment.</p>
|
||||
<h3>1.Environment Configuration</h3>
|
||||
<p>Seata provides two ways to set up different environments:</p>
|
||||
<ul>
|
||||
<li><strong>-Denv=test</strong>,where test is the name of the environment.</li>
|
||||
</ul>
|
||||
<pre><code class="language-shell">
|
||||
e.g.(Linux)
|
||||
|
||||
sh seata-server.sh -Denv=test
|
||||
</code></pre>
|
||||
<ul>
|
||||
<li>Use <strong>SEATA_CONFIG_ENV</strong> as the key of environment variable,and it's value will be the name of the environment.[<strong>recommended</strong>]</li>
|
||||
</ul>
|
||||
<pre><code class="language-shell">
|
||||
e.g.(Linux)
|
||||
<span class="hljs-meta">
|
||||
#</span><span class="bash">vi /etc/profile </span>
|
||||
|
||||
export SEATA_CONFIG_ENV=test
|
||||
|
||||
:wq
|
||||
<span class="hljs-meta">
|
||||
#</span><span class="bash"><span class="hljs-built_in">source</span> /etc/profile</span>
|
||||
</code></pre>
|
||||
<h3><a href="http://2.Name">2.Name</a> the new configuration file</h3>
|
||||
<ul>
|
||||
<li>Rename file.conf to file-env.conf,where env is the name of the environment. e.g. <strong>file-test.conf</strong></li>
|
||||
<li>Rename registry.conf to registry-env.conf,where env is the name of the environment. e.g. <strong>registry-test.conf</strong></li>
|
||||
</ul>
|
||||
<p>After all the steps have been set up, you can start using Seata configuration isolation.</p>
|
||||
</div></section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is an Alibaba open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/documentation.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"filename": "multi-configuration-isolation.md",
|
||||
"__html": "<h1>Multi-configuration Isolation</h1>\n<p>Seata supports Multi-configuration Isolation since 0.6.1,You can configure it in the following steps.</p>\n<h2>use case</h2>\n<p>Suppose we now have a test environment in which we want to read only the configuration items corresponding to the test environment.</p>\n<h3>1.Environment Configuration</h3>\n<p>Seata provides two ways to set up different environments:</p>\n<ul>\n<li><strong>-Denv=test</strong>,where test is the name of the environment.</li>\n</ul>\n<pre><code class=\"language-shell\">\ne.g.(Linux)\n\nsh seata-server.sh -Denv=test\n</code></pre>\n<ul>\n<li>Use <strong>SEATA_CONFIG_ENV</strong> as the key of environment variable,and it's value will be the name of the environment.[<strong>recommended</strong>]</li>\n</ul>\n<pre><code class=\"language-shell\">\ne.g.(Linux)\n<span class=\"hljs-meta\">\n#</span><span class=\"bash\">vi /etc/profile </span>\n\nexport SEATA_CONFIG_ENV=test\n\n:wq\n<span class=\"hljs-meta\">\n#</span><span class=\"bash\"><span class=\"hljs-built_in\">source</span> /etc/profile</span>\n</code></pre>\n<h3><a href=\"http://2.Name\">2.Name</a> the new configuration file</h3>\n<ul>\n<li>Rename file.conf to file-env.conf,where env is the name of the environment. e.g. <strong>file-test.conf</strong></li>\n<li>Rename registry.conf to registry-env.conf,where env is the name of the environment. e.g. <strong>registry-test.conf</strong></li>\n</ul>\n<p>After all the steps have been set up, you can start using Seata configuration isolation.</p>\n",
|
||||
"link": "/en-us/docs/ops/multi-configuration-isolation.html",
|
||||
"meta": {
|
||||
"title": "Multi-configuration Isolation",
|
||||
"keywords": "Seata",
|
||||
"description": "Seata supports Multi-configuration Isolation since 0.6.1,You can configure it in the following steps."
|
||||
}
|
||||
}
|
|
@ -1,137 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Seata" />
|
||||
<meta name="description" content="Seata FAQ." />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>Seata FAQ</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/documentation.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="documentation-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/developers/developers_dev.html" target="_self">DEVELOPERS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><div class="bar"><div class="bar-body"><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="front-img"/><span>Documentation</span><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="back-img"/></div></div><section class="content-section"><div class="sidemenu"><div class="sidemenu-toggle"><img src="https://img.alicdn.com/tfs/TB1E6apXHGYBuNjy0FoXXciBFXa-200-200.png"/></div><ul><li class="menu-item menu-item-level-1"><span>Overview</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/terminology.html" target="_self">Terminology</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/faq.html" target="_self">FAQ</a></li></ul></li><li class="menu-item menu-item-level-1"><span>User Doc</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/api.html" target="_self">API Guide</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/microservice.html" target="_self">Microservices Framework Supports</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Developer Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Transaction Mode<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/at-mode.html" target="_self">Seata AT mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/tcc-mode.html" target="_self">Seata TCC mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/saga-mode.html" target="_self">Seata Saga mode</a></li></ul></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/dev/seata-mertics.html" target="_self">Metrics design</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Ops Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/ops/multi-configuration-isolation.html" target="_self">Configuration Isolation</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Deploy<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-server.html" target="_self">Deploy Directly</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-docker.html" target="_self">Deploy by Docker</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-kubernetes.html" target="_self">Deploy by Kubernetes</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-helm.html" target="_self">Deploy by Helm</a></li></ul></li></ul></li></ul></div><div class="doc-content markdown-body"><h1>FAQ</h1>
|
||||
<p><a href="#1" target="_self">1.Can Seata be used in a production environment?</a></p>
|
||||
<p><a href="#2" target="_self">2.Dose Seata support high availability ?</a></p>
|
||||
<p><a href="#3" target="_self">3.What is the use of the record of undo log table log status = 1 ?</a></p>
|
||||
<p><a href="#4" target="_self">4.How to use the Seata framework to ensure transaction isolation?</a></p>
|
||||
<p><a href="#5" target="_self">5.When Failed to roll back dirty data, what shall I do ?</a></p>
|
||||
<p><a href="#6" target="_self">6.Why the global transaction state is not "begin" when a branch transaction is registered ?</a></p>
|
||||
<p><a href="#7" target="_self">7.When Nacos is used as the Seata configuration center, the project startup error report cannot find the service. How to check and deal with it ?</a></p>
|
||||
<p><a href="#8" target="_self">8.When Eureka is the registry and TC is highly available, how to overwrite Eureka properties at the TC end?</a></p>
|
||||
<p><a href="#9" target="_self">9.java.lang.NoSuchMethodError: com.fasterxml.jackson.databind.jsontype.TypeSerializer.typeId(Ljava/lang/Object;Lcom/fasterxml/jackson/core/JsonToken;)?</a></p>
|
||||
<p><a href="#10" target="_self">10. Why didn't my mybatis operation return auto-generated ID? </a></p>
|
||||
<hr>
|
||||
<h3 id='1'>Q: 1.Can Seata be used in a production environment?</h3>
|
||||
<p><strong>A:</strong>
|
||||
Since version 0.4.2,it is supported in production environment,Users who are using seata are welcome to complete this issue together:<a href="https://github.com/seata/seata/issues/1246">who's using Seata</a></p>
|
||||
<hr>
|
||||
<h3 id='2'>Q: 2.Dose Seata support high availability ?</h3>
|
||||
<p><strong>A:</strong>
|
||||
supported from version 0.6, tc USES db mode to share global transaction session information, and the registry USES non-file seata-supported third-party registries</p>
|
||||
<hr>
|
||||
<h3 id='3'>Q: 3.What is the use of the record of undo log table log status = 1 ?</h3>
|
||||
<p><strong>A:</strong></p>
|
||||
<p><strong>Scenario:</strong> after A branch transaction A registers TC, A global transaction rollback occurs before A local transaction commits</p>
|
||||
<p><strong>Consequence:</strong> global transaction rollback succeeds, a resource is occupied, resulting in resource suspension problem</p>
|
||||
<p><strong>Anti-suspension measures:</strong> when a rolls back and finds that the rollback undo has not been inserted, an undo record with log_status=1 is inserted. When a local transaction (business write operation SQL and corresponding undo are a local transaction) is committed, it fails due to the primary key conflict of the undo table.</p>
|
||||
<hr>
|
||||
<h3 id='4'>Q: 4.How to use the Seata framework to ensure transaction isolation?</h3>
|
||||
<p><strong>A:</strong>
|
||||
Since seata phase 1 local transactions have been committed, enhanced isolation is needed to prevent other transactions from dirty reads and dirty writes.</p>
|
||||
<ol>
|
||||
<li>Dirty read Select statement with for update, proxy method with @GlobalLock or @GlobalTransaction</li>
|
||||
<li>Dirty write You must use @globaltransaction
|
||||
note:If the interface of the business you are querying does not use the @globaltransactional annotation, which means there is no need for distributed transactions on the method, you can annotate the @globallock annotation on the method and add a for update statement to the query.
|
||||
If your query interface has the @globaltransactional annotation on the outer edge of the transactional link, you can simply add a for update statement to your query. The reason for designing this annotation is that before it is available, distributed transactions need to query the committed data, but the business does not need distributed transactions.
|
||||
Using the GlobalTransactional annotation adds some unnecessary additional RPC overhead such as begin returning xid, commit transaction, etc. GlobalLock simplifies the RPC process for higher performance.</li>
|
||||
</ol>
|
||||
<hr>
|
||||
<h3 id='5'>Q: 5.When Failed to roll back dirty data, what shall I do ?</h3>
|
||||
<p><strong>A:</strong></p>
|
||||
<ol>
|
||||
<li>The dirty data needs to be processed manually, and the data can be corrected according to the log prompt, or the corresponding undo can be deleted (the FailureHandler can be customized for email notification or other purposes).</li>
|
||||
<li>This option is not recommended when "undo" mirror validation is turned off during rollback.
|
||||
node:It is recommended to isolate the dirty data in advance</li>
|
||||
</ol>
|
||||
<hr>
|
||||
<h3 id='6'>Q: 6.Why the global transaction state is not "begin" when a branch transaction is registered ?</h3>
|
||||
<p><strong>A:</strong></p>
|
||||
<p><strong>abnormal:</strong> Could not register branch into global session xid = status = Rollbacked(Two phase state and Rollbacking, AsyncCommitting, etc) while expecting Begin</p>
|
||||
<p><strong>describe:</strong> When a branch transaction is registered, the global transaction status must be a one-phase state "begin", and registration other than "begin" is not allowed. It belongs to the normal processing at the seata framework level, and users can solve it from their own business level.</p>
|
||||
<p>This exception can occur in the following situations (you can continue to add).</p>
|
||||
<ol>
|
||||
<li>The branch transaction is asynchronous. The global transaction is not aware of its progress. The global transaction has entered phase 2 before the asynchronous branch comes to register.</li>
|
||||
<li>Service a rpc service b timed out (dubbo, feign, etc. timeout by default for 1 second), a throws an exception to tm, tm informs tc to roll back, but b still receives the request (network delay or rpc framework retry), and then registers at tc Global transaction was found to be rolling back.</li>
|
||||
<li>Tc is aware of the global transaction timeout (@globaltransactional (timeoutMills = default 60 seconds)), actively changes the state and notifies each branch transaction to rollback when a new branch transaction is registered.</li>
|
||||
</ol>
|
||||
<hr>
|
||||
<h3 id='7'>Q: 7.When Nacos is used as the Seata configuration center, the project startup error report cannot find the service. How to check and deal with it ?</h3>
|
||||
<p><strong>A:</strong>
|
||||
abnormal:io.seata.common.exception.FrameworkException: can not register RM,err:can not connect to services-server.</p>
|
||||
<ol>
|
||||
<li>Check the nacos configuration list to see if the seata configuration has been imported successfully.</li>
|
||||
<li>Check the list of nacos services to see if serverAddr has been registered successfully.</li>
|
||||
<li>Check the namespace, registry.nacos.namespace and config.nacos.namespace in the client's registry.conf and enter the nacos namespace ID. The default is "". The server and client correspond to the namespace.
|
||||
It is public and is a reserved control of nacos. If you need to create your own namespace, it is better not to use the same name as public, and use a name that has specific semantics in an actual business scenario.</li>
|
||||
<li>For the list of services on nacos, the IP address corresponding to serverAddr address should be the IP address specified for seata startup, such as: sh seata-server.sh-p 8091-h 122.51.204.197-m file.</li>
|
||||
<li>Check to see if the seata/conf/nacos-config.txt, transaction group service.vgroup_mapping.trade_group=default configuration is the same as the project group configuration name.</li>
|
||||
<li>Telnet IP port view ports are open as well as firewall status.
|
||||
note:1.Version 080 starts the specified IP problem, the exception "Exception in thread "main" java.lang.RuntimeException: java.net.BindException: Cannot assign request address", please upgrade to version 081 or above.
|
||||
The project USES jdk13 and starts with</li>
|
||||
</ol>
|
||||
<pre><code class="language-verilog"> Error: Could <span class="hljs-keyword">not</span> create the Java Virtual Machine
|
||||
Error: A fatal exception has occurred. Program will exit.
|
||||
</code></pre>
|
||||
<p> If the environment is sh, replace the last paragraph in the script:</p>
|
||||
<pre><code class="language-shell"> exec "$JAVACMD" $JAVA_OPTS -server -Xmx2048m -Xms2048m -Xmn1024m -Xss512k -XX:SurvivorRatio=10 -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=256m -XX:
|
||||
MaxDirectMemorySize=1024m -XX:-OmitStackTraceInFastThrow -XX:-UseAdaptiveSizePolicy -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath="$BASEDIR"/logs
|
||||
/java_heapdump.hprof -XX:+DisableExplicitGC -XX:+CMSParallelRemarkEnabled -XX:+
|
||||
UseCMSInitiatingOccupancyOnly -XX:CMSInitiatingOccupancyFraction=75 -verbose:gc -Dio.netty.leakDetectionLevel=advanced \
|
||||
-classpath "$CLASSPATH" \
|
||||
-Dapp.name="seata-server" \
|
||||
-Dapp.pid="$$" \
|
||||
-Dapp.repo="$REPO" \
|
||||
-Dapp.home="$BASEDIR" \
|
||||
-Dbasedir="$BASEDIR" \
|
||||
io.seata.server.Server \
|
||||
"$@"
|
||||
</code></pre>
|
||||
<hr>
|
||||
<h3 id='8'>Q: 8.When Eureka is the registry and TC is highly available, how to overwrite Eureka properties at the TC end?</h3>
|
||||
<p><strong>A:</strong>
|
||||
Add the eureka-client.properties file in the seata\conf directory and add the Eureka properties to be overwritten.
|
||||
For example, to overwrite eureka.instance.lease-renewal-interval-in-seconds and eureka.instance.lease-expiration-duration-in-seconds, add the following:</p>
|
||||
<pre><code class="language-java">eureka.lease.renewalInterval=<span class="hljs-number">1</span>
|
||||
eureka.lease.duration=<span class="hljs-number">2</span>
|
||||
</code></pre>
|
||||
<p>The attribute prefix is eureka, and the subsequent attribute names can refer to the class com.netflix.appinfo.PropertyBasedInstanceConfigConstants. You can also study the seata-discovery-eureka project of the discovery module in the seata source code.</p>
|
||||
<hr>
|
||||
<h3 id='9'>Q: 9.What's the reason of java.lang.NoSuchMethodError: com.fasterxml.jackson.databind.jsontype.TypeSerializer.typeId(Ljava/lang/Object;Lcom/fasterxml/jackson/core/JsonToken;) ?</h3>
|
||||
<p><strong>A:</strong>
|
||||
when the undolog serialization is configured as Jackson, the Jackson version needs to be 2.9.9+</p>
|
||||
<hr>
|
||||
<h3 id='10'>Q: 10. Why didn't my mybatis operation return auto-generated ID? </h3>
|
||||
<p><strong>A:</strong>
|
||||
You should update the configuraton of <code>mybatis</code>: set annotation <code>@Options(useGeneratedKeys = true, keyProperty = "id")</code> or set the value of useGeneratedKeys and keyProperty in <code>mybatis</code> xml configuraton</p>
|
||||
<hr>
|
||||
</div></section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is an Alibaba open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/documentation.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
|
@ -1,39 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Seata" />
|
||||
<meta name="description" content="Seata Terminology." />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>Seata Terminology</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/documentation.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="documentation-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/developers/developers_dev.html" target="_self">DEVELOPERS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><div class="bar"><div class="bar-body"><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="front-img"/><span>Documentation</span><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="back-img"/></div></div><section class="content-section"><div class="sidemenu"><div class="sidemenu-toggle"><img src="https://img.alicdn.com/tfs/TB1E6apXHGYBuNjy0FoXXciBFXa-200-200.png"/></div><ul><li class="menu-item menu-item-level-1"><span>Overview</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/terminology.html" target="_self">Terminology</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/faq.html" target="_self">FAQ</a></li></ul></li><li class="menu-item menu-item-level-1"><span>User Doc</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/api.html" target="_self">API Guide</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/microservice.html" target="_self">Microservices Framework Supports</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Developer Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Transaction Mode<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/at-mode.html" target="_self">Seata AT mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/tcc-mode.html" target="_self">Seata TCC mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/saga-mode.html" target="_self">Seata Saga mode</a></li></ul></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/dev/seata-mertics.html" target="_self">Metrics design</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Ops Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/ops/multi-configuration-isolation.html" target="_self">Configuration Isolation</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Deploy<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-server.html" target="_self">Deploy Directly</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-docker.html" target="_self">Deploy by Docker</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-kubernetes.html" target="_self">Deploy by Kubernetes</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-helm.html" target="_self">Deploy by Helm</a></li></ul></li></ul></li></ul></div><div class="doc-content markdown-body"><h1>Seata Terminology</h1>
|
||||
<h4>TC - Transaction Coordinator</h4>
|
||||
<p>Maintain status of global and branch transactions, drive the global commit or rollback.</p>
|
||||
<h4>TM - Transaction Manager</h4>
|
||||
<p>Define the scope of global transaction: begin a global transaction, commit or rollback a global transaction.</p>
|
||||
<h4>RM - Resource Manager</h4>
|
||||
<p>Manage resources that branch transactions working on, talk to TC for registering branch transactions and reporting status of branch transactions, and drive the branch transaction commit or rollback.</p>
|
||||
</div></section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is an Alibaba open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/documentation.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,10 +0,0 @@
|
|||
{
|
||||
"filename": "terminology.md",
|
||||
"__html": "<h1>Seata Terminology</h1>\n<h4>TC - Transaction Coordinator</h4>\n<p>Maintain status of global and branch transactions, drive the global commit or rollback.</p>\n<h4>TM - Transaction Manager</h4>\n<p>Define the scope of global transaction: begin a global transaction, commit or rollback a global transaction.</p>\n<h4>RM - Resource Manager</h4>\n<p>Manage resources that branch transactions working on, talk to TC for registering branch transactions and reporting status of branch transactions, and drive the branch transaction commit or rollback.</p>\n",
|
||||
"link": "/en-us/docs/overview/terminology.html",
|
||||
"meta": {
|
||||
"title": "Seata Terminology",
|
||||
"keywords": "Seata",
|
||||
"description": "Seata Terminology."
|
||||
}
|
||||
}
|
|
@ -1,318 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Seata" />
|
||||
<meta name="description" content="Seata is an open source distributed transaction solution dedicated to providing high performance and easy to use distributed transaction services. Seata will provide users with AT, TCC, SAGA, and XA transaction models to create a one-stop distributed solution for users." />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>What Is Seata</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/documentation.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="documentation-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/developers/developers_dev.html" target="_self">DEVELOPERS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><div class="bar"><div class="bar-body"><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="front-img"/><span>Documentation</span><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="back-img"/></div></div><section class="content-section"><div class="sidemenu"><div class="sidemenu-toggle"><img src="https://img.alicdn.com/tfs/TB1E6apXHGYBuNjy0FoXXciBFXa-200-200.png"/></div><ul><li class="menu-item menu-item-level-1"><span>Overview</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/terminology.html" target="_self">Terminology</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/faq.html" target="_self">FAQ</a></li></ul></li><li class="menu-item menu-item-level-1"><span>User Doc</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/api.html" target="_self">API Guide</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/microservice.html" target="_self">Microservices Framework Supports</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Developer Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Transaction Mode<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/at-mode.html" target="_self">Seata AT mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/tcc-mode.html" target="_self">Seata TCC mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/saga-mode.html" target="_self">Seata Saga mode</a></li></ul></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/dev/seata-mertics.html" target="_self">Metrics design</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Ops Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/ops/multi-configuration-isolation.html" target="_self">Configuration Isolation</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Deploy<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-server.html" target="_self">Deploy Directly</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-docker.html" target="_self">Deploy by Docker</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-kubernetes.html" target="_self">Deploy by Kubernetes</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-helm.html" target="_self">Deploy by Helm</a></li></ul></li></ul></li></ul></div><div class="doc-content markdown-body"><h1>What Is Seata?</h1>
|
||||
<p>Seata is an open source distributed transaction solution dedicated to providing high performance and easy to use distributed transaction services. Seata will provide users with AT, TCC, SAGA, and XA transaction models to create a one-stop distributed solution for users.</p>
|
||||
<h1>AT Mode</h1>
|
||||
<h2>Prerequisite</h2>
|
||||
<ul>
|
||||
<li>Relational databases that support local ACID transaction.</li>
|
||||
<li>Java applications that access database via JDBC.</li>
|
||||
</ul>
|
||||
<h2>Overall mechanism</h2>
|
||||
<p>Evolution from the two phases commit protocol:</p>
|
||||
<ul>
|
||||
<li>Phase 1:commit business data and rollback log in the same local transaction, then release local lock and connection resources.</li>
|
||||
<li>Phase 2:
|
||||
<ul>
|
||||
<li>for commit case, do the work asynchronously and quickly.</li>
|
||||
<li>for rollback case, do compensation, base on the rollback log created in the phase 1.</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<h1>Write isolation</h1>
|
||||
<ul>
|
||||
<li>The <strong>global lock</strong> must be acquired before committing the local transaction of phase 1.</li>
|
||||
<li>If the <strong>global lock</strong> is not acquired, the local transaction should not be committed.</li>
|
||||
<li>One transaction will try to acquire the <strong>global lock</strong> many times if it fails to, but there is a timeout, if it's timeout, rollback local transaction and release local lock as well.</li>
|
||||
</ul>
|
||||
<p>For example:</p>
|
||||
<p>Two transactions tx1 and tx2 are trying to update field m of table a. The original value of m is 1000.</p>
|
||||
<p>tx1 starts first, begins a local transaction, acquires the local lock, do the update operation: m = 1000 - 100 = 900. tx1 must acquire the <strong>global lock</strong> before committing the local transaction, after that, commit local transaction and release local lock.</p>
|
||||
<p>next, tx2 begins local transaction, acquires local lock, do the update operation: m = 900 - 100 = 800. Before tx2 can commit local transaction, it must acquire the <strong>global lock</strong>, but the <strong>global lock</strong> may be hold by tx1, so tx2 will do retry. After tx1 does the global commit and releases the <strong>global lock</strong>, tx2 can acquire the <strong>global lock</strong>, then it can commit local transaction and release local lock.</p>
|
||||
<p><img src="/img/overview-1.png" alt="Write-Isolation: Commit"></p>
|
||||
<p>See the figure above, tx1 does the global commit in phase 2 and release the <strong>global lock</strong>, tx2 acquires the <strong>global lock</strong> and commits local transaction.</p>
|
||||
<p><img src="/img/overview-2.png" alt="Write-Isolation: Rollback"></p>
|
||||
<p>See the figure above, if tx1 wants to do the global rollback, it must acquire local lock to revert the update operation of phase 1.</p>
|
||||
<p>However, now the local lock is held by tx2 which hopes to acquire the <strong>global lock</strong>, so tx1 fails to rollback, but it would try it many times until it's timeout for tx2 to acquire the <strong>global lock</strong>, then tx2 rollbacks local transaction and releases local lock, after that, tx1 can acquire the local lock, and do the branch rollback successfully.</p>
|
||||
<p>Because the <strong>global lock</strong> is held by tx1 during the whole process, there isn't no problem of <strong>dirty write</strong>.</p>
|
||||
<h1>Read isolation</h1>
|
||||
<p>The isolation level of local database is <strong>read committed</strong> or above, so the default isolation level of the global transaction is <strong>read uncommitted</strong>.</p>
|
||||
<p>If it needs the isolation level of the global transaction is <strong>read committed</strong>, currently, Seata implements it via SELECT FOR UPDATE statement.</p>
|
||||
<p><img src="/img/overview-3.png" alt="Read Isolation: SELECT FOR UPDATE"></p>
|
||||
<p>The <strong>global lock</strong> is be applied during the execution of SELECT FOR UPDATE statement, if the <strong>global lock</strong> is held by other transactions, the transaction will release local lock retry execute the SELECT FOR UPDATE statement. During the whole process, the query is blocked until the <strong>global lock</strong> is acquired, if the lock is acquired, it means the other global transaction has committed, so the isolation level of global transaction is <strong>read committed</strong>.</p>
|
||||
<p>For the performance consideration, Seata only does proxy work for SELECT FOR UPDATE. For the general SELECT statement, do nothing.</p>
|
||||
<h1>Work process</h1>
|
||||
<p>Take an example to illustrate it.</p>
|
||||
<p>A business table:<code>product</code></p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Type</th>
|
||||
<th>Key</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>id</td>
|
||||
<td>bigint(20)</td>
|
||||
<td>PRI</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>name</td>
|
||||
<td>varchar(100)</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>since</td>
|
||||
<td>varchar(100)</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>The sql of branch transaction in AT mode:</p>
|
||||
<pre><code class="language-sql"><span class="hljs-keyword">update</span> product <span class="hljs-keyword">set</span> <span class="hljs-keyword">name</span> = <span class="hljs-string">'GTS'</span> <span class="hljs-keyword">where</span> <span class="hljs-keyword">name</span> = <span class="hljs-string">'TXC'</span>;
|
||||
</code></pre>
|
||||
<h2>Phase 1</h2>
|
||||
<p>Process:</p>
|
||||
<ol>
|
||||
<li>Parse sql: know the sql type is update operation, table name is product, the where condition is name = 'TXC' and so on.</li>
|
||||
<li>Query the data before update(Named before image): In order to locate the data that will be updated, generate a query statement by the where condition above.</li>
|
||||
</ol>
|
||||
<pre><code class="language-sql"><span class="hljs-keyword">select</span> <span class="hljs-keyword">id</span>, <span class="hljs-keyword">name</span>, since <span class="hljs-keyword">from</span> product <span class="hljs-keyword">where</span> <span class="hljs-keyword">name</span> = <span class="hljs-string">'TXC'</span>;
|
||||
</code></pre>
|
||||
<p>Got the "before image":</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>id</th>
|
||||
<th>name</th>
|
||||
<th>since</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>TXC</td>
|
||||
<td>2014</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<ol start="3">
|
||||
<li>Execute the update sql: update the record of name equals 'GTS'.</li>
|
||||
<li>Query the data after update(Named after image): locate the record by the <strong>primary key</strong> of image data before update.</li>
|
||||
</ol>
|
||||
<pre><code class="language-sql"><span class="hljs-keyword">select</span> <span class="hljs-keyword">id</span>, <span class="hljs-keyword">name</span>, since <span class="hljs-keyword">from</span> product <span class="hljs-keyword">where</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">1</span>;
|
||||
</code></pre>
|
||||
<p>Got the after image:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>id</th>
|
||||
<th>name</th>
|
||||
<th>since</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>1</td>
|
||||
<td>GTS</td>
|
||||
<td>2014</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<ol start="5">
|
||||
<li>Insert a rollback log: build the rollback log with image before and after, as well as SQL statement relelated information, then insert into table <code>UNDO_LOG</code> .</li>
|
||||
</ol>
|
||||
<pre><code class="language-json">{
|
||||
<span class="hljs-attr">"branchId"</span>: <span class="hljs-number">641789253</span>,
|
||||
<span class="hljs-attr">"undoItems"</span>: [{
|
||||
<span class="hljs-attr">"afterImage"</span>: {
|
||||
<span class="hljs-attr">"rows"</span>: [{
|
||||
<span class="hljs-attr">"fields"</span>: [{
|
||||
<span class="hljs-attr">"name"</span>: <span class="hljs-string">"id"</span>,
|
||||
<span class="hljs-attr">"type"</span>: <span class="hljs-number">4</span>,
|
||||
<span class="hljs-attr">"value"</span>: <span class="hljs-number">1</span>
|
||||
}, {
|
||||
<span class="hljs-attr">"name"</span>: <span class="hljs-string">"name"</span>,
|
||||
<span class="hljs-attr">"type"</span>: <span class="hljs-number">12</span>,
|
||||
<span class="hljs-attr">"value"</span>: <span class="hljs-string">"GTS"</span>
|
||||
}, {
|
||||
<span class="hljs-attr">"name"</span>: <span class="hljs-string">"since"</span>,
|
||||
<span class="hljs-attr">"type"</span>: <span class="hljs-number">12</span>,
|
||||
<span class="hljs-attr">"value"</span>: <span class="hljs-string">"2014"</span>
|
||||
}]
|
||||
}],
|
||||
<span class="hljs-attr">"tableName"</span>: <span class="hljs-string">"product"</span>
|
||||
},
|
||||
<span class="hljs-attr">"beforeImage"</span>: {
|
||||
<span class="hljs-attr">"rows"</span>: [{
|
||||
<span class="hljs-attr">"fields"</span>: [{
|
||||
<span class="hljs-attr">"name"</span>: <span class="hljs-string">"id"</span>,
|
||||
<span class="hljs-attr">"type"</span>: <span class="hljs-number">4</span>,
|
||||
<span class="hljs-attr">"value"</span>: <span class="hljs-number">1</span>
|
||||
}, {
|
||||
<span class="hljs-attr">"name"</span>: <span class="hljs-string">"name"</span>,
|
||||
<span class="hljs-attr">"type"</span>: <span class="hljs-number">12</span>,
|
||||
<span class="hljs-attr">"value"</span>: <span class="hljs-string">"TXC"</span>
|
||||
}, {
|
||||
<span class="hljs-attr">"name"</span>: <span class="hljs-string">"since"</span>,
|
||||
<span class="hljs-attr">"type"</span>: <span class="hljs-number">12</span>,
|
||||
<span class="hljs-attr">"value"</span>: <span class="hljs-string">"2014"</span>
|
||||
}]
|
||||
}],
|
||||
<span class="hljs-attr">"tableName"</span>: <span class="hljs-string">"product"</span>
|
||||
},
|
||||
<span class="hljs-attr">"sqlType"</span>: <span class="hljs-string">"UPDATE"</span>
|
||||
}],
|
||||
<span class="hljs-attr">"xid"</span>: <span class="hljs-string">"xid:xxx"</span>
|
||||
}
|
||||
</code></pre>
|
||||
<ol start="6">
|
||||
<li>Before local commit, the transaction submmit an application to TC to acquire a <strong>global lock</strong> for the record whose primary key equals 1 in the table product.</li>
|
||||
<li>Commit local transaction: commit the update of PRODUCT table and the insert of UNDO_LOG table in the same local transaction.</li>
|
||||
<li>Report the result of step 7 to TC.</li>
|
||||
</ol>
|
||||
<h2>Phase 2 - Rollback case</h2>
|
||||
<ol>
|
||||
<li>After receive the rollback request from TC, begin a local transaction, execute operation as following.</li>
|
||||
<li>Retrieve the UNDO LOG by XID and Branch ID.</li>
|
||||
<li>Validate data: Compare the image data after update in UNDO LOG with current data, if there is difference, it means the data has been changed by operation out of current transaction, it should be handled in different policy, we will describe it detailedly in other document.</li>
|
||||
<li>Generate rollback SQL statement base on before image in UNDO LOG and related information of the business SQL.</li>
|
||||
</ol>
|
||||
<pre><code class="language-sql"><span class="hljs-keyword">update</span> product <span class="hljs-keyword">set</span> <span class="hljs-keyword">name</span> = <span class="hljs-string">'TXC'</span> <span class="hljs-keyword">where</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">1</span>;
|
||||
</code></pre>
|
||||
<ol start="5">
|
||||
<li>Commit local transaction, report the result of execution of local transaction(The rollback result of the Branch transaction) to TC.</li>
|
||||
</ol>
|
||||
<h2>Phase 2 - Commit case</h2>
|
||||
<ol>
|
||||
<li>After receive the commit request from TC, put the request into a work queue, return success to TC immediately.</li>
|
||||
<li>During the phase of doing the asynchronous work in the queue, the UNDO LOGs are deleted in batch way.</li>
|
||||
</ol>
|
||||
<h1>Appendix</h1>
|
||||
<h2>Undo log table</h2>
|
||||
<p>UNDO_LOG Table:there is a little bit difference on the data type for different databases.</p>
|
||||
<p>For MySQL example:</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Field</th>
|
||||
<th>Type</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>branch_id</td>
|
||||
<td>bigint PK</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>xid</td>
|
||||
<td>varchar(100)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>context</td>
|
||||
<td>varchar(128)</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>rollback_info</td>
|
||||
<td>longblob</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>log_status</td>
|
||||
<td>tinyint</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>log_created</td>
|
||||
<td>datetime</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>log_modified</td>
|
||||
<td>datetime</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<pre><code class="language-sql"><span class="hljs-comment">-- Note that 0.7.0+ adds the field context</span>
|
||||
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`undo_log`</span> (
|
||||
<span class="hljs-string">`id`</span> <span class="hljs-built_in">bigint</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> AUTO_INCREMENT,
|
||||
<span class="hljs-string">`branch_id`</span> <span class="hljs-built_in">bigint</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`xid`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`context`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">128</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`rollback_info`</span> longblob <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`log_status`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`log_created`</span> datetime <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`log_modified`</span> datetime <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
PRIMARY <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`id`</span>),
|
||||
<span class="hljs-keyword">UNIQUE</span> <span class="hljs-keyword">KEY</span> <span class="hljs-string">`ux_undo_log`</span> (<span class="hljs-string">`xid`</span>,<span class="hljs-string">`branch_id`</span>)
|
||||
) <span class="hljs-keyword">ENGINE</span>=<span class="hljs-keyword">InnoDB</span> AUTO_INCREMENT=<span class="hljs-number">1</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CHARSET</span>=utf8;
|
||||
</code></pre>
|
||||
<h1>TCC Mode</h1>
|
||||
<p>Review the description in the overview: A distributed global transaction, the whole is a <strong>two-phase commit</strong> model. The global transaction is composed of several branch transactions. The branch transaction must meet the requirements of the <strong>two-phase commit</strong> model, that is, each branch transaction must have its own:</p>
|
||||
<ul>
|
||||
<li>One-stage prepare behavior</li>
|
||||
<li>Two-phase commit or rollback behavior</li>
|
||||
</ul>
|
||||
<p><img src="/img/overview-4.png" alt="Overview of a global transaction"></p>
|
||||
<p>According to the two-phase behavior mode, we divide branch transactions into <strong>Automatic (Branch) Transaction Mode</strong> and <strong>TCC (Branch) Transaction Mode</strong>.</p>
|
||||
<p>The AT mode (<a href="">Reference Link TBD</a>) is based on a <strong>relational database</strong> that <strong>supports local ACID transactions</strong>:</p>
|
||||
<ul>
|
||||
<li>One-stage prepare behavior: In local transactions, business data updates and corresponding rollback log records are submitted together.</li>
|
||||
<li>Two-phase commit behavior: Immediately completed successfully, <strong>automatically</strong> asynchronously clean up the rollback log.</li>
|
||||
<li>Two-phase rollback behavior: Through the rollback log, <strong>automatically</strong> generates compensation operations to complete data rollback.</li>
|
||||
</ul>
|
||||
<p>Correspondingly, the TCC mode does not rely on transaction support of the underlying data resources:</p>
|
||||
<ul>
|
||||
<li>One-stage prepare behavior: Call the <strong>custom</strong> prepare logic.</li>
|
||||
<li>Two-phase commit behavior: Call <strong>custom</strong> commit logic.</li>
|
||||
<li>Two-phase rollback behavior: Call the <strong>custom</strong> rollback logic.</li>
|
||||
</ul>
|
||||
<p>The so-called TCC mode refers to the support of <strong>customized's</strong> branch transactions into the management of global transactions.</p>
|
||||
<h1>Saga Mode</h1>
|
||||
<p>The Saga model is a long transaction solution provided by SEATA. In the Saga model, each participant in the business process submits a local transaction. When a participant fails, the previous successful participant is compensated. One stage is positive serving and The two-stage compensation services are implemented by business development.</p>
|
||||
<p><img src="/img/saga/sagas.png" alt="Saga mode diagram"></p>
|
||||
<p>Theoretical basis: Hector & Kenneth Post a comment Sagas (1987)</p>
|
||||
<h2>Applicable scene:</h2>
|
||||
<ul>
|
||||
<li>Long business processes, many business processes</li>
|
||||
<li>Participants include other company or legacy system services and cannot provide the three interfaces required by the TCC model</li>
|
||||
</ul>
|
||||
<h2>Advantage:</h2>
|
||||
<ul>
|
||||
<li>Commit local transactions in one phase, lock-free, high performance</li>
|
||||
<li>Event-driven architecture, participants can execute asynchronously, high throughput</li>
|
||||
<li>Compensation services are easy to implement</li>
|
||||
</ul>
|
||||
<h2>Disadvantages:</h2>
|
||||
<ul>
|
||||
<li>Isolation is not guaranteed see <a href="../user/saga.html">User Documentation</a></li>
|
||||
</ul>
|
||||
</div></section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is an Alibaba open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/documentation.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
|
@ -1,24 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="what_is_seata" />
|
||||
<meta name="description" content="what_is_seata" />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>what_is_seata</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/documentation.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="documentation-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/docs/overview/what_is_seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li></ul></div></div></header><div class="bar"><div class="bar-body"><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="front-img"/><span>Documentation</span><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="back-img"/></div></div><section class="content-section"><div class="sidemenu"><div class="sidemenu-toggle"><img src="https://img.alicdn.com/tfs/TB1E6apXHGYBuNjy0FoXXciBFXa-200-200.png"/></div><ul><li class="menu-item menu-item-level-1"><span>Overview</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/what_is_seata.html" target="_self">What is Seata?</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/terminology.html" target="_self">Terminology</a></li></ul></li><li class="menu-item menu-item-level-1"><span>User Doc</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/api.html" target="_self">API Guide</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/microservice.html" target="_self">Microservices Framework Supports</a></li></ul></li><li class="menu-item menu-item-level-1"><span>FAQ</span><ul></ul></li></ul></div><div class="doc-content markdown-body"><h1>What Is Seata?</h1>
|
||||
</div></section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_white.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is dedicated to improving the efficiency of large-scale file distribution, building the go-to solution and standards of container image distribution, and providing you with file and image distribution service which is efficient, easy-to-use, and of high availability.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what_is_seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/documentation.js"></script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,6 +0,0 @@
|
|||
{
|
||||
"filename": "what_is_seata.md",
|
||||
"__html": "<h1>What Is Seata?</h1>\n",
|
||||
"link": "/en-us/docs/overview/what_is_seata.html",
|
||||
"meta": {}
|
||||
}
|
|
@ -1,247 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Seata" />
|
||||
<meta name="description" content="Api Guide." />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>Api Guide</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/documentation.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="documentation-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/developers/developers_dev.html" target="_self">DEVELOPERS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><div class="bar"><div class="bar-body"><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="front-img"/><span>Documentation</span><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="back-img"/></div></div><section class="content-section"><div class="sidemenu"><div class="sidemenu-toggle"><img src="https://img.alicdn.com/tfs/TB1E6apXHGYBuNjy0FoXXciBFXa-200-200.png"/></div><ul><li class="menu-item menu-item-level-1"><span>Overview</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/terminology.html" target="_self">Terminology</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/faq.html" target="_self">FAQ</a></li></ul></li><li class="menu-item menu-item-level-1"><span>User Doc</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/api.html" target="_self">API Guide</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/microservice.html" target="_self">Microservices Framework Supports</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Developer Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Transaction Mode<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/at-mode.html" target="_self">Seata AT mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/tcc-mode.html" target="_self">Seata TCC mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/saga-mode.html" target="_self">Seata Saga mode</a></li></ul></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/dev/seata-mertics.html" target="_self">Metrics design</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Ops Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/ops/multi-configuration-isolation.html" target="_self">Configuration Isolation</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Deploy<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-server.html" target="_self">Deploy Directly</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-docker.html" target="_self">Deploy by Docker</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-kubernetes.html" target="_self">Deploy by Kubernetes</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-helm.html" target="_self">Deploy by Helm</a></li></ul></li></ul></li></ul></div><div class="doc-content markdown-body"><h1>1. Overview</h1>
|
||||
<p>Seata API is devided into 2 categories: High-Level API and Low-Level API</p>
|
||||
<ul>
|
||||
<li><strong>High-Level API</strong> : Used for defining and controlling transaction boundary, and querying transaction status.</li>
|
||||
<li><strong>Low-Level API</strong> : Used for controlling the propagation of transaction context.</li>
|
||||
</ul>
|
||||
<h1>2. High-Level API</h1>
|
||||
<h2>2.1 GlobalTransaction</h2>
|
||||
<p>GlobalTransaction class contains methods about begin transaction, commit transaction, rollback transaction and get status of transaction and so on.</p>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">GlobalTransaction</span> </span>{
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* Begin a global transaction(Use default transaction name and timeout)
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">begin</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> TransactionException</span>;
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* Begin a global transaction, and point out the timeout(use default transaction name)
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">begin</span><span class="hljs-params">(<span class="hljs-keyword">int</span> timeout)</span> <span class="hljs-keyword">throws</span> TransactionException</span>;
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* Begin a global transaction, and point out the transaction name and timeout.
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">begin</span><span class="hljs-params">(<span class="hljs-keyword">int</span> timeout, String name)</span> <span class="hljs-keyword">throws</span> TransactionException</span>;
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* Commit globally
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">commit</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> TransactionException</span>;
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* Rollback globally
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">rollback</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> TransactionException</span>;
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* Get the status of transaction
|
||||
*/</span>
|
||||
<span class="hljs-function">GlobalStatus <span class="hljs-title">getStatus</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> TransactionException</span>;
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* Get the XID of transaction
|
||||
*/</span>
|
||||
<span class="hljs-function">String <span class="hljs-title">getXid</span><span class="hljs-params">()</span></span>;
|
||||
|
||||
}
|
||||
</code></pre>
|
||||
<h2>2.2 GlobalTransactionContext</h2>
|
||||
<p>GlobalTransaction instance can be retrieved from GlobalTransactionContext:</p>
|
||||
<pre><code class="language-java">
|
||||
<span class="hljs-comment">/**
|
||||
* Retrieve current global transaction instance, if it doesn't exist, create a new one.
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> GlobalTransaction <span class="hljs-title">getCurrentOrCreate</span><span class="hljs-params">()</span> </span>{
|
||||
GlobalTransaction tx = getCurrent();
|
||||
<span class="hljs-keyword">if</span> (tx == <span class="hljs-keyword">null</span>) {
|
||||
<span class="hljs-keyword">return</span> createNew();
|
||||
}
|
||||
<span class="hljs-keyword">return</span> tx;
|
||||
}
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* Reload the global transaction identified by XID, the instance aren't allowed to begin transaction.
|
||||
* This API is usually used for centralized handling of failed transaction later.
|
||||
* For example, if it's time out to commit globally, the subsequent centralized processing steps are like this: reload the instance, from which retrieve the status, then recommit the transaction globally or not depends on the status value.
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> GlobalTransaction <span class="hljs-title">reload</span><span class="hljs-params">(String xid)</span> <span class="hljs-keyword">throws</span> TransactionException </span>{
|
||||
GlobalTransaction tx = <span class="hljs-keyword">new</span> DefaultGlobalTransaction(xid, GlobalStatus.UnKnown, GlobalTransactionRole.Launcher) {
|
||||
<span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">begin</span><span class="hljs-params">(<span class="hljs-keyword">int</span> timeout, String name)</span> <span class="hljs-keyword">throws</span> TransactionException </span>{
|
||||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalStateException(<span class="hljs-string">"Never BEGIN on a RELOADED GlobalTransaction. "</span>);
|
||||
}
|
||||
};
|
||||
<span class="hljs-keyword">return</span> tx;
|
||||
}
|
||||
</code></pre>
|
||||
<h2>2.3 TransactionalTemplate</h2>
|
||||
<p>TransactionalTemplate: Wrap a business service invoke into a distributed transaction supported service with preceding GlobalTransaction and GlobalTransactionContext API.</p>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TransactionalTemplate</span> </span>{
|
||||
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> Object <span class="hljs-title">execute</span><span class="hljs-params">(TransactionalExecutor business)</span> <span class="hljs-keyword">throws</span> TransactionalExecutor.ExecutionException </span>{
|
||||
|
||||
<span class="hljs-comment">// 1. Get current global transaction instance or create a new one</span>
|
||||
GlobalTransaction tx = GlobalTransactionContext.getCurrentOrCreate();
|
||||
|
||||
<span class="hljs-comment">// 2. Begin the global transaction</span>
|
||||
<span class="hljs-keyword">try</span> {
|
||||
tx.begin(business.timeout(), business.name());
|
||||
|
||||
} <span class="hljs-keyword">catch</span> (TransactionException txe) {
|
||||
<span class="hljs-comment">// 2.1 Fail to begin</span>
|
||||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> TransactionalExecutor.ExecutionException(tx, txe,
|
||||
TransactionalExecutor.Code.BeginFailure);
|
||||
|
||||
}
|
||||
|
||||
Object rs = <span class="hljs-keyword">null</span>;
|
||||
<span class="hljs-keyword">try</span> {
|
||||
<span class="hljs-comment">// 3. invoke service</span>
|
||||
rs = business.execute();
|
||||
|
||||
} <span class="hljs-keyword">catch</span> (Throwable ex) {
|
||||
|
||||
<span class="hljs-comment">// Exception from business service invoke</span>
|
||||
<span class="hljs-keyword">try</span> {
|
||||
<span class="hljs-comment">// Rollback globally</span>
|
||||
tx.rollback();
|
||||
|
||||
<span class="hljs-comment">// 3.1 Global rollback success, throw original business exception</span>
|
||||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> TransactionalExecutor.ExecutionException(tx, TransactionalExecutor.Code.RollbackDone, ex);
|
||||
|
||||
} <span class="hljs-keyword">catch</span> (TransactionException txe) {
|
||||
<span class="hljs-comment">// 3.2 Global rollback failed</span>
|
||||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> TransactionalExecutor.ExecutionException(tx, txe,
|
||||
TransactionalExecutor.Code.RollbackFailure, ex);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
<span class="hljs-comment">// 4. Commit globally</span>
|
||||
<span class="hljs-keyword">try</span> {
|
||||
tx.commit();
|
||||
|
||||
} <span class="hljs-keyword">catch</span> (TransactionException txe) {
|
||||
<span class="hljs-comment">// 4.1 Global commit failed</span>
|
||||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> TransactionalExecutor.ExecutionException(tx, txe,
|
||||
TransactionalExecutor.Code.CommitFailure);
|
||||
|
||||
}
|
||||
<span class="hljs-keyword">return</span> rs;
|
||||
}
|
||||
|
||||
}
|
||||
</code></pre>
|
||||
<p>The exception of template method: ExecutionException</p>
|
||||
<pre><code> class ExecutionException extends Exception {
|
||||
|
||||
// Transaction instance threw exception
|
||||
private GlobalTransaction transaction;
|
||||
|
||||
// Exception code:
|
||||
// BeginFailure(Fail to begin transaction)
|
||||
// CommitFailure(Fail to commit globally)
|
||||
// RollbackFailure(Fail to rollback globally)
|
||||
// RollbackDone(Global rollback success)
|
||||
private Code code;
|
||||
|
||||
// Original exception triggered by rollback
|
||||
private Throwable originalException;
|
||||
</code></pre>
|
||||
<p>Outer calling logic try-catch the exception, and do something based on the exception code:</p>
|
||||
<ul>
|
||||
<li><strong>BeginFailure</strong> (Fail to begin transaction): getCause() gets the framework exception of begin transaction, getOriginalException() is null.</li>
|
||||
<li><strong>CommitFailure</strong>(Fail to commit globally): getCause() gets the framework exception of commit transaction, getOriginalException() is null.</li>
|
||||
<li><strong>RollbackFailure</strong> (Fail to rollback globally):getCause() gets the framework exception of rollback transaction,getOriginalException() gets the original exception of business invoke.</li>
|
||||
<li><strong>RollbackDone</strong>(Global rollback success): getCause() is null, getOriginalException() gets the original exception of business invoke.</li>
|
||||
</ul>
|
||||
<h1>3. Low-Level API</h1>
|
||||
<h2>3.1 RootContext</h2>
|
||||
<p>RootContext: It's responsible for maintaining XID during runtime of application.</p>
|
||||
<pre><code class="language-java"> <span class="hljs-comment">/**
|
||||
* Get the global XID of the current running application
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> String <span class="hljs-title">getXID</span><span class="hljs-params">()</span> </span>{
|
||||
<span class="hljs-keyword">return</span> CONTEXT_HOLDER.get(KEY_XID);
|
||||
}
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* Bind the global XID to the current application runtime
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">void</span> <span class="hljs-title">bind</span><span class="hljs-params">(String xid)</span> </span>{
|
||||
<span class="hljs-keyword">if</span> (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(<span class="hljs-string">"bind "</span> + xid);
|
||||
}
|
||||
CONTEXT_HOLDER.put(KEY_XID, xid);
|
||||
}
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* Unbind the global XID from the current application runtime, and return XID
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> String <span class="hljs-title">unbind</span><span class="hljs-params">()</span> </span>{
|
||||
String xid = CONTEXT_HOLDER.remove(KEY_XID);
|
||||
<span class="hljs-keyword">if</span> (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(<span class="hljs-string">"unbind "</span> + xid);
|
||||
}
|
||||
<span class="hljs-keyword">return</span> xid;
|
||||
}
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* Check if the current application runtime is in the global transaction context
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">inGlobalTransaction</span><span class="hljs-params">()</span> </span>{
|
||||
<span class="hljs-keyword">return</span> CONTEXT_HOLDER.get(KEY_XID) != <span class="hljs-keyword">null</span>;
|
||||
}
|
||||
</code></pre>
|
||||
<p>The implementation of High-Level API is based on maintaining XID in the RootContext.</p>
|
||||
<p>Whether or not the operation of the current running application is in a global transaction context, just check if there is an XID in the RootContext.</p>
|
||||
<p>The default implementation of RootContext is based on ThreadLocal, which is the XID is in the context of current thread.</p>
|
||||
<p>Two classic scenes of Low-Level API :</p>
|
||||
<h3>1. The propagation of transaction context by remote invoke</h3>
|
||||
<p>Retrieve current XID by remote invoke:</p>
|
||||
<pre><code class="language-java">String xid = RootContext.getXID();
|
||||
</code></pre>
|
||||
<p>Propagating the XID to the provider of service by RPC, bind the XID to current RootContext before executing the business logic of provider.</p>
|
||||
<pre><code class="language-java">RootContext.bind(rpcXid);
|
||||
</code></pre>
|
||||
<h3>2. Pause and recover of transaction</h3>
|
||||
<p>In a global transaction, if some business logic shouldn't be in the scope of the global transaction, unbind XID before invoke it.</p>
|
||||
<pre><code class="language-java">String unbindXid = RootContext.unbind();
|
||||
</code></pre>
|
||||
<p>Rebind the XID back after the execution of related business logic to achieve recovering the global transaction.</p>
|
||||
<pre><code class="language-java">RootContext.bind(unbindXid);
|
||||
</code></pre>
|
||||
</div></section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is an Alibaba open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/documentation.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
|
@ -1,148 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Seata" />
|
||||
<meta name="description" content="Microservice Framework Guide." />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>Microservice Framework Guide</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/documentation.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="documentation-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/developers/developers_dev.html" target="_self">DEVELOPERS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><div class="bar"><div class="bar-body"><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="front-img"/><span>Documentation</span><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="back-img"/></div></div><section class="content-section"><div class="sidemenu"><div class="sidemenu-toggle"><img src="https://img.alicdn.com/tfs/TB1E6apXHGYBuNjy0FoXXciBFXa-200-200.png"/></div><ul><li class="menu-item menu-item-level-1"><span>Overview</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/terminology.html" target="_self">Terminology</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/faq.html" target="_self">FAQ</a></li></ul></li><li class="menu-item menu-item-level-1"><span>User Doc</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/api.html" target="_self">API Guide</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/microservice.html" target="_self">Microservices Framework Supports</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Developer Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Transaction Mode<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/at-mode.html" target="_self">Seata AT mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/tcc-mode.html" target="_self">Seata TCC mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/saga-mode.html" target="_self">Seata Saga mode</a></li></ul></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/dev/seata-mertics.html" target="_self">Metrics design</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Ops Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/ops/multi-configuration-isolation.html" target="_self">Configuration Isolation</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Deploy<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-server.html" target="_self">Deploy Directly</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-docker.html" target="_self">Deploy by Docker</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-kubernetes.html" target="_self">Deploy by Kubernetes</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-helm.html" target="_self">Deploy by Helm</a></li></ul></li></ul></li></ul></div><div class="doc-content markdown-body"><h1>Transaction Context</h1>
|
||||
<p>Transaction context of Seata is managed by RootContext.</p>
|
||||
<p>When application begins a global transaction, RootContext will bind the XID of the transaction automatically, at the end of transaction(commit or rollback), RootContext will unbind the XID automatically.</p>
|
||||
<pre><code class="language-java"><span class="hljs-comment">// Bind XID</span>
|
||||
RootContext.bind(xid);
|
||||
|
||||
<span class="hljs-comment">// Unbind XID</span>
|
||||
String xid = RootContext.unbind();
|
||||
</code></pre>
|
||||
<p>Application retrieve the global transaction XID through the API of RootContext.</p>
|
||||
<pre><code class="language-java"><span class="hljs-comment">// Retrieve XID</span>
|
||||
String xid = RootContext.getXID();
|
||||
</code></pre>
|
||||
<p>Whether application is running a global transaction, just check if an XID bound to RootContext.</p>
|
||||
<pre><code class="language-java"> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">inGlobalTransaction</span><span class="hljs-params">()</span> </span>{
|
||||
<span class="hljs-keyword">return</span> CONTEXT_HOLDER.get(KEY_XID) != <span class="hljs-keyword">null</span>;
|
||||
}
|
||||
</code></pre>
|
||||
<h1>Transaction propagation</h1>
|
||||
<p>The mechanism of the global transaction of Seata is the propagation of transaction context, primarily, it's the propagation way of XID in runtime.</p>
|
||||
<p><em>1. The propagation of transaction in the service</em></p>
|
||||
<p>By default, RootContext is based on ThreadLocal, which is the XID is bound in the context of thread.</p>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ThreadLocalContextCore</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">ContextCore</span> </span>{
|
||||
|
||||
<span class="hljs-keyword">private</span> ThreadLocal<Map<String, String>> threadLocal = <span class="hljs-keyword">new</span> ThreadLocal<Map<String, String>>() {
|
||||
<span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">protected</span> Map<String, String> <span class="hljs-title">initialValue</span><span class="hljs-params">()</span> </span>{
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> HashMap<String, String>();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
<span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">put</span><span class="hljs-params">(String key, String value)</span> </span>{
|
||||
<span class="hljs-keyword">return</span> threadLocal.get().put(key, value);
|
||||
}
|
||||
|
||||
<span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">get</span><span class="hljs-params">(String key)</span> </span>{
|
||||
<span class="hljs-keyword">return</span> threadLocal.get().get(key);
|
||||
}
|
||||
|
||||
<span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">remove</span><span class="hljs-params">(String key)</span> </span>{
|
||||
<span class="hljs-keyword">return</span> threadLocal.get().remove(key);
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<p>So the inner XID of service is tracing by the same thread naturally, do nothing to propagate the transaction by default.</p>
|
||||
<p>If it hopes to hung up the transaction context, implement it by the API of RootContext:</p>
|
||||
<pre><code class="language-java"><span class="hljs-comment">// Hung up(pause)</span>
|
||||
String xid = RootContext.unbind();
|
||||
|
||||
<span class="hljs-comment">// <span class="hljs-doctag">TODO:</span> Logic running out of the global transaction scope</span>
|
||||
|
||||
<span class="hljs-comment">// recover the global transaction</span>
|
||||
RootContext.bind(xid);
|
||||
|
||||
</code></pre>
|
||||
<p><em>2. Transactional propagation across service calls</em></p>
|
||||
<p>It's easy to know by the basic idea preceding:</p>
|
||||
<blockquote>
|
||||
<p>The transaction propagation across service calls, essentially, propagate the XID via service call to service provider, and bind it to RootContext.</p>
|
||||
</blockquote>
|
||||
<p>As long as it can be done, Seata can support any microservice framework in theory.</p>
|
||||
<h1>Interpretation of supporting Dubbo</h1>
|
||||
<p>Let's interpret the inner support for Dubbo RPC to illustrate how Seata supports a specific microservice framework in follows:</p>
|
||||
<p>We use the org.apache.dubbo.rpc.Filter of Dubbo to support propagation of transaction.</p>
|
||||
<pre><code class="language-java"><span class="hljs-comment">/**
|
||||
* The type Transaction propagation filter.
|
||||
*/</span>
|
||||
<span class="hljs-meta">@Activate</span>(group = { Constants.PROVIDER, Constants.CONSUMER }, order = <span class="hljs-number">100</span>)
|
||||
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TransactionPropagationFilter</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Filter</span> </span>{
|
||||
|
||||
<span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> Logger LOGGER = LoggerFactory.getLogger(TransactionPropagationFilter<span class="hljs-class">.<span class="hljs-keyword">class</span>)</span>;
|
||||
|
||||
<span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> Result <span class="hljs-title">invoke</span><span class="hljs-params">(Invoker<?> invoker, Invocation invocation)</span> <span class="hljs-keyword">throws</span> RpcException </span>{
|
||||
String xid = RootContext.getXID(); <span class="hljs-comment">// Get XID of current transaction</span>
|
||||
String rpcXid = RpcContext.getContext().getAttachment(RootContext.KEY_XID); <span class="hljs-comment">// Acquire the XID from RPC invoke</span>
|
||||
<span class="hljs-keyword">if</span> (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(<span class="hljs-string">"xid in RootContext["</span> + xid + <span class="hljs-string">"] xid in RpcContext["</span> + rpcXid + <span class="hljs-string">"]"</span>);
|
||||
}
|
||||
<span class="hljs-keyword">boolean</span> bind = <span class="hljs-keyword">false</span>;
|
||||
<span class="hljs-keyword">if</span> (xid != <span class="hljs-keyword">null</span>) { <span class="hljs-comment">// Consumer:Put XID into the attachment of RPC</span>
|
||||
RpcContext.getContext().setAttachment(RootContext.KEY_XID, xid);
|
||||
} <span class="hljs-keyword">else</span> {
|
||||
<span class="hljs-keyword">if</span> (rpcXid != <span class="hljs-keyword">null</span>) { <span class="hljs-comment">// Provider:Bind the XID propagated by RPC to current runtime</span>
|
||||
RootContext.bind(rpcXid);
|
||||
bind = <span class="hljs-keyword">true</span>;
|
||||
<span class="hljs-keyword">if</span> (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(<span class="hljs-string">"bind["</span> + rpcXid + <span class="hljs-string">"] to RootContext"</span>);
|
||||
}
|
||||
}
|
||||
}
|
||||
<span class="hljs-keyword">try</span> {
|
||||
<span class="hljs-keyword">return</span> invoker.invoke(invocation); <span class="hljs-comment">// Business method invoke</span>
|
||||
|
||||
} <span class="hljs-keyword">finally</span> {
|
||||
<span class="hljs-keyword">if</span> (bind) { <span class="hljs-comment">// Provider:Clean up XID after invoke</span>
|
||||
String unbindXid = RootContext.unbind();
|
||||
<span class="hljs-keyword">if</span> (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(<span class="hljs-string">"unbind["</span> + unbindXid + <span class="hljs-string">"] from RootContext"</span>);
|
||||
}
|
||||
<span class="hljs-keyword">if</span> (!rpcXid.equalsIgnoreCase(unbindXid)) {
|
||||
LOGGER.warn(<span class="hljs-string">"xid in change during RPC from "</span> + rpcXid + <span class="hljs-string">" to "</span> + unbindXid);
|
||||
<span class="hljs-keyword">if</span> (unbindXid != <span class="hljs-keyword">null</span>) { <span class="hljs-comment">// if there is new transaction begin, can't do clean up</span>
|
||||
RootContext.bind(unbindXid);
|
||||
LOGGER.warn(<span class="hljs-string">"bind ["</span> + unbindXid + <span class="hljs-string">"] back to RootContext"</span>);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
</div></section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is an Alibaba open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/documentation.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
|
@ -1,212 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Seata" />
|
||||
<meta name="description" content="Let's begin with a Microservices example." />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>Quick Start</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/documentation.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="documentation-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/en-us/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">中</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/en-us/index.html" target="_self">HOME</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">DOCS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/docs/developers/developers_dev.html" target="_self">DEVELOPERS</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/index.html" target="_self">BLOG</a></li><li class="menu-item menu-item-normal"><a href="/en-us/community/index.html" target="_self">COMMUNITY</a></li><li class="menu-item menu-item-normal"><a href="/en-us/blog/download.html" target="_self">DOWNLOAD</a></li></ul></div></div></header><div class="bar"><div class="bar-body"><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="front-img"/><span>Documentation</span><img src="https://img.alicdn.com/tfs/TB1cm8nJwDqK1RjSZSyXXaxEVXa-160-160.png" class="back-img"/></div></div><section class="content-section"><div class="sidemenu"><div class="sidemenu-toggle"><img src="https://img.alicdn.com/tfs/TB1E6apXHGYBuNjy0FoXXciBFXa-200-200.png"/></div><ul><li class="menu-item menu-item-level-1"><span>Overview</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/terminology.html" target="_self">Terminology</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/overview/faq.html" target="_self">FAQ</a></li></ul></li><li class="menu-item menu-item-level-1"><span>User Doc</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/api.html" target="_self">API Guide</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/user/microservice.html" target="_self">Microservices Framework Supports</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Developer Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Transaction Mode<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/at-mode.html" target="_self">Seata AT mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/tcc-mode.html" target="_self">Seata TCC mode</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/dev/mode/saga-mode.html" target="_self">Seata Saga mode</a></li></ul></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/dev/seata-mertics.html" target="_self">Metrics design</a></li></ul></li><li class="menu-item menu-item-level-1"><span>Ops Guide</span><ul><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><a href="/en-us/docs/ops/multi-configuration-isolation.html" target="_self">Configuration Isolation</a></li><li style="height:36px;overflow:hidden" class="menu-item menu-item-level-2"><span>Deploy<img style="transform:rotate(-90deg)" class="menu-toggle" src="/img/system/arrow_down.png"/></span><ul><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-server.html" target="_self">Deploy Directly</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-docker.html" target="_self">Deploy by Docker</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-kubernetes.html" target="_self">Deploy by Kubernetes</a></li><li class="menu-item menu-item-level-3"><a href="/en-us/docs/ops/deploy-by-helm.html" target="_self">Deploy by Helm</a></li></ul></li></ul></li></ul></div><div class="doc-content markdown-body"><h1>Quick Start</h1>
|
||||
<p>Let's begin with a Microservices example.</p>
|
||||
<h2>Use case</h2>
|
||||
<p>A business logic for user purchasing commodities. The whole business logic is powered by 3 microservices:</p>
|
||||
<ul>
|
||||
<li>Storage service: deduct storage count on given commodity.</li>
|
||||
<li>Order service: create order according to purchase request.</li>
|
||||
<li>Account service: debit the balance of user's account.</li>
|
||||
</ul>
|
||||
<h3>Architecture</h3>
|
||||
<p><img src="/img/architecture.png" alt="Architecture"></p>
|
||||
<h3>StorageService</h3>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">StorageService</span> </span>{
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* deduct storage count
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">deduct</span><span class="hljs-params">(String commodityCode, <span class="hljs-keyword">int</span> count)</span></span>;
|
||||
}
|
||||
</code></pre>
|
||||
<h3>OrderService</h3>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">OrderService</span> </span>{
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* create order
|
||||
*/</span>
|
||||
<span class="hljs-function">Order <span class="hljs-title">create</span><span class="hljs-params">(String userId, String commodityCode, <span class="hljs-keyword">int</span> orderCount)</span></span>;
|
||||
}
|
||||
</code></pre>
|
||||
<h3>AccountService</h3>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">AccountService</span> </span>{
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* debit balance of user's account
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">debit</span><span class="hljs-params">(String userId, <span class="hljs-keyword">int</span> money)</span></span>;
|
||||
}
|
||||
</code></pre>
|
||||
<h3>Main business logic</h3>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BusinessServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">BusinessService</span> </span>{
|
||||
|
||||
<span class="hljs-keyword">private</span> StorageService storageService;
|
||||
|
||||
<span class="hljs-keyword">private</span> OrderService orderService;
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* purchase
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">purchase</span><span class="hljs-params">(String userId, String commodityCode, <span class="hljs-keyword">int</span> orderCount)</span> </span>{
|
||||
|
||||
storageService.deduct(commodityCode, orderCount);
|
||||
|
||||
orderService.create(userId, commodityCode, orderCount);
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">OrderServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">OrderService</span> </span>{
|
||||
|
||||
<span class="hljs-keyword">private</span> OrderDAO orderDAO;
|
||||
|
||||
<span class="hljs-keyword">private</span> AccountService accountService;
|
||||
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> Order <span class="hljs-title">create</span><span class="hljs-params">(String userId, String commodityCode, <span class="hljs-keyword">int</span> orderCount)</span> </span>{
|
||||
|
||||
<span class="hljs-keyword">int</span> orderMoney = calculate(commodityCode, orderCount);
|
||||
|
||||
accountService.debit(userId, orderMoney);
|
||||
|
||||
Order order = <span class="hljs-keyword">new</span> Order();
|
||||
order.userId = userId;
|
||||
order.commodityCode = commodityCode;
|
||||
order.count = orderCount;
|
||||
order.money = orderMoney;
|
||||
|
||||
<span class="hljs-comment">// INSERT INTO orders ...</span>
|
||||
<span class="hljs-keyword">return</span> orderDAO.insert(order);
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<h2>Distributed Transaction Solution with SEATA</h2>
|
||||
<p><img src="/img/solution.png" alt=""></p>
|
||||
<p>We just need an annotation <code>@GlobalTransactional</code> on business method:</p>
|
||||
<pre><code class="language-java">
|
||||
<span class="hljs-meta">@GlobalTransactional</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">purchase</span><span class="hljs-params">(String userId, String commodityCode, <span class="hljs-keyword">int</span> orderCount)</span> </span>{
|
||||
......
|
||||
}
|
||||
</code></pre>
|
||||
<h2>Example powered by Dubbo + SEATA</h2>
|
||||
<h3>Step 1: Setup database</h3>
|
||||
<ul>
|
||||
<li>Requirement: MySQL with InnoDB engine.</li>
|
||||
</ul>
|
||||
<p><strong>Note:</strong> In fact, there should be 3 database for the 3 services in the example use case. However, we can just create one database and configure 3 data sources for simple.</p>
|
||||
<p>Modify Spring XML with the database URL/username/password you just created.</p>
|
||||
<p>dubbo-account-service.xml
|
||||
dubbo-order-service.xml
|
||||
dubbo-storage-service.xml</p>
|
||||
<pre><code class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"url"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"jdbc:mysql://x.x.x.x:3306/xxx"</span> /></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"username"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"xxx"</span> /></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"xxx"</span> /></span>
|
||||
</code></pre>
|
||||
<h3>Step 2: Create UNDO_LOG table</h3>
|
||||
<p><code>UNDO_LOG</code> table is required by SEATA AT mode.</p>
|
||||
<pre><code class="language-sql"><span class="hljs-comment">-- 注意此处0.3.0+ 增加唯一索引 ux_undo_log</span>
|
||||
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`undo_log`</span> (
|
||||
<span class="hljs-string">`id`</span> <span class="hljs-built_in">bigint</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> AUTO_INCREMENT,
|
||||
<span class="hljs-string">`branch_id`</span> <span class="hljs-built_in">bigint</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`xid`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`context`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">128</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`rollback_info`</span> longblob <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`log_status`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`log_created`</span> datetime <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`log_modified`</span> datetime <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`ext`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
|
||||
PRIMARY <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`id`</span>),
|
||||
<span class="hljs-keyword">UNIQUE</span> <span class="hljs-keyword">KEY</span> <span class="hljs-string">`ux_undo_log`</span> (<span class="hljs-string">`xid`</span>,<span class="hljs-string">`branch_id`</span>)
|
||||
) <span class="hljs-keyword">ENGINE</span>=<span class="hljs-keyword">InnoDB</span> AUTO_INCREMENT=<span class="hljs-number">1</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CHARSET</span>=utf8;
|
||||
</code></pre>
|
||||
<h3>Step 3: Create tables for example business</h3>
|
||||
<pre><code class="language-sql">
|
||||
<span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">IF</span> <span class="hljs-keyword">EXISTS</span> <span class="hljs-string">`storage_tbl`</span>;
|
||||
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`storage_tbl`</span> (
|
||||
<span class="hljs-string">`id`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> AUTO_INCREMENT,
|
||||
<span class="hljs-string">`commodity_code`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`count`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span>,
|
||||
PRIMARY <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`id`</span>),
|
||||
<span class="hljs-keyword">UNIQUE</span> <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`commodity_code`</span>)
|
||||
) <span class="hljs-keyword">ENGINE</span>=<span class="hljs-keyword">InnoDB</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CHARSET</span>=utf8;
|
||||
|
||||
|
||||
<span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">IF</span> <span class="hljs-keyword">EXISTS</span> <span class="hljs-string">`order_tbl`</span>;
|
||||
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`order_tbl`</span> (
|
||||
<span class="hljs-string">`id`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> AUTO_INCREMENT,
|
||||
<span class="hljs-string">`user_id`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`commodity_code`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`count`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span>,
|
||||
<span class="hljs-string">`money`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span>,
|
||||
PRIMARY <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`id`</span>)
|
||||
) <span class="hljs-keyword">ENGINE</span>=<span class="hljs-keyword">InnoDB</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CHARSET</span>=utf8;
|
||||
|
||||
|
||||
<span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">IF</span> <span class="hljs-keyword">EXISTS</span> <span class="hljs-string">`account_tbl`</span>;
|
||||
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`account_tbl`</span> (
|
||||
<span class="hljs-string">`id`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> AUTO_INCREMENT,
|
||||
<span class="hljs-string">`user_id`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`money`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span>,
|
||||
PRIMARY <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`id`</span>)
|
||||
) <span class="hljs-keyword">ENGINE</span>=<span class="hljs-keyword">InnoDB</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CHARSET</span>=utf8;
|
||||
</code></pre>
|
||||
<h3>Step 4: Start Server</h3>
|
||||
<ul>
|
||||
<li>Download server package from <a href="https://github.com/seata/seata/releases">https://github.com/seata/seata/releases</a>, unzip it.</li>
|
||||
</ul>
|
||||
<pre><code class="language-shell">Usage: sh seata-server.sh(for linux and mac) or cmd seata-server.bat(for windows) [options]
|
||||
Options:
|
||||
--host, -h
|
||||
The host to bind.
|
||||
Default: 0.0.0.0
|
||||
--port, -p
|
||||
The port to listen.
|
||||
Default: 8091
|
||||
--storeMode, -m
|
||||
log store mode : file、db
|
||||
Default: file
|
||||
--help
|
||||
|
||||
e.g.
|
||||
|
||||
sh seata-server.sh -p 8091 -h 127.0.0.1 -m file
|
||||
</code></pre>
|
||||
<h3>Step 5: Run example</h3>
|
||||
<p>Go to samples repo: <a href="https://github.com/seata/seata-samples">seata-samples</a></p>
|
||||
<ul>
|
||||
<li>Start DubboAccountServiceStarter</li>
|
||||
<li>Start DubboStorageServiceStarter</li>
|
||||
<li>Start DubboOrderServiceStarter</li>
|
||||
<li>Run DubboBusinessTester for demo test</li>
|
||||
</ul>
|
||||
<p>TBD: scripts for run demo applications</p>
|
||||
</div></section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>Vision</h3><p>Seata is an Alibaba open source distributed transaction solution that delivers high performance and easy to use distributed transaction services under a microservices architecture.</p></div><div class="col col-6"><dl><dt>Documentation</dt><dd><a href="/en-us/docs/overview/what-is-seata.html" target="_self">What is Seata?</a></dd><dd><a href="/en-us/docs/user/quickstart.html" target="_self">Quick Start</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">Report a doc issue</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">Edit This Page on GitHub</a></dd></dl></div><div class="col col-6"><dl><dt>Resources</dt><dd><a href="/en-us/blog/index.html" target="_self">Blog</a></dd><dd><a href="/en-us/community/index.html" target="_self">Community</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/documentation.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
18
index.html
18
index.html
|
@ -1,18 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
</head>
|
||||
<body>
|
||||
<script src="//cdn.jsdelivr.net/npm/js-cookie@2/src/js.cookie.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
window.defaultLanguage = 'en-us';
|
||||
var lang = Cookies.get('docsite_language');
|
||||
if (!lang) {
|
||||
lang = 'en-us';
|
||||
}
|
||||
window.location = window.rootPath + '/' + lang;
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,258 +0,0 @@
|
|||
{
|
||||
"en-us": [
|
||||
{
|
||||
"filename": "download.md",
|
||||
"link": "/en-us/blog/download.html",
|
||||
"meta": {
|
||||
"title": "Downloads",
|
||||
"keywords": "Seata, Downloads, Version",
|
||||
"description": "This article will introduce you how to understand the details of each version and upgrade matters needing attention."
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "manual-transaction-mode.md",
|
||||
"link": "/en-us/blog/manual-transaction-mode.html",
|
||||
"meta": {
|
||||
"title": "MT mode",
|
||||
"keywords": "MT mode",
|
||||
"description": "introduce MT mode",
|
||||
"author": "kmmshmily",
|
||||
"date": "2019-02-13"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "quick-start-use-seata-and-dubbo-services.md",
|
||||
"link": "/en-us/blog/quick-start-use-seata-and-dubbo-services.html",
|
||||
"meta": {
|
||||
"title": "How to use Seata to ensure consistency between Dubbo Microservices",
|
||||
"keywords": "Dubbo,Seata,Consistency",
|
||||
"description": "This article will introduce you how to use Seata to ensure consistency between Dubbo Microservices.",
|
||||
"author": "slievrly",
|
||||
"date": "2019-03-07"
|
||||
}
|
||||
}
|
||||
],
|
||||
"zh-cn": [
|
||||
{
|
||||
"filename": "design-more-flexable-application-by-saga.md",
|
||||
"link": "/zh-cn/blog/design-more-flexable-application-by-saga.html",
|
||||
"meta": {
|
||||
"title": "基于 Seata Saga 设计更有弹性的金融应用",
|
||||
"keywords": "Saga,Seata,一致性,金融,弹性,分布式,事务",
|
||||
"description": "本文从金融分布式应用开发的一些痛点出发,结合理论和实践对社区和行业的解决方案进行了分析,并讲解了如何基于Seata saga设计更有弹性的金融应用",
|
||||
"author": "long187",
|
||||
"date": "2019-11-04"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "download.md",
|
||||
"link": "/zh-cn/blog/download.html",
|
||||
"meta": {
|
||||
"title": "下载中心",
|
||||
"keywords": "Seata, Downloads, Version",
|
||||
"description": "本文将向你介绍如何点击了解各版本详情和升级注意事项。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "how-to-support-spring-cloud.md",
|
||||
"link": "/zh-cn/blog/how-to-support-spring-cloud.html",
|
||||
"meta": {
|
||||
"title": "Fescar 与 Spring Cloud 集成源码深度剖析",
|
||||
"author": "郭树抗 季敏",
|
||||
"date": "2019/04/15",
|
||||
"keywords": "fescar、seata、分布式事务"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "integrate-seata-with-spring-cloud.md",
|
||||
"link": "/zh-cn/blog/integrate-seata-with-spring-cloud.html",
|
||||
"meta": {
|
||||
"title": "Seata(Fescar)分布式事务 整合 Spring Cloud",
|
||||
"author": "大菲.Fei",
|
||||
"date": "2019/04/15",
|
||||
"keywords": "fescar、seata、分布式事务"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "manual-transaction-mode.md",
|
||||
"link": "/zh-cn/blog/manual-transaction-mode.html",
|
||||
"meta": {
|
||||
"title": "MT 模式",
|
||||
"keywords": "MT 模式",
|
||||
"description": "介绍 MT 模式",
|
||||
"author": "kmmshmily",
|
||||
"date": "2019-02-13"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "quick-start-use-seata-and-dubbo-services.md",
|
||||
"link": "/zh-cn/blog/quick-start-use-seata-and-dubbo-services.html",
|
||||
"meta": {
|
||||
"title": "如何使用Seata保证Dubbo微服务间的一致性",
|
||||
"keywords": "Dubbo,Seata,一致性",
|
||||
"description": "本文主要介绍如何使用Seata保证Dubbo微服务间的一致性",
|
||||
"author": "slievrly",
|
||||
"date": "2019-03-07"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "seata-analysis-go-server.md",
|
||||
"link": "/zh-cn/blog/seata-analysis-go-server.html",
|
||||
"meta": {
|
||||
"title": "Seata分布式Go Server正式开源-TaaS设计简介",
|
||||
"author": "fagongzi(zhangxu19830126@gmail.com)",
|
||||
"date": "2019/04/23",
|
||||
"keywords": "seata、分布式事务、高可用"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "seata-analysis-java-client.md",
|
||||
"link": "/zh-cn/blog/seata-analysis-java-client.html",
|
||||
"meta": {
|
||||
"title": "分布式事务之Seata-Client原理及流程详解",
|
||||
"author": "fangliangsheng",
|
||||
"date": "2019/04/15",
|
||||
"keywords": "fescar、seata、分布式事务"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "seata-analysis-java-server.md",
|
||||
"link": "/zh-cn/blog/seata-analysis-java-server.html",
|
||||
"meta": {
|
||||
"title": "深度剖析一站式分布式事务方案Seata-Server",
|
||||
"author": "李钊,季敏",
|
||||
"date": "2019/04/08",
|
||||
"keywords": "fescar、seata、分布式事务"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "seata-analysis-simple.md",
|
||||
"link": "/zh-cn/blog/seata-analysis-simple.html",
|
||||
"meta": {
|
||||
"title": "Fescar分布式事务原理解析探秘",
|
||||
"author": "陈凯玲",
|
||||
"keywords": "Fescar、分布式事务",
|
||||
"date": "2019/02/18"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "seata-at-mode-design.md",
|
||||
"link": "/zh-cn/blog/seata-at-mode-design.html",
|
||||
"meta": {
|
||||
"title": "分布式事务中间件 Seata 的设计原理",
|
||||
"author": "张乘辉",
|
||||
"keywords": "Seata、分布式事务、AT模式",
|
||||
"description": "AT 模式设计原理",
|
||||
"date": "2019/07/11"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "seata-at-mode-start-rm-tm.md",
|
||||
"link": "/zh-cn/blog/seata-at-mode-start-rm-tm.html",
|
||||
"meta": {
|
||||
"title": "Seata 客户端需要同时启动 RM 和 TM 吗?",
|
||||
"author": "张乘辉",
|
||||
"keywords": "Seata、分布式事务、AT模式、RM、TM",
|
||||
"description": "关于 Seata 后续优化的一个讨论点",
|
||||
"date": "2019/11/28"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "seata-at-mode-start.md",
|
||||
"link": "/zh-cn/blog/seata-at-mode-start.html",
|
||||
"meta": {
|
||||
"title": "Seata AT 模式启动源码分析",
|
||||
"author": "张乘辉",
|
||||
"keywords": "Seata、分布式事务、AT模式",
|
||||
"description": "Seata 源码分析系列",
|
||||
"date": "2019/11/27"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "seata-at-tcc-saga.md",
|
||||
"link": "/zh-cn/blog/seata-at-tcc-saga.html",
|
||||
"meta": {
|
||||
"title": "分布式事务 Seata 及其三种模式详解",
|
||||
"keywords": "Saga,Seata,AT,TCC,一致性,金融,分布式,事务",
|
||||
"description": "着重分享分布式事务产生的背景、理论基础,以及 Seata 分布式事务的原理以及三种模式(AT、TCC、Saga)的分布式事务实现",
|
||||
"author": "long187",
|
||||
"date": "2019-08-11"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "seata-config-center.md",
|
||||
"link": "/zh-cn/blog/seata-config-center.html",
|
||||
"meta": {
|
||||
"title": "Seata 配置中心实现原理",
|
||||
"author": "张乘辉",
|
||||
"keywords": "Seata、Config",
|
||||
"description": "Seata 可以支持多个第三方配置中心,那么 Seata 是如何同时兼容那么多个配置中心的呢?",
|
||||
"date": "2019/12/12"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "seata-mybatisplus-analysis.md",
|
||||
"link": "/zh-cn/blog/seata-mybatisplus-analysis.html",
|
||||
"meta": {
|
||||
"title": "透过源码解决SeataAT模式整合Mybatis-Plus失去MP特性的问题",
|
||||
"keywords": "Seata,Mybatis-Plus,分布式事务",
|
||||
"description": "本文讲述如何透过源码解决Seata整合Mybatis-Plus失去MP特性的问题",
|
||||
"author": "FUNKYE",
|
||||
"date": "2019/11/30"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "seata-nacos-analysis.md",
|
||||
"link": "/zh-cn/blog/seata-nacos-analysis.html",
|
||||
"meta": {
|
||||
"title": "Seata分布式事务启用Nacos做配置中心",
|
||||
"keywords": "Seata,Nacos,分布式事务",
|
||||
"description": "本文讲述如何使用Seata整合Nacos配置",
|
||||
"author": "FUNKYE",
|
||||
"date": "2019/12/02"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "seata-nacos-docker.md",
|
||||
"link": "/zh-cn/blog/seata-nacos-docker.html",
|
||||
"meta": {
|
||||
"title": "Docker部署Seata与Nacos整合",
|
||||
"keywords": "Seata,Nacos,分布式事务",
|
||||
"description": "本文讲述如何使用Seata整合Nacos配置的Docker部署",
|
||||
"author": "FUNKYE",
|
||||
"date": "2019/12/03"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "springboot-dubbo-mybatisplus-seata.md",
|
||||
"link": "/zh-cn/blog/springboot-dubbo-mybatisplus-seata.html",
|
||||
"meta": {
|
||||
"title": "SpringBoot+Dubbo+MybatisPlus整合seata分布式事务",
|
||||
"keywords": "Seata,dubbo,mybatis,分布式事务",
|
||||
"description": "本文讲述如何将springboot+dubbo+mybatisplus整合seata直连方式搭建",
|
||||
"author": "FUNKYE",
|
||||
"date": "2019/11/29"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "tcc-mode-applicable-scenario-analysis.md",
|
||||
"link": "/zh-cn/blog/tcc-mode-applicable-scenario-analysis.html",
|
||||
"meta": {
|
||||
"title": "TCC适用模型与适用场景分析",
|
||||
"author": "zhangthen",
|
||||
"date": "2019/03/27",
|
||||
"keywords": "seata、分布式事务、TCC、roadmap"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "tcc-mode-design-principle.md",
|
||||
"link": "/zh-cn/blog/tcc-mode-design-principle.html",
|
||||
"meta": {
|
||||
"title": "TCC 理论及设计实现指南介绍",
|
||||
"author": "zhangthen",
|
||||
"date": "2019/03/26",
|
||||
"keywords": "fescar、分布式事务、TCC、roadmap"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,506 +0,0 @@
|
|||
{
|
||||
"en-us": [
|
||||
{
|
||||
"filename": "at-mode.md",
|
||||
"link": "/en-us/docs/dev/mode/at-mode.html",
|
||||
"meta": {
|
||||
"title": "Seata AT Mode",
|
||||
"keywords": "Seata, AT mode",
|
||||
"description": "Seata AT mode."
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "saga-mode.md",
|
||||
"link": "/en-us/docs/dev/mode/saga-mode.html",
|
||||
"meta": {
|
||||
"title": "Seata Saga Mode",
|
||||
"keywords": "Seata, Saga mode",
|
||||
"description": "Seata Saga mode."
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "tcc-mode.md",
|
||||
"link": "/en-us/docs/dev/mode/tcc-mode.html",
|
||||
"meta": {
|
||||
"title": "Seata TCC Mode",
|
||||
"keywords": "Seata, TCC Mode",
|
||||
"description": "Seata TCC mode."
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "seata-mertics.md",
|
||||
"link": "/en-us/docs/dev/seata-mertics.html",
|
||||
"meta": {
|
||||
"title": "Seata Metrics",
|
||||
"keywords": "Seata, Metrics",
|
||||
"description": "Seata Metrics."
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "label-an-issue-guide_dev.md",
|
||||
"link": "/en-us/docs/developers/committer-guide/label-an-issue-guide_dev.html",
|
||||
"meta": {
|
||||
"title": "Label an Issue",
|
||||
"keywords": "Seata",
|
||||
"description": "Label an Issue."
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "release-guide_dev.md",
|
||||
"link": "/en-us/docs/developers/committer-guide/release-guide_dev.html",
|
||||
"meta": {}
|
||||
},
|
||||
{
|
||||
"filename": "website-guide_dev.md",
|
||||
"link": "/en-us/docs/developers/committer-guide/website-guide_dev.html",
|
||||
"meta": {
|
||||
"title": "Website Guide",
|
||||
"keywords": "Seata",
|
||||
"description": "Website Guide."
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "new-contributor-guide_dev.md",
|
||||
"link": "/en-us/docs/developers/contributor-guide/new-contributor-guide_dev.html",
|
||||
"meta": {
|
||||
"title": "New contributor guide",
|
||||
"keywords": "Seata, contributor",
|
||||
"description": "This is a guide for new comers who wants to contribute to Seata."
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "reporting-security-issues_dev.md",
|
||||
"link": "/en-us/docs/developers/contributor-guide/reporting-security-issues_dev.html",
|
||||
"meta": {
|
||||
"title": "New contributor guide",
|
||||
"keywords": "Seata, contributor",
|
||||
"description": "This is a guide for new comers who wants to contribute to Seata."
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "test-coverage-guide_dev.md",
|
||||
"link": "/en-us/docs/developers/contributor-guide/test-coverage-guide_dev.html",
|
||||
"meta": {
|
||||
"title": "Test coverage guide",
|
||||
"keywords": "Seata, coverage",
|
||||
"description": "Test coverage guide."
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "developers_dev.md",
|
||||
"link": "/en-us/docs/developers/developers_dev.html",
|
||||
"meta": {
|
||||
"title": "Developers",
|
||||
"keywords": "Seata, Developers",
|
||||
"description": "Seata Team."
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "guide_dev.md",
|
||||
"link": "/en-us/docs/developers/guide_dev.html",
|
||||
"meta": {
|
||||
"title": "Contributing to Seata",
|
||||
"keywords": "Seata",
|
||||
"description": "It is warmly welcomed if you have interest to hack on Seata. First, we encourage this kind of willing very much. And here is a list of contributing guide for you."
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "deploy-by-docker.md",
|
||||
"link": "/en-us/docs/ops/deploy-by-docker.html",
|
||||
"meta": {
|
||||
"hidden": "true",
|
||||
"title": "Deploy Seata Server By Docker",
|
||||
"keywords": "docker",
|
||||
"description": "Deploy Seata Server By Docker",
|
||||
"author": "helloworlde",
|
||||
"date": "2019-11-25"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "deploy-by-helm.md",
|
||||
"link": "/en-us/docs/ops/deploy-by-helm.html",
|
||||
"meta": {
|
||||
"hidden": "true",
|
||||
"title": "Deploy Seata Server By Helm",
|
||||
"keywords": "kubernetes,helm,ops",
|
||||
"description": "Deploy Seata Server By Helm",
|
||||
"author": "helloworlde",
|
||||
"date": "2019-12-01"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "deploy-by-kubernetes.md",
|
||||
"link": "/en-us/docs/ops/deploy-by-kubernetes.html",
|
||||
"meta": {
|
||||
"hidden": "true",
|
||||
"title": "Deploy Seata Server By Kubernetes",
|
||||
"keywords": "kubernetes,ops",
|
||||
"description": "Deploy Seata Server By Kubernetes",
|
||||
"author": "helloworlde",
|
||||
"date": "2019-12-01"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "deploy-server.md",
|
||||
"link": "/en-us/docs/ops/deploy-server.html",
|
||||
"meta": {
|
||||
"title": "Deploy Server",
|
||||
"keywords": "Seata",
|
||||
"description": "The server can deploy by multiple method: Directly, Docker, Docker-Compose, Kubernetes, Helm."
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "multi-configuration-isolation.md",
|
||||
"link": "/en-us/docs/ops/multi-configuration-isolation.html",
|
||||
"meta": {
|
||||
"title": "Multi-configuration Isolation",
|
||||
"keywords": "Seata",
|
||||
"description": "Seata supports Multi-configuration Isolation since 0.6.1,You can configure it in the following steps."
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "faq.md",
|
||||
"link": "/en-us/docs/overview/faq.html",
|
||||
"meta": {
|
||||
"title": "Seata FAQ",
|
||||
"keywords": "Seata",
|
||||
"description": "Seata FAQ."
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "terminology.md",
|
||||
"link": "/en-us/docs/overview/terminology.html",
|
||||
"meta": {
|
||||
"title": "Seata Terminology",
|
||||
"keywords": "Seata",
|
||||
"description": "Seata Terminology."
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "what-is-seata.md",
|
||||
"link": "/en-us/docs/overview/what-is-seata.html",
|
||||
"meta": {
|
||||
"title": "What Is Seata",
|
||||
"keywords": "Seata",
|
||||
"description": "Seata is an open source distributed transaction solution dedicated to providing high performance and easy to use distributed transaction services. Seata will provide users with AT, TCC, SAGA, and XA transaction models to create a one-stop distributed solution for users."
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "api.md",
|
||||
"link": "/en-us/docs/user/api.html",
|
||||
"meta": {
|
||||
"title": "Api Guide",
|
||||
"keywords": "Seata",
|
||||
"description": "Api Guide."
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "microservice.md",
|
||||
"link": "/en-us/docs/user/microservice.html",
|
||||
"meta": {
|
||||
"title": "Microservice Framework Guide",
|
||||
"keywords": "Seata",
|
||||
"description": "Microservice Framework Guide."
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "quickstart.md",
|
||||
"link": "/en-us/docs/user/quickstart.html",
|
||||
"meta": {
|
||||
"title": "Quick Start",
|
||||
"keywords": "Seata",
|
||||
"description": "Let's begin with a Microservices example."
|
||||
}
|
||||
}
|
||||
],
|
||||
"zh-cn": [
|
||||
{
|
||||
"filename": "at-mode.md",
|
||||
"link": "/zh-cn/docs/dev/mode/at-mode.html",
|
||||
"meta": {
|
||||
"title": "Seata AT 模式",
|
||||
"keywords": "Seata",
|
||||
"description": "Seata AT 模式。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "saga-mode.md",
|
||||
"link": "/zh-cn/docs/dev/mode/saga-mode.html",
|
||||
"meta": {
|
||||
"title": "Seata Saga 模式",
|
||||
"keywords": "Seata",
|
||||
"description": "Seata Saga 模式。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "tcc-mode.md",
|
||||
"link": "/zh-cn/docs/dev/mode/tcc-mode.html",
|
||||
"meta": {
|
||||
"title": "Seata Tcc 模式",
|
||||
"keywords": "Seata",
|
||||
"description": "Seata Tcc 模式。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "seata-mertics.md",
|
||||
"link": "/zh-cn/docs/dev/seata-mertics.html",
|
||||
"meta": {
|
||||
"title": "Metrics",
|
||||
"keywords": "Seata",
|
||||
"description": "Metrics。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "label-an-issue-guide_dev.md",
|
||||
"link": "/zh-cn/docs/developers/committer-guide/label-an-issue-guide_dev.html",
|
||||
"meta": {
|
||||
"title": "给问题打标签",
|
||||
"keywords": "Seata",
|
||||
"description": "如果您正在处理一个问题,请记得给这个问题标记一个或者多个您认为有意义的标签。有了标签,其他开发人员就会很轻松地识别出问题,以便对其进行分类并跟踪进度。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "release-guide_dev.md",
|
||||
"link": "/zh-cn/docs/developers/committer-guide/release-guide_dev.html",
|
||||
"meta": {
|
||||
"title": "Seata版本向导",
|
||||
"keywords": "Seata",
|
||||
"description": "Seata版本向导。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "website-guide_dev.md",
|
||||
"link": "/zh-cn/docs/developers/committer-guide/website-guide_dev.html",
|
||||
"meta": {
|
||||
"title": "网站向导",
|
||||
"keywords": "Seata",
|
||||
"description": "Seata 网站向导。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "new-contributor-guide_dev.md",
|
||||
"link": "/zh-cn/docs/developers/contributor-guide/new-contributor-guide_dev.html",
|
||||
"meta": {
|
||||
"title": "新贡献者向导",
|
||||
"keywords": "Seata",
|
||||
"description": "这篇向导旨在给正在准备向Seata提交贡献的新手提供指导。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "reporting-security-issues_dev.md",
|
||||
"link": "/zh-cn/docs/developers/contributor-guide/reporting-security-issues_dev.html",
|
||||
"meta": {
|
||||
"title": "报告安全问题",
|
||||
"keywords": "Seata",
|
||||
"description": "Seata在消除其软件项目中的安全性问题方面采取严格的立场,对与其功能和特性有关的问题非常敏感并很快提出。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "test-coverage-guide_dev.md",
|
||||
"link": "/zh-cn/docs/developers/contributor-guide/test-coverage-guide_dev.html",
|
||||
"meta": {
|
||||
"title": "测试覆盖率向导",
|
||||
"keywords": "Seata",
|
||||
"description": "测试覆盖率向导。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "developers_dev.md",
|
||||
"link": "/zh-cn/docs/developers/developers_dev.html",
|
||||
"meta": {
|
||||
"title": "Seata 维护者",
|
||||
"keywords": "Seata, 维护者",
|
||||
"description": "Seata 维护者名单"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "guide_dev.md",
|
||||
"link": "/zh-cn/docs/developers/guide_dev.html",
|
||||
"meta": {
|
||||
"title": "为Seata贡献",
|
||||
"keywords": "Seata",
|
||||
"description": "如果您有兴趣攻克Seata,欢迎您。首先,我们非常鼓励这种意愿。这是为您提供帮助的列表。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "config-center.md",
|
||||
"link": "/zh-cn/docs/ops/config-center.html",
|
||||
"meta": {
|
||||
"title": "配置中心初始化",
|
||||
"keywords": "Seata",
|
||||
"description": "配置中心初始化。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "deploy-by-docker.md",
|
||||
"link": "/zh-cn/docs/ops/deploy-by-docker.html",
|
||||
"meta": {
|
||||
"hidden": "true",
|
||||
"title": "使用 Docker 部署 Seata Server",
|
||||
"keywords": "docker,docker-compose,ops",
|
||||
"description": "使用 Docker 部署 Seata Server",
|
||||
"author": "helloworlde",
|
||||
"date": "2019-11-25"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "deploy-by-helm.md",
|
||||
"link": "/zh-cn/docs/ops/deploy-by-helm.html",
|
||||
"meta": {
|
||||
"hidden": "true",
|
||||
"title": "使用 Helm 部署 Seata Server",
|
||||
"keywords": "kubernetes,helm,ops",
|
||||
"description": "使用 Helm 部署 Seata Server",
|
||||
"author": "helloworlde",
|
||||
"date": "2019-12-01"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "deploy-by-kubernetes.md",
|
||||
"link": "/zh-cn/docs/ops/deploy-by-kubernetes.html",
|
||||
"meta": {
|
||||
"hidden": "true",
|
||||
"title": "使用 Kubernetes 部署 Seata Server",
|
||||
"keywords": "kubernetes,ops",
|
||||
"description": "使用 Kubernetes 部署 Seata Server",
|
||||
"author": "helloworlde",
|
||||
"date": "2019-12-01"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "deploy-guide-beginner.md",
|
||||
"link": "/zh-cn/docs/ops/deploy-guide-beginner.html",
|
||||
"meta": {
|
||||
"title": "Seata部署指南",
|
||||
"keywords": "Seata",
|
||||
"description": "Seata分TC、TM和RM三个角色,TC(Server端)为单独服务端部署,TM和RM(Client端)由业务系统集成。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "deploy-server.md",
|
||||
"link": "/zh-cn/docs/ops/deploy-server.html",
|
||||
"meta": {
|
||||
"title": "部署 Server",
|
||||
"keywords": "Seata",
|
||||
"description": "Server支持多种方式部署:直接部署,使用 Docker, 使用 Docker-Compose, 使用 Kubernetes, 使用 Helm。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "operation.md",
|
||||
"link": "/zh-cn/docs/ops/operation.html",
|
||||
"meta": {
|
||||
"title": "运维指南",
|
||||
"keywords": "Seata",
|
||||
"description": "Seata支持在TC、TM和RM三个角色开启Metrics数据采集并输出到Prometheus监控系统中。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "faq.md",
|
||||
"link": "/zh-cn/docs/overview/faq.html",
|
||||
"meta": {
|
||||
"title": "Seata常见问题",
|
||||
"keywords": "Seata",
|
||||
"description": "Seata 常见问题。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "terminology.md",
|
||||
"link": "/zh-cn/docs/overview/terminology.html",
|
||||
"meta": {
|
||||
"title": "Seata术语",
|
||||
"keywords": "Seata",
|
||||
"description": "Seata术语。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "what-is-seata.md",
|
||||
"link": "/zh-cn/docs/overview/what-is-seata.html",
|
||||
"meta": {
|
||||
"title": "Seata 是什么",
|
||||
"keywords": "Seata",
|
||||
"description": "Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服务。Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "api.md",
|
||||
"link": "/zh-cn/docs/user/api.html",
|
||||
"meta": {
|
||||
"title": "Seata api",
|
||||
"keywords": "Seata",
|
||||
"description": "Seata API 分为两大类:High-Level API 和 Low-Level API。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "configurations.md",
|
||||
"link": "/zh-cn/docs/user/configurations.html",
|
||||
"meta": {
|
||||
"title": "Seata 参数配置",
|
||||
"keywords": "Seata",
|
||||
"description": "Seata 参数配置。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "configurations090.md",
|
||||
"link": "/zh-cn/docs/user/configurations090.html",
|
||||
"meta": {
|
||||
"title": "Seata 参数配置 0.9.0版本",
|
||||
"keywords": "Seata",
|
||||
"description": "Seata 参数配置 0.9.0版本。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "datasource.md",
|
||||
"link": "/zh-cn/docs/user/datasource.html",
|
||||
"meta": {
|
||||
"title": "Seata 数据源支持",
|
||||
"keywords": "Seata",
|
||||
"description": "Seata 数据源支持。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "microservice.md",
|
||||
"link": "/zh-cn/docs/user/microservice.html",
|
||||
"meta": {
|
||||
"title": "Seata 微服务框架支持",
|
||||
"keywords": "Seata",
|
||||
"description": "Seata 微服务框架支持。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "ormframework.md",
|
||||
"link": "/zh-cn/docs/user/ormframework.html",
|
||||
"meta": {
|
||||
"title": "Seata ORM框架支持",
|
||||
"keywords": "Seata",
|
||||
"description": "Seata ORM框架支持。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "quickstart.md",
|
||||
"link": "/zh-cn/docs/user/quickstart.html",
|
||||
"meta": {
|
||||
"title": "Seata 快速开始",
|
||||
"keywords": "Seata",
|
||||
"description": "Seata 快速开始。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "saga.md",
|
||||
"link": "/zh-cn/docs/user/saga.html",
|
||||
"meta": {
|
||||
"title": "Seata Saga 模式",
|
||||
"keywords": "Seata",
|
||||
"description": "Saga模式是SEATA提供的长事务解决方案,在Saga模式中,业务流程中每个参与者都提交本地事务,当出现某一个参与者失败则补偿前面已经成功的参与者,一阶段正向服务和二阶段补偿服务都由业务开发实现。"
|
||||
}
|
||||
},
|
||||
{
|
||||
"filename": "spring.md",
|
||||
"link": "/zh-cn/docs/user/spring.html",
|
||||
"meta": {
|
||||
"title": "Seata Spring支持",
|
||||
"keywords": "Seata",
|
||||
"description": "Seata Spring支持。"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,506 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Saga,Seata,一致性,金融,弹性,分布式,事务" />
|
||||
<meta name="description" content="本文从金融分布式应用开发的一些痛点出发,结合理论和实践对社区和行业的解决方案进行了分析,并讲解了如何基于Seata saga设计更有弹性的金融应用" />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>基于 Seata Saga 设计更有弹性的金融应用</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/blogDetail.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="blog-detail-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/zh-cn/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">En</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/zh-cn/index.html" target="_self">首页</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/docs/overview/what-is-seata.html" target="_self">文档</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/docs/developers/developers_dev.html" target="_self">开发者</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/zh-cn/blog/index.html" target="_self">博客</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/community/index.html" target="_self">社区</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/blog/download.html" target="_self">下载</a></li></ul></div></div></header><section class="blog-content markdown-body"><h1>基于 Seata Saga 设计更有弹性的金融应用</h1>
|
||||
<p>Seata 意为:Simple Extensible Autonomous Transaction Architecture,是一套一站式分布式事务解决方案,提供了 AT、TCC、Saga 和 XA 事务模式,本文详解其中的 Saga 模式。<br />项目地址:<a href="https://github.com/seata/seata">https://github.com/seata/seata</a></p>
|
||||
<p>本文作者:屹远(陈龙),蚂蚁金服分布式事务核心研发,Seata Committer。</p>
|
||||
<p><a name="uTwja"></a></p>
|
||||
<h1>金融分布式应用开发的痛点</h1>
|
||||
<p>分布式系统有一个比较明显的问题就是,一个业务流程需要组合一组服务。这样的事情在微服务下就更为明显了,因为这需要业务上的一致性的保证。也就是说,如果一个步骤失败了,那么要么回滚到以前的服务调用,要么不断重试保证所有的步骤都成功。---《左耳听风-弹力设计之“补偿事务”》</p>
|
||||
<p>而在金融领域微服务架构下的业务流程往往会更复杂,流程很长,比如一个互联网微贷业务流程调十几个服务很正常,再加上异常处理的流程那就更复杂了,做过金融业务开发的同学会很有体感。</p>
|
||||
<p>所以在金融分布式应用开发过程中我们面临一些痛点:</p>
|
||||
<ul>
|
||||
<li><strong>业务一致性难以保障</strong><br /></li>
|
||||
</ul>
|
||||
<p>我们接触到的大多数业务(比如在渠道层、产品层、集成层的系统),为了保障业务最终一致性,往往会采用“补偿”的方式来做,如果没有一个协调器来支持,开发难度是比较大的,每一步都要在 catch 里去处理前面所有的“回滚”操作,这将会形成“箭头形”的代码,可读性及维护性差。或者重试异常的操作,如果重试不成功可能要转异步重试,甚至最后转人工处理。这些都给开发人员带来极大的负担,开发效率低,且容易出错。</p>
|
||||
<ul>
|
||||
<li><strong>业务状态难以管理</strong><br /></li>
|
||||
</ul>
|
||||
<p>业务实体很多、实体的状态也很多,往往做完一个业务活动后就将实体的状态更新到了数据库里,没有一个状态机来管理整个状态的变迁过程,不直观,容易出错,造成业务进入一个不正确的状态。</p>
|
||||
<ul>
|
||||
<li><strong>幂等性难以保障</strong><br /></li>
|
||||
</ul>
|
||||
<p>服务的幂等性是分布式环境下的基本要求,为了保证服务的幂等性往往需要服务开发者逐个去设计,有用数据库唯一键实现的,有用分布式缓存实现的,没有一个统一的方案,开发人员负担大,也容易遗漏,从而造成资损。</p>
|
||||
<ul>
|
||||
<li><strong>业务监控运维难,缺乏统一的差错守护能力</strong><br /></li>
|
||||
</ul>
|
||||
<p>业务的执行情况监控一般通过打印日志,再基于日志监控平台查看,大多数情况是没有问题的,但是如果业务出错,这些监控缺乏当时的业务上下文,对排查问题不友好,往往需要再去数据库里查。同时日志的打印也依赖于开发,容易遗漏。对于补偿事务往往需要有“差错守护触发补偿”、“工人触发补偿”操作,没有统一的差错守护和处理规范,这些都要开发者逐个开发,负担沉重。</p>
|
||||
<p><a name="hvEU6"></a></p>
|
||||
<h1>理论基础</h1>
|
||||
<p>一些场景下,我们对数据有强一致性的需求时,会采用在业务层上需要使用“两阶段提交”这样的分布式事务方案。而在另外一些场景下,我们并不需要这么强的一致性,那就只需要保证最终一致性就可以了。</p>
|
||||
<p>例如蚂蚁金服目前在金融核心系统使用的就是 TCC 模式,金融核心系统的特点是一致性要求高(业务上的隔离性)、短流程、并发高。</p>
|
||||
<p>而在很多金融核心以上的业务(比如在渠道层、产品层、集成层的系统),这些系统的特点是最终一致即可、流程多、流程长、还可能要调用其它公司的服务(如金融网络)。这是如果每个服务都开发 Try、Confirm、Cancel 三个方法成本高。如果事务中有其它公司的服务,也无法要求其它公司的服务也遵循 TCC 这种开发模式。同时流程长,事务边界太长会影响性能。</p>
|
||||
<p>对于事务我们都知道 ACID,也很熟悉 CAP 理论最多只能满足其中两个,所以,为了提高性能,出现了 ACID 的一个变种 BASE。ACID 强调的是一致性(CAP 中的 C),而 BASE 强调的是可用性(CAP 中的 A)。我们知道,在很多情况下,我们是无法做到强一致性的 ACID 的。特别是我们需要跨多个系统的时候,而且这些系统还不是由一个公司所提供的。BASE 的系统倾向于设计出更加有弹力的系统,在短时间内,就算是有数据不同步的风险,我们也应该允许新的交易可以发生,而后面我们在业务上将可能出现问题的事务通过补偿的方式处理掉,以保证最终的一致性。</p>
|
||||
<p>所以我们在实际开发中会进行取舍,对于更多的金融核心以上的业务系统可以采用补偿事务,补偿事务处理方面在30年前就提出了 Saga 理论,随着微服务的发展,近些年才逐步受到大家的关注。目前业界比较也公认 Saga 是作为长事务的解决方案。</p>
|
||||
<blockquote>
|
||||
<p><a href="https://github.com/aphyr/dist-sagas/blob/master/sagas.pdf">https://github.com/aphyr/dist-sagas/blob/master/sagas.pdf</a>[1]
|
||||
<a href="http://microservices.io/patterns/data/saga.html">http://microservices.io/patterns/data/saga.html</a>[2]</p>
|
||||
</blockquote>
|
||||
<p><a name="k8kbY"></a></p>
|
||||
<h1>社区和业界的方案</h1>
|
||||
<p><a name="Oc5Er"></a></p>
|
||||
<h2>Apache Camel Saga</h2>
|
||||
<p>Camel 是实现 EIP(Enterprise Integration Patterns)企业集成模式的一款开源产品,它基于事件驱动的架构,有着良好的性能和吞吐量,它在2.21版本新增加了 Saga EIP。</p>
|
||||
<p>Saga EIP 提供了一种方式可以通过 camel route 定义一系列有关联关系的 Action,这些 Action 要么都执行成功,要么都回滚,Saga 可以协调任何通讯协议的分布式服务或本地服务,并达到全局的最终一致性。Saga 不要求整个处理在短时间内完成,因为它不占用任何数据库锁,它可以支持需要长时间处理的请求,从几秒到几天,Camel 的 Saga EIP 是基于 <a href="https://github.com/eclipse/microprofile-sandbox/tree/master/proposals/0009-LRA">Microprofile 的 LRA</a>[3](Long Running Action),同样也是支持协调任何通讯协议任何语言实现的分布式服务。</p>
|
||||
<p>Saga 的实现不会对数据进行加锁,而是在给操作定义它的“补偿操作”,当正常流程执行出错的时候触发那些已经执行过的操作的“补偿操作”,将流程回滚掉。“补偿操作”可以在 Camel route 上用 Java 或 XML DSL(Definition Specific Language)来定义。</p>
|
||||
<p>下面是一个 Java DSL 示例:</p>
|
||||
<pre><code class="language-java"><span class="hljs-comment">// action</span>
|
||||
from(<span class="hljs-string">"direct:reserveCredit"</span>)
|
||||
.bean(idService, <span class="hljs-string">"generateCustomId"</span>) <span class="hljs-comment">// generate a custom Id and set it in the body</span>
|
||||
.to(<span class="hljs-string">"direct:creditReservation"</span>)
|
||||
|
||||
<span class="hljs-comment">// delegate action</span>
|
||||
from(<span class="hljs-string">"direct:creditReservation"</span>)
|
||||
.saga()
|
||||
.propagation(SagaPropagation.SUPPORTS)
|
||||
.option(<span class="hljs-string">"CreditId"</span>, body()) <span class="hljs-comment">// mark the current body as needed in the compensating action</span>
|
||||
.compensation(<span class="hljs-string">"direct:creditRefund"</span>)
|
||||
.bean(creditService, <span class="hljs-string">"reserveCredit"</span>)
|
||||
.log(<span class="hljs-string">"Credit ${header.amount} reserved. Custom Id used is ${body}"</span>);
|
||||
|
||||
<span class="hljs-comment">// called only if the saga is cancelled</span>
|
||||
from(<span class="hljs-string">"direct:creditRefund"</span>)
|
||||
.transform(header(<span class="hljs-string">"CreditId"</span>)) <span class="hljs-comment">// retrieve the CreditId option from headers</span>
|
||||
.bean(creditService, <span class="hljs-string">"refundCredit"</span>)
|
||||
.log(<span class="hljs-string">"Credit for Custom Id ${body} refunded"</span>);
|
||||
</code></pre>
|
||||
<p>XML DSL 示例:</p>
|
||||
<pre><code class="language-xml"><span class="hljs-tag"><<span class="hljs-name">route</span>></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">from</span> <span class="hljs-attr">uri</span>=<span class="hljs-string">"direct:start"</span>/></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">saga</span>></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">compensation</span> <span class="hljs-attr">uri</span>=<span class="hljs-string">"direct:compensation"</span> /></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">completion</span> <span class="hljs-attr">uri</span>=<span class="hljs-string">"direct:completion"</span> /></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">option</span> <span class="hljs-attr">optionName</span>=<span class="hljs-string">"myOptionKey"</span>></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">constant</span>></span>myOptionValue<span class="hljs-tag"></<span class="hljs-name">constant</span>></span>
|
||||
<span class="hljs-tag"></<span class="hljs-name">option</span>></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">option</span> <span class="hljs-attr">optionName</span>=<span class="hljs-string">"myOptionKey2"</span>></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">constant</span>></span>myOptionValue2<span class="hljs-tag"></<span class="hljs-name">constant</span>></span>
|
||||
<span class="hljs-tag"></<span class="hljs-name">option</span>></span>
|
||||
<span class="hljs-tag"></<span class="hljs-name">saga</span>></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">to</span> <span class="hljs-attr">uri</span>=<span class="hljs-string">"direct:action1"</span> /></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">to</span> <span class="hljs-attr">uri</span>=<span class="hljs-string">"direct:action2"</span> /></span>
|
||||
<span class="hljs-tag"></<span class="hljs-name">route</span>></span>
|
||||
</code></pre>
|
||||
<p><a name="pQWuF"></a></p>
|
||||
<h2>Eventuate Tram Saga</h2>
|
||||
<p><a href="https://github.com/eventuate-tram/eventuate-tram-sagas">Eventuate Tram Saga</a>[4] 框架是使用 JDBC / JPA 的 Java 微服务的一个 Saga 框架。它也和 Camel Saga 一样采用了 Java DSL 来定义补偿操作:</p>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CreateOrderSaga</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">SimpleSaga</span><<span class="hljs-title">CreateOrderSagaData</span>> </span>{
|
||||
|
||||
<span class="hljs-keyword">private</span> SagaDefinition<CreateOrderSagaData> sagaDefinition =
|
||||
step()
|
||||
.withCompensation(<span class="hljs-keyword">this</span>::reject)
|
||||
.step()
|
||||
.invokeParticipant(<span class="hljs-keyword">this</span>::reserveCredit)
|
||||
.step()
|
||||
.invokeParticipant(<span class="hljs-keyword">this</span>::approve)
|
||||
.build();
|
||||
|
||||
|
||||
<span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> SagaDefinition<CreateOrderSagaData> <span class="hljs-title">getSagaDefinition</span><span class="hljs-params">()</span> </span>{
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.sagaDefinition;
|
||||
}
|
||||
|
||||
|
||||
<span class="hljs-function"><span class="hljs-keyword">private</span> CommandWithDestination <span class="hljs-title">reserveCredit</span><span class="hljs-params">(CreateOrderSagaData data)</span> </span>{
|
||||
<span class="hljs-keyword">long</span> orderId = data.getOrderId();
|
||||
Long customerId = data.getOrderDetails().getCustomerId();
|
||||
Money orderTotal = data.getOrderDetails().getOrderTotal();
|
||||
<span class="hljs-keyword">return</span> send(<span class="hljs-keyword">new</span> ReserveCreditCommand(customerId, orderId, orderTotal))
|
||||
.to(<span class="hljs-string">"customerService"</span>)
|
||||
.build();
|
||||
|
||||
...
|
||||
</code></pre>
|
||||
<p><a name="scN9h"></a></p>
|
||||
<h2>Apache ServiceComb Saga</h2>
|
||||
<p><a href="https://github.com/apache/incubator-servicecomb-saga">ServiceComb Saga</a>[5] 也是一个微服务应用的数据最终一致性解决方案。相对于 <a href="http://design.inf.usi.ch/sites/default/files/biblio/rest-tcc.pdf">TCC</a> 而言,在 try 阶段,Saga 会直接提交事务,后续 rollback 阶段则通过反向的补偿操作来完成。与前面两种不同是它是采用 Java 注解+拦截器的方式来进行“补偿”服务的定义。<br /></p>
|
||||
<p><a name="ouwrmp"></a></p>
|
||||
<h4>架构:</h4>
|
||||
<p>Saga 是由 <strong>alpha</strong> 和 **omega **组成,其中:</p>
|
||||
<ul>
|
||||
<li>alpha 充当协调者的角色,主要负责对事务进行管理和协调;<br /></li>
|
||||
<li>omega 是微服务中内嵌的一个 agent,负责对网络请求进行拦截并向 alpha 上报事务事件;<br /></li>
|
||||
</ul>
|
||||
<p>下图展示了 alpha,omega 以及微服务三者的关系:<br />
|
||||
<img src="/img/saga/service-comb-saga.png?raw=true" alt="ServiceComb Saga"></p>
|
||||
<p><a name="ggflbq"></a></p>
|
||||
<h4>使用示例:</h4>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ServiceA</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">AbsService</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">IServiceA</span> </span>{
|
||||
|
||||
<span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> Logger LOG = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
|
||||
|
||||
<span class="hljs-meta">@Autowired</span>
|
||||
<span class="hljs-keyword">private</span> IServiceB serviceB;
|
||||
|
||||
<span class="hljs-meta">@Autowired</span>
|
||||
<span class="hljs-keyword">private</span> IServiceC serviceC;
|
||||
|
||||
<span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getServiceName</span><span class="hljs-params">()</span> </span>{
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-string">"servicea"</span>;
|
||||
}
|
||||
|
||||
<span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getTableName</span><span class="hljs-params">()</span> </span>{
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-string">"testa"</span>;
|
||||
}
|
||||
|
||||
<span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-meta">@SagaStart</span>
|
||||
<span class="hljs-meta">@Compensable</span>(compensationMethod = <span class="hljs-string">"cancelRun"</span>)
|
||||
<span class="hljs-meta">@Transactional</span>(rollbackFor = Exception<span class="hljs-class">.<span class="hljs-keyword">class</span>)
|
||||
<span class="hljs-title">public</span> <span class="hljs-title">Object</span> <span class="hljs-title">run</span>(<span class="hljs-title">InvokeContext</span> <span class="hljs-title">invokeContext</span>) <span class="hljs-title">throws</span> <span class="hljs-title">Exception</span> </span>{
|
||||
LOG.info(<span class="hljs-string">"A.run called"</span>);
|
||||
doRunBusi();
|
||||
<span class="hljs-keyword">if</span> (invokeContext.isInvokeB(getServiceName())) {
|
||||
serviceB.run(invokeContext);
|
||||
}
|
||||
<span class="hljs-keyword">if</span> (invokeContext.isInvokeC(getServiceName())) {
|
||||
serviceC.run(invokeContext);
|
||||
}
|
||||
<span class="hljs-keyword">if</span> (invokeContext.isException(getServiceName())) {
|
||||
LOG.info(<span class="hljs-string">"A.run exception"</span>);
|
||||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> Exception(<span class="hljs-string">"A.run exception"</span>);
|
||||
}
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-keyword">null</span>;
|
||||
}
|
||||
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">cancelRun</span><span class="hljs-params">(InvokeContext invokeContext)</span> </span>{
|
||||
LOG.info(<span class="hljs-string">"A.cancel called"</span>);
|
||||
doCancelBusi();
|
||||
}
|
||||
</code></pre>
|
||||
<p><a name="CnD8r"></a></p>
|
||||
<h2>蚂蚁金服的实践</h2>
|
||||
<p>蚂蚁金服内部大规模在使用 TCC 模式分布式事务,主要用于金融核心等对一致性要求高、性能要求高的场景。在更上层的业务系统因为流程多流程长,开发 TCC 成本比较高,大都会权衡采用 Saga 模式来到达业务最终一致性,由于历史的原因不同的 BU 有自己的一套“补偿”事务的方案,基本上是两种:</p>
|
||||
<ul>
|
||||
<li>一种是当一个服务在失败时需要“重试”或“补偿”时,在执行服务前在数据库插入一条记录,记录状态,当异常时通过定时任务去查询数据库记录并进行“重试”或“补偿”,当业务流程执行成功则删除记录;</li>
|
||||
<li>另一种是设计一个状态机引擎和简单的 DSL,编排业务流程和记录业务状态,状态机引擎可以定义“补偿服务”,当异常时由状态机引擎反向调用“补偿服务”进行回滚,同时还会有一个“差错守护”平台,监控那些执行失败或补偿失败的业务流水,并不断进行“补偿”或“重试”;</li>
|
||||
</ul>
|
||||
<p><a name="MAZEu"></a></p>
|
||||
<h2>方案对比</h2>
|
||||
<p>社区和业界的解决方案一般是两种,一种基本状态机或流程引擎通过 DSL 方式编排流程程和补偿定义,一种是基于 Java 注解+拦截器实现补偿,那么这两种方案有什么优缺点呢?</p>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th><strong>方式</strong></th>
|
||||
<th><strong>优点</strong></th>
|
||||
<th><strong>缺点</strong></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>状态机+DSL</td>
|
||||
<td><br />- 可以用可视化工具来定义业务流程,标准化,可读性高,可实现服务编排的功能<br />- 提高业务分析人员与程序开发人员的沟通效率<br />- 业务状态管理:流程本质就是一个状态机,可以很好的反映业务状态的流转<br />- 提高异常处理灵活性:可以实现宕机恢复后的“向前重试”或“向后补偿”<br />- 天然可以使用 Actor 模型或 SEDA 架构等异步处理引擎来执行,提高整体吞吐量<br /></td>
|
||||
<td><br />- 业务流程实际是由 JAVA 程序与 DSL 配置组成,程序与配置分离,开发起来比较繁琐<br />- 如果是改造现有业务,对业务侵入性高<br />- 引擎实现成本高<br /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>拦截器+java 注解</td>
|
||||
<td><br />- 程序与注解是在一起的,开发简单,学习成本低<br />- 方便接入现有业务<br />- 基于动态代理拦截器,框架实现成本低<br /></td>
|
||||
<td><br />- 框架无法提供 Actor 模型或 SEDA 架构等异步处理模式来提高系统吞吐量<br />- 框架无法提供业务状态管理<br />- 难以实现宕机恢复后的“向前重试”,因为无法恢复线程上下文<br /></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p><a name="EKm6f"></a></p>
|
||||
<h1></h1>
|
||||
<p><a name="tw6CG"></a></p>
|
||||
<h1>Seata Saga 的方案</h1>
|
||||
<p>Seata Saga 的简介可以看一下<a href="http://seata.io/zh-cn/docs/user/saga.html">《Seata Saga 官网文档》</a>[6]。</p>
|
||||
<p>Seata Saga 采用了状态机+DSL 方案来实现,原因有以下几个:</p>
|
||||
<ul>
|
||||
<li>状态机+DSL 方案在实际生产中应用更广泛;</li>
|
||||
<li>可以使用 Actor 模型或 SEDA 架构等异步处理引擎来执行,提高整体吞吐量;</li>
|
||||
<li>通常在核心系统以上层的业务系统会伴随有“服务编排”的需求,而服务编排又有事务最终一致性要求,两者很难分割开,状态机+DSL 方案可以同时满足这两个需求;</li>
|
||||
<li>由于 Saga 模式在理论上是不保证隔离性的,在极端情况下可能由于脏写无法完成回滚操作,比如举一个极端的例子, 分布式事务内先给用户 A 充值,然后给用户 B 扣减余额,如果在给A用户充值成功,在事务提交以前,A 用户把线消费掉了,如果事务发生回滚,这时则没有办法进行补偿了,有些业务场景可以允许让业务最终成功,在回滚不了的情况下可以继续重试完成后面的流程,状态机+DSL的方案可以实现“向前”恢复上下文继续执行的能力, 让业务最终执行成功,达到最终一致性的目的。</li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<p>在不保证隔离性的情况下:业务流程设计时要遵循“宁可长款, 不可短款”的原则,长款意思是客户少了线机构多了钱,以机构信誉可以给客户退款,反之则是短款,少的线可能追不回来了。所以在业务流程设计上一定是先扣款。</p>
|
||||
</blockquote>
|
||||
<p><a name="4yL9U"></a></p>
|
||||
<h3>状态定义语言(Seata State Language)</h3>
|
||||
<ol>
|
||||
<li>通过状态图来定义服务调用的流程并生成 json 状态语言定义文件;</li>
|
||||
<li>状态图中一个节点可以是调用一个服务,节点可以配置它的补偿节点;</li>
|
||||
<li>状态图 json 由状态机引擎驱动执行,当出现异常时状态引擎反向执行已成功节点对应的补偿节点将事务回滚;</li>
|
||||
</ol>
|
||||
<blockquote>
|
||||
<p>注意: 异常发生时是否进行补偿也可由用户自定义决定</p>
|
||||
</blockquote>
|
||||
<ol start="4">
|
||||
<li>可以实现服务编排需求,支持单项选择、并发、异步、子状态机、参数转换、参数映射、服务执行状态判断、异常捕获等功能;</li>
|
||||
</ol>
|
||||
<p>假设有一个业务流程要调两个服务,先调库存扣减(InventoryService),再调余额扣减(BalanceService),保证在一个分布式内要么同时成功,要么同时回滚。两个参与者服务都有一个 reduce 方法,表示库存扣减或余额扣减,还有一个 compensateReduce 方法,表示补偿扣减操作。以 InventoryService 为例看一下它的接口定义:</p>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">InventoryService</span> </span>{
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* reduce
|
||||
* <span class="hljs-doctag">@param</span> businessKey
|
||||
* <span class="hljs-doctag">@param</span> amount
|
||||
* <span class="hljs-doctag">@param</span> params
|
||||
* <span class="hljs-doctag">@return</span>
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">boolean</span> <span class="hljs-title">reduce</span><span class="hljs-params">(String businessKey, BigDecimal amount, Map<String, Object> params)</span></span>;
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* compensateReduce
|
||||
* <span class="hljs-doctag">@param</span> businessKey
|
||||
* <span class="hljs-doctag">@param</span> params
|
||||
* <span class="hljs-doctag">@return</span>
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">boolean</span> <span class="hljs-title">compensateReduce</span><span class="hljs-params">(String businessKey, Map<String, Object> params)</span></span>;
|
||||
}
|
||||
</code></pre>
|
||||
<p>这个业务流程对应的状态图:</p>
|
||||
<p><img src="/img/saga/demo_statelang.png?raw=true" alt="示例状态图">
|
||||
<br />对应的 JSON</p>
|
||||
<pre><code class="language-json">{
|
||||
<span class="hljs-attr">"Name"</span>: <span class="hljs-string">"reduceInventoryAndBalance"</span>,
|
||||
<span class="hljs-attr">"Comment"</span>: <span class="hljs-string">"reduce inventory then reduce balance in a transaction"</span>,
|
||||
<span class="hljs-attr">"StartState"</span>: <span class="hljs-string">"ReduceInventory"</span>,
|
||||
<span class="hljs-attr">"Version"</span>: <span class="hljs-string">"0.0.1"</span>,
|
||||
<span class="hljs-attr">"States"</span>: {
|
||||
<span class="hljs-attr">"ReduceInventory"</span>: {
|
||||
<span class="hljs-attr">"Type"</span>: <span class="hljs-string">"ServiceTask"</span>,
|
||||
<span class="hljs-attr">"ServiceName"</span>: <span class="hljs-string">"inventoryAction"</span>,
|
||||
<span class="hljs-attr">"ServiceMethod"</span>: <span class="hljs-string">"reduce"</span>,
|
||||
<span class="hljs-attr">"CompensateState"</span>: <span class="hljs-string">"CompensateReduceInventory"</span>,
|
||||
<span class="hljs-attr">"Next"</span>: <span class="hljs-string">"ChoiceState"</span>,
|
||||
<span class="hljs-attr">"Input"</span>: [
|
||||
<span class="hljs-string">"$.[businessKey]"</span>,
|
||||
<span class="hljs-string">"$.[count]"</span>
|
||||
],
|
||||
<span class="hljs-attr">"Output"</span>: {
|
||||
<span class="hljs-attr">"reduceInventoryResult"</span>: <span class="hljs-string">"$.#root"</span>
|
||||
},
|
||||
<span class="hljs-attr">"Status"</span>: {
|
||||
<span class="hljs-attr">"#root == true"</span>: <span class="hljs-string">"SU"</span>,
|
||||
<span class="hljs-attr">"#root == false"</span>: <span class="hljs-string">"FA"</span>,
|
||||
<span class="hljs-attr">"$Exception{java.lang.Throwable}"</span>: <span class="hljs-string">"UN"</span>
|
||||
}
|
||||
},
|
||||
<span class="hljs-attr">"ChoiceState"</span>:{
|
||||
<span class="hljs-attr">"Type"</span>: <span class="hljs-string">"Choice"</span>,
|
||||
<span class="hljs-attr">"Choices"</span>:[
|
||||
{
|
||||
<span class="hljs-attr">"Expression"</span>:<span class="hljs-string">"[reduceInventoryResult] == true"</span>,
|
||||
<span class="hljs-attr">"Next"</span>:<span class="hljs-string">"ReduceBalance"</span>
|
||||
}
|
||||
],
|
||||
<span class="hljs-attr">"Default"</span>:<span class="hljs-string">"Fail"</span>
|
||||
},
|
||||
<span class="hljs-attr">"ReduceBalance"</span>: {
|
||||
<span class="hljs-attr">"Type"</span>: <span class="hljs-string">"ServiceTask"</span>,
|
||||
<span class="hljs-attr">"ServiceName"</span>: <span class="hljs-string">"balanceAction"</span>,
|
||||
<span class="hljs-attr">"ServiceMethod"</span>: <span class="hljs-string">"reduce"</span>,
|
||||
<span class="hljs-attr">"CompensateState"</span>: <span class="hljs-string">"CompensateReduceBalance"</span>,
|
||||
<span class="hljs-attr">"Input"</span>: [
|
||||
<span class="hljs-string">"$.[businessKey]"</span>,
|
||||
<span class="hljs-string">"$.[amount]"</span>,
|
||||
{
|
||||
<span class="hljs-attr">"throwException"</span> : <span class="hljs-string">"$.[mockReduceBalanceFail]"</span>
|
||||
}
|
||||
],
|
||||
<span class="hljs-attr">"Output"</span>: {
|
||||
<span class="hljs-attr">"compensateReduceBalanceResult"</span>: <span class="hljs-string">"$.#root"</span>
|
||||
},
|
||||
<span class="hljs-attr">"Status"</span>: {
|
||||
<span class="hljs-attr">"#root == true"</span>: <span class="hljs-string">"SU"</span>,
|
||||
<span class="hljs-attr">"#root == false"</span>: <span class="hljs-string">"FA"</span>,
|
||||
<span class="hljs-attr">"$Exception{java.lang.Throwable}"</span>: <span class="hljs-string">"UN"</span>
|
||||
},
|
||||
<span class="hljs-attr">"Catch"</span>: [
|
||||
{
|
||||
<span class="hljs-attr">"Exceptions"</span>: [
|
||||
<span class="hljs-string">"java.lang.Throwable"</span>
|
||||
],
|
||||
<span class="hljs-attr">"Next"</span>: <span class="hljs-string">"CompensationTrigger"</span>
|
||||
}
|
||||
],
|
||||
<span class="hljs-attr">"Next"</span>: <span class="hljs-string">"Succeed"</span>
|
||||
},
|
||||
<span class="hljs-attr">"CompensateReduceInventory"</span>: {
|
||||
<span class="hljs-attr">"Type"</span>: <span class="hljs-string">"ServiceTask"</span>,
|
||||
<span class="hljs-attr">"ServiceName"</span>: <span class="hljs-string">"inventoryAction"</span>,
|
||||
<span class="hljs-attr">"ServiceMethod"</span>: <span class="hljs-string">"compensateReduce"</span>,
|
||||
<span class="hljs-attr">"Input"</span>: [
|
||||
<span class="hljs-string">"$.[businessKey]"</span>
|
||||
]
|
||||
},
|
||||
<span class="hljs-attr">"CompensateReduceBalance"</span>: {
|
||||
<span class="hljs-attr">"Type"</span>: <span class="hljs-string">"ServiceTask"</span>,
|
||||
<span class="hljs-attr">"ServiceName"</span>: <span class="hljs-string">"balanceAction"</span>,
|
||||
<span class="hljs-attr">"ServiceMethod"</span>: <span class="hljs-string">"compensateReduce"</span>,
|
||||
<span class="hljs-attr">"Input"</span>: [
|
||||
<span class="hljs-string">"$.[businessKey]"</span>
|
||||
]
|
||||
},
|
||||
<span class="hljs-attr">"CompensationTrigger"</span>: {
|
||||
<span class="hljs-attr">"Type"</span>: <span class="hljs-string">"CompensationTrigger"</span>,
|
||||
<span class="hljs-attr">"Next"</span>: <span class="hljs-string">"Fail"</span>
|
||||
},
|
||||
<span class="hljs-attr">"Succeed"</span>: {
|
||||
<span class="hljs-attr">"Type"</span>:<span class="hljs-string">"Succeed"</span>
|
||||
},
|
||||
<span class="hljs-attr">"Fail"</span>: {
|
||||
<span class="hljs-attr">"Type"</span>:<span class="hljs-string">"Fail"</span>,
|
||||
<span class="hljs-attr">"ErrorCode"</span>: <span class="hljs-string">"PURCHASE_FAILED"</span>,
|
||||
<span class="hljs-attr">"Message"</span>: <span class="hljs-string">"purchase failed"</span>
|
||||
}
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<p>状态语言在一定程度上参考了 <a href="https://docs.aws.amazon.com/zh_cn/step-functions/latest/dg/tutorial-creating-lambda-state-machine.html">AWS Step Functions</a>[7]。</p>
|
||||
<p><a name="2de9b28a"></a></p>
|
||||
<h4>"状态机" 属性简介:</h4>
|
||||
<ul>
|
||||
<li>Name: 表示状态机的名称,必须唯一;</li>
|
||||
<li>Comment: 状态机的描述;</li>
|
||||
<li>Version: 状态机定义版本;</li>
|
||||
<li>StartState: 启动时运行的第一个"状态";</li>
|
||||
<li>States: 状态列表,是一个 map 结构,key 是"状态"的名称,在状态机内必须唯一;</li>
|
||||
</ul>
|
||||
<p><a name="2b956670"></a></p>
|
||||
<h4>"状态" 属性简介:</h4>
|
||||
<ul>
|
||||
<li>Type:"状态" 的类型,比如有:
|
||||
<ul>
|
||||
<li>ServiceTask: 执行调用服务任务;</li>
|
||||
<li>Choice: 单条件选择路由;</li>
|
||||
<li>CompensationTrigger: 触发补偿流程;</li>
|
||||
<li>Succeed: 状态机正常结束;</li>
|
||||
<li>Fail: 状态机异常结束;</li>
|
||||
<li>SubStateMachine: 调用子状态机;</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>ServiceName: 服务名称,通常是服务的beanId;</li>
|
||||
<li>ServiceMethod: 服务方法名称;</li>
|
||||
<li>CompensateState: 该"状态"的补偿"状态";</li>
|
||||
<li>Input: 调用服务的输入参数列表,是一个数组,对应于服务方法的参数列表, $.表示使用表达式从状态机上下文中取参数,表达使用的 <a href="https://docs.spring.io/spring/docs/4.3.10.RELEASE/spring-framework-reference/html/expressions.html">SpringEL</a>[8], 如果是常量直接写值即可;</li>
|
||||
<li>Output: 将服务返回的参数赋值到状态机上下文中,是一个 map 结构,key 为放入到状态机上文时的 key(状态机上下文也是一个 map),value 中 $. 是表示 SpringEL 表达式,表示从服务的返回参数中取值,#root 表示服务的整个返回参数;</li>
|
||||
<li>Status: 服务执行状态映射,框架定义了三个状态,SU 成功、FA 失败、UN 未知,我们需要把服务执行的状态映射成这三个状态,帮助框架判断整个事务的一致性,是一个 map 结构,key 是条件表达式,一般是取服务的返回值或抛出的异常进行判断,默认是 SpringEL 表达式判断服务返回参数,带 $Exception{开头表示判断异常类型,value 是当这个条件表达式成立时则将服务执行状态映射成这个值;</li>
|
||||
<li>Catch: 捕获到异常后的路由;</li>
|
||||
<li>Next: 服务执行完成后下一个执行的"状态";</li>
|
||||
<li>Choices: Choice 类型的"状态"里, 可选的分支列表, 分支中的 Expression 为 SpringEL 表达式,Next 为当表达式成立时执行的下一个"状态";</li>
|
||||
<li>ErrorCode: Fail 类型"状态"的错误码;</li>
|
||||
<li>Message: Fail 类型"状态"的错误信息;</li>
|
||||
</ul>
|
||||
<p>更多详细的状态语言解释请看<a href="http://seata.io/zh-cn/docs/user/saga.html">《Seata Saga 官网文档》</a>[6<a href="http://seata.io/zh-cn/docs/user/saga.html">http://seata.io/zh-cn/docs/user/saga.html</a>]。</p>
|
||||
<p><a name="209f0e37"></a></p>
|
||||
<h3>状态机引擎原理:</h3>
|
||||
<p><img src="/img/saga/saga_engine_mechanism.png?raw=true" alt="状态机引擎原理"></p>
|
||||
<ul>
|
||||
<li>图中的状态图是先执行 stateA, 再执行 stataB,然后执行 stateC;</li>
|
||||
<li>"状态"的执行是基于事件驱动的模型,stataA 执行完成后,会产生路由消息放入 EventQueue,事件消费端从 EventQueue 取出消息,执行 stateB;</li>
|
||||
<li>在整个状态机启动时会调用 Seata Server 开启分布式事务,并生产 xid, 然后记录"状态机实例"启动事件到本地数据库;</li>
|
||||
<li>当执行到一个"状态"时会调用 Seata Server 注册分支事务,并生产 branchId, 然后记录"状态实例"开始执行事件到本地数据库;</li>
|
||||
<li>当一个"状态"执行完成后会记录"状态实例"执行结束事件到本地数据库, 然后调用 Seata Server 上报分支事务的状态;</li>
|
||||
<li>当整个状态机执行完成,会记录"状态机实例"执行完成事件到本地数据库, 然后调用 Seata Server 提交或回滚分布式事务;</li>
|
||||
</ul>
|
||||
<p><a name="808e95dc"></a></p>
|
||||
<h3>状态机引擎设计:</h3>
|
||||
<p><img src="/img/saga/saga_engine.png?raw=true" alt="状态机引擎设计"></p>
|
||||
<p>状态机引擎的设计主要分成三层, 上层依赖下层,从下往上分别是:</p>
|
||||
<ul>
|
||||
<li>
|
||||
<p>Eventing 层:</p>
|
||||
<ul>
|
||||
<li>实现事件驱动架构, 可以压入事件, 并由消费端消费事件, 本层不关心事件是什么消费端执行什么,由上层实现;</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<p>ProcessController 层:</p>
|
||||
<ul>
|
||||
<li>由于上层的 Eventing 驱动一个“空”流程执行的执行,"state"的行为和路由都未实现,由上层实现;</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<blockquote>
|
||||
<p>基于以上两层理论上可以自定义扩展任何"流程"引擎。这两层的设计是参考了内部金融网络平台的设计。</p>
|
||||
</blockquote>
|
||||
<ul>
|
||||
<li>StateMachineEngine 层:
|
||||
<ul>
|
||||
<li>实现状态机引擎每种 state 的行为和路由逻辑;</li>
|
||||
<li>提供 API、状态机语言仓库;</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p><a name="73a9fddd"></a></p>
|
||||
<h3>Saga 模式下服务设计的实践经验</h3>
|
||||
<p>下面是实践中总结的在 Saga 模式下微服务设计的一些经验,当然这是推荐做法,并不是说一定要 100% 遵循,没有遵循也有“绕过”方案。</p>
|
||||
<blockquote>
|
||||
<p>好消息:Seata Saga 模式对微服务的接口参数没有任务要求,这使得 Saga 模式可用于集成遗留系统或外部机构的服务。</p>
|
||||
</blockquote>
|
||||
<p><a name="d64c5051"></a></p>
|
||||
<h4>允许空补偿</h4>
|
||||
<ul>
|
||||
<li>空补偿:原服务未执行,补偿服务执行了;</li>
|
||||
<li>出现原因:
|
||||
<ul>
|
||||
<li>原服务 超时(丢包);</li>
|
||||
<li>Saga 事务触发 回滚;</li>
|
||||
<li>未收到原服务请求,先收到补偿请求;</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>所以服务设计时需要允许空补偿,即没有找到要补偿的业务主键时返回补偿成功并将原业务主键记录下来。</p>
|
||||
<p><a name="88a92b17"></a></p>
|
||||
<h4>防悬挂控制</h4>
|
||||
<ul>
|
||||
<li>悬挂:补偿服务 比 原服务 先执行;</li>
|
||||
<li>出现原因:
|
||||
<ul>
|
||||
<li>原服务 超时(拥堵);</li>
|
||||
<li>Saga 事务回滚,触发 回滚;</li>
|
||||
<li>拥堵的原服务到达;</li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
<p>所以要检查当前业务主键是否已经在空补偿记录下来的业务主键中存在,如果存在则要拒绝服务的执行。</p>
|
||||
<p><a name="ce766631"></a></p>
|
||||
<h4>幂等控制</h4>
|
||||
<ul>
|
||||
<li>原服务与补偿服务都需要保证幂等性, 由于网络可能超时,可以设置重试策略,重试发生时要通过幂等控制避免业务数据重复更新。</li>
|
||||
</ul>
|
||||
<p><a name="FO5YS"></a></p>
|
||||
<h1>总结</h1>
|
||||
<p>很多时候我们不需要强调强一性,我们基于 BASE 和 Saga 理论去设计更有弹性的系统,在分布式架构下获得更好的性能和容错能力。分布式架构没有银弹,只有适合特定场景的方案,事实上 Seata Saga 是一个具备“服务编排”和“Saga 分布式事务”能力的产品,总结下来它的适用场景是:</p>
|
||||
<ul>
|
||||
<li>适用于微服务架构下的“长事务”处理;</li>
|
||||
<li>适用于微服务架构下的“服务编排”需求;</li>
|
||||
<li>适用于金融核心系统以上的有大量组合服务的业务系统(比如在渠道层、产品层、集成层的系统);</li>
|
||||
<li>适用于业务流程中需要集成遗留系统或外部机构提供的服务的场景(这些服务不可变不能对其提出改造要求)。</li>
|
||||
</ul>
|
||||
<p><a name="3X7vO"></a></p>
|
||||
<h2>文中涉及相关链接</h2>
|
||||
<p>[1]<a href="https://github.com/aphyr/dist-sagas/blob/master/sagas.pdf">https://github.com/aphyr/dist-sagas/blob/master/sagas.pdf</a><br />[2]<a href="http://microservices.io/patterns/data/saga.html">http://microservices.io/patterns/data/saga.html</a><br />[3]<a href="https://github.com/eclipse/microprofile-sandbox/tree/master/proposals/0009-LRA">Microprofile 的 LRA</a>:<a href="https://github.com/eclipse/microprofile-sandbox/tree/master/proposals/0009-LRA">https://github.com/eclipse/microprofile-sandbox/tree/master/proposals/0009-LRA</a><br />[4]<a href="https://github.com/eventuate-tram/eventuate-tram-sagas">Eventuate Tram Saga</a>:<a href="https://github.com/eventuate-tram/eventuate-tram-sagas">https://github.com/eventuate-tram/eventuate-tram-sagas</a><br />[5]<a href="https://github.com/apache/incubator-servicecomb-saga">ServiceComb Saga</a>:<a href="https://github.com/apache/servicecomb-pack">https://github.com/apache/servicecomb-pack</a><br />[6]<a href="http://seata.io/zh-cn/docs/user/saga.html">Seata Saga 官网文档</a>:<a href="http://seata.io/zh-cn/docs/user/saga.html">http://seata.io/zh-cn/docs/user/saga.html</a><br />[7]<a href="https://docs.aws.amazon.com/zh_cn/step-functions/latest/dg/tutorial-creating-lambda-state-machine.html">AWS Step Functions</a>:<a href="https://docs.aws.amazon.com/zh_cn/step-functions/latest/dg/tutorial-creating-lambda-state-machine.html">https://docs.aws.amazon.com/zh_cn/step-functions/latest/dg/tutorial-creating-lambda-state-machine.html</a><br />[8]<a href="https://docs.spring.io/spring/docs/4.3.10.RELEASE/spring-framework-reference/html/expressions.html">SpringEL</a>:<a href="https://docs.spring.io/spring/docs/4.3.10.RELEASE/spring-framework-reference/html/expressions.html">https://docs.spring.io/spring/docs/4.3.10.RELEASE/spring-framework-reference/html/expressions.html</a><br /></p>
|
||||
</section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>愿景</h3><p>Seata 是一款阿里巴巴开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。</p></div><div class="col col-6"><dl><dt>文档</dt><dd><a href="/zh-cn/docs/overview/what-is-seata.html" target="_self">Seata 是什么?</a></dd><dd><a href="/zh-cn/docs/user/quickstart.html" target="_self">快速开始</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">报告文档问题</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">在Github上编辑此文档</a></dd></dl></div><div class="col col-6"><dl><dt>资源</dt><dd><a href="/zh-cn/blog/index.html" target="_self">博客</a></dd><dd><a href="/zh-cn/community/index.html" target="_self">社区</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/blogDetail.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
|
@ -1,331 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Seata, Downloads, Version" />
|
||||
<meta name="description" content="本文将向你介绍如何点击了解各版本详情和升级注意事项。" />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>下载中心</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/blogDetail.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="blog-detail-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/zh-cn/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">En</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/zh-cn/index.html" target="_self">首页</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/docs/overview/what-is-seata.html" target="_self">文档</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/docs/developers/developers_dev.html" target="_self">开发者</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/zh-cn/blog/index.html" target="_self">博客</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/community/index.html" target="_self">社区</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/blog/download.html" target="_self">下载</a></li></ul></div></div></header><section class="blog-content markdown-body"><h1>下载中心</h1>
|
||||
<h2>Seata</h2>
|
||||
<blockquote>
|
||||
<p>GitHub: <a href="https://github.com/seata/seata">https://github.com/seata/seata</a> <br>
|
||||
发布说明: <a href="https://github.com/seata/seata/releases">https://github.com/seata/seata/releases</a></p>
|
||||
</blockquote>
|
||||
<h3>0.9.0 (2019-10-16)</h3>
|
||||
<p><a href="https://github.com/seata/seata/archive/v0.9.0.zip">source</a> |
|
||||
<a href="https://github.com/seata/seata/releases/download/v0.9.0/seata-server-0.9.0.zip">binary</a></p>
|
||||
<details>
|
||||
<summary><mark>Release notes</mark></summary>
|
||||
<h3>Seata 0.9.0</h3>
|
||||
<p>Seata 0.9.0 正式发布。</p>
|
||||
<p>Seata 是一款开源的分布式事务解决方案,提供高性能和简单易用的分布式事务服务。</p>
|
||||
<p>此版本更新如下:</p>
|
||||
<h4>feature:</h4>
|
||||
<ul>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1608">#1608</a>] 长事务解决方案: Saga 模式(基于状态机实现)</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1625">#1625</a>] 支持自定义配置和注册中心类型</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1656">#1656</a>] 支持 spring cloud config 配置中心</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1689">#1689</a>] 支持 -e 启动参数,用于指定环境名称</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1739">#1739</a>] 支持 TM commit 或rollback 失败时的重试</li>
|
||||
</ul>
|
||||
<h4>bugfix:</h4>
|
||||
<ul>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1605">#1605</a>] 修复对象锁和全局锁可能造成的死锁和优化锁的粒度</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1685">#1685</a>] 修复db存储类异常被忽略的问题</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1691">#1691</a>] 修复 DruidDataSourceWrapper 反射问题</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1699">#1699</a>] 修复 mysql 和 oracle 中 'in' 和 'between' 在 where 条件的支持</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1713">#1713</a>] 修复 LockManagerTest.concurrentUseAbilityTest 中的测试条件</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1720">#1720</a>] 修复了不能获取 oracle tableMeta 问题</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1729">#1729</a>] 修复 oracle 的批量获取问题</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1735">#1735</a>] 修复当 TM commit 或 rollback 出现网络异常无法清除 xid 的问题</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1749">#1749</a>] 修复无法获取 oracle tableMeta cache 问题</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1751">#1751</a>] 修复文件存储模式下由于hash冲突导致的锁无法释放问题</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1761">#1761</a>] 修复 oracle 在回滚时 Blob 或 Clob null 值回滚失败问题</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1759">#1759</a>] 修复 saga 模式下 service method 不支持接口类型参数问题</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1401">#1401</a>] 修复 RM 启动时第一次注册 resource 为 null 的问题</li>
|
||||
</ul>
|
||||
<h4>optimize:</h4>
|
||||
<ul>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1701">#1701</a>] 移除无用的 imports</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1705">#1705</a>] 优化了一些基于 java5 的语法结构</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1706">#1706</a>] 将内部类声明为 static</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1707">#1707</a>] 使用 StandardCharsets.UTF_8 代替 utf-8 编码</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1712">#1712</a>] 抽象 undologManager 的通用方法</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1722">#1722</a>] 简化代码提高代码的可读性</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1726">#1726</a>] 格式化日志输出</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1738">#1738</a>] 增加 seata-server jvm 参数</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1743">#1743</a>] 提高批量打印日志的性能</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1747">#1747</a>] 使用基本类型避免数据装箱</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1750">#1750</a>] 抽象 tableMetaCache 方法</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1755">#1755</a>] 提高 seata-common 模块的单测覆盖率</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1756">#1756</a>] 升级 jackson 版本防止潜在的安全漏洞</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1657">#1657</a>] 优化文件存储模式下文件 rolling 时占用较大 direct buffer的问题</li>
|
||||
</ul>
|
||||
<p>非常感谢以下 contributors 的代码贡献。若有无意遗漏,请报告。</p>
|
||||
<ul>
|
||||
<li><a href="https://github.com/slievrly">slievrly</a></li>
|
||||
<li><a href="https://github.com/long187">long187</a></li>
|
||||
<li><a href="https://github.com/ggndnn">ggndnn</a></li>
|
||||
<li><a href="https://github.com/xingfudeshi">xingfudeshi</a></li>
|
||||
<li><a href="https://github.com/BeiKeJieDeLiuLangMao">BeiKeJieDeLiuLangMao</a></li>
|
||||
<li><a href="https://github.com/zjinlei">zjinlei</a></li>
|
||||
<li><a href="https://github.com/cmonkey">cmonkey</a></li>
|
||||
<li><a href="https://github.com/jsbxyyx">jsbxyyx</a></li>
|
||||
<li><a href="https://github.com/zaqweb">zaqweb</a></li>
|
||||
<li><a href="https://github.com/tjnettech">tjnettech</a></li>
|
||||
<li><a href="https://github.com/l81893521">l81893521</a></li>
|
||||
<li><a href="https://github.com/abel533">abel533</a></li>
|
||||
<li><a href="https://github.com/suhli">suhli</a></li>
|
||||
<li><a href="https://github.com/github-ygy">github-ygy</a></li>
|
||||
<li><a href="https://github.com/worstenemy">worstenemy</a></li>
|
||||
<li><a href="https://github.com/caioguedes">caioguedes</a></li>
|
||||
</ul>
|
||||
<p>同时,我们收到了社区反馈的很多有价值的issue和建议,非常感谢大家。</p>
|
||||
<h4>常用链接</h4>
|
||||
<ul>
|
||||
<li><strong>Seata:</strong> <a href="https://github.com/seata/seata">https://github.com/seata/seata</a></li>
|
||||
<li><strong>Seata-Samples:</strong> <a href="https://github.com/seata/seata-samples">https://github.com/seata/seata-samples</a></li>
|
||||
<li><strong>Release:</strong> <a href="https://github.com/seata/seata/releases">https://github.com/seata/seata/releases</a></li>
|
||||
</ul>
|
||||
</details>
|
||||
<h3>0.8.1 (2019-09-18)</h3>
|
||||
<p><a href="https://github.com/seata/seata/archive/v0.8.1.zip">source</a> |
|
||||
<a href="https://github.com/seata/seata/releases/download/v0.8.1/seata-server-0.8.1.zip">binary</a></p>
|
||||
<details>
|
||||
<summary><mark>Release notes</mark></summary>
|
||||
<h3>Seata 0.8.1</h3>
|
||||
<p>Seata 0.8.1 正式发布。</p>
|
||||
<p>Seata 是一款开源的分布式事务解决方案,提供高性能和简单易用的分布式事务服务。</p>
|
||||
<p>此版本更新如下:</p>
|
||||
<h4>feature:</h4>
|
||||
<ul>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1598">#1598</a>] 支持配置文件使用绝对路径</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1617">#1617</a>] 支持配置文件名称(registry.conf) 可配置</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1418">#1418</a>] 支持 undo_log 数据的 kryo 序列化</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1489">#1489</a>] 支持 protobuf 生成插件</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1437">#1437</a>] 支持通信协议的 kryo 编解码</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1478">#1478</a>] 支持 db mock</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1512">#1512</a>] 扩展支持 mysql 和 oracle 的多种批量插入语法</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1496">#1496</a>] 支持 DataSource 的自动代理</li>
|
||||
</ul>
|
||||
<h4>bugfix:</h4>
|
||||
<ul>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1646">#1646</a>] 修复 file 存储模式的 selectForUpdate lockQuery exception</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1572">#1572</a>] 修复在oracle 小写表名时获取 tablemeta 失败问题</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1663">#1663</a>] 修复表名为关键字获取 tablemeta 失败问题</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1666">#1666</a>] 修复数据库连接使用后的 autocommit 问题</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1643">#1643</a>] 修复 java.sql.Blob, java.sql.Clob 类型的序列化</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1628">#1628</a>] 修复 oracle 支持 ROWNUM 查询</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1552">#1552</a>] 修复当分支太大时的 BufferOverflow 问题</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1609">#1609</a>] 修复 oracle 关键字的线程安全问题</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1599">#1599</a>] 修复 mysql 关键字的线程安全问题</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1607">#1607</a>] 修复当druid版本小于1.1.3时 NoSuchMethodError</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1581">#1581</a>] 修复文件存储模式下 GlobalSession 长度计算不准确问题</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1594">#1594</a>] 修复 nacos 配置中心的默认 namespace</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1550">#1550</a>] 修复计算 BranchSession 丢失 xidBytes 长度问题</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1558">#1558</a>] 修复 rpcMessage 的 body 字段 NPE问题</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1505">#1505</a>] 修复绑定公网注册地址server监听失败问题</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1539">#1539</a>] 修复 nacos namespace 配置项不生效</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1537">#1537</a>] 修复 nacos-config.txt 缺失 store.db.driver-class-name 配置项</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1522">#1522</a>] 修复 ProtocolV1CodecTest 中 testAll 运行中可能出现测试失败问题</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1525">#1525</a>] 修复当 getAfterImage 获取失败时,事务自动被提交问题</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1518">#1518</a>] 修复 EnhancedServiceLoader SPI 顺序加载第三方依赖失败问题</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1514">#1514</a>] 修复当缺少序列化依赖无法生成undolog并report true问题</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1445">#1445</a>] 修复 DefaultCoordinatorMetricsTest 单测失败问题</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1481">#1481</a>] 修复 TableMetaCache 在多数据源刷新失败问题</li>
|
||||
</ul>
|
||||
<h4>optimize:</h4>
|
||||
<ul>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1629">#1629</a>] 优化etcd3中watcher订阅的效率</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1661">#1661</a>] 优化 global_table 中 transaction_name 长度问题</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1633">#1633</a>] 优化分支事务获取全局锁失败重复report(false)问题</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1654">#1654</a>] 优化 slf4j 的错误使用</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1593">#1593</a>] 优化和规范化 server 的日志</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1648">#1648</a>] 优化 transaction_name 在建表时的长度</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1576">#1576</a>] 消除重排序对 session 异步提交的影响</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1618">#1618</a>] 优化 undolog manager 和 修复oracle undolog 的删除</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1469">#1469</a>] 提供不释放数据库锁情况下等待全局锁的释放以减少锁冲突</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1416">#1619</a>] 使用 StringBuffer 代替 StringBuilder</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1580">#1580</a>] 优化 LockKeyConflictException 和更改 register 方法</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1574">#1574</a>] 优化db存储模式下globalCommit 一次性删除全局锁</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1601">#1601</a>] 优化 typo</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1602">#1602</a>] 升级 fastjson 版本至 1.2.60 应对安全漏洞</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1583">#1583</a>] 优化 oracle 主键的获取</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1575">#1575</a>] 增加 RegisterTMRequest 的单元测试</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1559">#1559</a>] 启动时延迟删除过期 undo_log</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1547">#1547</a>] 删除 TableRecords 的 jackson 注解</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1542">#1542</a>] 优化 AbstractSessionManager 日志</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1535">#1535</a>] 去除 H2 和 pgsql 获取主键代码,修复 resultset 关闭问题</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1541">#1541</a>] 代码清理</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1544">#1544</a>] 去除中文注释</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1533">#1533</a>] 重构多环境配置的代码逻辑</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1493">#1493</a>] 增加 tableMeta 检测任务开关</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1530">#1530</a>] 优化当数据表无索引时抛出显式异常</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1444">#1444</a>] 简化map操作</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1497">#1497</a>] 增加 seata-all 依赖</li>
|
||||
<li>[<a href="https://github.com/seata/seata/pull/1490">#1490</a>] 移除不必要代码</li>
|
||||
</ul>
|
||||
<p>非常感谢以下 contributors 的代码贡献。若有无意遗漏,请报告。</p>
|
||||
<ul>
|
||||
<li><a href="https://github.com/slievrly">slievrly</a></li>
|
||||
<li><a href="https://github.com/BeiKeJieDeLiuLangMao">BeiKeJieDeLiuLangMao</a></li>
|
||||
<li><a href="https://github.com/jsbxyyx">jsbxyyx</a></li>
|
||||
<li><a href="https://github.com/ldcsaa">ldcsaa</a></li>
|
||||
<li><a href="https://github.com/zjinlei">zjinlei</a></li>
|
||||
<li><a href="https://github.com/l81893521">l81893521</a></li>
|
||||
<li><a href="https://github.com/ggndnn">ggndnn</a></li>
|
||||
<li><a href="https://github.com/github-ygy">github-ygy</a></li>
|
||||
<li><a href="https://github.com/chenxi-null">chenxi-null</a></li>
|
||||
<li><a href="https://github.com/tq02ksu">tq02ksu</a></li>
|
||||
<li><a href="https://github.com/AjaxXu">AjaxXu</a></li>
|
||||
<li><a href="https://github.com/finalcola">finalcola</a></li>
|
||||
<li><a href="https://github.com/lovepoem">lovepoem</a></li>
|
||||
<li><a href="https://github.com/cmonkey">cmonkey</a></li>
|
||||
<li><a href="https://github.com/xingfudeshi">xingfudeshi</a></li>
|
||||
<li><a href="https://github.com/andyqian">andyqian</a></li>
|
||||
<li><a href="https://github.com/tswstarplanet">tswstarplanet</a></li>
|
||||
<li><a href="https://github.com/zhengyangyong">zhengyangyong</a></li>
|
||||
</ul>
|
||||
<p>同时,我们收到了社区反馈的很多有价值的issue和建议,非常感谢大家。</p>
|
||||
<h4>常用链接</h4>
|
||||
<ul>
|
||||
<li><strong>Seata:</strong> <a href="https://github.com/seata/seata">https://github.com/seata/seata</a></li>
|
||||
<li><strong>Seata-Samples:</strong> <a href="https://github.com/seata/seata-samples">https://github.com/seata/seata-samples</a></li>
|
||||
<li><strong>Release:</strong> <a href="https://github.com/seata/seata/releases">https://github.com/seata/seata/releases</a></li>
|
||||
</ul>
|
||||
</details>
|
||||
<h3>0.8.0 (2019-08-16)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.8.0.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.8.0/seata-server-0.8.0.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.7.1 (2019-07-15)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.7.1.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.7.1/seata-server-0.7.1.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.7.0 (2019-07-12)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.7.0.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.7.0/seata-server-0.7.0.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.6.1 (2019-05-31)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.6.1.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.6.1/seata-server-0.6.1.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.6.0 (2019-05-24)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.6.0.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.6.0/seata-server-0.6.0.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.5.2 (2019-05-17)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.5.2.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.5.2/seata-server-0.5.2.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.5.1 (2019-04-30)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.5.1.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.5.1/seata-server-0.5.1.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.5.0 (2019-04-19)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/0.5.0.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/0.5.0/seata-server-0.5.0.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.4.2 (2019-04-12)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.4.2.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.4.2/fescar-server-0.4.2.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.4.1 (2019-03-29)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.4.1.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.4.1/fescar-server-0.4.1.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.4.0 (2019-03-19)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.4.0.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.4.0/fescar-server-0.4.0.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.3.1 (2019-03-15)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.3.1.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.3.1/fescar-server-0.3.1.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.3.0 (2019-03-08)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.3.0.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.3.0/fescar-server-0.3.0.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.2.3 (2019-03-02)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.2.3.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.2.3/fescar-server-0.2.3.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.2.2 (2019-02-22)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.2.2.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.2.2/fescar-server-0.2.2.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.2.1 (2019-02-18)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.2.1.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.2.1/fescar-server-0.2.1.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.2.0 (2019-02-14)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.2.0.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.2.0/fescar-server-0.2.0.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.1.4 (2019-02-11)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.1.4.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.1.4/fescar-server-0.1.4.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.1.3 (2019-01-29)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.1.3.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.1.3/fescar-server-0.1.3.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.1.2 (2019-01-25)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/V0.1.2.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/V0.1.2/fescar-server-0.1.2.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.1.1 (2019-01-18)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.1.1.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.1.1/fescar-server-0.1.1.zip">binary</a></li>
|
||||
</ul>
|
||||
<h3>0.1.0 (2019-01-09)</h3>
|
||||
<ul>
|
||||
<li><a href="https://github.com/seata/seata/archive/v0.1.0.zip">source</a></li>
|
||||
<li><a href="https://github.com/seata/seata/releases/download/v0.1.0/fescar-server-0.1.0.zip">binary</a></li>
|
||||
</ul>
|
||||
</section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>愿景</h3><p>Seata 是一款阿里巴巴开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。</p></div><div class="col col-6"><dl><dt>文档</dt><dd><a href="/zh-cn/docs/overview/what-is-seata.html" target="_self">Seata 是什么?</a></dd><dd><a href="/zh-cn/docs/user/quickstart.html" target="_self">快速开始</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">报告文档问题</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">在Github上编辑此文档</a></dd></dl></div><div class="col col-6"><dl><dt>资源</dt><dd><a href="/zh-cn/blog/index.html" target="_self">博客</a></dd><dd><a href="/zh-cn/community/index.html" target="_self">社区</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/blogDetail.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
|
@ -1,205 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Dubbo,Seata,一致性" />
|
||||
<meta name="description" content="本文主要介绍如何使用Seata保证Dubbo微服务间的一致性" />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>如何使用Seata保证Dubbo微服务间的一致性</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/blogDetail.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="blog-detail-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/zh-cn/index.html"><img class="logo" src="/img/seata_logo.png"/></a><span class="language-switch language-switch-normal">En</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/zh-cn/index.html" target="_self">首页</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/docs/overview/what_is_seata.html" target="_self">文档</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/zh-cn/blog/index.html" target="_self">博客</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/community/index.html" target="_self">社区</a></li></ul></div></div></header><section class="blog-content markdown-body"><h1>如何使用Seata保证Dubbo微服务间的一致性</h1>
|
||||
<h2>案例</h2>
|
||||
<p>用户采购商品业务,整个业务包含3个微服务:</p>
|
||||
<ul>
|
||||
<li>库存服务: 扣减给定商品的库存数量。</li>
|
||||
<li>订单服务: 根据采购请求生成订单。</li>
|
||||
<li>账户服务: 用户账户金额扣减。</li>
|
||||
</ul>
|
||||
<h3>业务结构图</h3>
|
||||
<p><img src="/img/blog/seata/seata-1.png" alt="Architecture"></p>
|
||||
<h3>StorageService</h3>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">StorageService</span> </span>{
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* deduct storage count
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">deduct</span><span class="hljs-params">(String commodityCode, <span class="hljs-keyword">int</span> count)</span></span>;
|
||||
}
|
||||
</code></pre>
|
||||
<h3>OrderService</h3>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">OrderService</span> </span>{
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* create order
|
||||
*/</span>
|
||||
<span class="hljs-function">Order <span class="hljs-title">create</span><span class="hljs-params">(String userId, String commodityCode, <span class="hljs-keyword">int</span> orderCount)</span></span>;
|
||||
}
|
||||
</code></pre>
|
||||
<h3>AccountService</h3>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">AccountService</span> </span>{
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* debit balance of user's account
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">debit</span><span class="hljs-params">(String userId, <span class="hljs-keyword">int</span> money)</span></span>;
|
||||
}
|
||||
</code></pre>
|
||||
<h3>主要的业务逻辑:</h3>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BusinessServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">BusinessService</span> </span>{
|
||||
|
||||
<span class="hljs-keyword">private</span> StorageService storageService;
|
||||
|
||||
<span class="hljs-keyword">private</span> OrderService orderService;
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* purchase
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">purchase</span><span class="hljs-params">(String userId, String commodityCode, <span class="hljs-keyword">int</span> orderCount)</span> </span>{
|
||||
|
||||
storageService.deduct(commodityCode, orderCount);
|
||||
|
||||
orderService.create(userId, commodityCode, orderCount);
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StorageServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">StorageService</span> </span>{
|
||||
|
||||
<span class="hljs-keyword">private</span> StorageDAO storageDAO;
|
||||
|
||||
<span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deduct</span><span class="hljs-params">(String commodityCode, <span class="hljs-keyword">int</span> count)</span> </span>{
|
||||
Storage storage = <span class="hljs-keyword">new</span> Storage();
|
||||
storage.setCount(count);
|
||||
storage.setCommodityCode(commodityCode);
|
||||
storageDAO.update(storage);
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">OrderServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">OrderService</span> </span>{
|
||||
|
||||
<span class="hljs-keyword">private</span> OrderDAO orderDAO;
|
||||
|
||||
<span class="hljs-keyword">private</span> AccountService accountService;
|
||||
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> Order <span class="hljs-title">create</span><span class="hljs-params">(String userId, String commodityCode, <span class="hljs-keyword">int</span> orderCount)</span> </span>{
|
||||
|
||||
<span class="hljs-keyword">int</span> orderMoney = calculate(commodityCode, orderCount);
|
||||
|
||||
accountService.debit(userId, orderMoney);
|
||||
|
||||
Order order = <span class="hljs-keyword">new</span> Order();
|
||||
order.userId = userId;
|
||||
order.commodityCode = commodityCode;
|
||||
order.count = orderCount;
|
||||
order.money = orderMoney;
|
||||
|
||||
<span class="hljs-keyword">return</span> orderDAO.insert(order);
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<h2>Seata 分布式事务解决方案</h2>
|
||||
<p><img src="/img/blog/seata/seata-2.png" alt="undefined"></p>
|
||||
<p>此处仅仅需要一行注解 <code>@GlobalTransactional</code> 写在业务发起方的方法上:</p>
|
||||
<pre><code class="language-java">
|
||||
<span class="hljs-meta">@GlobalTransactional</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">purchase</span><span class="hljs-params">(String userId, String commodityCode, <span class="hljs-keyword">int</span> orderCount)</span> </span>{
|
||||
......
|
||||
}
|
||||
</code></pre>
|
||||
<h2>Dubbo 与 Seata 结合的例子</h2>
|
||||
<h3>Step 1: 安装数据库</h3>
|
||||
<ul>
|
||||
<li>要求: MySQL (InnoDB 存储引擎)。</li>
|
||||
</ul>
|
||||
<p><strong>提示:</strong> 事实上例子中3个微服务需要3个独立的数据库,但为了方便我们使用同一物理库并配置3个逻辑连接串。</p>
|
||||
<p>更改以下xml文件中的数据库url、username和password</p>
|
||||
<p>dubbo-account-service.xml
|
||||
dubbo-order-service.xml
|
||||
dubbo-storage-service.xml</p>
|
||||
<pre><code class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"url"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"jdbc:mysql://x.x.x.x:3306/xxx"</span> /></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"username"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"xxx"</span> /></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"xxx"</span> /></span>
|
||||
</code></pre>
|
||||
<h3>Step 2: 为 Seata 创建 UNDO_LOG 表</h3>
|
||||
<p><code>UNDO_LOG</code> 此表用于 Seata 的AT模式。</p>
|
||||
<pre><code class="language-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`undo_log`</span> (
|
||||
<span class="hljs-string">`id`</span> <span class="hljs-built_in">bigint</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> AUTO_INCREMENT,
|
||||
<span class="hljs-string">`branch_id`</span> <span class="hljs-built_in">bigint</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`xid`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`rollback_info`</span> longblob <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`log_status`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`log_created`</span> datetime <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`log_modified`</span> datetime <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`ext`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
|
||||
PRIMARY <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`id`</span>),
|
||||
<span class="hljs-keyword">KEY</span> <span class="hljs-string">`idx_unionkey`</span> (<span class="hljs-string">`xid`</span>,<span class="hljs-string">`branch_id`</span>)
|
||||
) <span class="hljs-keyword">ENGINE</span>=<span class="hljs-keyword">InnoDB</span> AUTO_INCREMENT=<span class="hljs-number">159</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CHARSET</span>=utf8
|
||||
</code></pre>
|
||||
<h3>Step 3: 创建相关业务表</h3>
|
||||
<pre><code class="language-sql">
|
||||
<span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">IF</span> <span class="hljs-keyword">EXISTS</span> <span class="hljs-string">`storage_tbl`</span>;
|
||||
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`storage_tbl`</span> (
|
||||
<span class="hljs-string">`id`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> AUTO_INCREMENT,
|
||||
<span class="hljs-string">`commodity_code`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`count`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span>,
|
||||
PRIMARY <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`id`</span>),
|
||||
<span class="hljs-keyword">UNIQUE</span> <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`commodity_code`</span>)
|
||||
) <span class="hljs-keyword">ENGINE</span>=<span class="hljs-keyword">InnoDB</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CHARSET</span>=utf8;
|
||||
|
||||
|
||||
<span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">IF</span> <span class="hljs-keyword">EXISTS</span> <span class="hljs-string">`order_tbl`</span>;
|
||||
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`order_tbl`</span> (
|
||||
<span class="hljs-string">`id`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> AUTO_INCREMENT,
|
||||
<span class="hljs-string">`user_id`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`commodity_code`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`count`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span>,
|
||||
<span class="hljs-string">`money`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span>,
|
||||
PRIMARY <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`id`</span>)
|
||||
) <span class="hljs-keyword">ENGINE</span>=<span class="hljs-keyword">InnoDB</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CHARSET</span>=utf8;
|
||||
|
||||
|
||||
<span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">IF</span> <span class="hljs-keyword">EXISTS</span> <span class="hljs-string">`account_tbl`</span>;
|
||||
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`account_tbl`</span> (
|
||||
<span class="hljs-string">`id`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> AUTO_INCREMENT,
|
||||
<span class="hljs-string">`user_id`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`money`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span>,
|
||||
PRIMARY <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`id`</span>)
|
||||
) <span class="hljs-keyword">ENGINE</span>=<span class="hljs-keyword">InnoDB</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CHARSET</span>=utf8;
|
||||
</code></pre>
|
||||
<h3>Step 4: 启动 Seata-Server 服务</h3>
|
||||
<ul>
|
||||
<li>下载Server <a href="https://github.com/seata/seata/releases">package</a>, 并解压。</li>
|
||||
<li>运行bin目录下的启动脚本。</li>
|
||||
</ul>
|
||||
<pre><code class="language-shell">sh seata-server.sh $LISTEN_PORT $PATH_FOR_PERSISTENT_DATA
|
||||
|
||||
e.g.
|
||||
|
||||
sh seata-server.sh 8091 /home/admin/seata/data/
|
||||
</code></pre>
|
||||
<h3>Step 5: 运行例子</h3>
|
||||
<ul>
|
||||
<li>启动账户服务 (<a href="https://github.com/seata/seata-samples/blob/master/dubbo/src/main/java/com/seata/seata/samples/dubbo/starter/DubboAccountServiceStarter.java">DubboAccountServiceStarter</a>)。</li>
|
||||
<li>启动库存服务 (<a href="https://github.com/seata/seata-samples/blob/master/dubbo/src/main/java/com/seata/seata/samples/dubbo/starter/DubboStorageServiceStarter.java">DubboStorageServiceStarter</a>)。</li>
|
||||
<li>启动订单服务 (<a href="https://github.com/seata/seata-samples/blob/master/dubbo/src/main/java/com/seata/seata/samples/dubbo/starter/DubboOrderServiceStarter.java">DubboOrderServiceStarter</a>)。</li>
|
||||
<li>运行BusinessService入口 (<a href="https://github.com/seata/seata-samples/blob/master/dubbo/src/main/java/com/seata/seata/samples/dubbo/starter/DubboBusinessTester.java">DubboBusinessTester</a>)。</li>
|
||||
</ul>
|
||||
<h3>相关项目</h3>
|
||||
<ul>
|
||||
<li>seata: <a href="https://github.com/seata/seata/">https://github.com/seata/seata/</a></li>
|
||||
<li>seata-samples : <a href="https://github.com/seata/seata-samples">https://github.com/seata/seata-samples</a></li>
|
||||
</ul>
|
||||
</section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_white.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>愿景</h3><p>Seata 是一款阿里巴巴开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。</p></div><div class="col col-6"><dl><dt>文档</dt><dd><a href="/zh-cn/docs/overview/what_is_seata.html" target="_self">Seata 是什么?</a></dd><dd><a href="/zh-cn/docs/user/quickstart.html" target="_self">快速开始</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">报告文档问题</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">在Github上编辑此文档</a></dd></dl></div><div class="col col-6"><dl><dt>资源</dt><dd><a href="/zh-cn/blog/index.html" target="_self">博客</a></dd><dd><a href="/zh-cn/community/index.html" target="_self">社区</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/blogDetail.js"></script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
|
@ -1,489 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="fescar、seata、分布式事务" />
|
||||
<meta name="description" content="how-to-support-spring-cloud" />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>Fescar 与 Spring Cloud 集成源码深度剖析</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/blogDetail.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="blog-detail-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/zh-cn/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">En</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/zh-cn/index.html" target="_self">首页</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/docs/overview/what-is-seata.html" target="_self">文档</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/docs/developers/developers_dev.html" target="_self">开发者</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/zh-cn/blog/index.html" target="_self">博客</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/community/index.html" target="_self">社区</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/blog/download.html" target="_self">下载</a></li></ul></div></div></header><section class="blog-content markdown-body"><h1>Fescar 与 Spring Cloud 集成源码深度剖析</h1>
|
||||
<h3>Fescar 简介</h3>
|
||||
<p>常见的分布式事务方式有基于 2PC 的 XA (e.g. atomikos),从业务层入手的 TCC( e.g. byteTCC)、事务消息 ( e.g. RocketMQ Half Message) 等等。XA 是需要本地数据库支持的分布式事务的协议,资源锁在数据库层面导致性能较差,而支付宝作为布道师引入的 TCC 模式需要大量的业务代码保证,开发维护成本较高。</p>
|
||||
<p>分布式事务是业界比较关注的领域,这也是短短时间 Fescar 能收获6k Star的原因之一。Fescar 名字取自 <strong>Fast & Easy Commit And Rollback</strong> ,简单来说 Fescar 通过对本地 RDBMS 分支事务的协调来驱动完成全局事务,是工作在应用层的中间件。主要优点是相对于XA模式是性能较好不长时间占用连接资源,相对于 TCC 方式开发成本和业务侵入性较低。</p>
|
||||
<p>类似于 XA,Fescar 将角色分为 TC、RM、TM,事务整体过程模型如下:</p>
|
||||
<p><img src="/img/blog/fescar-microservices.png" alt="Fescar事务过程"></p>
|
||||
<pre><code>1. TM 向 TC 申请开启一个全局事务,全局事务创建成功并生成一个全局唯一的 XID。
|
||||
2. XID 在微服务调用链路的上下文中传播。
|
||||
3. RM 向 TC 注册分支事务,将其纳入 XID 对应全局事务的管辖。
|
||||
4. TM 向 TC 发起针对 XID 的全局提交或回滚决议。
|
||||
5. TC 调度 XID 下管辖的全部分支事务完成提交或回滚请求。
|
||||
</code></pre>
|
||||
<p>其中在目前的实现版本中 TC 是独立部署的进程,维护全局事务的操作记录和全局锁记录,负责协调并驱动全局事务的提交或回滚。TM RM 则与应用程序工作在同一应用进程。RM 对 JDBC 数据源采用代理的方式对底层数据库做管理,利用语法解析,在执行事务时保留快照,并生成 undo log。大概的流程和模型划分就介绍到这里,下面开始对 Fescar 事务传播机制的分析。</p>
|
||||
<h3>Fescar 事务传播机制</h3>
|
||||
<p>Fescar 事务传播包括应用内事务嵌套调用和跨服务调用的事务传播。Fescar 事务是怎么在微服务调用链中传播的呢?Fescar 提供了事务 API 允许用户手动绑定事务的 XID 并加入到全局事务中,所以我们根据不同的服务框架机制,将 XID 在链路中传递即可实现事务的传播。</p>
|
||||
<p>RPC 请求过程分为调用方与被调用方两部分,我们需要对 XID 在请求与响应时做相应的处理。大致过程为:调用方即请求方将当前事务上下文中的 XID 取出,通过RPC协议传递给被调用方;被调用方从请求中的将 XID 取出,并绑定到自己的事务上下文中,纳入全局事务。微服务框架一般都有相应的 Filter 和 Interceptor 机制,我们来具体分析下 Spring Cloud 与Fescar 的整合过程。</p>
|
||||
<h3>Fescar 与 Spring Cloud Alibaba 集成部分源码解析</h3>
|
||||
<p>本部分源码全部来自于 spring-cloud-alibaba-fescar. 源码解析部分主要包括 AutoConfiguration、微服务被调用方和微服务调用方三大部分。对于微服务调用方方式具体分为 RestTemplate 和 Feign,其中对于 Feign 请求方式又进一步细分为结合 Hystrix 和 Sentinel 的使用模式。</p>
|
||||
<h4>Fescar AutoConfiguration</h4>
|
||||
<p>对于 AutoConfiguration 的解析此处只介绍与 Fescar 启动相关的部分,其他部分的解析将穿插于【微服务被调用方】和 【微服务调用方】章节进行介绍。</p>
|
||||
<p>Fescar 的启动需要配置 GlobalTransactionScanner,GlobalTransactionScanner 负责初始化 Fescar 的 RM client、TM client 和 自动代理标注 GlobalTransactional 注解的类。GlobalTransactionScanner bean 的启动通过 GlobalTransactionAutoConfiguration 加载并注入FescarProperties。<br>
|
||||
FescarProperties 包含了 Fescar 的重要属性 txServiceGroup ,此属性的可通过 application.properties 文件中的 key: spring.cloud.alibaba.fescar.txServiceGroup 读取,默认值为 ${<a href="http://spring.application.name">spring.application.name</a>}-fescar-service-group 。txServiceGroup 表示 Fescar 的逻辑事务分组名,此分组名通过配置中心(目前支持文件、Apollo)获取逻辑事务分组名对应的 TC 集群名称,进一步通过集群名称构造出 TC 集群的服务名,通过注册中心(目前支持nacos、redis、zk和eureka)和服务名找到可用的 TC 服务节点,然后 RM client、TM client 与 TC 进行 rpc 交互。</p>
|
||||
<h4>微服务被调用方</h4>
|
||||
<p>由于调用方的逻辑比较多一点,我们先分析被调用方的逻辑。针对于 Spring Cloud 项目,默认采用的 RPC 传输协议是 HTTP 协议,所以使用了 HandlerInterceptor 机制来对HTTP的请求做拦截。</p>
|
||||
<p>HandlerInterceptor 是 Spring 提供的接口, 它有以下三个方法可以被覆写。</p>
|
||||
<pre><code class="language-java"> <span class="hljs-comment">/**
|
||||
* Intercept the execution of a handler. Called after HandlerMapping determined
|
||||
* an appropriate handler object, but before HandlerAdapter invokes the handler.
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">default</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">preHandle</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, Object handler)</span>
|
||||
<span class="hljs-keyword">throws</span> Exception </span>{
|
||||
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;
|
||||
}
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* Intercept the execution of a handler. Called after HandlerAdapter actually
|
||||
* invoked the handler, but before the DispatcherServlet renders the view.
|
||||
* Can expose additional model objects to the view via the given ModelAndView.
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">default</span> <span class="hljs-keyword">void</span> <span class="hljs-title">postHandle</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, Object handler,
|
||||
@Nullable ModelAndView modelAndView)</span> <span class="hljs-keyword">throws</span> Exception </span>{
|
||||
}
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* Callback after completion of request processing, that is, after rendering
|
||||
* the view. Will be called on any outcome of handler execution, thus allows
|
||||
* for proper resource cleanup.
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">default</span> <span class="hljs-keyword">void</span> <span class="hljs-title">afterCompletion</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response, Object handler,
|
||||
@Nullable Exception ex)</span> <span class="hljs-keyword">throws</span> Exception </span>{
|
||||
}
|
||||
</code></pre>
|
||||
<p>根据注释,我们可以很明确的看到各个方法的作用时间和常用用途。对于 Fescar 集成来讲,它根据需要重写了 preHandle、afterCompletion 方法。</p>
|
||||
<p>FescarHandlerInterceptor 的作用是将服务链路传递过来的 XID,绑定到服务节点的事务上下文中,并且在请求完成后清理相关资源。FescarHandlerInterceptorConfiguration 中配置了所有的 url 均进行拦截,对所有的请求过来均会执行该拦截器,进行 XID 的转换与事务绑定。</p>
|
||||
<pre><code class="language-java"><span class="hljs-comment">/**
|
||||
* <span class="hljs-doctag">@author</span> xiaojing
|
||||
*
|
||||
* Fescar HandlerInterceptor, Convert Fescar information into
|
||||
* <span class="hljs-doctag">@see</span> com.alibaba.fescar.core.context.RootContext from http request's header in
|
||||
* {<span class="hljs-doctag">@link</span> org.springframework.web.servlet.HandlerInterceptor#preHandle(HttpServletRequest , HttpServletResponse , Object )},
|
||||
* And clean up Fescar information after servlet method invocation in
|
||||
* {<span class="hljs-doctag">@link</span> org.springframework.web.servlet.HandlerInterceptor#afterCompletion(HttpServletRequest, HttpServletResponse, Object, Exception)}
|
||||
*/</span>
|
||||
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FescarHandlerInterceptor</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">HandlerInterceptor</span> </span>{
|
||||
|
||||
<span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> Logger log = LoggerFactory
|
||||
.getLogger(FescarHandlerInterceptor<span class="hljs-class">.<span class="hljs-keyword">class</span>)</span>;
|
||||
|
||||
<span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">boolean</span> <span class="hljs-title">preHandle</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response,
|
||||
Object handler)</span> <span class="hljs-keyword">throws</span> Exception </span>{
|
||||
|
||||
String xid = RootContext.getXID();
|
||||
String rpcXid = request.getHeader(RootContext.KEY_XID);
|
||||
<span class="hljs-keyword">if</span> (log.isDebugEnabled()) {
|
||||
log.debug(<span class="hljs-string">"xid in RootContext {} xid in RpcContext {}"</span>, xid, rpcXid);
|
||||
}
|
||||
|
||||
<span class="hljs-keyword">if</span> (xid == <span class="hljs-keyword">null</span> && rpcXid != <span class="hljs-keyword">null</span>) {
|
||||
RootContext.bind(rpcXid);
|
||||
<span class="hljs-keyword">if</span> (log.isDebugEnabled()) {
|
||||
log.debug(<span class="hljs-string">"bind {} to RootContext"</span>, rpcXid);
|
||||
}
|
||||
}
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;
|
||||
}
|
||||
|
||||
<span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">afterCompletion</span><span class="hljs-params">(HttpServletRequest request, HttpServletResponse response,
|
||||
Object handler, Exception e)</span> <span class="hljs-keyword">throws</span> Exception </span>{
|
||||
|
||||
String rpcXid = request.getHeader(RootContext.KEY_XID);
|
||||
|
||||
<span class="hljs-keyword">if</span> (StringUtils.isEmpty(rpcXid)) {
|
||||
<span class="hljs-keyword">return</span>;
|
||||
}
|
||||
|
||||
String unbindXid = RootContext.unbind();
|
||||
<span class="hljs-keyword">if</span> (log.isDebugEnabled()) {
|
||||
log.debug(<span class="hljs-string">"unbind {} from RootContext"</span>, unbindXid);
|
||||
}
|
||||
<span class="hljs-keyword">if</span> (!rpcXid.equalsIgnoreCase(unbindXid)) {
|
||||
log.warn(<span class="hljs-string">"xid in change during RPC from {} to {}"</span>, rpcXid, unbindXid);
|
||||
<span class="hljs-keyword">if</span> (unbindXid != <span class="hljs-keyword">null</span>) {
|
||||
RootContext.bind(unbindXid);
|
||||
log.warn(<span class="hljs-string">"bind {} back to RootContext"</span>, unbindXid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
</code></pre>
|
||||
<p>preHandle 在请求执行前被调用,xid 为当前事务上下文已经绑定的全局事务的唯一标识,rpcXid 为请求通过 HTTP Header 传递过来需要绑定的全局事务标识。preHandle 方法中判断如果当前事务上下文中没有 XID,且 rpcXid 不为空,那么就将 rpcXid 绑定到当前的事务上下文。</p>
|
||||
<p>afterCompletion 在请求完成后被调用,该方法用来执行资源的相关清理动作。Fescar 通过 RootContext.unbind() 方法对事务上下文涉及到的 XID 进行解绑。下面 if 中的逻辑是为了代码的健壮性考虑,如果遇到 rpcXid和 unbindXid 不相等的情况,再将 unbindXid 重新绑定回去。</p>
|
||||
<p>对于 Spring Cloud 来讲,默认采用的 RPC 方式是 HTTP 的方式,所以对被调用方来讲,它的请求拦截方式不用做任何区分,只需要从 Header 中将 XID 就可以取出绑定到自己的事务上下文中即可。但是对于调用方由于请求组件的多样化,包括熔断隔离机制,所以要区分不同的情况做处理,后面我们来具体分析一下。</p>
|
||||
<h4>微服务调用方</h4>
|
||||
<p>Fescar 将请求方式分为:RestTemplate、Feign、Feign+Hystrix 和 Feign+Sentinel 。不同的组件通过 Spring Boot 的 Auto Configuration 来完成自动的配置,具体的配置类清单可以看 spring.factories ,下文也会介绍相关的配置类。</p>
|
||||
<h5>RestTemplate</h5>
|
||||
<p>先来看下如果调用方如果是是基于 RestTemplate 的请求,Fescar 是怎么传递 XID 的。</p>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FescarRestTemplateInterceptor</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">ClientHttpRequestInterceptor</span> </span>{
|
||||
<span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> ClientHttpResponse <span class="hljs-title">intercept</span><span class="hljs-params">(HttpRequest httpRequest, <span class="hljs-keyword">byte</span>[] bytes,
|
||||
ClientHttpRequestExecution clientHttpRequestExecution)</span> <span class="hljs-keyword">throws</span> IOException </span>{
|
||||
HttpRequestWrapper requestWrapper = <span class="hljs-keyword">new</span> HttpRequestWrapper(httpRequest);
|
||||
|
||||
String xid = RootContext.getXID();
|
||||
|
||||
<span class="hljs-keyword">if</span> (!StringUtils.isEmpty(xid)) {
|
||||
requestWrapper.getHeaders().add(RootContext.KEY_XID, xid);
|
||||
}
|
||||
<span class="hljs-keyword">return</span> clientHttpRequestExecution.execute(requestWrapper, bytes);
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<p>FescarRestTemplateInterceptor 实现了 ClientHttpRequestInterceptor 接口的 intercept 方法,对调用的请求做了包装,在发送请求时若存在 Fescar 事务上下文 XID 则取出并放到 HTTP Header 中。</p>
|
||||
<p>FescarRestTemplateInterceptor 通过 FescarRestTemplateAutoConfiguration 实现将 FescarRestTemplateInterceptor 配置到 RestTemplate 中去。</p>
|
||||
<pre><code class="language-java"><span class="hljs-meta">@Configuration</span>
|
||||
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FescarRestTemplateAutoConfiguration</span> </span>{
|
||||
|
||||
<span class="hljs-meta">@Bean</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> FescarRestTemplateInterceptor <span class="hljs-title">fescarRestTemplateInterceptor</span><span class="hljs-params">()</span> </span>{
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> FescarRestTemplateInterceptor();
|
||||
}
|
||||
|
||||
<span class="hljs-meta">@Autowired</span>(required = <span class="hljs-keyword">false</span>)
|
||||
<span class="hljs-keyword">private</span> Collection<RestTemplate> restTemplates;
|
||||
|
||||
<span class="hljs-meta">@Autowired</span>
|
||||
<span class="hljs-keyword">private</span> FescarRestTemplateInterceptor fescarRestTemplateInterceptor;
|
||||
|
||||
<span class="hljs-meta">@PostConstruct</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">init</span><span class="hljs-params">()</span> </span>{
|
||||
<span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.restTemplates != <span class="hljs-keyword">null</span>) {
|
||||
<span class="hljs-keyword">for</span> (RestTemplate restTemplate : restTemplates) {
|
||||
List<ClientHttpRequestInterceptor> interceptors = <span class="hljs-keyword">new</span> ArrayList<ClientHttpRequestInterceptor>(
|
||||
restTemplate.getInterceptors());
|
||||
interceptors.add(<span class="hljs-keyword">this</span>.fescarRestTemplateInterceptor);
|
||||
restTemplate.setInterceptors(interceptors);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</code></pre>
|
||||
<p>init 方法遍历所有的 restTemplate ,并将原来 restTemplate 中的拦截器取出,增加 fescarRestTemplateInterceptor 后置入并重排序。</p>
|
||||
<h5>Feign</h5>
|
||||
<p><img src="/img/blog/20190305184812.png" alt="Feign 类关系图"></p>
|
||||
<p>接下来看下 Feign 的相关代码,该包下面的类还是比较多的,我们先从其 AutoConfiguration 入手。</p>
|
||||
<pre><code class="language-java"><span class="hljs-meta">@Configuration</span>
|
||||
<span class="hljs-meta">@ConditionalOnClass</span>(Client<span class="hljs-class">.<span class="hljs-keyword">class</span>)
|
||||
@<span class="hljs-title">AutoConfigureBefore</span>(<span class="hljs-title">FeignAutoConfiguration</span>.<span class="hljs-title">class</span>)
|
||||
<span class="hljs-title">public</span> <span class="hljs-title">class</span> <span class="hljs-title">FescarFeignClientAutoConfiguration</span> </span>{
|
||||
|
||||
<span class="hljs-meta">@Bean</span>
|
||||
<span class="hljs-meta">@Scope</span>(<span class="hljs-string">"prototype"</span>)
|
||||
<span class="hljs-meta">@ConditionalOnClass</span>(name = <span class="hljs-string">"com.netflix.hystrix.HystrixCommand"</span>)
|
||||
<span class="hljs-meta">@ConditionalOnProperty</span>(name = <span class="hljs-string">"feign.hystrix.enabled"</span>, havingValue = <span class="hljs-string">"true"</span>)
|
||||
Feign.<span class="hljs-function">Builder <span class="hljs-title">feignHystrixBuilder</span><span class="hljs-params">(BeanFactory beanFactory)</span> </span>{
|
||||
<span class="hljs-keyword">return</span> FescarHystrixFeignBuilder.builder(beanFactory);
|
||||
}
|
||||
|
||||
<span class="hljs-meta">@Bean</span>
|
||||
<span class="hljs-meta">@Scope</span>(<span class="hljs-string">"prototype"</span>)
|
||||
<span class="hljs-meta">@ConditionalOnClass</span>(name = <span class="hljs-string">"com.alibaba.csp.sentinel.SphU"</span>)
|
||||
<span class="hljs-meta">@ConditionalOnProperty</span>(name = <span class="hljs-string">"feign.sentinel.enabled"</span>, havingValue = <span class="hljs-string">"true"</span>)
|
||||
Feign.<span class="hljs-function">Builder <span class="hljs-title">feignSentinelBuilder</span><span class="hljs-params">(BeanFactory beanFactory)</span> </span>{
|
||||
<span class="hljs-keyword">return</span> FescarSentinelFeignBuilder.builder(beanFactory);
|
||||
}
|
||||
|
||||
<span class="hljs-meta">@Bean</span>
|
||||
<span class="hljs-meta">@ConditionalOnMissingBean</span>
|
||||
<span class="hljs-meta">@Scope</span>(<span class="hljs-string">"prototype"</span>)
|
||||
Feign.<span class="hljs-function">Builder <span class="hljs-title">feignBuilder</span><span class="hljs-params">(BeanFactory beanFactory)</span> </span>{
|
||||
<span class="hljs-keyword">return</span> FescarFeignBuilder.builder(beanFactory);
|
||||
}
|
||||
|
||||
<span class="hljs-meta">@Configuration</span>
|
||||
<span class="hljs-keyword">protected</span> <span class="hljs-keyword">static</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FeignBeanPostProcessorConfiguration</span> </span>{
|
||||
|
||||
<span class="hljs-meta">@Bean</span>
|
||||
<span class="hljs-function">FescarBeanPostProcessor <span class="hljs-title">fescarBeanPostProcessor</span><span class="hljs-params">(
|
||||
FescarFeignObjectWrapper fescarFeignObjectWrapper)</span> </span>{
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> FescarBeanPostProcessor(fescarFeignObjectWrapper);
|
||||
}
|
||||
|
||||
<span class="hljs-meta">@Bean</span>
|
||||
<span class="hljs-function">FescarContextBeanPostProcessor <span class="hljs-title">fescarContextBeanPostProcessor</span><span class="hljs-params">(
|
||||
BeanFactory beanFactory)</span> </span>{
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> FescarContextBeanPostProcessor(beanFactory);
|
||||
}
|
||||
|
||||
<span class="hljs-meta">@Bean</span>
|
||||
<span class="hljs-function">FescarFeignObjectWrapper <span class="hljs-title">fescarFeignObjectWrapper</span><span class="hljs-params">(BeanFactory beanFactory)</span> </span>{
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> FescarFeignObjectWrapper(beanFactory);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</code></pre>
|
||||
<p>FescarFeignClientAutoConfiguration 在存在 Client.class 时生效,且要求作用在 FeignAutoConfiguration 之前。由于FeignClientsConfiguration 是在 FeignAutoConfiguration 生成 FeignContext 生效的,所以根据依赖关系, FescarFeignClientAutoConfiguration 同样早于 FeignClientsConfiguration。</p>
|
||||
<p>FescarFeignClientAutoConfiguration 自定义了 Feign.Builder,针对于 feign.sentinel,feign.hystrix 和 feign 的情况做了适配,目的是自定义 feign 中 Client 的真正实现为 FescarFeignClient。</p>
|
||||
<pre><code class="language-java">HystrixFeign.builder().retryer(Retryer.NEVER_RETRY)
|
||||
.client(<span class="hljs-keyword">new</span> FescarFeignClient(beanFactory))
|
||||
</code></pre>
|
||||
<pre><code class="language-java">SentinelFeign.builder().retryer(Retryer.NEVER_RETRY)
|
||||
.client(<span class="hljs-keyword">new</span> FescarFeignClient(beanFactory));
|
||||
</code></pre>
|
||||
<pre><code class="language-java">Feign.builder().client(<span class="hljs-keyword">new</span> FescarFeignClient(beanFactory));
|
||||
</code></pre>
|
||||
<p>FescarFeignClient 是对原来的 Feign 客户端代理增强,具体代码见下图:</p>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FescarFeignClient</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Client</span> </span>{
|
||||
|
||||
<span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> Client delegate;
|
||||
<span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> BeanFactory beanFactory;
|
||||
|
||||
FescarFeignClient(BeanFactory beanFactory) {
|
||||
<span class="hljs-keyword">this</span>.beanFactory = beanFactory;
|
||||
<span class="hljs-keyword">this</span>.delegate = <span class="hljs-keyword">new</span> Client.Default(<span class="hljs-keyword">null</span>, <span class="hljs-keyword">null</span>);
|
||||
}
|
||||
|
||||
FescarFeignClient(BeanFactory beanFactory, Client delegate) {
|
||||
<span class="hljs-keyword">this</span>.delegate = delegate;
|
||||
<span class="hljs-keyword">this</span>.beanFactory = beanFactory;
|
||||
}
|
||||
|
||||
<span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> Response <span class="hljs-title">execute</span><span class="hljs-params">(Request request, Request.Options options)</span> <span class="hljs-keyword">throws</span> IOException </span>{
|
||||
|
||||
Request modifiedRequest = getModifyRequest(request);
|
||||
|
||||
<span class="hljs-keyword">try</span> {
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.delegate.execute(modifiedRequest, options);
|
||||
}
|
||||
<span class="hljs-keyword">finally</span> {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
<span class="hljs-function"><span class="hljs-keyword">private</span> Request <span class="hljs-title">getModifyRequest</span><span class="hljs-params">(Request request)</span> </span>{
|
||||
|
||||
String xid = RootContext.getXID();
|
||||
|
||||
<span class="hljs-keyword">if</span> (StringUtils.isEmpty(xid)) {
|
||||
<span class="hljs-keyword">return</span> request;
|
||||
}
|
||||
|
||||
Map<String, Collection<String>> headers = <span class="hljs-keyword">new</span> HashMap<>();
|
||||
headers.putAll(request.headers());
|
||||
|
||||
List<String> fescarXid = <span class="hljs-keyword">new</span> ArrayList<>();
|
||||
fescarXid.add(xid);
|
||||
headers.put(RootContext.KEY_XID, fescarXid);
|
||||
|
||||
<span class="hljs-keyword">return</span> Request.create(request.method(), request.url(), headers, request.body(),
|
||||
request.charset());
|
||||
}
|
||||
|
||||
</code></pre>
|
||||
<p>上面的过程中我们可以看到,FescarFeignClient 对原来的 Request 做了修改,它首先将 XID 从当前的事务上下文中取出,在 XID 不为空的情况下,将 XID 放到了 Header 中。</p>
|
||||
<p>FeignBeanPostProcessorConfiguration 定义了3个 bean:FescarContextBeanPostProcessor、FescarBeanPostProcessor 和 FescarFeignObjectWrapper。其中 FescarContextBeanPostProcessor FescarBeanPostProcessor 实现了Spring BeanPostProcessor 接口。
|
||||
以下为 FescarContextBeanPostProcessor 实现。</p>
|
||||
<pre><code class="language-java"> <span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> Object <span class="hljs-title">postProcessBeforeInitialization</span><span class="hljs-params">(Object bean, String beanName)</span>
|
||||
<span class="hljs-keyword">throws</span> BeansException </span>{
|
||||
<span class="hljs-keyword">if</span> (bean <span class="hljs-keyword">instanceof</span> FeignContext && !(bean <span class="hljs-keyword">instanceof</span> FescarFeignContext)) {
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> FescarFeignContext(getFescarFeignObjectWrapper(),
|
||||
(FeignContext) bean);
|
||||
}
|
||||
<span class="hljs-keyword">return</span> bean;
|
||||
}
|
||||
|
||||
<span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> Object <span class="hljs-title">postProcessAfterInitialization</span><span class="hljs-params">(Object bean, String beanName)</span>
|
||||
<span class="hljs-keyword">throws</span> BeansException </span>{
|
||||
<span class="hljs-keyword">return</span> bean;
|
||||
}
|
||||
</code></pre>
|
||||
<p>BeanPostProcessor 中的两个方法可以对 Spring 容器中的 Bean 做前后处理,postProcessBeforeInitialization 处理时机是初始化之前,postProcessAfterInitialization 的处理时机是初始化之后,这2个方法的返回值可以是原先生成的实例 bean,或者使用 wrapper 包装后的实例。</p>
|
||||
<p>FescarContextBeanPostProcessor 将 FeignContext 包装成 FescarFeignContext。<br>
|
||||
FescarBeanPostProcessor 将 FeignClient 根据是否继承了 LoadBalancerFeignClient 包装成 FescarLoadBalancerFeignClient 和 FescarFeignClient。</p>
|
||||
<p>FeignAutoConfiguration 中的 FeignContext 并没有加 ConditionalOnXXX 的条件,所以 Fescar 采用预置处理的方式将 FeignContext 包装成 FescarFeignContext。</p>
|
||||
<pre><code class="language-java"> <span class="hljs-meta">@Bean</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> FeignContext <span class="hljs-title">feignContext</span><span class="hljs-params">()</span> </span>{
|
||||
FeignContext context = <span class="hljs-keyword">new</span> FeignContext();
|
||||
context.setConfigurations(<span class="hljs-keyword">this</span>.configurations);
|
||||
<span class="hljs-keyword">return</span> context;
|
||||
}
|
||||
</code></pre>
|
||||
<p>而对于 Feign Client,FeignClientFactoryBean 中会获取 FeignContext 的实例对象。对于开发者采用 @Configuration 注解的自定义配置的 Feign Client 对象,这里会被配置到 builder,导致 FescarFeignBuilder 中增强后的 FescarFeignCliet 失效。FeignClientFactoryBean 中关键代码如下:</p>
|
||||
<pre><code class="language-java"> <span class="hljs-comment">/**
|
||||
* <span class="hljs-doctag">@param</span> <T> the target type of the Feign client
|
||||
* <span class="hljs-doctag">@return</span> a {<span class="hljs-doctag">@link</span> Feign} client created with the specified data and the context information
|
||||
*/</span>
|
||||
<T> <span class="hljs-function">T <span class="hljs-title">getTarget</span><span class="hljs-params">()</span> </span>{
|
||||
FeignContext context = applicationContext.getBean(FeignContext<span class="hljs-class">.<span class="hljs-keyword">class</span>)</span>;
|
||||
Feign.Builder builder = feign(context);
|
||||
|
||||
<span class="hljs-keyword">if</span> (!StringUtils.hasText(<span class="hljs-keyword">this</span>.url)) {
|
||||
<span class="hljs-keyword">if</span> (!<span class="hljs-keyword">this</span>.name.startsWith(<span class="hljs-string">"http"</span>)) {
|
||||
url = <span class="hljs-string">"http://"</span> + <span class="hljs-keyword">this</span>.name;
|
||||
}
|
||||
<span class="hljs-keyword">else</span> {
|
||||
url = <span class="hljs-keyword">this</span>.name;
|
||||
}
|
||||
url += cleanPath();
|
||||
<span class="hljs-keyword">return</span> (T) loadBalance(builder, context, <span class="hljs-keyword">new</span> HardCodedTarget<>(<span class="hljs-keyword">this</span>.type,
|
||||
<span class="hljs-keyword">this</span>.name, url));
|
||||
}
|
||||
<span class="hljs-keyword">if</span> (StringUtils.hasText(<span class="hljs-keyword">this</span>.url) && !<span class="hljs-keyword">this</span>.url.startsWith(<span class="hljs-string">"http"</span>)) {
|
||||
<span class="hljs-keyword">this</span>.url = <span class="hljs-string">"http://"</span> + <span class="hljs-keyword">this</span>.url;
|
||||
}
|
||||
String url = <span class="hljs-keyword">this</span>.url + cleanPath();
|
||||
Client client = getOptional(context, Client<span class="hljs-class">.<span class="hljs-keyword">class</span>)</span>;
|
||||
<span class="hljs-keyword">if</span> (client != <span class="hljs-keyword">null</span>) {
|
||||
<span class="hljs-keyword">if</span> (client <span class="hljs-keyword">instanceof</span> LoadBalancerFeignClient) {
|
||||
<span class="hljs-comment">// not load balancing because we have a url,</span>
|
||||
<span class="hljs-comment">// but ribbon is on the classpath, so unwrap</span>
|
||||
client = ((LoadBalancerFeignClient)client).getDelegate();
|
||||
}
|
||||
builder.client(client);
|
||||
}
|
||||
Targeter targeter = get(context, Targeter<span class="hljs-class">.<span class="hljs-keyword">class</span>)</span>;
|
||||
<span class="hljs-keyword">return</span> (T) targeter.target(<span class="hljs-keyword">this</span>, builder, context, <span class="hljs-keyword">new</span> HardCodedTarget<>(
|
||||
<span class="hljs-keyword">this</span>.type, <span class="hljs-keyword">this</span>.name, url));
|
||||
}
|
||||
</code></pre>
|
||||
<p>上述代码根据是否指定了注解参数中的 URL 来选择直接调用 URL 还是走负载均衡,targeter.target 通过动态代理创建对象。大致过程为:将解析出的feign方法放入map
|
||||
,再通过将其作为参数传入生成InvocationHandler,进而生成动态代理对象。<br>
|
||||
FescarContextBeanPostProcessor 的存在,即使开发者对 FeignClient 自定义操作,依旧可以完成 Fescar 所需的全局事务的增强。</p>
|
||||
<p>对于 FescarFeignObjectWrapper,我们重点关注下Wrapper方法:</p>
|
||||
<pre><code class="language-java"> <span class="hljs-function">Object <span class="hljs-title">wrap</span><span class="hljs-params">(Object bean)</span> </span>{
|
||||
<span class="hljs-keyword">if</span> (bean <span class="hljs-keyword">instanceof</span> Client && !(bean <span class="hljs-keyword">instanceof</span> FescarFeignClient)) {
|
||||
<span class="hljs-keyword">if</span> (bean <span class="hljs-keyword">instanceof</span> LoadBalancerFeignClient) {
|
||||
LoadBalancerFeignClient client = ((LoadBalancerFeignClient) bean);
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> FescarLoadBalancerFeignClient(client.getDelegate(), factory(),
|
||||
clientFactory(), <span class="hljs-keyword">this</span>.beanFactory);
|
||||
}
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> FescarFeignClient(<span class="hljs-keyword">this</span>.beanFactory, (Client) bean);
|
||||
}
|
||||
<span class="hljs-keyword">return</span> bean;
|
||||
}
|
||||
</code></pre>
|
||||
<p>wrap 方法中,如果 bean 是 LoadBalancerFeignClient 的实例对象,那么首先通过 client.getDelegate() 方法将 LoadBalancerFeignClient 代理的实际 Client 对象取出后包装成 FescarFeignClient,再生成 LoadBalancerFeignClient 的子类 FescarLoadBalancerFeignClient 对象。如果 bean 是 Client 的实例对象且不是 FescarFeignClient LoadBalancerFeignClient,那么 bean 会直接包装生成 FescarFeignClient。</p>
|
||||
<p>上面的流程设计还是比较巧妙的,首先根据 Spring boot 的 Auto Configuration 控制了配置的先后顺序,同时自定义了 Feign Builder 的Bean,保证了 Client 均是经过增强后的 FescarFeignClient 。再通过 BeanPostProcessor 对Spring 容器中的 Bean 做了一遍包装,保证容器内的Bean均是增强后 FescarFeignClient ,避免 FeignClientFactoryBean getTarget 方法的替换动作。</p>
|
||||
<h5>Hystrix 隔离</h5>
|
||||
<p>下面我们再来看下 Hystrix 部分,为什么要单独把 Hystrix 拆出来看呢,而且 Fescar 代码也单独实现了个策略类。目前事务上下文 RootContext 的默认实现是基于 ThreadLocal 方式的 ThreadLocalContextCore,也就是上下文其实是和线程绑定的。Hystrix 本身有两种隔离状态的模式,基于信号量或者基于线程池进行隔离。Hystrix 官方建议是采取线程池的方式来充分隔离,也是一般情况下在采用的模式:</p>
|
||||
<pre><code>Thread or Semaphore
|
||||
The default, and the recommended setting, is to run HystrixCommands using thread isolation (THREAD) and HystrixObservableCommands using semaphore isolation (SEMAPHORE).
|
||||
|
||||
Commands executed in threads have an extra layer of protection against latencies beyond what network timeouts can offer.
|
||||
|
||||
Generally the only time you should use semaphore isolation for HystrixCommands is when the call is so high volume (hundreds per second, per instance) that the overhead of separate threads is too high; this typically only applies to non-network calls.
|
||||
</code></pre>
|
||||
<p>service 层的业务代码和请求发出的线程肯定不是同一个,那么 ThreadLocal 的方式就没办法将 XID 传递给 Hystrix 的线程并传递给被调用方的。怎么处理这件事情呢,Hystrix 提供了机制让开发者去自定义并发策略,只需要继承 HystrixConcurrencyStrategy 重写 wrapCallable 方法即可。</p>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FescarHystrixConcurrencyStrategy</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">HystrixConcurrencyStrategy</span> </span>{
|
||||
|
||||
<span class="hljs-keyword">private</span> HystrixConcurrencyStrategy delegate;
|
||||
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">FescarHystrixConcurrencyStrategy</span><span class="hljs-params">()</span> </span>{
|
||||
<span class="hljs-keyword">this</span>.delegate = HystrixPlugins.getInstance().getConcurrencyStrategy();
|
||||
HystrixPlugins.reset();
|
||||
HystrixPlugins.getInstance().registerConcurrencyStrategy(<span class="hljs-keyword">this</span>);
|
||||
}
|
||||
|
||||
<span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-keyword">public</span> <K> <span class="hljs-function">Callable<K> <span class="hljs-title">wrapCallable</span><span class="hljs-params">(Callable<K> c)</span> </span>{
|
||||
<span class="hljs-keyword">if</span> (c <span class="hljs-keyword">instanceof</span> FescarContextCallable) {
|
||||
<span class="hljs-keyword">return</span> c;
|
||||
}
|
||||
|
||||
Callable<K> wrappedCallable;
|
||||
<span class="hljs-keyword">if</span> (<span class="hljs-keyword">this</span>.delegate != <span class="hljs-keyword">null</span>) {
|
||||
wrappedCallable = <span class="hljs-keyword">this</span>.delegate.wrapCallable(c);
|
||||
}
|
||||
<span class="hljs-keyword">else</span> {
|
||||
wrappedCallable = c;
|
||||
}
|
||||
<span class="hljs-keyword">if</span> (wrappedCallable <span class="hljs-keyword">instanceof</span> FescarContextCallable) {
|
||||
<span class="hljs-keyword">return</span> wrappedCallable;
|
||||
}
|
||||
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> FescarContextCallable<>(wrappedCallable);
|
||||
}
|
||||
|
||||
<span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FescarContextCallable</span><<span class="hljs-title">K</span>> <span class="hljs-keyword">implements</span> <span class="hljs-title">Callable</span><<span class="hljs-title">K</span>> </span>{
|
||||
|
||||
<span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> Callable<K> actual;
|
||||
<span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> String xid;
|
||||
|
||||
FescarContextCallable(Callable<K> actual) {
|
||||
<span class="hljs-keyword">this</span>.actual = actual;
|
||||
<span class="hljs-keyword">this</span>.xid = RootContext.getXID();
|
||||
}
|
||||
|
||||
<span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> K <span class="hljs-title">call</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> Exception </span>{
|
||||
<span class="hljs-keyword">try</span> {
|
||||
RootContext.bind(xid);
|
||||
<span class="hljs-keyword">return</span> actual.call();
|
||||
}
|
||||
<span class="hljs-keyword">finally</span> {
|
||||
RootContext.unbind();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<p>Fescar 也提供一个 FescarHystrixAutoConfiguration,在存在 HystrixCommand 的时候生成FescarHystrixConcurrencyStrategy</p>
|
||||
<pre><code class="language-java"><span class="hljs-meta">@Configuration</span>
|
||||
<span class="hljs-meta">@ConditionalOnClass</span>(HystrixCommand<span class="hljs-class">.<span class="hljs-keyword">class</span>)
|
||||
<span class="hljs-title">public</span> <span class="hljs-title">class</span> <span class="hljs-title">FescarHystrixAutoConfiguration</span> </span>{
|
||||
|
||||
<span class="hljs-meta">@Bean</span>
|
||||
<span class="hljs-function">FescarHystrixConcurrencyStrategy <span class="hljs-title">fescarHystrixConcurrencyStrategy</span><span class="hljs-params">()</span> </span>{
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> FescarHystrixConcurrencyStrategy();
|
||||
}
|
||||
|
||||
}
|
||||
</code></pre>
|
||||
<h3>参考文献</h3>
|
||||
<ul>
|
||||
<li>
|
||||
<p>Fescar: <a href="https://github.com/alibaba/fescar">https://github.com/alibaba/fescar</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>Spring Cloud Alibaba: <a href="https://github.com/spring-cloud-incubator/spring-cloud-alibaba">https://github.com/spring-cloud-incubator/spring-cloud-alibaba</a></p>
|
||||
</li>
|
||||
<li>
|
||||
<p>spring-cloud-openfeign: <a href="https://github.com/spring-cloud/spring-cloud-openfeign">https://github.com/spring-cloud/spring-cloud-openfeign</a></p>
|
||||
</li>
|
||||
</ul>
|
||||
<h3>本文作者</h3>
|
||||
<p>郭树抗,社区昵称 ywind,曾就职于华为终端云,现搜狐智能媒体中心Java工程师,目前主要负责搜狐号相关开发,对分布式事务、分布式系统和微服务架构有异常浓厚的兴趣。<br>
|
||||
季敏(清铭),社区昵称 slievrly,Fescar 开源项目负责人,阿里巴巴中间件 TXC/GTS 核心研发成员,长期从事于分布式中间件核心研发工作,在分布式事务领域有着较丰富的技术积累。</p>
|
||||
</section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>愿景</h3><p>Seata 是一款阿里巴巴开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。</p></div><div class="col col-6"><dl><dt>文档</dt><dd><a href="/zh-cn/docs/overview/what-is-seata.html" target="_self">Seata 是什么?</a></dd><dd><a href="/zh-cn/docs/user/quickstart.html" target="_self">快速开始</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">报告文档问题</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">在Github上编辑此文档</a></dd></dl></div><div class="col col-6"><dl><dt>资源</dt><dd><a href="/zh-cn/blog/index.html" target="_self">博客</a></dd><dd><a href="/zh-cn/community/index.html" target="_self">社区</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/blogDetail.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,240 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="fescar、seata、分布式事务" />
|
||||
<meta name="description" content="integrate-seata-with-spring-cloud" />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>Seata(Fescar)分布式事务 整合 Spring Cloud</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/blogDetail.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="blog-detail-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/zh-cn/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">En</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/zh-cn/index.html" target="_self">首页</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/docs/overview/what-is-seata.html" target="_self">文档</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/docs/developers/developers_dev.html" target="_self">开发者</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/zh-cn/blog/index.html" target="_self">博客</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/community/index.html" target="_self">社区</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/blog/download.html" target="_self">下载</a></li></ul></div></div></header><section class="blog-content markdown-body"><h1>1.前言</h1>
|
||||
<p>针对Fescar 相信很多开发者已经对他并不陌生,当然Fescar 已经成为了过去时,为什么说它是过去时,因为Fescar 已经华丽的变身为Seata。如果还不知道Seata 的朋友,请登录下面网址查看。</p>
|
||||
<p>SEATA GITHUB:[<a href="https://github.com/seata/seata">https://github.com/seata/seata</a>]</p>
|
||||
<p>对于阿里各位同学的前仆后继,给我们广大开发者带来很多开源软件,在这里对他们表示真挚的感谢与问候。</p>
|
||||
<p>今天在这里和大家分享下Spring Cloud 整合Seata 的相关心得。也让更多的朋友在搭建的道路上少走一些弯路,少踩一些坑。</p>
|
||||
<h1>2.工程内容</h1>
|
||||
<p>本次搭建流程为:client->网关->服务消费者->服务提供者.</p>
|
||||
<pre><code> 技术框架:spring cloud gateway
|
||||
|
||||
spring cloud fegin
|
||||
|
||||
nacos1.0.RC2
|
||||
|
||||
fescar-server0.4.1(Seata)
|
||||
</code></pre>
|
||||
<p>关于nacos的启动方式请参考:<a href="https://nacos.io/zh-cn/docs/quick-start.html">Nacos启动参考</a></p>
|
||||
<p>首先seata支持很多种注册服务方式,在 fescar-server-0.4.1\conf 目录下</p>
|
||||
<pre><code> file.conf
|
||||
logback.xml
|
||||
nacos-config.sh
|
||||
nacos-config.text
|
||||
registry.conf
|
||||
</code></pre>
|
||||
<p>总共包含五个文件,其中 file.conf和 registry.conf 分别是我们在 服务消费者 & 服务提供者 代码段需要用到的文件。
|
||||
注:file.conf和 registry.conf 必须在当前使用的应用程序中,即: 服务消费者 & 服务提供者 两个应用在都需要包含。
|
||||
如果你采用了配置中心 是nacos 、zk ,file.cnf 是可以忽略的。但是type=“file” 如果是为file 就必须得用file.cnf</p>
|
||||
<p>下面是registry.conf 文件中的配置信息,其中 registry 是注册服务中心配置。config为配置中心的配置地方。</p>
|
||||
<p>从下面可知道目前seata支持nacos,file eureka redis zookeeper 等注册配置方式,默认下载的type=“file” 文件方式,当然这里选用什么方式,取决于</p>
|
||||
<p>每个人项目的实际情况,这里我选用的是nacos,eureka的也是可以的,我这边分别对这两个版本进行整合测试均可以通过。</p>
|
||||
<p>注:如果整合eureka请选用官方最新版本。</p>
|
||||
<h1>3.核心配置</h1>
|
||||
<pre><code class="language-java">registry {
|
||||
# file 、nacos 、eureka、redis、zk
|
||||
type = "nacos"
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = "public"
|
||||
cluster = "default"
|
||||
}
|
||||
eureka {
|
||||
serviceUrl = "http://localhost:1001/eureka"
|
||||
application = "default"
|
||||
weight = "1"
|
||||
}
|
||||
redis {
|
||||
serverAddr = "localhost:6379"
|
||||
db = "0"
|
||||
}
|
||||
zk {
|
||||
cluster = "default"
|
||||
serverAddr = "127.0.0.1:2181"
|
||||
session.timeout = 6000
|
||||
connect.timeout = 2000
|
||||
}
|
||||
file {
|
||||
name = "file.conf"
|
||||
}
|
||||
}
|
||||
|
||||
config {
|
||||
# file、nacos 、apollo、zk
|
||||
type = "nacos"
|
||||
|
||||
nacos {
|
||||
serverAddr = "localhost"
|
||||
namespace = "public"
|
||||
cluster = "default"
|
||||
}
|
||||
apollo {
|
||||
app.id = "fescar-server"
|
||||
apollo.meta = "http://192.168.1.204:8801"
|
||||
}
|
||||
zk {
|
||||
serverAddr = "127.0.0.1:2181"
|
||||
session.timeout = 6000
|
||||
connect.timeout = 2000
|
||||
}
|
||||
file {
|
||||
name = "file.conf"
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<p><a href="http://xn--nacos-config-o59yhn663rer9ctyiytr5wi.sh">这里要说明的是nacos-config.sh</a> 是针对采用nacos配置中心的话,需要执行的一些默认初始化针对nacos的脚本。</p>
|
||||
<p>SEATA的启动方式参考官方: 注意,这里需要说明下,命令启动官方是通过 空格区分参数,所以要注意。这里的IP 是可选参数,因为涉及到DNS解析,在部分情况下,有的时候在注册中心fescar 注入nacos的时候会通过获取地址,如果启动报错注册发现是计算机名称,需要指定IP。或者host配置IP指向。不过这个问题,在最新的SEATA中已经进行了修复。</p>
|
||||
<pre><code class="language-shell">sh fescar-server.sh 8091 /home/admin/fescar/data/ IP(可选)
|
||||
</code></pre>
|
||||
<p>上面提到过,在我们的代码中也是需要file.conf 和registry.conf 这里着重的地方要说的是file.conf,file.conf只有当registry中 配置file的时候才会进行加载,如果采用ZK、nacos、作为配置中心,可以忽略。因为type指定其他是不加载file.conf的,但是对应的 service.localRgroup.grouplist 和 service.vgroup_mapping 需要在支持配置中心 进行指定,这样你的client 在启动后会通过自动从配置中心获取对应的 SEATA 服务 和地址。如果不配置会出现无法连接server的错误。当然如果你采用的eureka在config的地方就需要采用type="file" 目前SEATA config暂时不支持eureka的形势</p>
|
||||
<pre><code class="language-java">transport {
|
||||
# tcp udt unix-domain-socket
|
||||
type = "TCP"
|
||||
#NIO NATIVE
|
||||
server = "NIO"
|
||||
#enable heartbeat
|
||||
heartbeat = true
|
||||
#thread factory for netty
|
||||
thread-factory {
|
||||
boss-thread-prefix = "NettyBoss"
|
||||
worker-thread-prefix = "NettyServerNIOWorker"
|
||||
server-executor-thread-prefix = "NettyServerBizHandler"
|
||||
share-boss-worker = false
|
||||
client-selector-thread-prefix = "NettyClientSelector"
|
||||
client-selector-thread-size = 1
|
||||
client-worker-thread-prefix = "NettyClientWorkerThread"
|
||||
# netty boss thread size,will not be used for UDT
|
||||
boss-thread-size = 1
|
||||
#auto default pin or 8
|
||||
worker-thread-size = 8
|
||||
}
|
||||
}
|
||||
service {
|
||||
#vgroup->rgroup
|
||||
vgroup_mapping.service-provider-fescar-service-group = "default"
|
||||
#only support single node
|
||||
localRgroup.grouplist = "127.0.0.1:8091"
|
||||
#degrade current not support
|
||||
enableDegrade = false
|
||||
#disable
|
||||
disable = false
|
||||
}
|
||||
|
||||
client {
|
||||
async.commit.buffer.limit = 10000
|
||||
lock {
|
||||
retry.internal = 10
|
||||
retry.times = 30
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<h1>4.服务相关</h1>
|
||||
<p>这里有两个地方需要注意</p>
|
||||
<pre><code class="language-java"> grouplist IP,这里是当前fescar-sever的IP端口,
|
||||
vgroup_mapping的配置。
|
||||
</code></pre>
|
||||
<p>vgroup_mapping.服务名称-fescar-service-group,这里 要说下服务名称其实是你当前的consumer 或者provider application.properties的配置的应用名称:spring.application.name=service-provider,源代码中是 获取应用名称与 fescar-service-group 进行拼接,做key值。同理value是当前fescar的服务名称, cluster = "default" / application = "default"</p>
|
||||
<pre><code class="language-java"> vgroup_mapping.service-provider-fescar-service-group = "default"
|
||||
#only support single node
|
||||
localRgroup.grouplist = "127.0.0.1:8091"
|
||||
</code></pre>
|
||||
<p>同理无论是provider 还是consumer 都需要这两个文件进行配置。</p>
|
||||
<p>如果你采用nacos做配置中心,需要在nacos通过添加配置方式进行配置添加。</p>
|
||||
<h1>5.事务使用</h1>
|
||||
<p>我这里的代码逻辑是请求通过网关进行负载转发到我的consumer上,在consumer 中通过fegin进行provider请求。官方的例子中是通过fegin进行的,而我们这边直接通过网关转发,所以全局事务同官方的demo一样 也都是在controller层。</p>
|
||||
<pre><code class="language-java"><span class="hljs-meta">@RestController</span>
|
||||
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DemoController</span> </span>{
|
||||
<span class="hljs-meta">@Autowired</span>
|
||||
<span class="hljs-keyword">private</span> DemoFeignClient demoFeignClient;
|
||||
|
||||
<span class="hljs-meta">@Autowired</span>
|
||||
<span class="hljs-keyword">private</span> DemoFeignClient2 demoFeignClient2;
|
||||
<span class="hljs-meta">@GlobalTransactional</span>(timeoutMills = <span class="hljs-number">300000</span>, name = <span class="hljs-string">"spring-cloud-demo-tx"</span>)
|
||||
<span class="hljs-meta">@GetMapping</span>(<span class="hljs-string">"/getdemo"</span>)
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">demo</span><span class="hljs-params">()</span> </span>{
|
||||
|
||||
<span class="hljs-comment">// 调用A 服务 简单save</span>
|
||||
ResponseData<Integer> result = demoFeignClient.insertService(<span class="hljs-string">"test"</span>,<span class="hljs-number">1</span>);
|
||||
<span class="hljs-keyword">if</span>(result.getStatus()==<span class="hljs-number">400</span>) {
|
||||
System.out.println(result+<span class="hljs-string">"+++++++++++++++++++++++++++++++++++++++"</span>);
|
||||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"this is error1"</span>);
|
||||
}
|
||||
|
||||
<span class="hljs-comment">// 调用B 服务。报错测试A 服务回滚</span>
|
||||
ResponseData<Integer> result2 = demoFeignClient2.saveService();
|
||||
|
||||
<span class="hljs-keyword">if</span>(result2.getStatus()==<span class="hljs-number">400</span>) {
|
||||
System.out.println(result2+<span class="hljs-string">"+++++++++++++++++++++++++++++++++++++++"</span>);
|
||||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> RuntimeException(<span class="hljs-string">"this is error2"</span>);
|
||||
}
|
||||
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-string">"SUCCESS"</span>;
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<p>到此为止核心的事务整合基本到此结束了,我这里是针对A,B 两个provider进行调用,当B发生报错后,进行全局事务回滚。当然每个事务内部都可以通过自己的独立本地事务去处理自己本地事务方式。</p>
|
||||
<p>SEATA是通过全局的XID方式进行事务统一标识方式。这里就不列出SEATA需要用的数据库表。具体参考:<a href="https://github.com/spring-cloud-incubator/spring-cloud-alibaba/tree/master/spring-cloud-alibaba-examples/fescar-example">spring-cloud-fescar 官方DEMO</a></p>
|
||||
<h1>5.数据代理</h1>
|
||||
<p>这里还有一个重要的说明就是,在分库服务的情况下,每一个数据库内都需要有一个undo_log的数据库表进行XID统一存储处理。</p>
|
||||
<p>同事针对每个提供服务的项目,需要进行数据库连接池的代理。也就是:</p>
|
||||
<p>目前只支持Druid连接池,后续会继续支持。</p>
|
||||
<pre><code class="language-java"><span class="hljs-meta">@Configuration</span>
|
||||
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">DatabaseConfiguration</span> </span>{
|
||||
|
||||
|
||||
<span class="hljs-meta">@Bean</span>(destroyMethod = <span class="hljs-string">"close"</span>, initMethod = <span class="hljs-string">"init"</span>)
|
||||
<span class="hljs-meta">@ConfigurationProperties</span>(prefix=<span class="hljs-string">"spring.datasource"</span>)
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> DruidDataSource <span class="hljs-title">druidDataSource</span><span class="hljs-params">()</span> </span>{
|
||||
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> DruidDataSource();
|
||||
}
|
||||
|
||||
|
||||
<span class="hljs-meta">@Bean</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> DataSourceProxy <span class="hljs-title">dataSourceProxy</span><span class="hljs-params">(DruidDataSource druidDataSource)</span> </span>{
|
||||
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> DataSourceProxy(druidDataSource);
|
||||
}
|
||||
|
||||
|
||||
<span class="hljs-meta">@Bean</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> SqlSessionFactory <span class="hljs-title">sqlSessionFactory</span><span class="hljs-params">(DataSourceProxy dataSourceProxy)</span> <span class="hljs-keyword">throws</span> Exception </span>{
|
||||
SqlSessionFactoryBean factoryBean = <span class="hljs-keyword">new</span> SqlSessionFactoryBean();
|
||||
factoryBean.setDataSource(dataSourceProxy);
|
||||
<span class="hljs-keyword">return</span> factoryBean.getObject();
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<p>大家要注意的就是配置文件和数据代理。如果没有进行数据源代理,undo_log是无数据的,也就是没办进行XID的管理。</p>
|
||||
<p>本文作者:大菲.Fei</p>
|
||||
</section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>愿景</h3><p>Seata 是一款阿里巴巴开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。</p></div><div class="col col-6"><dl><dt>文档</dt><dd><a href="/zh-cn/docs/overview/what-is-seata.html" target="_self">Seata 是什么?</a></dd><dd><a href="/zh-cn/docs/user/quickstart.html" target="_self">快速开始</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">报告文档问题</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">在Github上编辑此文档</a></dd></dl></div><div class="col col-6"><dl><dt>资源</dt><dd><a href="/zh-cn/blog/index.html" target="_self">博客</a></dd><dd><a href="/zh-cn/community/index.html" target="_self">社区</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/blogDetail.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
|
@ -1,53 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="MT 模式" />
|
||||
<meta name="description" content="介绍 MT 模式" />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>MT 模式</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/blogDetail.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="blog-detail-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/zh-cn/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">En</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/zh-cn/index.html" target="_self">首页</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/docs/overview/what-is-seata.html" target="_self">文档</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/docs/developers/developers_dev.html" target="_self">开发者</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/zh-cn/blog/index.html" target="_self">博客</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/community/index.html" target="_self">社区</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/blog/download.html" target="_self">下载</a></li></ul></div></div></header><section class="blog-content markdown-body"><h1>Manual Transaction 模式</h1>
|
||||
<p>回顾总览中的描述:一个分布式的全局事务,整体是 <strong>两阶段提交</strong> 的模型。全局事务是由若干分支事务组成的,分支事务要满足 <strong>两阶段提交</strong> 的模型要求,即需要每个分支事务都具备自己的:</p>
|
||||
<ul>
|
||||
<li>一阶段 prepare 行为</li>
|
||||
<li>二阶段 commit 或 rollback 行为</li>
|
||||
</ul>
|
||||
<p><img src="https://upload-images.jianshu.io/upload_images/4420767-e48f0284a037d1df.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="Overview of a global transaction"></p>
|
||||
<p>根据两阶段行为模式的不同,我们将分支事务划分为 <strong>Automatic (Branch) Transaction Mode</strong> 和 <strong>Manual (Branch) Transaction Mode</strong>.</p>
|
||||
<p>AT 模式(<a href="">参考链接 TBD</a>)基于 <strong>支持本地 ACID 事务</strong> 的 <strong>关系型数据库</strong>:</p>
|
||||
<ul>
|
||||
<li>一阶段 prepare 行为:在本地事务中,一并提交业务数据更新和相应回滚日志记录。</li>
|
||||
<li>二阶段 commit 行为:马上成功结束,<strong>自动</strong> 异步批量清理回滚日志。</li>
|
||||
<li>二阶段 rollback 行为:通过回滚日志,<strong>自动</strong> 生成补偿操作,完成数据回滚。</li>
|
||||
</ul>
|
||||
<p>相应的,MT 模式,不依赖于底层数据资源的事务支持:</p>
|
||||
<ul>
|
||||
<li>一阶段 prepare 行为:调用 <strong>自定义</strong> 的 prepare 逻辑。</li>
|
||||
<li>二阶段 commit 行为:调用 <strong>自定义</strong> 的 commit 逻辑。</li>
|
||||
<li>二阶段 rollback 行为:调用 <strong>自定义</strong> 的 rollback 逻辑。</li>
|
||||
</ul>
|
||||
<p>所谓 MT 模式,是指支持把 <strong>自定义</strong> 的分支事务纳入到全局事务的管理中。</p>
|
||||
</section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>愿景</h3><p>Seata 是一款阿里巴巴开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。</p></div><div class="col col-6"><dl><dt>文档</dt><dd><a href="/zh-cn/docs/overview/what-is-seata.html" target="_self">Seata 是什么?</a></dd><dd><a href="/zh-cn/docs/user/quickstart.html" target="_self">快速开始</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">报告文档问题</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">在Github上编辑此文档</a></dd></dl></div><div class="col col-6"><dl><dt>资源</dt><dd><a href="/zh-cn/blog/index.html" target="_self">博客</a></dd><dd><a href="/zh-cn/community/index.html" target="_self">社区</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/blogDetail.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"filename": "manual-transaction-mode.md",
|
||||
"__html": "<h1>Manual Transaction 模式</h1>\n<p>回顾总览中的描述:一个分布式的全局事务,整体是 <strong>两阶段提交</strong> 的模型。全局事务是由若干分支事务组成的,分支事务要满足 <strong>两阶段提交</strong> 的模型要求,即需要每个分支事务都具备自己的:</p>\n<ul>\n<li>一阶段 prepare 行为</li>\n<li>二阶段 commit 或 rollback 行为</li>\n</ul>\n<p><img src=\"https://upload-images.jianshu.io/upload_images/4420767-e48f0284a037d1df.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240\" alt=\"Overview of a global transaction\"></p>\n<p>根据两阶段行为模式的不同,我们将分支事务划分为 <strong>Automatic (Branch) Transaction Mode</strong> 和 <strong>Manual (Branch) Transaction Mode</strong>.</p>\n<p>AT 模式(<a href=\"\">参考链接 TBD</a>)基于 <strong>支持本地 ACID 事务</strong> 的 <strong>关系型数据库</strong>:</p>\n<ul>\n<li>一阶段 prepare 行为:在本地事务中,一并提交业务数据更新和相应回滚日志记录。</li>\n<li>二阶段 commit 行为:马上成功结束,<strong>自动</strong> 异步批量清理回滚日志。</li>\n<li>二阶段 rollback 行为:通过回滚日志,<strong>自动</strong> 生成补偿操作,完成数据回滚。</li>\n</ul>\n<p>相应的,MT 模式,不依赖于底层数据资源的事务支持:</p>\n<ul>\n<li>一阶段 prepare 行为:调用 <strong>自定义</strong> 的 prepare 逻辑。</li>\n<li>二阶段 commit 行为:调用 <strong>自定义</strong> 的 commit 逻辑。</li>\n<li>二阶段 rollback 行为:调用 <strong>自定义</strong> 的 rollback 逻辑。</li>\n</ul>\n<p>所谓 MT 模式,是指支持把 <strong>自定义</strong> 的分支事务纳入到全局事务的管理中。</p>\n",
|
||||
"link": "/zh-cn/blog/manual-transaction-mode.html",
|
||||
"meta": {
|
||||
"title": "MT 模式",
|
||||
"keywords": "MT 模式",
|
||||
"description": "介绍 MT 模式",
|
||||
"author": "kmmshmily",
|
||||
"date": "2019-02-13"
|
||||
}
|
||||
}
|
|
@ -1,214 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Dubbo,Seata,一致性" />
|
||||
<meta name="description" content="本文主要介绍如何使用Seata保证Dubbo微服务间的一致性" />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>如何使用Seata保证Dubbo微服务间的一致性</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/blogDetail.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="blog-detail-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/zh-cn/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">En</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/zh-cn/index.html" target="_self">首页</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/docs/overview/what-is-seata.html" target="_self">文档</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/docs/developers/developers_dev.html" target="_self">开发者</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/zh-cn/blog/index.html" target="_self">博客</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/community/index.html" target="_self">社区</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/blog/download.html" target="_self">下载</a></li></ul></div></div></header><section class="blog-content markdown-body"><h1>如何使用Seata保证Dubbo微服务间的一致性</h1>
|
||||
<h2>案例</h2>
|
||||
<p>用户采购商品业务,整个业务包含3个微服务:</p>
|
||||
<ul>
|
||||
<li>库存服务: 扣减给定商品的库存数量。</li>
|
||||
<li>订单服务: 根据采购请求生成订单。</li>
|
||||
<li>账户服务: 用户账户金额扣减。</li>
|
||||
</ul>
|
||||
<h3>业务结构图</h3>
|
||||
<p><img src="/img/blog/seata/seata-1.png" alt="Architecture"></p>
|
||||
<h3>StorageService</h3>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">StorageService</span> </span>{
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* deduct storage count
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">deduct</span><span class="hljs-params">(String commodityCode, <span class="hljs-keyword">int</span> count)</span></span>;
|
||||
}
|
||||
</code></pre>
|
||||
<h3>OrderService</h3>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">OrderService</span> </span>{
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* create order
|
||||
*/</span>
|
||||
<span class="hljs-function">Order <span class="hljs-title">create</span><span class="hljs-params">(String userId, String commodityCode, <span class="hljs-keyword">int</span> orderCount)</span></span>;
|
||||
}
|
||||
</code></pre>
|
||||
<h3>AccountService</h3>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">AccountService</span> </span>{
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* debit balance of user's account
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">void</span> <span class="hljs-title">debit</span><span class="hljs-params">(String userId, <span class="hljs-keyword">int</span> money)</span></span>;
|
||||
}
|
||||
</code></pre>
|
||||
<h3>主要的业务逻辑:</h3>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BusinessServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">BusinessService</span> </span>{
|
||||
|
||||
<span class="hljs-keyword">private</span> StorageService storageService;
|
||||
|
||||
<span class="hljs-keyword">private</span> OrderService orderService;
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* purchase
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">purchase</span><span class="hljs-params">(String userId, String commodityCode, <span class="hljs-keyword">int</span> orderCount)</span> </span>{
|
||||
|
||||
storageService.deduct(commodityCode, orderCount);
|
||||
|
||||
orderService.create(userId, commodityCode, orderCount);
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">StorageServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">StorageService</span> </span>{
|
||||
|
||||
<span class="hljs-keyword">private</span> StorageDAO storageDAO;
|
||||
|
||||
<span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deduct</span><span class="hljs-params">(String commodityCode, <span class="hljs-keyword">int</span> count)</span> </span>{
|
||||
Storage storage = <span class="hljs-keyword">new</span> Storage();
|
||||
storage.setCount(count);
|
||||
storage.setCommodityCode(commodityCode);
|
||||
storageDAO.update(storage);
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">OrderServiceImpl</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">OrderService</span> </span>{
|
||||
|
||||
<span class="hljs-keyword">private</span> OrderDAO orderDAO;
|
||||
|
||||
<span class="hljs-keyword">private</span> AccountService accountService;
|
||||
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> Order <span class="hljs-title">create</span><span class="hljs-params">(String userId, String commodityCode, <span class="hljs-keyword">int</span> orderCount)</span> </span>{
|
||||
|
||||
<span class="hljs-keyword">int</span> orderMoney = calculate(commodityCode, orderCount);
|
||||
|
||||
accountService.debit(userId, orderMoney);
|
||||
|
||||
Order order = <span class="hljs-keyword">new</span> Order();
|
||||
order.userId = userId;
|
||||
order.commodityCode = commodityCode;
|
||||
order.count = orderCount;
|
||||
order.money = orderMoney;
|
||||
|
||||
<span class="hljs-keyword">return</span> orderDAO.insert(order);
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<h2>Seata 分布式事务解决方案</h2>
|
||||
<p><img src="/img/blog/seata/seata-2.png" alt="undefined"></p>
|
||||
<p>此处仅仅需要一行注解 <code>@GlobalTransactional</code> 写在业务发起方的方法上:</p>
|
||||
<pre><code class="language-java">
|
||||
<span class="hljs-meta">@GlobalTransactional</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">purchase</span><span class="hljs-params">(String userId, String commodityCode, <span class="hljs-keyword">int</span> orderCount)</span> </span>{
|
||||
......
|
||||
}
|
||||
</code></pre>
|
||||
<h2>Dubbo 与 Seata 结合的例子</h2>
|
||||
<h3>Step 1: 安装数据库</h3>
|
||||
<ul>
|
||||
<li>要求: MySQL (InnoDB 存储引擎)。</li>
|
||||
</ul>
|
||||
<p><strong>提示:</strong> 事实上例子中3个微服务需要3个独立的数据库,但为了方便我们使用同一物理库并配置3个逻辑连接串。</p>
|
||||
<p>更改以下xml文件中的数据库url、username和password</p>
|
||||
<p>dubbo-account-service.xml
|
||||
dubbo-order-service.xml
|
||||
dubbo-storage-service.xml</p>
|
||||
<pre><code class="language-xml"> <span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"url"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"jdbc:mysql://x.x.x.x:3306/xxx"</span> /></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"username"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"xxx"</span> /></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">property</span> <span class="hljs-attr">name</span>=<span class="hljs-string">"password"</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"xxx"</span> /></span>
|
||||
</code></pre>
|
||||
<h3>Step 2: 为 Seata 创建 UNDO_LOG 表</h3>
|
||||
<p><code>UNDO_LOG</code> 此表用于 Seata 的AT模式。</p>
|
||||
<pre><code class="language-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`undo_log`</span> (
|
||||
<span class="hljs-string">`id`</span> <span class="hljs-built_in">bigint</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> AUTO_INCREMENT,
|
||||
<span class="hljs-string">`branch_id`</span> <span class="hljs-built_in">bigint</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`xid`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`rollback_info`</span> longblob <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`log_status`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`log_created`</span> datetime <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`log_modified`</span> datetime <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`ext`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
|
||||
PRIMARY <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`id`</span>),
|
||||
<span class="hljs-keyword">KEY</span> <span class="hljs-string">`idx_unionkey`</span> (<span class="hljs-string">`xid`</span>,<span class="hljs-string">`branch_id`</span>)
|
||||
) <span class="hljs-keyword">ENGINE</span>=<span class="hljs-keyword">InnoDB</span> AUTO_INCREMENT=<span class="hljs-number">159</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CHARSET</span>=utf8
|
||||
</code></pre>
|
||||
<h3>Step 3: 创建相关业务表</h3>
|
||||
<pre><code class="language-sql">
|
||||
<span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">IF</span> <span class="hljs-keyword">EXISTS</span> <span class="hljs-string">`storage_tbl`</span>;
|
||||
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`storage_tbl`</span> (
|
||||
<span class="hljs-string">`id`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> AUTO_INCREMENT,
|
||||
<span class="hljs-string">`commodity_code`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`count`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span>,
|
||||
PRIMARY <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`id`</span>),
|
||||
<span class="hljs-keyword">UNIQUE</span> <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`commodity_code`</span>)
|
||||
) <span class="hljs-keyword">ENGINE</span>=<span class="hljs-keyword">InnoDB</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CHARSET</span>=utf8;
|
||||
|
||||
|
||||
<span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">IF</span> <span class="hljs-keyword">EXISTS</span> <span class="hljs-string">`order_tbl`</span>;
|
||||
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`order_tbl`</span> (
|
||||
<span class="hljs-string">`id`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> AUTO_INCREMENT,
|
||||
<span class="hljs-string">`user_id`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`commodity_code`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`count`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span>,
|
||||
<span class="hljs-string">`money`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span>,
|
||||
PRIMARY <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`id`</span>)
|
||||
) <span class="hljs-keyword">ENGINE</span>=<span class="hljs-keyword">InnoDB</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CHARSET</span>=utf8;
|
||||
|
||||
|
||||
<span class="hljs-keyword">DROP</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-keyword">IF</span> <span class="hljs-keyword">EXISTS</span> <span class="hljs-string">`account_tbl`</span>;
|
||||
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`account_tbl`</span> (
|
||||
<span class="hljs-string">`id`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> AUTO_INCREMENT,
|
||||
<span class="hljs-string">`user_id`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">255</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`money`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-number">0</span>,
|
||||
PRIMARY <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`id`</span>)
|
||||
) <span class="hljs-keyword">ENGINE</span>=<span class="hljs-keyword">InnoDB</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CHARSET</span>=utf8;
|
||||
</code></pre>
|
||||
<h3>Step 4: 启动 Seata-Server 服务</h3>
|
||||
<ul>
|
||||
<li>下载Server <a href="https://github.com/seata/seata/releases">package</a>, 并解压。</li>
|
||||
<li>运行bin目录下的启动脚本。</li>
|
||||
</ul>
|
||||
<pre><code class="language-shell">sh seata-server.sh $LISTEN_PORT $PATH_FOR_PERSISTENT_DATA
|
||||
|
||||
e.g.
|
||||
|
||||
sh seata-server.sh 8091 /home/admin/seata/data/
|
||||
</code></pre>
|
||||
<h3>Step 5: 运行例子</h3>
|
||||
<ul>
|
||||
<li>启动账户服务 (<a href="https://github.com/seata/seata-samples/blob/master/dubbo/src/main/java/com/seata/seata/samples/dubbo/starter/DubboAccountServiceStarter.java">DubboAccountServiceStarter</a>)。</li>
|
||||
<li>启动库存服务 (<a href="https://github.com/seata/seata-samples/blob/master/dubbo/src/main/java/com/seata/seata/samples/dubbo/starter/DubboStorageServiceStarter.java">DubboStorageServiceStarter</a>)。</li>
|
||||
<li>启动订单服务 (<a href="https://github.com/seata/seata-samples/blob/master/dubbo/src/main/java/com/seata/seata/samples/dubbo/starter/DubboOrderServiceStarter.java">DubboOrderServiceStarter</a>)。</li>
|
||||
<li>运行BusinessService入口 (<a href="https://github.com/seata/seata-samples/blob/master/dubbo/src/main/java/com/seata/seata/samples/dubbo/starter/DubboBusinessTester.java">DubboBusinessTester</a>)。</li>
|
||||
</ul>
|
||||
<h3>相关项目</h3>
|
||||
<ul>
|
||||
<li>seata: <a href="https://github.com/seata/seata/">https://github.com/seata/seata/</a></li>
|
||||
<li>seata-samples : <a href="https://github.com/seata/seata-samples">https://github.com/seata/seata-samples</a></li>
|
||||
</ul>
|
||||
</section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>愿景</h3><p>Seata 是一款阿里巴巴开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。</p></div><div class="col col-6"><dl><dt>文档</dt><dd><a href="/zh-cn/docs/overview/what-is-seata.html" target="_self">Seata 是什么?</a></dd><dd><a href="/zh-cn/docs/user/quickstart.html" target="_self">快速开始</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">报告文档问题</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">在Github上编辑此文档</a></dd></dl></div><div class="col col-6"><dl><dt>资源</dt><dd><a href="/zh-cn/blog/index.html" target="_self">博客</a></dd><dd><a href="/zh-cn/community/index.html" target="_self">社区</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/blogDetail.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
|
@ -1,92 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="seata、分布式事务、高可用" />
|
||||
<meta name="description" content="seata-analysis-go-server" />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>Seata分布式Go Server正式开源-TaaS设计简介</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/blogDetail.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="blog-detail-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/zh-cn/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">En</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/zh-cn/index.html" target="_self">首页</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/docs/overview/what-is-seata.html" target="_self">文档</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/docs/developers/developers_dev.html" target="_self">开发者</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/zh-cn/blog/index.html" target="_self">博客</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/community/index.html" target="_self">社区</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/blog/download.html" target="_self">下载</a></li></ul></div></div></header><section class="blog-content markdown-body"><h1>Seata 高可用服务端 TaaS 正式开源</h1>
|
||||
<h3>前言</h3>
|
||||
<p>TaaS 是 Seata 服务端(TC, Transaction Coordinator)的一种高可用实现,使用 <code>Golang</code> 编写。Taas 由InfiniVision (<a href="http://infinivision.cn">http://infinivision.cn</a>) 贡献给Seata开源社区。现已正式开源,并贡献给 Seata 社区。</p>
|
||||
<p>在Seata开源之前,我们内部开始借鉴GTS以及一些开源项目来实现分布式事务的解决方案TaaS(Transaction as a Service)。</p>
|
||||
<p>在我们完成TaaS的服务端的开发工作后,Seata(当时还叫Fescar)开源了,并且引起了开源社区的广泛关注,加上阿里巴巴的平台影响力以及社区活跃度,我们认为Seata会成为今后开源分布式事务的标准,我们决定TaaS兼容Seata。</p>
|
||||
<p>在发现Seata的服务端的实现是单机的,高可用等并没有实现,于是我们与Seata社区负责人取得联系,并且决定把TaaS开源,回馈开源社区。 同时,我们会长期维护,并且和Seata版本保持同步。</p>
|
||||
<p>目前,Seata官方的Java高可用版本也在开发中,TaaS和该高可用版本的设计思想不同,在今后会长期共存。</p>
|
||||
<p>TaaS已经开源, github (<a href="https://github.com/seata/seata-go-server">https://github.com/seata/seata-go-server</a>),欢迎大家试用。</p>
|
||||
<h3>设计原则</h3>
|
||||
<ol>
|
||||
<li>高性能,性能和机器数量成正比,即通过加入新机器到集群中,就可以提升性能</li>
|
||||
<li>高可用,一台机器出现故障,系统能依旧可以对外提供服务,或者在较短的时间内恢复对外服务(Leader切换的时间)</li>
|
||||
<li>Auto-Rebalance,集群中增加新的机器,或者有机器下线,系统能够自动的做负载均衡</li>
|
||||
<li>强一致,系统的元数据强一致在多个副本中存储</li>
|
||||
</ol>
|
||||
<h3>设计</h3>
|
||||
<p><img src="/img/blog/taas.png" alt=""></p>
|
||||
<h4>高性能</h4>
|
||||
<p>TaaS的性能和机器数量成正比,为了支持这个特性,在TaaS中处理全局事务的最小单元称为<code>Fragment</code>,系统在启动的时候会设定每个Fragment支持的活跃全局事务的并发数,同时系统会对每个Fragment进行采样,一旦发现Fragment超负荷,会生成新的Fragment来处理更多的并发。</p>
|
||||
<h4>高可用</h4>
|
||||
<p>每个<code>Fragment</code>有多个副本和一个Leader,由Leader来处理请求。当Leader出现故障,系统会产生一个新的Leader来处理请求,在新Leader的选举过程中,这个Fragment对外不提供服务,通常这个间隔时间是几秒钟。</p>
|
||||
<h4>强一致</h4>
|
||||
<p>TaaS本身不存储全局事务的元数据,元数据存储在Elasticell (<a href="https://github.com/deepfabric/elasticell">https://github.com/deepfabric/elasticell</a>) 中,Elasticell是一个兼容redis协议的分布式的KV存储,它基于Raft协议来保证数据的一致性。</p>
|
||||
<h4>Auto-Rebalance</h4>
|
||||
<p>随着系统的运行,在系统中会存在许多<code>Fragment</code>以及它们的副本,这样会导致在每个机器上,<code>Fragment</code>的分布不均匀,特别是当旧的机器下线或者新的机器上线的时候。TaaS在启动的时候,会选择3个节点作为调度器的角色,调度器负责调度这些<code>Fragment</code>,用来保证每个机器上的Fragment的数量以及Leader个数大致相等,同时还会保证每个Fragment的副本数维持在指定的副本个数。</p>
|
||||
<h5>Fragment副本创建</h5>
|
||||
<p><img src="/img/blog/taas_add.png" alt=""></p>
|
||||
<ol>
|
||||
<li>t0时间点,Fragment1在Seata-TC1机器上创建</li>
|
||||
<li>t1时间点,Fragment1的副本Fragment1'在Seata-TC2机器上创建</li>
|
||||
<li>t2时间点,Fragment1的副本Fragment1"在Seata-TC3机器上创建</li>
|
||||
</ol>
|
||||
<p>在t2时间点,Fragment1的三个副本创建完毕。</p>
|
||||
<h5>Fragment副本迁移</h5>
|
||||
<p><img src="/img/blog/taas_move.png" alt=""></p>
|
||||
<ol>
|
||||
<li>t0时刻点,系统一个存在4个Fragment,分别存在于Seata-TC1,Seata-TC2,Seata-TC3三台机器上</li>
|
||||
<li>t1时刻,加入新机器Seata-TC4</li>
|
||||
<li>t2时刻,有3个Fragment的副本被迁移到了Seata-TC4这台机器上</li>
|
||||
</ol>
|
||||
<h3>在线快速体验</h3>
|
||||
<p>我们在公网搭建了一个体验的环境:</p>
|
||||
<ul>
|
||||
<li>Seata服务端地址: 39.97.115.141:8091</li>
|
||||
<li>UI: <a href="http://39.97.115.141:8084/ui/index.html">http://39.97.115.141:8084/ui/index.html</a></li>
|
||||
</ul>
|
||||
<h3>本地快速体验</h3>
|
||||
<p>使用docker-compose快速体验TaaS的功能。</p>
|
||||
<pre><code class="language-bash">git <span class="hljs-built_in">clone</span> https://github.com/seata/taas.git
|
||||
docker-compse up -d
|
||||
</code></pre>
|
||||
<p>由于组件依赖较多,docker-compose启动30秒后,可以对外服务</p>
|
||||
<h4>Seata服务地址</h4>
|
||||
<p>服务默认监听在8091端口,修改Seata对应的服务端地址体验</p>
|
||||
<h4>Seata UI</h4>
|
||||
<p>访问WEB UI <code>http://127.0.0.1:8084/ui/index.html</code></p>
|
||||
<h3>关于InfiniVision</h3>
|
||||
<p>深见网络是一家技术驱动的企业级服务提供商,致力于利用人工智能、云计算、区块链、大数据,以及物联网边缘计算技术助力传统企业的数字化转型和升级。深见网络积极拥抱开源文化并将核心算法和架构开源,知名人脸识别软件 InsightFace (<a href="https://github.com/deepinsight/insightface">https://github.com/deepinsight/insightface</a>) (曾多次获得大规模人脸识别挑战冠军),以及分布式存储引擎 Elasticell (<a href="https://github.com/deepfabric/elasticell">https://github.com/deepfabric/elasticell</a>) 等均是深见网络的开源产品。</p>
|
||||
<h3>关于作者</h3>
|
||||
<p>作者张旭,开源网关Gateway (<a href="https://github.com/fagongzi/gateway">https://github.com/fagongzi/gateway</a>) 作者,目前就职于InfiniVision,负责基础架构相关的研发工作。</p>
|
||||
</section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>愿景</h3><p>Seata 是一款阿里巴巴开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。</p></div><div class="col col-6"><dl><dt>文档</dt><dd><a href="/zh-cn/docs/overview/what-is-seata.html" target="_self">Seata 是什么?</a></dd><dd><a href="/zh-cn/docs/user/quickstart.html" target="_self">快速开始</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">报告文档问题</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">在Github上编辑此文档</a></dd></dl></div><div class="col col-6"><dl><dt>资源</dt><dd><a href="/zh-cn/blog/index.html" target="_self">博客</a></dd><dd><a href="/zh-cn/community/index.html" target="_self">社区</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/blogDetail.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
|
@ -1,682 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="fescar、seata、分布式事务" />
|
||||
<meta name="description" content="seata-analysis-java-client" />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>分布式事务之Seata-Client原理及流程详解</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/blogDetail.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="blog-detail-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/zh-cn/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">En</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/zh-cn/index.html" target="_self">首页</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/docs/overview/what-is-seata.html" target="_self">文档</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/docs/developers/developers_dev.html" target="_self">开发者</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/zh-cn/blog/index.html" target="_self">博客</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/community/index.html" target="_self">社区</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/blog/download.html" target="_self">下载</a></li></ul></div></div></header><section class="blog-content markdown-body"><h2>前言</h2>
|
||||
<p>在分布式系统中,分布式事务是一个必须要解决的问题,目前使用较多的是最终一致性方案。自年初阿里开源了Fescar(四月初更名为Seata)后,该项目受到了极大的关注度,目前已接近8000Star。<a href="https://github.com/seata/seata">Seata</a>以高性能和零侵入的方式为目标解决微服务领域的分布式事务难题,目前正处于快速迭代中,近期小目标是生产可用的Mysql版本。关于Seata的总体介绍,可以查看<a href="https://github.com/seata/seata/wiki/%E6%A6%82%E8%A7%88">官方WIKI</a>获得更多更全面的内容介绍。</p>
|
||||
<p>本文主要基于spring cloud+spring jpa+spring cloud alibaba fescar+mysql+seata的结构,搭建一个分布式系统的demo,通过seata的debug日志和源代码,从client端(RM、TM)的角度分析说明其工作流程及原理。</p>
|
||||
<p>文中代码基于fescar-0.4.1,由于项目刚更名为seata不久,例如一些包名、类名、jar包名称还都是fescar的命名,故下文中仍使用fescar进行表述。</p>
|
||||
<p>示例项目:<a href="https://github.com/fescar-group/fescar-samples/tree/master/springcloud-jpa-seata">https://github.com/fescar-group/fescar-samples/tree/master/springcloud-jpa-seata</a></p>
|
||||
<h2>相关概念</h2>
|
||||
<ul>
|
||||
<li>XID:全局事务的唯一标识,由ip:port:sequence组成</li>
|
||||
<li>Transaction Coordinator (TC):事务协调器,维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚</li>
|
||||
<li>Transaction Manager (TM ):控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议</li>
|
||||
<li>Resource Manager (RM):控制分支事务,负责分支注册、状态汇报,并接收事务协调器的指令,驱动分支(本地)事务的提交和回滚</li>
|
||||
</ul>
|
||||
<h2>分布式框架支持</h2>
|
||||
<p>Fescar使用XID表示一个分布式事务,XID需要在一次分布式事务请求所涉的系统中进行传递,从而向feacar-server发送分支事务的处理情况,以及接收feacar-server的commit、rollback指令。
|
||||
Fescar官方已支持全版本的dubbo协议,而对于spring cloud(spring-boot)的分布式项目社区也提供了相应的实现</p>
|
||||
<pre><code class="language-xml"><span class="hljs-tag"><<span class="hljs-name">dependency</span>></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">groupId</span>></span>org.springframework.cloud<span class="hljs-tag"></<span class="hljs-name">groupId</span>></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>spring-cloud-alibaba-fescar<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">version</span>></span>2.1.0.BUILD-SNAPSHOT<span class="hljs-tag"></<span class="hljs-name">version</span>></span>
|
||||
<span class="hljs-tag"></<span class="hljs-name">dependency</span>></span>
|
||||
</code></pre>
|
||||
<p>该组件实现了基于RestTemplate、Feign通信时的XID传递功能。</p>
|
||||
<h2>业务逻辑</h2>
|
||||
<p>业务逻辑是经典的下订单、扣余额、减库存流程。
|
||||
根据模块划分为三个独立的服务,且分别连接对应的数据库</p>
|
||||
<ul>
|
||||
<li>订单:order-server</li>
|
||||
<li>账户:account-server</li>
|
||||
<li>库存:storage-server</li>
|
||||
</ul>
|
||||
<p>另外还有发起分布式事务的业务系统</p>
|
||||
<ul>
|
||||
<li>业务:business-server</li>
|
||||
</ul>
|
||||
<p>项目结构如下图
|
||||
<img src="/img/blog/20190410114411366.png" alt="在这里插入图片描述"></p>
|
||||
<p><strong>正常业务</strong></p>
|
||||
<ol>
|
||||
<li>business发起购买请求</li>
|
||||
<li>storage扣减库存</li>
|
||||
<li>order创建订单</li>
|
||||
<li>account扣减余额</li>
|
||||
</ol>
|
||||
<p><strong>异常业务</strong></p>
|
||||
<ol>
|
||||
<li>business发起购买请求</li>
|
||||
<li>storage扣减库存</li>
|
||||
<li>order创建订单</li>
|
||||
<li>account<code>扣减余额异常</code></li>
|
||||
</ol>
|
||||
<p>正常流程下2、3、4步的数据正常更新全局commit,异常流程下的数据则由于第4步的异常报错全局回滚。</p>
|
||||
<h2>配置文件</h2>
|
||||
<p>fescar的配置入口文件是<a href="https://github.com/seata/seata/blob/develop/config/src/main/resources/registry.conf">registry.conf</a>,查看代码<a href="https://github.com/seata/seata/blob/develop/config/src/main/java/com/alibaba/fescar/config/ConfigurationFactory.java">ConfigurationFactory</a>得知目前还不能指定该配置文件,所以配置文件名称只能为registry.conf</p>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> String REGISTRY_CONF = <span class="hljs-string">"registry.conf"</span>;
|
||||
<span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> Configuration FILE_INSTANCE = <span class="hljs-keyword">new</span> FileConfiguration(REGISTRY_CONF);
|
||||
</code></pre>
|
||||
<p>在<code>registry</code>中可以指定具体配置的形式,默认使用file类型,在file.conf中有3部分配置内容</p>
|
||||
<ol>
|
||||
<li>transport
|
||||
transport部分的配置对应<a href="https://github.com/seata/seata/blob/develop/core/src/main/java/com/alibaba/fescar/core/rpc/netty/NettyServerConfig.java">NettyServerConfig</a>类,用于定义Netty相关的参数,TM、RM与fescar-server之间使用Netty进行通信</li>
|
||||
<li>service</li>
|
||||
</ol>
|
||||
<pre><code class="language-js"> service {
|
||||
#vgroup->rgroup
|
||||
vgroup_mapping.my_test_tx_group = "default"
|
||||
#配置Client连接TC的地址
|
||||
default.grouplist = "127.0.0.1:8091"
|
||||
#degrade current not support
|
||||
enableDegrade = false
|
||||
#disable
|
||||
是否启用seata的分布式事务
|
||||
disableGlobalTransaction = false
|
||||
}
|
||||
</code></pre>
|
||||
<ol start="3">
|
||||
<li>client</li>
|
||||
</ol>
|
||||
<pre><code class="language-js"> client {
|
||||
#RM接收TC的commit通知后缓冲上限
|
||||
async.commit.buffer.limit = 10000
|
||||
lock {
|
||||
retry.internal = 10
|
||||
retry.times = 30
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<h2>数据源Proxy</h2>
|
||||
<p>除了前面的配置文件,fescar在AT模式下稍微有点代码量的地方就是对数据源的代理指定,且目前只能基于<code>DruidDataSource</code>的代理。
|
||||
注:在最新发布的0.4.2版本中已支持任意数据源类型</p>
|
||||
<pre><code class="language-java"><span class="hljs-meta">@Bean</span>
|
||||
<span class="hljs-meta">@ConfigurationProperties</span>(prefix = <span class="hljs-string">"spring.datasource"</span>)
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> DruidDataSource <span class="hljs-title">druidDataSource</span><span class="hljs-params">()</span> </span>{
|
||||
DruidDataSource druidDataSource = <span class="hljs-keyword">new</span> DruidDataSource();
|
||||
<span class="hljs-keyword">return</span> druidDataSource;
|
||||
}
|
||||
|
||||
<span class="hljs-meta">@Primary</span>
|
||||
<span class="hljs-meta">@Bean</span>(<span class="hljs-string">"dataSource"</span>)
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> DataSourceProxy <span class="hljs-title">dataSource</span><span class="hljs-params">(DruidDataSource druidDataSource)</span> </span>{
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> DataSourceProxy(druidDataSource);
|
||||
}
|
||||
</code></pre>
|
||||
<p>使用<code>DataSourceProxy</code>的目的是为了引入<code>ConnectionProxy</code>,fescar无侵入的一方面就体现在<code>ConnectionProxy</code>的实现上,即分支事务加入全局事务的切入点是在本地事务的<code>commit</code>阶段,这样设计可以保证业务数据与<code>undo_log</code>是在一个本地事务中。</p>
|
||||
<p><code>undo_log</code>是需要在业务库上创建的一个表,fescar依赖该表记录每笔分支事务的状态及二阶段<code>rollback</code>的回放数据。不用担心该表的数据量过大形成单点问题,在全局事务<code>commit</code>的场景下事务对应的<code>undo_log</code>会异步删除。</p>
|
||||
<pre><code class="language-sql"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TABLE</span> <span class="hljs-string">`undo_log`</span> (
|
||||
<span class="hljs-string">`id`</span> <span class="hljs-built_in">bigint</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span> AUTO_INCREMENT,
|
||||
<span class="hljs-string">`branch_id`</span> <span class="hljs-built_in">bigint</span>(<span class="hljs-number">20</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`xid`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`rollback_info`</span> longblob <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`log_status`</span> <span class="hljs-built_in">int</span>(<span class="hljs-number">11</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`log_created`</span> datetime <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`log_modified`</span> datetime <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
|
||||
<span class="hljs-string">`ext`</span> <span class="hljs-built_in">varchar</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">DEFAULT</span> <span class="hljs-literal">NULL</span>,
|
||||
PRIMARY <span class="hljs-keyword">KEY</span> (<span class="hljs-string">`id`</span>),
|
||||
<span class="hljs-keyword">UNIQUE</span> <span class="hljs-keyword">KEY</span> <span class="hljs-string">`ux_undo_log`</span> (<span class="hljs-string">`xid`</span>,<span class="hljs-string">`branch_id`</span>)
|
||||
) <span class="hljs-keyword">ENGINE</span>=<span class="hljs-keyword">InnoDB</span> AUTO_INCREMENT=<span class="hljs-number">1</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">CHARSET</span>=utf8;
|
||||
</code></pre>
|
||||
<h2>启动Server</h2>
|
||||
<p>前往<a href="https://github.com/seata/seata/releases">https://github.com/seata/seata/releases</a> 下载与Client版本对应的fescar-server,避免由于版本的不同导致的协议不一致问题
|
||||
进入解压之后的 bin 目录,执行</p>
|
||||
<pre><code class="language-shell">./fescar-server.sh 8091 ../data
|
||||
</code></pre>
|
||||
<p>启动成功输出</p>
|
||||
<pre><code class="language-shell">2019-04-09 20:27:24.637 INFO [main]c.a.fescar.core.rpc.netty.AbstractRpcRemotingServer.start:152 -Server started ...
|
||||
</code></pre>
|
||||
<h2>启动Client</h2>
|
||||
<p>fescar的加载入口类位于<a href="https://github.com/spring-cloud-incubator/spring-cloud-alibaba/blob/finchley/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/GlobalTransactionAutoConfiguration.java">GlobalTransactionAutoConfiguration</a>,对基于spring boot的项目能够自动加载,当然也可以通过其他方式示例化<code>GlobalTransactionScanner</code></p>
|
||||
<pre><code class="language-java"><span class="hljs-meta">@Configuration</span>
|
||||
<span class="hljs-meta">@EnableConfigurationProperties</span>({FescarProperties<span class="hljs-class">.<span class="hljs-keyword">class</span>})
|
||||
<span class="hljs-title">public</span> <span class="hljs-title">class</span> <span class="hljs-title">GlobalTransactionAutoConfiguration</span> </span>{
|
||||
<span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> ApplicationContext applicationContext;
|
||||
<span class="hljs-keyword">private</span> <span class="hljs-keyword">final</span> FescarProperties fescarProperties;
|
||||
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">GlobalTransactionAutoConfiguration</span><span class="hljs-params">(ApplicationContext applicationContext, FescarProperties fescarProperties)</span> </span>{
|
||||
<span class="hljs-keyword">this</span>.applicationContext = applicationContext;
|
||||
<span class="hljs-keyword">this</span>.fescarProperties = fescarProperties;
|
||||
}
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* 示例化GlobalTransactionScanner
|
||||
* scanner为client初始化的发起类
|
||||
*/</span>
|
||||
<span class="hljs-meta">@Bean</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> GlobalTransactionScanner <span class="hljs-title">globalTransactionScanner</span><span class="hljs-params">()</span> </span>{
|
||||
String applicationName = <span class="hljs-keyword">this</span>.applicationContext.getEnvironment().getProperty(<span class="hljs-string">"spring.application.name"</span>);
|
||||
String txServiceGroup = <span class="hljs-keyword">this</span>.fescarProperties.getTxServiceGroup();
|
||||
<span class="hljs-keyword">if</span> (StringUtils.isEmpty(txServiceGroup)) {
|
||||
txServiceGroup = applicationName + <span class="hljs-string">"-fescar-service-group"</span>;
|
||||
<span class="hljs-keyword">this</span>.fescarProperties.setTxServiceGroup(txServiceGroup);
|
||||
}
|
||||
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> GlobalTransactionScanner(applicationName, txServiceGroup);
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<p>可以看到支持一个配置项FescarProperties,用于配置事务分组名称</p>
|
||||
<pre><code class="language-json">spring.cloud.alibaba.fescar.tx-service-group=my_test_tx_group
|
||||
</code></pre>
|
||||
<p>如果不指定服务组,则默认使用spring.application.name+ -fescar-service-group生成名称,所以不指定spring.application.name启动会报错</p>
|
||||
<pre><code class="language-java"><span class="hljs-meta">@ConfigurationProperties</span>(<span class="hljs-string">"spring.cloud.alibaba.fescar"</span>)
|
||||
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">FescarProperties</span> </span>{
|
||||
<span class="hljs-keyword">private</span> String txServiceGroup;
|
||||
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-title">FescarProperties</span><span class="hljs-params">()</span> </span>{
|
||||
}
|
||||
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">getTxServiceGroup</span><span class="hljs-params">()</span> </span>{
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-keyword">this</span>.txServiceGroup;
|
||||
}
|
||||
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">setTxServiceGroup</span><span class="hljs-params">(String txServiceGroup)</span> </span>{
|
||||
<span class="hljs-keyword">this</span>.txServiceGroup = txServiceGroup;
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<p>获取applicationId和txServiceGroup后,创建<a href="https://github.com/seata/seata/blob/develop/spring/src/main/java/com/alibaba/fescar/spring/annotation/GlobalTransactionScanner.java">GlobalTransactionScanner</a>对象,主要看类中initClient方法</p>
|
||||
<pre><code class="language-java"><span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">initClient</span><span class="hljs-params">()</span> </span>{
|
||||
<span class="hljs-keyword">if</span> (StringUtils.isNullOrEmpty(applicationId) || StringUtils.isNullOrEmpty(txServiceGroup)) {
|
||||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalArgumentException(
|
||||
<span class="hljs-string">"applicationId: "</span> + applicationId + <span class="hljs-string">", txServiceGroup: "</span> + txServiceGroup);
|
||||
}
|
||||
<span class="hljs-comment">//init TM</span>
|
||||
TMClient.init(applicationId, txServiceGroup);
|
||||
|
||||
<span class="hljs-comment">//init RM</span>
|
||||
RMClient.init(applicationId, txServiceGroup);
|
||||
|
||||
}
|
||||
</code></pre>
|
||||
<p>方法中可以看到初始化了<code>TMClient</code>和<code>RMClient</code>,对于一个服务既可以是TM角色也可以是RM角色,至于什么时候是TM或者RM则要看在一次全局事务中<code>@GlobalTransactional</code>注解标注在哪。
|
||||
Client创建的结果是与TC的一个Netty连接,所以在启动日志中可以看到两个Netty Channel,其中标明了transactionRole分别为<code>TMROLE</code>和<code>RMROLE</code></p>
|
||||
<pre><code class="language-java"><span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">13</span>:<span class="hljs-number">42</span>:<span class="hljs-number">57.417</span> INFO <span class="hljs-number">93715</span> --- [imeoutChecker_1] c.a.f.c.rpc.netty.NettyPoolableFactory : NettyPool create channel to {<span class="hljs-string">"address"</span>:<span class="hljs-string">"127.0.0.1:8091"</span>,<span class="hljs-string">"message"</span>:{<span class="hljs-string">"applicationId"</span>:<span class="hljs-string">"business-service"</span>,<span class="hljs-string">"byteBuffer"</span>:{<span class="hljs-string">"char"</span>:<span class="hljs-string">"\u0000"</span>,<span class="hljs-string">"direct"</span>:<span class="hljs-keyword">false</span>,<span class="hljs-string">"double"</span>:<span class="hljs-number">0.0</span>,<span class="hljs-string">"float"</span>:<span class="hljs-number">0.0</span>,<span class="hljs-string">"int"</span>:<span class="hljs-number">0</span>,<span class="hljs-string">"long"</span>:<span class="hljs-number">0</span>,<span class="hljs-string">"readOnly"</span>:<span class="hljs-keyword">false</span>,<span class="hljs-string">"short"</span>:<span class="hljs-number">0</span>},<span class="hljs-string">"transactionServiceGroup"</span>:<span class="hljs-string">"my_test_tx_group"</span>,<span class="hljs-string">"typeCode"</span>:<span class="hljs-number">101</span>,<span class="hljs-string">"version"</span>:<span class="hljs-string">"0.4.1"</span>},<span class="hljs-string">"transactionRole"</span>:<span class="hljs-string">"TMROLE"</span>}
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">13</span>:<span class="hljs-number">42</span>:<span class="hljs-number">57.505</span> INFO <span class="hljs-number">93715</span> --- [imeoutChecker_1] c.a.f.c.rpc.netty.NettyPoolableFactory : NettyPool create channel to {<span class="hljs-string">"address"</span>:<span class="hljs-string">"127.0.0.1:8091"</span>,<span class="hljs-string">"message"</span>:{<span class="hljs-string">"applicationId"</span>:<span class="hljs-string">"business-service"</span>,<span class="hljs-string">"byteBuffer"</span>:{<span class="hljs-string">"char"</span>:<span class="hljs-string">"\u0000"</span>,<span class="hljs-string">"direct"</span>:<span class="hljs-keyword">false</span>,<span class="hljs-string">"double"</span>:<span class="hljs-number">0.0</span>,<span class="hljs-string">"float"</span>:<span class="hljs-number">0.0</span>,<span class="hljs-string">"int"</span>:<span class="hljs-number">0</span>,<span class="hljs-string">"long"</span>:<span class="hljs-number">0</span>,<span class="hljs-string">"readOnly"</span>:<span class="hljs-keyword">false</span>,<span class="hljs-string">"short"</span>:<span class="hljs-number">0</span>},<span class="hljs-string">"transactionServiceGroup"</span>:<span class="hljs-string">"my_test_tx_group"</span>,<span class="hljs-string">"typeCode"</span>:<span class="hljs-number">103</span>,<span class="hljs-string">"version"</span>:<span class="hljs-string">"0.4.1"</span>},<span class="hljs-string">"transactionRole"</span>:<span class="hljs-string">"RMROLE"</span>}
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">13</span>:<span class="hljs-number">42</span>:<span class="hljs-number">57.629</span> DEBUG <span class="hljs-number">93715</span> --- [lector_TMROLE_1] c.a.f.c.rpc.netty.MessageCodecHandler : Send:RegisterTMRequest{applicationId=<span class="hljs-string">'business-service'</span>, transactionServiceGroup=<span class="hljs-string">'my_test_tx_group'</span>}
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">13</span>:<span class="hljs-number">42</span>:<span class="hljs-number">57.629</span> DEBUG <span class="hljs-number">93715</span> --- [lector_RMROLE_1] c.a.f.c.rpc.netty.MessageCodecHandler : Send:RegisterRMRequest{resourceIds=<span class="hljs-string">'null'</span>, applicationId=<span class="hljs-string">'business-service'</span>, transactionServiceGroup=<span class="hljs-string">'my_test_tx_group'</span>}
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">13</span>:<span class="hljs-number">42</span>:<span class="hljs-number">57.699</span> DEBUG <span class="hljs-number">93715</span> --- [lector_RMROLE_1] c.a.f.c.rpc.netty.MessageCodecHandler : Receive:version=<span class="hljs-number">0.4</span><span class="hljs-number">.1</span>,extraData=<span class="hljs-keyword">null</span>,identified=<span class="hljs-keyword">true</span>,resultCode=<span class="hljs-keyword">null</span>,msg=<span class="hljs-keyword">null</span>,messageId:<span class="hljs-number">1</span>
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">13</span>:<span class="hljs-number">42</span>:<span class="hljs-number">57.699</span> DEBUG <span class="hljs-number">93715</span> --- [lector_TMROLE_1] c.a.f.c.rpc.netty.MessageCodecHandler : Receive:version=<span class="hljs-number">0.4</span><span class="hljs-number">.1</span>,extraData=<span class="hljs-keyword">null</span>,identified=<span class="hljs-keyword">true</span>,resultCode=<span class="hljs-keyword">null</span>,msg=<span class="hljs-keyword">null</span>,messageId:<span class="hljs-number">2</span>
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">13</span>:<span class="hljs-number">42</span>:<span class="hljs-number">57.701</span> DEBUG <span class="hljs-number">93715</span> --- [lector_RMROLE_1] c.a.f.c.rpc.netty.AbstractRpcRemoting : com.alibaba.fescar.core.rpc.netty.RmRpcClient@<span class="hljs-number">3</span>b06d101 msgId:<span class="hljs-number">1</span>, future :com.alibaba.fescar.core.protocol.MessageFuture@<span class="hljs-number">28</span>bb1abd, body:version=<span class="hljs-number">0.4</span><span class="hljs-number">.1</span>,extraData=<span class="hljs-keyword">null</span>,identified=<span class="hljs-keyword">true</span>,resultCode=<span class="hljs-keyword">null</span>,msg=<span class="hljs-keyword">null</span>
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">13</span>:<span class="hljs-number">42</span>:<span class="hljs-number">57.701</span> DEBUG <span class="hljs-number">93715</span> --- [lector_TMROLE_1] c.a.f.c.rpc.netty.AbstractRpcRemoting : com.alibaba.fescar.core.rpc.netty.TmRpcClient@<span class="hljs-number">65f</span>c3fb7 msgId:<span class="hljs-number">2</span>, future :com.alibaba.fescar.core.protocol.MessageFuture@<span class="hljs-number">9</span>a1e3df, body:version=<span class="hljs-number">0.4</span><span class="hljs-number">.1</span>,extraData=<span class="hljs-keyword">null</span>,identified=<span class="hljs-keyword">true</span>,resultCode=<span class="hljs-keyword">null</span>,msg=<span class="hljs-keyword">null</span>
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">13</span>:<span class="hljs-number">42</span>:<span class="hljs-number">57.710</span> INFO <span class="hljs-number">93715</span> --- [imeoutChecker_1] c.a.fescar.core.rpc.netty.RmRpcClient : register RM success. server version:<span class="hljs-number">0.4</span><span class="hljs-number">.1</span>,channel:[id: <span class="hljs-number">0xe6468995</span>, L:/<span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>:<span class="hljs-number">57397</span> - R:/<span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>:<span class="hljs-number">8091</span>]
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">13</span>:<span class="hljs-number">42</span>:<span class="hljs-number">57.710</span> INFO <span class="hljs-number">93715</span> --- [imeoutChecker_1] c.a.f.c.rpc.netty.NettyPoolableFactory : register success, cost <span class="hljs-number">114</span> ms, version:<span class="hljs-number">0.4</span><span class="hljs-number">.1</span>,role:TMROLE,channel:[id: <span class="hljs-number">0xd22fe0c5</span>, L:/<span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>:<span class="hljs-number">57398</span> - R:/<span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>:<span class="hljs-number">8091</span>]
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">13</span>:<span class="hljs-number">42</span>:<span class="hljs-number">57.711</span> INFO <span class="hljs-number">93715</span> --- [imeoutChecker_1] c.a.f.c.rpc.netty.NettyPoolableFactory : register success, cost <span class="hljs-number">125</span> ms, version:<span class="hljs-number">0.4</span><span class="hljs-number">.1</span>,role:RMROLE,channel:[id: <span class="hljs-number">0xe6468995</span>, L:/<span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>:<span class="hljs-number">57397</span> - R:/<span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>:<span class="hljs-number">8091</span>]
|
||||
|
||||
</code></pre>
|
||||
<p>日志中可以看到</p>
|
||||
<ol>
|
||||
<li>创建Netty连接</li>
|
||||
<li>发送注册请求</li>
|
||||
<li>得到响应结果</li>
|
||||
<li><code>RmRpcClient</code>、<code>TmRpcClient</code>成功实例化</li>
|
||||
</ol>
|
||||
<h2>TM处理流程</h2>
|
||||
<p>在本例中,TM的角色是business-service,BusinessService的purchase方法标注了<code>@GlobalTransactional</code>注解</p>
|
||||
<pre><code class="language-java"><span class="hljs-meta">@Service</span>
|
||||
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">BusinessService</span> </span>{
|
||||
|
||||
<span class="hljs-meta">@Autowired</span>
|
||||
<span class="hljs-keyword">private</span> StorageFeignClient storageFeignClient;
|
||||
<span class="hljs-meta">@Autowired</span>
|
||||
<span class="hljs-keyword">private</span> OrderFeignClient orderFeignClient;
|
||||
|
||||
<span class="hljs-meta">@GlobalTransactional</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">purchase</span><span class="hljs-params">(String userId, String commodityCode, <span class="hljs-keyword">int</span> orderCount)</span></span>{
|
||||
storageFeignClient.deduct(commodityCode, orderCount);
|
||||
|
||||
orderFeignClient.create(userId, commodityCode, orderCount);
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<p>方法调用后将会创建一个全局事务,首先关注<code>@GlobalTransactional</code>注解的作用,在<a href="https://github.com/seata/seata/blob/develop/spring/src/main/java/com/alibaba/fescar/spring/annotation/GlobalTransactionalInterceptor.java">GlobalTransactionalInterceptor</a>中被拦截处理</p>
|
||||
<pre><code class="language-java"><span class="hljs-comment">/**
|
||||
* AOP拦截方法调用
|
||||
*/</span>
|
||||
<span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> Object <span class="hljs-title">invoke</span><span class="hljs-params">(<span class="hljs-keyword">final</span> MethodInvocation methodInvocation)</span> <span class="hljs-keyword">throws</span> Throwable </span>{
|
||||
Class<?> targetClass = (methodInvocation.getThis() != <span class="hljs-keyword">null</span> ? AopUtils.getTargetClass(methodInvocation.getThis()) : <span class="hljs-keyword">null</span>);
|
||||
Method specificMethod = ClassUtils.getMostSpecificMethod(methodInvocation.getMethod(), targetClass);
|
||||
<span class="hljs-keyword">final</span> Method method = BridgeMethodResolver.findBridgedMethod(specificMethod);
|
||||
|
||||
<span class="hljs-comment">//获取方法GlobalTransactional注解</span>
|
||||
<span class="hljs-keyword">final</span> GlobalTransactional globalTransactionalAnnotation = getAnnotation(method, GlobalTransactional<span class="hljs-class">.<span class="hljs-keyword">class</span>)</span>;
|
||||
<span class="hljs-keyword">final</span> GlobalLock globalLockAnnotation = getAnnotation(method, GlobalLock<span class="hljs-class">.<span class="hljs-keyword">class</span>)</span>;
|
||||
|
||||
<span class="hljs-comment">//如果方法有GlobalTransactional注解,则拦截到相应方法处理</span>
|
||||
<span class="hljs-keyword">if</span> (globalTransactionalAnnotation != <span class="hljs-keyword">null</span>) {
|
||||
<span class="hljs-keyword">return</span> handleGlobalTransaction(methodInvocation, globalTransactionalAnnotation);
|
||||
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (globalLockAnnotation != <span class="hljs-keyword">null</span>) {
|
||||
<span class="hljs-keyword">return</span> handleGlobalLock(methodInvocation);
|
||||
} <span class="hljs-keyword">else</span> {
|
||||
<span class="hljs-keyword">return</span> methodInvocation.proceed();
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<p><code>handleGlobalTransaction</code>方法中对<a href="https://github.com/seata/seata/blob/develop/tm/src/main/java/com/alibaba/fescar/tm/api/TransactionalTemplate.java">TransactionalTemplate</a>的execute进行了调用,从类名可以看到这是一个标准的模版方法,它定义了TM对全局事务处理的标准步骤,注释已经比较清楚了</p>
|
||||
<pre><code class="language-java"><span class="hljs-function"><span class="hljs-keyword">public</span> Object <span class="hljs-title">execute</span><span class="hljs-params">(TransactionalExecutor business)</span> <span class="hljs-keyword">throws</span> TransactionalExecutor.ExecutionException </span>{
|
||||
<span class="hljs-comment">// 1. get or create a transaction</span>
|
||||
GlobalTransaction tx = GlobalTransactionContext.getCurrentOrCreate();
|
||||
|
||||
<span class="hljs-keyword">try</span> {
|
||||
<span class="hljs-comment">// 2. begin transaction</span>
|
||||
<span class="hljs-keyword">try</span> {
|
||||
triggerBeforeBegin();
|
||||
tx.begin(business.timeout(), business.name());
|
||||
triggerAfterBegin();
|
||||
} <span class="hljs-keyword">catch</span> (TransactionException txe) {
|
||||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> TransactionalExecutor.ExecutionException(tx, txe,
|
||||
TransactionalExecutor.Code.BeginFailure);
|
||||
}
|
||||
Object rs = <span class="hljs-keyword">null</span>;
|
||||
<span class="hljs-keyword">try</span> {
|
||||
<span class="hljs-comment">// Do Your Business</span>
|
||||
rs = business.execute();
|
||||
} <span class="hljs-keyword">catch</span> (Throwable ex) {
|
||||
<span class="hljs-comment">// 3. any business exception, rollback.</span>
|
||||
<span class="hljs-keyword">try</span> {
|
||||
triggerBeforeRollback();
|
||||
tx.rollback();
|
||||
triggerAfterRollback();
|
||||
<span class="hljs-comment">// 3.1 Successfully rolled back</span>
|
||||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> TransactionalExecutor.ExecutionException(tx, TransactionalExecutor.Code.RollbackDone, ex);
|
||||
} <span class="hljs-keyword">catch</span> (TransactionException txe) {
|
||||
<span class="hljs-comment">// 3.2 Failed to rollback</span>
|
||||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> TransactionalExecutor.ExecutionException(tx, txe,
|
||||
TransactionalExecutor.Code.RollbackFailure, ex);
|
||||
}
|
||||
}
|
||||
<span class="hljs-comment">// 4. everything is fine, commit.</span>
|
||||
<span class="hljs-keyword">try</span> {
|
||||
triggerBeforeCommit();
|
||||
tx.commit();
|
||||
triggerAfterCommit();
|
||||
} <span class="hljs-keyword">catch</span> (TransactionException txe) {
|
||||
<span class="hljs-comment">// 4.1 Failed to commit</span>
|
||||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> TransactionalExecutor.ExecutionException(tx, txe,
|
||||
TransactionalExecutor.Code.CommitFailure);
|
||||
}
|
||||
<span class="hljs-keyword">return</span> rs;
|
||||
} <span class="hljs-keyword">finally</span> {
|
||||
<span class="hljs-comment">//5. clear</span>
|
||||
triggerAfterCompletion();
|
||||
cleanUp();
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<p>通过<a href="https://github.com/seata/seata/blob/develop/tm/src/main/java/com/alibaba/fescar/tm/api/DefaultGlobalTransaction.java">DefaultGlobalTransaction</a>的begin方法开启全局事务</p>
|
||||
<pre><code class="language-java"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">begin</span><span class="hljs-params">(<span class="hljs-keyword">int</span> timeout, String name)</span> <span class="hljs-keyword">throws</span> TransactionException </span>{
|
||||
<span class="hljs-keyword">if</span> (role != GlobalTransactionRole.Launcher) {
|
||||
check();
|
||||
<span class="hljs-keyword">if</span> (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(<span class="hljs-string">"Ignore Begin(): just involved in global transaction ["</span> + xid + <span class="hljs-string">"]"</span>);
|
||||
}
|
||||
<span class="hljs-keyword">return</span>;
|
||||
}
|
||||
<span class="hljs-keyword">if</span> (xid != <span class="hljs-keyword">null</span>) {
|
||||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalStateException();
|
||||
}
|
||||
<span class="hljs-keyword">if</span> (RootContext.getXID() != <span class="hljs-keyword">null</span>) {
|
||||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalStateException();
|
||||
}
|
||||
<span class="hljs-comment">//具体开启事务的方法,获取TC返回的XID</span>
|
||||
xid = transactionManager.begin(<span class="hljs-keyword">null</span>, <span class="hljs-keyword">null</span>, name, timeout);
|
||||
status = GlobalStatus.Begin;
|
||||
RootContext.bind(xid);
|
||||
<span class="hljs-keyword">if</span> (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(<span class="hljs-string">"Begin a NEW global transaction ["</span> + xid + <span class="hljs-string">"]"</span>);
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<p>方法开头处<code>if (role != GlobalTransactionRole.Launcher)</code>对role的判断有关键的作用,表明当前是全局事务的发起者(Launcher)还是参与者(Participant)。如果在分布式事务的下游系统方法中也加上<code>@GlobalTransactional</code>注解,那么它的角色就是Participant,会忽略后面的begin直接return,而判断是Launcher还是Participant是根据当前上下文是否已存在XID来判断,没有XID的就是Launcher,已经存在XID的就是Participant.
|
||||
由此可见,全局事务的创建只能由Launcher执行,而一次分布式事务中也只有一个Launcher存在。</p>
|
||||
<p><a href="https://github.com/seata/seata/blob/develop/tm/src/main/java/com/alibaba/fescar/tm/DefaultTransactionManager.java">DefaultTransactionManager</a>负责TM与TC通讯,发送begin、commit、rollback指令</p>
|
||||
<pre><code class="language-java"><span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> String <span class="hljs-title">begin</span><span class="hljs-params">(String applicationId, String transactionServiceGroup, String name, <span class="hljs-keyword">int</span> timeout)</span>
|
||||
<span class="hljs-keyword">throws</span> TransactionException </span>{
|
||||
GlobalBeginRequest request = <span class="hljs-keyword">new</span> GlobalBeginRequest();
|
||||
request.setTransactionName(name);
|
||||
request.setTimeout(timeout);
|
||||
GlobalBeginResponse response = (GlobalBeginResponse)syncCall(request);
|
||||
<span class="hljs-keyword">return</span> response.getXid();
|
||||
}
|
||||
</code></pre>
|
||||
<p>至此拿到fescar-server返回的XID表示一个全局事务创建成功,日志中也反应了上述流程</p>
|
||||
<pre><code class="language-java"><span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">13</span>:<span class="hljs-number">46</span>:<span class="hljs-number">57.417</span> DEBUG <span class="hljs-number">31326</span> --- [nio-<span class="hljs-number">8084</span>-exec-<span class="hljs-number">1</span>] c.a.f.c.rpc.netty.AbstractRpcRemoting : offer message: timeout=<span class="hljs-number">60000</span>,transactionName=purchase(java.lang.String,java.lang.String,<span class="hljs-keyword">int</span>)
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">13</span>:<span class="hljs-number">46</span>:<span class="hljs-number">57.417</span> DEBUG <span class="hljs-number">31326</span> --- [geSend_TMROLE_1] c.a.f.c.rpc.netty.AbstractRpcRemoting : write message:FescarMergeMessage timeout=<span class="hljs-number">60000</span>,transactionName=purchase(java.lang.String,java.lang.String,<span class="hljs-keyword">int</span>), channel:[id: <span class="hljs-number">0xa148545e</span>, L:/<span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>:<span class="hljs-number">56120</span> - R:/<span class="hljs-number">127.0</span><span class="hljs-number">.0</span><span class="hljs-number">.1</span>:<span class="hljs-number">8091</span>],active?<span class="hljs-keyword">true</span>,writable?<span class="hljs-keyword">true</span>,isopen?<span class="hljs-keyword">true</span>
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">13</span>:<span class="hljs-number">46</span>:<span class="hljs-number">57.418</span> DEBUG <span class="hljs-number">31326</span> --- [lector_TMROLE_1] c.a.f.c.rpc.netty.MessageCodecHandler : Send:FescarMergeMessage timeout=<span class="hljs-number">60000</span>,transactionName=purchase(java.lang.String,java.lang.String,<span class="hljs-keyword">int</span>)
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">13</span>:<span class="hljs-number">46</span>:<span class="hljs-number">57.421</span> DEBUG <span class="hljs-number">31326</span> --- [lector_TMROLE_1] c.a.f.c.rpc.netty.MessageCodecHandler : Receive:MergeResultMessage com.alibaba.fescar.core.protocol.transaction.GlobalBeginResponse@<span class="hljs-number">2</span>dc480dc,messageId:<span class="hljs-number">1196</span>
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">13</span>:<span class="hljs-number">46</span>:<span class="hljs-number">57.421</span> DEBUG <span class="hljs-number">31326</span> --- [nio-<span class="hljs-number">8084</span>-exec-<span class="hljs-number">1</span>] c.a.fescar.core.context.RootContext : bind <span class="hljs-number">192.168</span><span class="hljs-number">.224</span><span class="hljs-number">.93</span>:<span class="hljs-number">8091</span>:<span class="hljs-number">2008502699</span>
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">13</span>:<span class="hljs-number">46</span>:<span class="hljs-number">57.421</span> DEBUG <span class="hljs-number">31326</span> --- [nio-<span class="hljs-number">8084</span>-exec-<span class="hljs-number">1</span>] c.a.f.tm.api.DefaultGlobalTransaction : Begin a NEW global transaction [<span class="hljs-number">192.168</span><span class="hljs-number">.224</span><span class="hljs-number">.93</span>:<span class="hljs-number">8091</span>:<span class="hljs-number">2008502699</span>]
|
||||
</code></pre>
|
||||
<p>全局事务创建后,就开始执行business.execute(),即业务代码<code>storageFeignClient.deduct(commodityCode, orderCount)</code>进入RM处理流程,此处的业务逻辑为调用storage-service的扣减库存接口。</p>
|
||||
<h2>RM处理流程</h2>
|
||||
<pre><code class="language-java"><span class="hljs-meta">@GetMapping</span>(path = <span class="hljs-string">"/deduct"</span>)
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> Boolean <span class="hljs-title">deduct</span><span class="hljs-params">(String commodityCode, Integer count)</span></span>{
|
||||
storageService.deduct(commodityCode,count);
|
||||
<span class="hljs-keyword">return</span> <span class="hljs-keyword">true</span>;
|
||||
}
|
||||
|
||||
<span class="hljs-meta">@Transactional</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">deduct</span><span class="hljs-params">(String commodityCode, <span class="hljs-keyword">int</span> count)</span></span>{
|
||||
Storage storage = storageDAO.findByCommodityCode(commodityCode);
|
||||
storage.setCount(storage.getCount()-count);
|
||||
|
||||
storageDAO.save(storage);
|
||||
}
|
||||
</code></pre>
|
||||
<p>storage的接口和service方法并未出现fescar相关的代码和注解,体现了fescar的无侵入。那它是如何加入到这次全局事务中的呢?答案在<a href="https://github.com/seata/seata/blob/develop/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/ConnectionProxy.java">ConnectionProxy</a>中,这也是前面说为什么必须要使用<code>DataSourceProxy</code>的原因,通过DataSourceProxy才能在业务代码的本地事务提交时,fescar通过该切入点,向TC注册分支事务并发送RM的处理结果。</p>
|
||||
<p>由于业务代码本身的事务提交被<code>ConnectionProxy</code>代理实现,所以在提交本地事务时,实际执行的是ConnectionProxy的commit方法</p>
|
||||
<pre><code class="language-java"><span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">commit</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> SQLException </span>{
|
||||
<span class="hljs-comment">//如果当前是全局事务,则执行全局事务的提交</span>
|
||||
<span class="hljs-comment">//判断是不是全局事务,就是看当前上下文是否存在XID</span>
|
||||
<span class="hljs-keyword">if</span> (context.inGlobalTransaction()) {
|
||||
processGlobalTransactionCommit();
|
||||
} <span class="hljs-keyword">else</span> <span class="hljs-keyword">if</span> (context.isGlobalLockRequire()) {
|
||||
processLocalCommitWithGlobalLocks();
|
||||
} <span class="hljs-keyword">else</span> {
|
||||
targetConnection.commit();
|
||||
}
|
||||
}
|
||||
|
||||
<span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">processGlobalTransactionCommit</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> SQLException </span>{
|
||||
<span class="hljs-keyword">try</span> {
|
||||
<span class="hljs-comment">//首先是向TC注册RM,拿到TC分配的branchId</span>
|
||||
register();
|
||||
} <span class="hljs-keyword">catch</span> (TransactionException e) {
|
||||
recognizeLockKeyConflictException(e);
|
||||
}
|
||||
|
||||
<span class="hljs-keyword">try</span> {
|
||||
<span class="hljs-keyword">if</span> (context.hasUndoLog()) {
|
||||
<span class="hljs-comment">//写入undolog</span>
|
||||
UndoLogManager.flushUndoLogs(<span class="hljs-keyword">this</span>);
|
||||
}
|
||||
|
||||
<span class="hljs-comment">//提交本地事务,写入undo_log和业务数据在同一个本地事务中</span>
|
||||
targetConnection.commit();
|
||||
} <span class="hljs-keyword">catch</span> (Throwable ex) {
|
||||
<span class="hljs-comment">//向TC发送RM的事务处理失败的通知</span>
|
||||
report(<span class="hljs-keyword">false</span>);
|
||||
<span class="hljs-keyword">if</span> (ex <span class="hljs-keyword">instanceof</span> SQLException) {
|
||||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> SQLException(ex);
|
||||
}
|
||||
}
|
||||
<span class="hljs-comment">//向TC发送RM的事务处理成功的通知</span>
|
||||
report(<span class="hljs-keyword">true</span>);
|
||||
context.reset();
|
||||
}
|
||||
|
||||
<span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">register</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> TransactionException </span>{
|
||||
<span class="hljs-comment">//注册RM,构建request通过netty向TC发送注册指令</span>
|
||||
Long branchId = DefaultResourceManager.get().branchRegister(BranchType.AT, getDataSourceProxy().getResourceId(),
|
||||
<span class="hljs-keyword">null</span>, context.getXid(), <span class="hljs-keyword">null</span>, context.buildLockKeys());
|
||||
<span class="hljs-comment">//将返回的branchId存在上下文中</span>
|
||||
context.setBranchId(branchId);
|
||||
}
|
||||
</code></pre>
|
||||
<p>通过日志印证一下上面的流程</p>
|
||||
<pre><code class="language-java"><span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">48.341</span> DEBUG <span class="hljs-number">38933</span> --- [nio-<span class="hljs-number">8081</span>-exec-<span class="hljs-number">1</span>] o.s.c.a.f.web.FescarHandlerInterceptor : xid in RootContext <span class="hljs-keyword">null</span> xid in RpcContext <span class="hljs-number">192.168</span><span class="hljs-number">.0</span><span class="hljs-number">.2</span>:<span class="hljs-number">8091</span>:<span class="hljs-number">2008546211</span>
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">48.341</span> DEBUG <span class="hljs-number">38933</span> --- [nio-<span class="hljs-number">8081</span>-exec-<span class="hljs-number">1</span>] c.a.fescar.core.context.RootContext : bind <span class="hljs-number">192.168</span><span class="hljs-number">.0</span><span class="hljs-number">.2</span>:<span class="hljs-number">8091</span>:<span class="hljs-number">2008546211</span>
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">48.341</span> DEBUG <span class="hljs-number">38933</span> --- [nio-<span class="hljs-number">8081</span>-exec-<span class="hljs-number">1</span>] o.s.c.a.f.web.FescarHandlerInterceptor : bind <span class="hljs-number">192.168</span><span class="hljs-number">.0</span><span class="hljs-number">.2</span>:<span class="hljs-number">8091</span>:<span class="hljs-number">2008546211</span> to RootContext
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">48.386</span> INFO <span class="hljs-number">38933</span> --- [nio-<span class="hljs-number">8081</span>-exec-<span class="hljs-number">1</span>] o.h.h.i.QueryTranslatorFactoryInitiator : HHH000397: Using ASTQueryTranslatorFactory
|
||||
Hibernate: select storage0_.id as id1_0_, storage0_.commodity_code as commodit2_0_, storage0_.count as count3_0_ from storage_tbl storage0_ where storage0_.commodity_code=?
|
||||
Hibernate: update storage_tbl set count=? where id=?
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">48.673</span> INFO <span class="hljs-number">38933</span> --- [nio-<span class="hljs-number">8081</span>-exec-<span class="hljs-number">1</span>] c.a.fescar.core.rpc.netty.RmRpcClient : will connect to <span class="hljs-number">192.168</span><span class="hljs-number">.0</span><span class="hljs-number">.2</span>:<span class="hljs-number">8091</span>
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">48.673</span> INFO <span class="hljs-number">38933</span> --- [nio-<span class="hljs-number">8081</span>-exec-<span class="hljs-number">1</span>] c.a.fescar.core.rpc.netty.RmRpcClient : RM will register :jdbc:mysql:<span class="hljs-comment">//127.0.0.1:3306/db_storage?useSSL=false</span>
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">48.673</span> INFO <span class="hljs-number">38933</span> --- [nio-<span class="hljs-number">8081</span>-exec-<span class="hljs-number">1</span>] c.a.f.c.rpc.netty.NettyPoolableFactory : NettyPool create channel to {<span class="hljs-string">"address"</span>:<span class="hljs-string">"192.168.0.2:8091"</span>,<span class="hljs-string">"message"</span>:{<span class="hljs-string">"applicationId"</span>:<span class="hljs-string">"storage-service"</span>,<span class="hljs-string">"byteBuffer"</span>:{<span class="hljs-string">"char"</span>:<span class="hljs-string">"\u0000"</span>,<span class="hljs-string">"direct"</span>:<span class="hljs-keyword">false</span>,<span class="hljs-string">"double"</span>:<span class="hljs-number">0.0</span>,<span class="hljs-string">"float"</span>:<span class="hljs-number">0.0</span>,<span class="hljs-string">"int"</span>:<span class="hljs-number">0</span>,<span class="hljs-string">"long"</span>:<span class="hljs-number">0</span>,<span class="hljs-string">"readOnly"</span>:<span class="hljs-keyword">false</span>,<span class="hljs-string">"short"</span>:<span class="hljs-number">0</span>},<span class="hljs-string">"resourceIds"</span>:<span class="hljs-string">"jdbc:mysql://127.0.0.1:3306/db_storage?useSSL=false"</span>,<span class="hljs-string">"transactionServiceGroup"</span>:<span class="hljs-string">"hello-service-fescar-service-group"</span>,<span class="hljs-string">"typeCode"</span>:<span class="hljs-number">103</span>,<span class="hljs-string">"version"</span>:<span class="hljs-string">"0.4.0"</span>},<span class="hljs-string">"transactionRole"</span>:<span class="hljs-string">"RMROLE"</span>}
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">48.677</span> DEBUG <span class="hljs-number">38933</span> --- [lector_RMROLE_1] c.a.f.c.rpc.netty.MessageCodecHandler : Send:RegisterRMRequest{resourceIds=<span class="hljs-string">'jdbc:mysql://127.0.0.1:3306/db_storage?useSSL=false'</span>, applicationId=<span class="hljs-string">'storage-service'</span>, transactionServiceGroup=<span class="hljs-string">'hello-service-fescar-service-group'</span>}
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">48.680</span> DEBUG <span class="hljs-number">38933</span> --- [lector_RMROLE_1] c.a.f.c.rpc.netty.MessageCodecHandler : Receive:version=<span class="hljs-number">0.4</span><span class="hljs-number">.1</span>,extraData=<span class="hljs-keyword">null</span>,identified=<span class="hljs-keyword">true</span>,resultCode=<span class="hljs-keyword">null</span>,msg=<span class="hljs-keyword">null</span>,messageId:<span class="hljs-number">9</span>
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">48.680</span> DEBUG <span class="hljs-number">38933</span> --- [lector_RMROLE_1] c.a.f.c.rpc.netty.AbstractRpcRemoting : com.alibaba.fescar.core.rpc.netty.RmRpcClient@<span class="hljs-number">7</span>d61f5d4 msgId:<span class="hljs-number">9</span>, future :com.alibaba.fescar.core.protocol.MessageFuture@<span class="hljs-number">186</span>cd3e0, body:version=<span class="hljs-number">0.4</span><span class="hljs-number">.1</span>,extraData=<span class="hljs-keyword">null</span>,identified=<span class="hljs-keyword">true</span>,resultCode=<span class="hljs-keyword">null</span>,msg=<span class="hljs-keyword">null</span>
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">48.680</span> INFO <span class="hljs-number">38933</span> --- [nio-<span class="hljs-number">8081</span>-exec-<span class="hljs-number">1</span>] c.a.fescar.core.rpc.netty.RmRpcClient : register RM success. server version:<span class="hljs-number">0.4</span><span class="hljs-number">.1</span>,channel:[id: <span class="hljs-number">0xd40718e3</span>, L:/<span class="hljs-number">192.168</span><span class="hljs-number">.0</span><span class="hljs-number">.2</span>:<span class="hljs-number">62607</span> - R:/<span class="hljs-number">192.168</span><span class="hljs-number">.0</span><span class="hljs-number">.2</span>:<span class="hljs-number">8091</span>]
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">48.680</span> INFO <span class="hljs-number">38933</span> --- [nio-<span class="hljs-number">8081</span>-exec-<span class="hljs-number">1</span>] c.a.f.c.rpc.netty.NettyPoolableFactory : register success, cost <span class="hljs-number">3</span> ms, version:<span class="hljs-number">0.4</span><span class="hljs-number">.1</span>,role:RMROLE,channel:[id: <span class="hljs-number">0xd40718e3</span>, L:/<span class="hljs-number">192.168</span><span class="hljs-number">.0</span><span class="hljs-number">.2</span>:<span class="hljs-number">62607</span> - R:/<span class="hljs-number">192.168</span><span class="hljs-number">.0</span><span class="hljs-number">.2</span>:<span class="hljs-number">8091</span>]
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">48.680</span> DEBUG <span class="hljs-number">38933</span> --- [nio-<span class="hljs-number">8081</span>-exec-<span class="hljs-number">1</span>] c.a.f.c.rpc.netty.AbstractRpcRemoting : offer message: transactionId=<span class="hljs-number">2008546211</span>,branchType=AT,resourceId=jdbc:mysql:<span class="hljs-comment">//127.0.0.1:3306/db_storage?useSSL=false,lockKey=storage_tbl:1</span>
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">48.681</span> DEBUG <span class="hljs-number">38933</span> --- [geSend_RMROLE_1] c.a.f.c.rpc.netty.AbstractRpcRemoting : write message:FescarMergeMessage transactionId=<span class="hljs-number">2008546211</span>,branchType=AT,resourceId=jdbc:mysql:<span class="hljs-comment">//127.0.0.1:3306/db_storage?useSSL=false,lockKey=storage_tbl:1, channel:[id: 0xd40718e3, L:/192.168.0.2:62607 - R:/192.168.0.2:8091],active?true,writable?true,isopen?true</span>
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">48.681</span> DEBUG <span class="hljs-number">38933</span> --- [lector_RMROLE_1] c.a.f.c.rpc.netty.MessageCodecHandler : Send:FescarMergeMessage transactionId=<span class="hljs-number">2008546211</span>,branchType=AT,resourceId=jdbc:mysql:<span class="hljs-comment">//127.0.0.1:3306/db_storage?useSSL=false,lockKey=storage_tbl:1</span>
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">48.687</span> DEBUG <span class="hljs-number">38933</span> --- [lector_RMROLE_1] c.a.f.c.rpc.netty.MessageCodecHandler : Receive:MergeResultMessage BranchRegisterResponse: transactionId=<span class="hljs-number">2008546211</span>,branchId=<span class="hljs-number">2008546212</span>,result code =Success,getMsg =<span class="hljs-keyword">null</span>,messageId:<span class="hljs-number">11</span>
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">48.702</span> DEBUG <span class="hljs-number">38933</span> --- [nio-<span class="hljs-number">8081</span>-exec-<span class="hljs-number">1</span>] c.a.f.rm.datasource.undo.UndoLogManager : Flushing UNDO LOG: {<span class="hljs-string">"branchId"</span>:<span class="hljs-number">2008546212</span>,<span class="hljs-string">"sqlUndoLogs"</span>:[{<span class="hljs-string">"afterImage"</span>:{<span class="hljs-string">"rows"</span>:[{<span class="hljs-string">"fields"</span>:[{<span class="hljs-string">"keyType"</span>:<span class="hljs-string">"PrimaryKey"</span>,<span class="hljs-string">"name"</span>:<span class="hljs-string">"id"</span>,<span class="hljs-string">"type"</span>:<span class="hljs-number">4</span>,<span class="hljs-string">"value"</span>:<span class="hljs-number">1</span>},{<span class="hljs-string">"keyType"</span>:<span class="hljs-string">"NULL"</span>,<span class="hljs-string">"name"</span>:<span class="hljs-string">"count"</span>,<span class="hljs-string">"type"</span>:<span class="hljs-number">4</span>,<span class="hljs-string">"value"</span>:<span class="hljs-number">993</span>}]}],<span class="hljs-string">"tableName"</span>:<span class="hljs-string">"storage_tbl"</span>},<span class="hljs-string">"beforeImage"</span>:{<span class="hljs-string">"rows"</span>:[{<span class="hljs-string">"fields"</span>:[{<span class="hljs-string">"keyType"</span>:<span class="hljs-string">"PrimaryKey"</span>,<span class="hljs-string">"name"</span>:<span class="hljs-string">"id"</span>,<span class="hljs-string">"type"</span>:<span class="hljs-number">4</span>,<span class="hljs-string">"value"</span>:<span class="hljs-number">1</span>},{<span class="hljs-string">"keyType"</span>:<span class="hljs-string">"NULL"</span>,<span class="hljs-string">"name"</span>:<span class="hljs-string">"count"</span>,<span class="hljs-string">"type"</span>:<span class="hljs-number">4</span>,<span class="hljs-string">"value"</span>:<span class="hljs-number">994</span>}]}],<span class="hljs-string">"tableName"</span>:<span class="hljs-string">"storage_tbl"</span>},<span class="hljs-string">"sqlType"</span>:<span class="hljs-string">"UPDATE"</span>,<span class="hljs-string">"tableName"</span>:<span class="hljs-string">"storage_tbl"</span>}],<span class="hljs-string">"xid"</span>:<span class="hljs-string">"192.168.0.2:8091:2008546211"</span>}
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">48.755</span> DEBUG <span class="hljs-number">38933</span> --- [nio-<span class="hljs-number">8081</span>-exec-<span class="hljs-number">1</span>] c.a.f.c.rpc.netty.AbstractRpcRemoting : offer message: transactionId=<span class="hljs-number">2008546211</span>,branchId=<span class="hljs-number">2008546212</span>,resourceId=<span class="hljs-keyword">null</span>,status=PhaseOne_Done,applicationData=<span class="hljs-keyword">null</span>
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">48.755</span> DEBUG <span class="hljs-number">38933</span> --- [geSend_RMROLE_1] c.a.f.c.rpc.netty.AbstractRpcRemoting : write message:FescarMergeMessage transactionId=<span class="hljs-number">2008546211</span>,branchId=<span class="hljs-number">2008546212</span>,resourceId=<span class="hljs-keyword">null</span>,status=PhaseOne_Done,applicationData=<span class="hljs-keyword">null</span>, channel:[id: <span class="hljs-number">0xd40718e3</span>, L:/<span class="hljs-number">192.168</span><span class="hljs-number">.0</span><span class="hljs-number">.2</span>:<span class="hljs-number">62607</span> - R:/<span class="hljs-number">192.168</span><span class="hljs-number">.0</span><span class="hljs-number">.2</span>:<span class="hljs-number">8091</span>],active?<span class="hljs-keyword">true</span>,writable?<span class="hljs-keyword">true</span>,isopen?<span class="hljs-keyword">true</span>
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">48.756</span> DEBUG <span class="hljs-number">38933</span> --- [lector_RMROLE_1] c.a.f.c.rpc.netty.MessageCodecHandler : Send:FescarMergeMessage transactionId=<span class="hljs-number">2008546211</span>,branchId=<span class="hljs-number">2008546212</span>,resourceId=<span class="hljs-keyword">null</span>,status=PhaseOne_Done,applicationData=<span class="hljs-keyword">null</span>
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">48.758</span> DEBUG <span class="hljs-number">38933</span> --- [lector_RMROLE_1] c.a.f.c.rpc.netty.MessageCodecHandler : Receive:MergeResultMessage com.alibaba.fescar.core.protocol.transaction.BranchReportResponse@<span class="hljs-number">582</span>a08cf,messageId:<span class="hljs-number">13</span>
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">48.799</span> DEBUG <span class="hljs-number">38933</span> --- [nio-<span class="hljs-number">8081</span>-exec-<span class="hljs-number">1</span>] c.a.fescar.core.context.RootContext : unbind <span class="hljs-number">192.168</span><span class="hljs-number">.0</span><span class="hljs-number">.2</span>:<span class="hljs-number">8091</span>:<span class="hljs-number">2008546211</span>
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">48.799</span> DEBUG <span class="hljs-number">38933</span> --- [nio-<span class="hljs-number">8081</span>-exec-<span class="hljs-number">1</span>] o.s.c.a.f.web.FescarHandlerInterceptor : unbind <span class="hljs-number">192.168</span><span class="hljs-number">.0</span><span class="hljs-number">.2</span>:<span class="hljs-number">8091</span>:<span class="hljs-number">2008546211</span> from RootContext
|
||||
</code></pre>
|
||||
<ol>
|
||||
<li>获取business-service传来的XID</li>
|
||||
<li>绑定XID到当前上下文中</li>
|
||||
<li>执行业务逻辑sql</li>
|
||||
<li>向TC创建本次RM的Netty连接</li>
|
||||
<li>向TC发送分支事务的相关信息</li>
|
||||
<li>获得TC返回的branchId</li>
|
||||
<li>记录Undo Log数据</li>
|
||||
<li>向TC发送本次事务PhaseOne阶段的处理结果</li>
|
||||
<li>从当前上下文中解绑XID</li>
|
||||
</ol>
|
||||
<p>其中第1步和第9步,是在<a href="https://github.com/dongsheep/spring-cloud-alibaba/blob/master/spring-cloud-alibaba-fescar/src/main/java/org/springframework/cloud/alibaba/fescar/web/FescarHandlerInterceptor.java">FescarHandlerInterceptor</a>中完成的,该类并不属于fescar,是前面提到的spring-cloud-alibaba-fescar,它实现了基于feign、rest通信时将xid bind和unbind到当前请求上下文中。到这里RM完成了PhaseOne阶段的工作,接着看PhaseTwo阶段的处理逻辑。</p>
|
||||
<h2>事务提交</h2>
|
||||
<p>各分支事务执行完成后,TC对各RM的汇报结果进行汇总,给各RM发送commit或rollback的指令</p>
|
||||
<pre><code class="language-java"><span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">49.813</span> DEBUG <span class="hljs-number">38933</span> --- [lector_RMROLE_1] c.a.f.c.rpc.netty.MessageCodecHandler : Receive:xid=<span class="hljs-number">192.168</span><span class="hljs-number">.0</span><span class="hljs-number">.2</span>:<span class="hljs-number">8091</span>:<span class="hljs-number">2008546211</span>,branchId=<span class="hljs-number">2008546212</span>,branchType=AT,resourceId=jdbc:mysql:<span class="hljs-comment">//127.0.0.1:3306/db_storage?useSSL=false,applicationData=null,messageId:1</span>
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">49.813</span> DEBUG <span class="hljs-number">38933</span> --- [lector_RMROLE_1] c.a.f.c.rpc.netty.AbstractRpcRemoting : com.alibaba.fescar.core.rpc.netty.RmRpcClient@<span class="hljs-number">7</span>d61f5d4 msgId:<span class="hljs-number">1</span>, body:xid=<span class="hljs-number">192.168</span><span class="hljs-number">.0</span><span class="hljs-number">.2</span>:<span class="hljs-number">8091</span>:<span class="hljs-number">2008546211</span>,branchId=<span class="hljs-number">2008546212</span>,branchType=AT,resourceId=jdbc:mysql:<span class="hljs-comment">//127.0.0.1:3306/db_storage?useSSL=false,applicationData=null</span>
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">49.814</span> INFO <span class="hljs-number">38933</span> --- [atch_RMROLE_1_8] c.a.f.core.rpc.netty.RmMessageListener : onMessage:xid=<span class="hljs-number">192.168</span><span class="hljs-number">.0</span><span class="hljs-number">.2</span>:<span class="hljs-number">8091</span>:<span class="hljs-number">2008546211</span>,branchId=<span class="hljs-number">2008546212</span>,branchType=AT,resourceId=jdbc:mysql:<span class="hljs-comment">//127.0.0.1:3306/db_storage?useSSL=false,applicationData=null</span>
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">49.816</span> INFO <span class="hljs-number">38933</span> --- [atch_RMROLE_1_8] com.alibaba.fescar.rm.AbstractRMHandler : Branch committing: <span class="hljs-number">192.168</span><span class="hljs-number">.0</span><span class="hljs-number">.2</span>:<span class="hljs-number">8091</span>:<span class="hljs-number">2008546211</span> <span class="hljs-number">2008546212</span> jdbc:mysql:<span class="hljs-comment">//127.0.0.1:3306/db_storage?useSSL=false null</span>
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">49.816</span> INFO <span class="hljs-number">38933</span> --- [atch_RMROLE_1_8] com.alibaba.fescar.rm.AbstractRMHandler : Branch commit result: PhaseTwo_Committed
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">49.817</span> INFO <span class="hljs-number">38933</span> --- [atch_RMROLE_1_8] c.a.fescar.core.rpc.netty.RmRpcClient : RmRpcClient sendResponse branchStatus=PhaseTwo_Committed,result code =Success,getMsg =<span class="hljs-keyword">null</span>
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">49.817</span> DEBUG <span class="hljs-number">38933</span> --- [atch_RMROLE_1_8] c.a.f.c.rpc.netty.AbstractRpcRemoting : send response:branchStatus=PhaseTwo_Committed,result code =Success,getMsg =<span class="hljs-keyword">null</span>,channel:[id: <span class="hljs-number">0xd40718e3</span>, L:/<span class="hljs-number">192.168</span><span class="hljs-number">.0</span><span class="hljs-number">.2</span>:<span class="hljs-number">62607</span> - R:/<span class="hljs-number">192.168</span><span class="hljs-number">.0</span><span class="hljs-number">.2</span>:<span class="hljs-number">8091</span>]
|
||||
<span class="hljs-number">2019</span>-<span class="hljs-number">04</span>-<span class="hljs-number">09</span> <span class="hljs-number">21</span>:<span class="hljs-number">57</span>:<span class="hljs-number">49.817</span> DEBUG <span class="hljs-number">38933</span> --- [lector_RMROLE_1] c.a.f.c.rpc.netty.MessageCodecHandler : Send:branchStatus=PhaseTwo_Committed,result code =Success,getMsg =<span class="hljs-keyword">null</span>
|
||||
</code></pre>
|
||||
<p>从日志中可以看到</p>
|
||||
<ol>
|
||||
<li>RM收到XID=192.168.0.2:8091:2008546211,branchId=2008546212的commit通知</li>
|
||||
<li>执行commit动作</li>
|
||||
<li>将commit结果发送给TC,branchStatus为PhaseTwo_Committed</li>
|
||||
</ol>
|
||||
<p>具体看下二阶段commit的执行过程,在<a href="https://github.com/seata/seata/blob/develop/rm/src/main/java/com/alibaba/fescar/rm/AbstractRMHandler.java">AbstractRMHandler</a>类的doBranchCommit方法</p>
|
||||
<pre><code class="language-java"><span class="hljs-comment">/**
|
||||
* 拿到通知的xid、branchId等关键参数
|
||||
* 然后调用RM的branchCommit
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doBranchCommit</span><span class="hljs-params">(BranchCommitRequest request, BranchCommitResponse response)</span> <span class="hljs-keyword">throws</span> TransactionException </span>{
|
||||
String xid = request.getXid();
|
||||
<span class="hljs-keyword">long</span> branchId = request.getBranchId();
|
||||
String resourceId = request.getResourceId();
|
||||
String applicationData = request.getApplicationData();
|
||||
LOGGER.info(<span class="hljs-string">"Branch committing: "</span> + xid + <span class="hljs-string">" "</span> + branchId + <span class="hljs-string">" "</span> + resourceId + <span class="hljs-string">" "</span> + applicationData);
|
||||
BranchStatus status = getResourceManager().branchCommit(request.getBranchType(), xid, branchId, resourceId, applicationData);
|
||||
response.setBranchStatus(status);
|
||||
LOGGER.info(<span class="hljs-string">"Branch commit result: "</span> + status);
|
||||
}
|
||||
</code></pre>
|
||||
<p>最终会将branchCommit的请求调用到<a href="https://github.com/seata/seata/blob/develop/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/AsyncWorker.java">AsyncWorker</a>的branchCommit方法。AsyncWorker的处理方式是fescar架构的一个关键部分,因为大部分事务都是会正常提交的,所以在PhaseOne阶段就已经结束了,这样就可以将锁最快的释放。PhaseTwo阶段接收commit的指令后,异步处理即可。将PhaseTwo的时间消耗排除在一次分布式事务之外。</p>
|
||||
<pre><code class="language-java"><span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> List<Phase2Context> ASYNC_COMMIT_BUFFER = Collections.synchronizedList( <span class="hljs-keyword">new</span> ArrayList<Phase2Context>());
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* 将需要提交的XID加入list
|
||||
*/</span>
|
||||
<span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> BranchStatus <span class="hljs-title">branchCommit</span><span class="hljs-params">(BranchType branchType, String xid, <span class="hljs-keyword">long</span> branchId, String resourceId, String applicationData)</span> <span class="hljs-keyword">throws</span> TransactionException </span>{
|
||||
<span class="hljs-keyword">if</span> (ASYNC_COMMIT_BUFFER.size() < ASYNC_COMMIT_BUFFER_LIMIT) {
|
||||
ASYNC_COMMIT_BUFFER.add(<span class="hljs-keyword">new</span> Phase2Context(branchType, xid, branchId, resourceId, applicationData));
|
||||
} <span class="hljs-keyword">else</span> {
|
||||
LOGGER.warn(<span class="hljs-string">"Async commit buffer is FULL. Rejected branch ["</span> + branchId + <span class="hljs-string">"/"</span> + xid + <span class="hljs-string">"] will be handled by housekeeping later."</span>);
|
||||
}
|
||||
<span class="hljs-keyword">return</span> BranchStatus.PhaseTwo_Committed;
|
||||
}
|
||||
|
||||
<span class="hljs-comment">/**
|
||||
* 通过定时任务消费list中的XID
|
||||
*/</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">synchronized</span> <span class="hljs-keyword">void</span> <span class="hljs-title">init</span><span class="hljs-params">()</span> </span>{
|
||||
LOGGER.info(<span class="hljs-string">"Async Commit Buffer Limit: "</span> + ASYNC_COMMIT_BUFFER_LIMIT);
|
||||
timerExecutor = <span class="hljs-keyword">new</span> ScheduledThreadPoolExecutor(<span class="hljs-number">1</span>,
|
||||
<span class="hljs-keyword">new</span> NamedThreadFactory(<span class="hljs-string">"AsyncWorker"</span>, <span class="hljs-number">1</span>, <span class="hljs-keyword">true</span>));
|
||||
timerExecutor.scheduleAtFixedRate(<span class="hljs-keyword">new</span> Runnable() {
|
||||
<span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">run</span><span class="hljs-params">()</span> </span>{
|
||||
<span class="hljs-keyword">try</span> {
|
||||
doBranchCommits();
|
||||
} <span class="hljs-keyword">catch</span> (Throwable e) {
|
||||
LOGGER.info(<span class="hljs-string">"Failed at async committing ... "</span> + e.getMessage());
|
||||
}
|
||||
}
|
||||
}, <span class="hljs-number">10</span>, <span class="hljs-number">1000</span> * <span class="hljs-number">1</span>, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
<span class="hljs-function"><span class="hljs-keyword">private</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doBranchCommits</span><span class="hljs-params">()</span> </span>{
|
||||
<span class="hljs-keyword">if</span> (ASYNC_COMMIT_BUFFER.size() == <span class="hljs-number">0</span>) {
|
||||
<span class="hljs-keyword">return</span>;
|
||||
}
|
||||
Map<String, List<Phase2Context>> mappedContexts = <span class="hljs-keyword">new</span> HashMap<>();
|
||||
Iterator<Phase2Context> iterator = ASYNC_COMMIT_BUFFER.iterator();
|
||||
|
||||
<span class="hljs-comment">//一次定时循环取出ASYNC_COMMIT_BUFFER中的所有待办数据</span>
|
||||
<span class="hljs-comment">//以resourceId作为key分组待commit数据,resourceId是一个数据库的连接url</span>
|
||||
<span class="hljs-comment">//在前面的日志中可以看到,目的是为了覆盖应用的多数据源创建</span>
|
||||
<span class="hljs-keyword">while</span> (iterator.hasNext()) {
|
||||
Phase2Context commitContext = iterator.next();
|
||||
List<Phase2Context> contextsGroupedByResourceId = mappedContexts.get(commitContext.resourceId);
|
||||
<span class="hljs-keyword">if</span> (contextsGroupedByResourceId == <span class="hljs-keyword">null</span>) {
|
||||
contextsGroupedByResourceId = <span class="hljs-keyword">new</span> ArrayList<>();
|
||||
mappedContexts.put(commitContext.resourceId, contextsGroupedByResourceId);
|
||||
}
|
||||
contextsGroupedByResourceId.add(commitContext);
|
||||
|
||||
iterator.remove();
|
||||
|
||||
}
|
||||
|
||||
<span class="hljs-keyword">for</span> (Map.Entry<String, List<Phase2Context>> entry : mappedContexts.entrySet()) {
|
||||
Connection conn = <span class="hljs-keyword">null</span>;
|
||||
<span class="hljs-keyword">try</span> {
|
||||
<span class="hljs-keyword">try</span> {
|
||||
<span class="hljs-comment">//根据resourceId获取数据源以及连接</span>
|
||||
DataSourceProxy dataSourceProxy = DataSourceManager.get().get(entry.getKey());
|
||||
conn = dataSourceProxy.getPlainConnection();
|
||||
} <span class="hljs-keyword">catch</span> (SQLException sqle) {
|
||||
LOGGER.warn(<span class="hljs-string">"Failed to get connection for async committing on "</span> + entry.getKey(), sqle);
|
||||
<span class="hljs-keyword">continue</span>;
|
||||
}
|
||||
List<Phase2Context> contextsGroupedByResourceId = entry.getValue();
|
||||
<span class="hljs-keyword">for</span> (Phase2Context commitContext : contextsGroupedByResourceId) {
|
||||
<span class="hljs-keyword">try</span> {
|
||||
<span class="hljs-comment">//执行undolog的处理,即删除xid、branchId对应的记录</span>
|
||||
UndoLogManager.deleteUndoLog(commitContext.xid, commitContext.branchId, conn);
|
||||
} <span class="hljs-keyword">catch</span> (Exception ex) {
|
||||
LOGGER.warn(
|
||||
<span class="hljs-string">"Failed to delete undo log ["</span> + commitContext.branchId + <span class="hljs-string">"/"</span> + commitContext.xid + <span class="hljs-string">"]"</span>, ex);
|
||||
}
|
||||
}
|
||||
|
||||
} <span class="hljs-keyword">finally</span> {
|
||||
<span class="hljs-keyword">if</span> (conn != <span class="hljs-keyword">null</span>) {
|
||||
<span class="hljs-keyword">try</span> {
|
||||
conn.close();
|
||||
} <span class="hljs-keyword">catch</span> (SQLException closeEx) {
|
||||
LOGGER.warn(<span class="hljs-string">"Failed to close JDBC resource while deleting undo_log "</span>, closeEx);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<p>所以对于commit动作的处理,RM只需删除xid、branchId对应的undo_log即可。</p>
|
||||
<h2>事务回滚</h2>
|
||||
<p>对于rollback场景的触发有两种情况</p>
|
||||
<ol>
|
||||
<li>分支事务处理异常,即<a href="https://github.com/seata/seata/blob/develop/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/ConnectionProxy.java">ConnectionProxy</a>中<code>report(false)</code>的情况</li>
|
||||
<li>TM捕获到下游系统上抛的异常,即发起全局事务标有<code>@GlobalTransactional</code>注解的方法捕获到的异常。在前面<a href="https://github.com/seata/seata/blob/develop/tm/src/main/java/com/alibaba/fescar/tm/api/TransactionalTemplate.java">TransactionalTemplate</a>类的execute模版方法中,对business.execute()的调用进行了catch,catch后会调用rollback,由TM通知TC对应XID需要回滚事务</li>
|
||||
</ol>
|
||||
<pre><code class="language-java"> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">rollback</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> TransactionException </span>{
|
||||
<span class="hljs-comment">//只有Launcher能发起这个rollback</span>
|
||||
<span class="hljs-keyword">if</span> (role == GlobalTransactionRole.Participant) {
|
||||
<span class="hljs-comment">// Participant has no responsibility of committing</span>
|
||||
<span class="hljs-keyword">if</span> (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(<span class="hljs-string">"Ignore Rollback(): just involved in global transaction ["</span> + xid + <span class="hljs-string">"]"</span>);
|
||||
}
|
||||
<span class="hljs-keyword">return</span>;
|
||||
}
|
||||
<span class="hljs-keyword">if</span> (xid == <span class="hljs-keyword">null</span>) {
|
||||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> IllegalStateException();
|
||||
}
|
||||
|
||||
status = transactionManager.rollback(xid);
|
||||
<span class="hljs-keyword">if</span> (RootContext.getXID() != <span class="hljs-keyword">null</span>) {
|
||||
<span class="hljs-keyword">if</span> (xid.equals(RootContext.getXID())) {
|
||||
RootContext.unbind();
|
||||
}
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<p>TC汇总后向参与者发送rollback指令,RM在<a href="https://github.com/seata/seata/blob/develop/rm/src/main/java/com/alibaba/fescar/rm/AbstractRMHandler.java">AbstractRMHandler</a>类的doBranchRollback方法中接收这个rollback的通知</p>
|
||||
<pre><code class="language-java"><span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doBranchRollback</span><span class="hljs-params">(BranchRollbackRequest request, BranchRollbackResponse response)</span> <span class="hljs-keyword">throws</span> TransactionException </span>{
|
||||
String xid = request.getXid();
|
||||
<span class="hljs-keyword">long</span> branchId = request.getBranchId();
|
||||
String resourceId = request.getResourceId();
|
||||
String applicationData = request.getApplicationData();
|
||||
LOGGER.info(<span class="hljs-string">"Branch rolling back: "</span> + xid + <span class="hljs-string">" "</span> + branchId + <span class="hljs-string">" "</span> + resourceId);
|
||||
BranchStatus status = getResourceManager().branchRollback(request.getBranchType(), xid, branchId, resourceId, applicationData);
|
||||
response.setBranchStatus(status);
|
||||
LOGGER.info(<span class="hljs-string">"Branch rollback result: "</span> + status);
|
||||
}
|
||||
</code></pre>
|
||||
<p>然后将rollback请求传递到<code>DataSourceManager</code>类的branchRollback方法</p>
|
||||
<pre><code class="language-java"><span class="hljs-function"><span class="hljs-keyword">public</span> BranchStatus <span class="hljs-title">branchRollback</span><span class="hljs-params">(BranchType branchType, String xid, <span class="hljs-keyword">long</span> branchId, String resourceId, String applicationData)</span> <span class="hljs-keyword">throws</span> TransactionException </span>{
|
||||
<span class="hljs-comment">//根据resourceId获取对应的数据源</span>
|
||||
DataSourceProxy dataSourceProxy = get(resourceId);
|
||||
<span class="hljs-keyword">if</span> (dataSourceProxy == <span class="hljs-keyword">null</span>) {
|
||||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ShouldNeverHappenException();
|
||||
}
|
||||
<span class="hljs-keyword">try</span> {
|
||||
UndoLogManager.undo(dataSourceProxy, xid, branchId);
|
||||
} <span class="hljs-keyword">catch</span> (TransactionException te) {
|
||||
<span class="hljs-keyword">if</span> (te.getCode() == TransactionExceptionCode.BranchRollbackFailed_Unretriable) {
|
||||
<span class="hljs-keyword">return</span> BranchStatus.PhaseTwo_RollbackFailed_Unretryable;
|
||||
} <span class="hljs-keyword">else</span> {
|
||||
<span class="hljs-keyword">return</span> BranchStatus.PhaseTwo_RollbackFailed_Retryable;
|
||||
}
|
||||
}
|
||||
<span class="hljs-keyword">return</span> BranchStatus.PhaseTwo_Rollbacked;
|
||||
}
|
||||
</code></pre>
|
||||
<p>最终会执行<a href="https://github.com/seata/seata/blob/develop/rm-datasource/src/main/java/com/alibaba/fescar/rm/datasource/undo/UndoLogManager.java">UndoLogManager</a>类的undo方法,因为是纯jdbc操作代码比较长就不贴出来了,可以通过连接到github查看源码,说一下undo的具体流程</p>
|
||||
<ol>
|
||||
<li>根据xid和branchId查找PhaseOne阶段提交的undo_log</li>
|
||||
<li>如果找到了就根据undo_log中记录的数据生成回放sql并执行,即还原PhaseOne阶段修改的数据</li>
|
||||
<li>第2步处理完后,删除该条undo_log数据</li>
|
||||
<li>如果第1步没有找到对应的undo_log,就插入一条状态为<code>GlobalFinished</code>的undo_log.
|
||||
出现没找到的原因可能是PhaseOne阶段的本地事务异常了,导致没有正常写入。
|
||||
因为xid和branchId是唯一索引,所以第4步的插入,可以防止PhaseOne阶段恢复后的成功写入,那么PhaseOne阶段就会异常,这样一来业务数据也就不会提交成功,数据达到了最终回滚了的效果</li>
|
||||
</ol>
|
||||
<h2>总结</h2>
|
||||
<p>本地结合分布式业务场景,分析了fescar client侧的主要处理流程,对TM和RM角色的主要源码进行了解析,希望能对大家理解fescar的工作原理有所帮助。</p>
|
||||
<p>随着fescar的快速迭代以及后期的Roadmap规划,假以时日相信fescar能够成为开源分布式事务的标杆解决方案。</p>
|
||||
</section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>愿景</h3><p>Seata 是一款阿里巴巴开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。</p></div><div class="col col-6"><dl><dt>文档</dt><dd><a href="/zh-cn/docs/overview/what-is-seata.html" target="_self">Seata 是什么?</a></dd><dd><a href="/zh-cn/docs/user/quickstart.html" target="_self">快速开始</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">报告文档问题</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">在Github上编辑此文档</a></dd></dl></div><div class="col col-6"><dl><dt>资源</dt><dd><a href="/zh-cn/blog/index.html" target="_self">博客</a></dd><dd><a href="/zh-cn/community/index.html" target="_self">社区</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/blogDetail.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
|
@ -1,282 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="fescar、seata、分布式事务" />
|
||||
<meta name="description" content="seata-analysis-java-server" />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>深度剖析一站式分布式事务方案Seata-Server</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/blogDetail.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="blog-detail-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/zh-cn/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">En</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/zh-cn/index.html" target="_self">首页</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/docs/overview/what-is-seata.html" target="_self">文档</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/docs/developers/developers_dev.html" target="_self">开发者</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/zh-cn/blog/index.html" target="_self">博客</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/community/index.html" target="_self">社区</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/blog/download.html" target="_self">下载</a></li></ul></div></div></header><section class="blog-content markdown-body"><h1>1.关于Seata</h1>
|
||||
<p>再前不久,我写了一篇关于分布式事务中间件Fescar的解析,没过几天Fescar团队对其进行了品牌升级,取名为Seata(Simpe Extensible Autonomous Transcaction Architecture),而以前的Fescar的英文全称为Fast & EaSy Commit And Rollback。可以看见Fescar从名字上来看更加局限于Commit和Rollback,而新的品牌名字Seata旨在打造一套一站式分布式事务解决方案。更换名字之后,我对其未来的发展更有信心。</p>
|
||||
<p>这里先大概回忆一下Seata的整个过程模型:</p>
|
||||
<p><img src="/img/20190327000119.png" alt=""></p>
|
||||
<ul>
|
||||
<li>TM:事务的发起者。用来告诉TC,全局事务的开始,提交,回滚。</li>
|
||||
<li>RM:具体的事务资源,每一个RM都会作为一个分支事务注册在TC。</li>
|
||||
<li>TC:事务的协调者。也可以看做是Fescar-server,用于接收我们的事务的注册,提交和回滚。</li>
|
||||
</ul>
|
||||
<p>在之前的文章中对整个角色有个大体的介绍,在这篇文章中我将重点介绍其中的核心角色TC,也就是事务协调器。</p>
|
||||
<h1>2.Transcation Coordinator</h1>
|
||||
<p>为什么之前一直强调 TC 是核心呢?那因为TC这个角色就好像上帝一样,管控着云云众生的RM和TM。如果TC一旦不好使,那么RM和TM一旦出现小问题,那必定会乱的一塌糊涂。所以要想了解Seata,那么必须要了解它的TC。</p>
|
||||
<p>那么一个优秀的事务协调者应该具备哪些能力呢?我觉得应该有以下几个:</p>
|
||||
<ul>
|
||||
<li>正确的协调:能正确的协调RM和TM接下来应该做什么,做错了应该怎么办,做对了应该怎么办。</li>
|
||||
<li>高可用: 事务协调器在分布式事务中很重要,如果不能保证高可用,那么它也没有存在的必要了。</li>
|
||||
<li>高性能:事务协调器的性能一定要高,如果事务协调器性能有瓶颈那么它所管理的RM和TM那么会经常遇到超时,从而引起回滚频繁。</li>
|
||||
<li>高扩展性:这个特点是属于代码层面的,如果是一个优秀的框架,那么需要给使用方很多自定义扩展,比如服务注册/发现,读取配置等等。</li>
|
||||
</ul>
|
||||
<p>下面我也将逐步阐述Seata是如何做到上面四点。</p>
|
||||
<h2>2.1 Seata-Server的设计</h2>
|
||||
<p><img src="/img/seata-server/design.png" alt=""></p>
|
||||
<p>Seata-Server整体的模块图如上所示:</p>
|
||||
<ul>
|
||||
<li>Coordinator Core: 在最下面的模块是事务协调器核心代码,主要用来处理事务协调的逻辑,如是否commit,rollback等协调活动。</li>
|
||||
<li>Store:存储模块,用来将我们的数据持久化,防止重启或者宕机数据丢失。</li>
|
||||
<li>Discovery: 服务注册/发现模块,用于将Server地址暴露给我们Client。</li>
|
||||
<li>Config: 用来存储和查找我们服务端的配置。</li>
|
||||
<li>Lock: 锁模块,用于给Seata提供全局锁的功能。</li>
|
||||
<li>RPC:用于和其它端通信。</li>
|
||||
<li>HA-Cluster:高可用集群,目前还没开源,为Seata提供可靠的高可用服务,预计将会在0.6版本开源。</li>
|
||||
</ul>
|
||||
<h2>2.2 Discovery</h2>
|
||||
<p>首先来讲讲比较基础的Discovery模块,又称服务注册/发现模块。我们将Seata-Sever启动之后,需要将自己的地址暴露给其它使用者,那么就需要我们这个模块帮忙。</p>
|
||||
<p><img src="/img/seata-server/discover.png" alt=""></p>
|
||||
<p>这个模块有个核心接口RegistryService,如上图所示:</p>
|
||||
<ul>
|
||||
<li>register:服务端使用,进行服务注册。</li>
|
||||
<li>unregister:服务端使用,一般在JVM关闭钩子,ShutdownHook中调用。</li>
|
||||
<li>subscribe:客户端使用,注册监听事件,用来监听地址的变化。</li>
|
||||
<li>unsubscribe:客户端使用,取消注册监听事件。</li>
|
||||
<li>lookup:客户端使用,根据key查找服务地址列表。</li>
|
||||
<li>close:都可以使用,用于关闭Registry资源。</li>
|
||||
</ul>
|
||||
<p>如果需要添加自己定义的服务注册/发现,那么实现这个接口即可。截止目前在社区的不断开发推动下,已经有五种服务注册/发现,分别是redis、zk、nacos、eruka 和 consul。下面简单介绍下Nacos的实现:</p>
|
||||
<h4>2.2.1 register接口:</h4>
|
||||
<p><img src="/img/seata-server/register.png" alt=""></p>
|
||||
<p>step1:校验地址是否合法</p>
|
||||
<p>step2:获取Nacos的 Naming 实例,然后将地址注册到服务名为 serverAddr(固定服务名) 的对应集群分组(registry.conf 文件配置)上面。</p>
|
||||
<p>unregister接口类似,这里不做详解。</p>
|
||||
<h4>2.2.2 lookup接口:</h4>
|
||||
<p><img src="/img/seata-server/lookup.png" alt=""></p>
|
||||
<p>step1:获取当前clusterName名字。</p>
|
||||
<p>step2:判断当前集群名对应的服务是否已经订阅过了,如果是直接从map中取订阅返回的数据。</p>
|
||||
<p>step3:如果没有订阅先主动查询一次服务实例列表,然后添加订阅并将订阅返回的数据存放到map中,之后直接从map获取最新数据。</p>
|
||||
<h4>2.2.3 subscribe接口</h4>
|
||||
<p><img src="/img/seata-server/subscribe.png" alt=""></p>
|
||||
<p>这个接口比较简单,具体分两步:</p>
|
||||
<p>step1:对将要订阅的cluster-> listener 存放到map中,此处nacos未提交单机已订阅列表,所以需要自己实现。</p>
|
||||
<p>step2:使用Nacos api 订阅。</p>
|
||||
<h2>2.3 Config</h2>
|
||||
<p>配置模块也是一个比较基础,比较简单的模块。我们需要配置一些常用的参数比如:Netty的select线程数量,work线程数量,session允许最大为多少等等,当然这些参数再Seata中都有自己的默认设置。</p>
|
||||
<p>同样的在Seata中也提供了一个接口Configuration,用来自定义我们需要的获取配置的地方:</p>
|
||||
<p><img src="/img/seata-server/config.png" alt=""></p>
|
||||
<ul>
|
||||
<li>getInt/Long/Boolean/getConfig():通过dataId来获取对应的值,读取不到配置、异常或超时将返回参数中的默认值。</li>
|
||||
<li>putConfig:用于添加配置。</li>
|
||||
<li>removeConfig:删除一个配置。</li>
|
||||
<li>add/remove/get ConfigListener:添加/删除/获取 配置监听器,一般用来监听配置的变更。</li>
|
||||
</ul>
|
||||
<p>目前为止有四种方式获取Config:File(文件获取)、Nacos、Apollo 和 ZK(不推荐)。在Seata中首先需要配置registry.conf,来配置config.type 。实现conf比较简单这里就不深入分析。</p>
|
||||
<h2>2.4 Store</h2>
|
||||
<p>存储层的实现对于Seata是否高性能,是否可靠非常关键。
|
||||
如果存储层没有实现好,那么如果发生宕机,在TC中正在进行分布式事务处理的数据将会被丢失,既然使用了分布式事务,那么其肯定不能容忍丢失。如果存储层实现好了,但是其性能有很大问题,RM可能会发生频繁回滚那么其完全无法应对高并发的场景。</p>
|
||||
<p>在Seata中默认提供了文件方式的存储,下面我们定义我们存储的数据为Session,而我们的TM创造的全局事务操作数据叫GloabSession,RM创造的分支事务操作数据叫BranchSession,一个GloabSession可以拥有多个BranchSession。我们的目的就是要将这么多Session存储下来。</p>
|
||||
<p>在FileTransactionStoreManager#writeSession代码中:</p>
|
||||
<p><img src="/img/seata-server/store.png" alt=""></p>
|
||||
<p>上面的代码主要分为下面几步:</p>
|
||||
<ul>
|
||||
<li>step1:生成一个TransactionWriteFuture。</li>
|
||||
<li>step2:将这个futureRequest丢进一个LinkedBlockingQueue中。为什么需要将所有数据都丢进队列中呢?当然这里其实也可以用锁来实现,再另外一个阿里开源的RocketMQ中,使用的锁。不论是队列还是锁它们的目的是为了保证单线程写,这又是为什么呢?有人会解释说,需要保证顺序写,这样速度就很快,这个理解是错误的,我们的FileChannel的写方法是线程安全的,已经能保证顺序写了。保证单线程写其实是为了让我们这个写逻辑都是单线程的,因为可能有些文件写满或者记录写数据位置等等逻辑,当然这些逻辑都可以主动加锁去做,但是为了实现简单方便,直接再整个写逻辑排队处理是最为合适的。</li>
|
||||
<li>step3:调用future.get,等待我们该条数据写逻辑完成通知。</li>
|
||||
</ul>
|
||||
<p>我们将数据提交到队列之后,我们接下来需要对其进行消费,代码如下:</p>
|
||||
<p><img src="/img/seata-server/storewrite.png" alt=""></p>
|
||||
<p>这里将一个WriteDataFileRunnable()提交进我们的线程池,这个Runnable的run()方法如下:</p>
|
||||
<p><img src="/img/seata-server/storerun.png" alt=""></p>
|
||||
<p>分为下面几步:</p>
|
||||
<p>step1: 判断是否停止,如果stopping为true则返回null。</p>
|
||||
<p>step2:从我们的队列中获取数据。</p>
|
||||
<p>step3:判断future是否已经超时了,如果超时,则设置结果为false,此时我们生产者get()方法会接触阻塞。</p>
|
||||
<p>step4:将我们的数据写进文件,此时数据还在pageCahce层并没有刷新到磁盘,如果写成功然后根据条件判断是否进行刷盘操作。</p>
|
||||
<p>step5:当写入数量到达一定的时候,或者写入时间到达一定的时候,需要将我们当前的文件保存为历史文件,删除以前的历史文件,然后创建新的文件。这一步是为了防止我们文件无限增长,大量无效数据浪费磁盘资源。</p>
|
||||
<p>在我们的writeDataFile中有如下代码:</p>
|
||||
<p><img src="/img/seata-server/writedatafile.png" alt=""></p>
|
||||
<p>step1:首先获取我们的ByteBuffer,如果超出最大循环BufferSize就直接创建一个新的,否则就使用我们缓存的Buffer。这一步可以很大的减少GC。</p>
|
||||
<p>step2:然后将数据添加进入ByteBuffer。</p>
|
||||
<p>step3:最后将ByteBuffer写入我们的fileChannel,这里会重试三次。此时的数据还在pageCache层,受两方面的影响,OS有自己的刷新策略,但是这个业务程序不能控制,为了防止宕机等事件出现造成大量数据丢失,所以就需要业务自己控制flush。下面是flush的代码:</p>
|
||||
<p><img src="/img/seata-server/flush.png" alt=""></p>
|
||||
<p>这里flush的条件写入一定数量或者写的时间超过一定时间,这样也会有个小问题如果是停电,那么pageCache中有可能还有数据并没有被刷盘,会导致少量的数据丢失。目前还不支持同步模式,也就是每条数据都需要做刷盘操作,这样可以保证每条消息都落盘,但是性能也会受到极大的影响,当然后续会不断的演进支持。</p>
|
||||
<p>我们的store核心流程主要是上面几个方法,当然还有一些比如,session重建等,这些比较简单,读者可以自行阅读。</p>
|
||||
<h2>2.5 Lock</h2>
|
||||
<p>大家知道数据库实现隔离级别主要是通过锁来实现的,同样的再分布式事务框架Seata中要实现隔离级别也需要通过锁。一般在数据库中数据库的隔离级别一共有四种:读未提交,读已提交,可重复读,串行化。在Seata中可以保证隔离级别是读已提交,但是提供了达到读已提交隔离的手段。</p>
|
||||
<p>Lock模块也就是Seata实现隔离级别的核心模块。在Lock模块中提供了一个接口用于管理我们的锁:
|
||||
<img src="/img/seata-server/lockManager.png" alt=""></p>
|
||||
<p>其中有三个方法:</p>
|
||||
<ul>
|
||||
<li>acquireLock:用于对我们的BranchSession加锁,这里虽然是传的分支事务Session,实际上是对分支事务的资源加锁,成功返回true。</li>
|
||||
<li>isLockable:根据事务ID,资源Id,锁住的Key来查询是否已经加锁。</li>
|
||||
<li>cleanAllLocks:清除所有的锁。
|
||||
对于锁我们可以在本地实现,也可以通过redis或者mysql来帮助我们实现。官方默认提供了本地全局锁的实现:
|
||||
<img src="/img/seata-server/defaultLock.png" alt=""></li>
|
||||
</ul>
|
||||
<p>在本地锁的实现中有两个常量需要关注:</p>
|
||||
<ul>
|
||||
<li>BUCKET_PER_TABLE:用来定义每个table有多少个bucket,目的是为了后续对同一个表加锁的时候减少竞争。</li>
|
||||
<li>LOCK_MAP:这个map从定义上来看非常复杂,里里外外套了很多层Map,这里用个表格具体说明一下:</li>
|
||||
</ul>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>层数</th>
|
||||
<th>key</th>
|
||||
<th>value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>1-LOCK_MAP</td>
|
||||
<td>resourceId(jdbcUrl)</td>
|
||||
<td>dbLockMap</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2- dbLockMap</td>
|
||||
<td>tableName (表名)</td>
|
||||
<td>tableLockMap</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>3- tableLockMap</td>
|
||||
<td>PK.hashcode%Bucket (主键值的hashcode%bucket)</td>
|
||||
<td>bucketLockMap</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>4- bucketLockMap</td>
|
||||
<td>PK</td>
|
||||
<td>trascationId</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p>可以看见实际上的加锁在bucketLockMap这个map中,这里具体的加锁方法比较简单就不作详细阐述,主要是逐步的找到bucketLockMap,然后将当前trascationId塞进去,如果这个主键当前有TranscationId,那么比较是否是自己,如果不是则加锁失败。</p>
|
||||
<h2>2.6 RPC</h2>
|
||||
<p>保证Seata高性能的关键之一也是使用了Netty作为RPC框架,采用默认配置的线程模型如下图所示:</p>
|
||||
<p><img src="/img/seata-server/reactor.png" alt=""></p>
|
||||
<p>如果采用默认的基本配置那么会有一个Acceptor线程用于处理客户端的链接,会有cpu*2数量的NIO-Thread,再这个线程中不会做业务太重的事情,只会做一些速度比较快的事情,比如编解码,心跳事件,和TM注册。一些比较费时间的业务操作将会交给业务线程池,默认情况下业务线程池配置为最小线程为100,最大为500。</p>
|
||||
<p>Seata 目前允许配置的传输层配置如图所示,用户可根据需要进行Netty传输层面的调优,配置通过配置中心配置,首次加载时生效。</p>
|
||||
<img src="/img/seata-server/transport.png" height="400" width="650">
|
||||
这里需要提一下的是Seata的心跳机制,这里是使用Netty的IdleStateHandler完成的,如下:
|
||||
<p><img src="/img/seata-server/idleStateHandler.png" alt=""></p>
|
||||
<p>在Sever端对于写没有设置最大空闲时间,对于读设置了最大空闲时间,默认为15s(客户端默认写空闲为5s,发送ping消息),如果超过15s则会将链接断开,关闭资源。</p>
|
||||
<p><img src="img/seata-server/userEventTriggered.png" alt=""></p>
|
||||
<p>step1:判断是否是读空闲的检测事件。</p>
|
||||
<p>step2:如果是则断开链接,关闭资源。<br>
|
||||
另外Seata 做了内存池、客户端做了批量小包合并发送、Netty连接池(减少连接创建时的服务不可用时间)等功能,以下为批量小包合并功能。<br>
|
||||
<img src="/img/seata-server/send.png" height="700" width="650"><br>
|
||||
客户端的消息发送并不是真正的消息发送通过 AbstractRpcRemoting#sendAsyncRequest 包装成 RpcMessage 存储至 basket 中并唤醒合并发送线程。合并发送线程通过 while true 的形式
|
||||
最长等待1ms对basket的消息取出包装成 merge 消息进行真正发送,此时若 channel 出现异常则会通过 fail-fast 快速失败返回结果。merge消息发送前在 map 中标识,收到结果后批量确认(AbstractRpcRemotingClient#channelRead),并通过 dispatch 分发至 messageListener 和 handler 去处理。同时,timerExecutor 定时对已发送
|
||||
消息进行超时检测,若超时置为失败。具体消息协议设计将会在后续的文章中给出,敬请关注。<br>
|
||||
Seata 的 Netty Client由 TMClient和RMClient 组成,根据事务角色功能区分,都继承 AbstractRpcRemotingClient,AbstractRpcRemotingClient 实现了 RemotingService(服务启停), RegisterMsgListener(netty 连接池连接创建回调)和 ClientMessageSender(消息发送)继承了 AbstractRpcRemoting( Client和Server 顶层消息发送和处理的模板)。<br>
|
||||
RMClient类关系图如下图所示:
|
||||
<img src="/img/seata-server/class.png" alt="">
|
||||
TMClient 和 RMClient 又会根据自身的 poolConfig 配置与 NettyPoolableFactory implements KeyedPoolableObjectFactory<NettyPoolKey, Channel> 进行 channel 连接的交互,channel 连接池根据角色 key+ip 作为连接池的 key 来定位各个连接池
|
||||
,连接池对 channel 进行统一的管理。TMClient 和 RMClient 在发送过程中对于每个 ip 只会使用一个长连接,但连接不可用时,会从连接池中快速取出已经创建好并可用的连接,减少服务的不可用时间。</p>
|
||||
<h2>2.7 HA-Cluster</h2>
|
||||
<p>目前官方没有公布HA-Cluster,但是通过一些其它中间件和官方的一些透露,可以将HA-Cluster用如下方式设计:
|
||||
<img src="/img/seata-server/hacluster.png" alt=""></p>
|
||||
<p>具体的流程如下:</p>
|
||||
<p>step1:客户端发布信息的时候根据transcationId保证同一个transcation是在同一个master上,通过多个Master水平扩展,提供并发处理性能。</p>
|
||||
<p>step2:在server端中一个master有多个slave,master中的数据近实时同步到slave上,保证当master宕机的时候,还能有其它slave顶上来可以用。</p>
|
||||
<p>当然上述一切都是猜测,具体的设计实现还得等0.5版本之后。目前有一个Go版本的Seata-Server也捐赠给了Seata(还在流程中),其通过raft实现副本一致性,其它细节不是太清楚。</p>
|
||||
<h2>2.8 Metrics</h2>
|
||||
<p>这个模块也是一个没有具体公布实现的模块,当然有可能会提供插件口,让其它第三方metric接入进来,最近Apache SkyWalking 正在和Seata小组商讨如何接入进来。</p>
|
||||
<h1>3.Coordinator Core</h1>
|
||||
<p>上面我们讲了很多Server基础模块,想必大家对Seata的实现已经有个大概,接下来我会讲解事务协调器具体逻辑是如何实现的,让大家更加了解Seata的实现内幕。</p>
|
||||
<h2>3.1 启动流程</h2>
|
||||
<p>启动方法在Server类有个main方法,定义了我们启动流程:</p>
|
||||
<p><img src="/img/seata-server/main.png" alt=""></p>
|
||||
<p>step1:创建一个RpcServer,再这个里面包含了我们网络的操作,用Netty实现了服务端。</p>
|
||||
<p>step2:解析端口号、本地文件地址(用户Server宕机未处理完成事务恢复)、IP(可选,本机只能获取内网ip,在跨网络时需要一个对外的vip注册服务)。</p>
|
||||
<p>step3:初始化SessionHoler,其中最重要的重要就是重我们dataDir这个文件夹中恢复我们的数据,重建我们的Session。</p>
|
||||
<p>step4:创建一个CoorDinator,这个也是我们事务协调器的逻辑核心代码,然后将其初始化,其内部初始化的逻辑会创建四个定时任务:</p>
|
||||
<ul>
|
||||
<li>retryRollbacking:重试rollback定时任务,用于将那些失败的rollback进行重试的,每隔5ms执行一次。</li>
|
||||
<li>retryCommitting:重试commit定时任务,用于将那些失败的commit进行重试的,每隔5ms执行一次。</li>
|
||||
<li>asyncCommitting:异步commit定时任务,用于执行异步的commit,每隔10ms一次。</li>
|
||||
<li>timeoutCheck:超时定时任务检测,用于检测超时的任务,然后执行超时的逻辑,每隔2ms执行一次。</li>
|
||||
</ul>
|
||||
<p>step5: 初始化UUIDGenerator这个也是我们生成各种ID(transcationId,branchId)的基本类。</p>
|
||||
<p>step6:将本地IP和监听端口设置到XID中,初始化rpcServer等待客户端的连接。</p>
|
||||
<p>启动流程比较简单,下面我会介绍分布式事务框架中的常见的一些业务逻辑Seata是如何处理的。</p>
|
||||
<h2>3.2 Begin-开启全局事务</h2>
|
||||
<p>一次分布式事务的起始点一定是开启全局事务,首先我们看看全局事务Seata是如何实现的:</p>
|
||||
<p><img src="/img/seata-server/begin.png" alt=""></p>
|
||||
<p>step1: 根据应用ID,事务分组,名字,超时时间创建一个GloabSession,这个在前面也提到过它和branchSession分别是什么。</p>
|
||||
<p>step2:对其添加一个RootSessionManager用于监听一些事件,这里要说一下目前在Seata里面有四种类型的Listener(这里要说明的是所有的sessionManager都实现了SessionLifecycleListener):</p>
|
||||
<ul>
|
||||
<li>ROOT_SESSION_MANAGER:最全,最大的,拥有所有的Session。</li>
|
||||
<li>ASYNC_COMMITTING_SESSION_MANAGER:用于管理需要做异步commit的Session。</li>
|
||||
<li>RETRY_COMMITTING_SESSION_MANAGER:用于管理重试commit的Session。</li>
|
||||
<li>RETRY_ROLLBACKING_SESSION_MANAGER:用于管理重试回滚的Session。
|
||||
由于这里是开启事务,其它SessionManager不需要关注,我们只添加RootSessionManager即可。</li>
|
||||
</ul>
|
||||
<p>step3:开启Globalsession</p>
|
||||
<p><img src="/img/seata-server/begin2.png" alt=""></p>
|
||||
<p>这一步会把状态变为Begin,记录开始时间,并且调用RootSessionManager的onBegin监听方法,将Session保存到map并写入到我们的文件。</p>
|
||||
<p>step4:最后返回XID,这个XID是由 ip+port+transactionId 组成的,非常重要,当TM申请到之后需要将这个ID传到RM中,RM通过XID来决定到底应该访问哪一台Server。</p>
|
||||
<h2>3.3 BranchRegister-分支事务注册</h2>
|
||||
<p>当我们全局事务在TM开启之后,我们RM的分支事务也需要注册到我们的全局事务之上,这里看看是如何处理的:</p>
|
||||
<p><img src="/img/seata-server/branchRegister.png" alt=""></p>
|
||||
<p>step1:通过transactionId获取并校验全局事务是否是开启状态。</p>
|
||||
<p>step2:创建一个新的分支事务,也就是我们的BranchSession。</p>
|
||||
<p>step3:对分支事务进行加全局锁,这里的逻辑就是使用的我们锁模块的逻辑。</p>
|
||||
<p>step4:添加branchSession,主要是将其添加到globalSession对象中,并写入到我们的文件中。</p>
|
||||
<p>step5:返回branchId,这个ID也很重要,我们后续需要用它来回滚我们的事务,或者对我们分支事务状态更新。</p>
|
||||
<p>分支事务注册之后,还需要汇报分支事务的本地事务的执行到底是成功还是失败,在Server目前只是简单的做一下保存记录,汇报的目的是,就算这个分支事务失败,如果TM还是执意要提交全局事务(catch 异常不抛出),那么再遍历提交分支事务的时候,这个失败的分支事务就不需要提交(用户选择性跳过)。</p>
|
||||
<h2>3.4 GlobalCommit - 全局提交</h2>
|
||||
<p>当我们分支事务执行完成之后,就轮到我们的TM-事务管理器来决定是提交还是回滚,如果是提交,那么就会走到下面的逻辑:</p>
|
||||
<p><img src="/img/seata-server/commit.png" alt=""></p>
|
||||
<p>step1:首先找到我们的globalSession。如果它为null证明已经被commit过了,那么直接幂等操作,返回成功。</p>
|
||||
<p>step2:关闭我们的GloabSession防止再次有新的branch进来(跨服务调用超时回滚,provider在继续执行)。</p>
|
||||
<p>step3:如果status是等于Begin,那么久证明还没有提交过,改变其状态为Committing也就是正在提交。</p>
|
||||
<p>step4:判断是否是可以异步提交,目前只有AT模式可以异步提交,二阶段全局提交时只是删除undolog并无严格顺序,此处使用定时任务,客户端收到后批量合并删除。</p>
|
||||
<p>step5:如果是异步提交,直接将其放进我们ASYNC_COMMITTING_SESSION_MANAGER,让其再后台线程异步去做我们的step6,如果是同步的那么直接执行我们的step6。</p>
|
||||
<p>step6:遍历我们的BranchSession进行提交,如果某个分支事务失败,根据不同的条件来判断是否进行重试,可异步执行此branchSession不成功可以继续执行下一个,因为其本身都在manager中,只要没有成功就不会被删除会一直重试,如果是同步提交的会放进重试队列进行定时重试并卡住按照顺序提交。</p>
|
||||
<h2>3.5 GlobalRollback - 全局回滚</h2>
|
||||
<p>如果我们的TM决定全局回滚,那么会走到下面的逻辑:</p>
|
||||
<p><img src="/img/seata-server/rollback.png" alt=""></p>
|
||||
<p>这个逻辑和提交流程基本一致,可以看作是它的反向,这里就不展开讲了。</p>
|
||||
<h1>4.总结</h1>
|
||||
<p>最后在总结一下开始我们提出了分布式事务的关键4点,Seata到底是怎么解决的:</p>
|
||||
<ul>
|
||||
<li>正确的协调:通过后台定时任务各种正确的重试,并且未来会推出监控平台有可能可以手动回滚。</li>
|
||||
<li>高可用: 通过HA-Cluster保证高可用。</li>
|
||||
<li>高性能:文件顺序写,RPC通过netty实现,Seata未来可以水平扩展,提高处理性能。</li>
|
||||
<li>高扩展性:提供给用户可以自由实现的地方,比如配置,服务发现和注册,全局锁等等。</li>
|
||||
</ul>
|
||||
<p>最后希望大家能从这篇文章能了解Seata-Server的核心设计原理,当然你也可以想象如果你自己去实现一个分布式事务的Server应该怎样去设计?</p>
|
||||
<p>Seata GitHub地址:<a href="https://github.com/seata/seata">https://github.com/seata/seata</a></p>
|
||||
<p>本文作者:</p>
|
||||
<p>李钊,GitHub ID @CoffeeLatte007,公众号「咖啡拿铁」作者,Seata社区 Committer,猿辅导Java工程师,曾就职于美团。对分布式中间件,分布式系统有浓厚的兴趣。<br>
|
||||
季敏(清铭),GitHub ID @slievrly,Seata 开源项目负责人,阿里巴巴中间件 TXC/GTS 核心研发成员,长期从事于分布式中间件核心研发工作,在分布式事务领域有着较丰富的技术积累。</p>
|
||||
</section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>愿景</h3><p>Seata 是一款阿里巴巴开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。</p></div><div class="col col-6"><dl><dt>文档</dt><dd><a href="/zh-cn/docs/overview/what-is-seata.html" target="_self">Seata 是什么?</a></dd><dd><a href="/zh-cn/docs/user/quickstart.html" target="_self">快速开始</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">报告文档问题</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">在Github上编辑此文档</a></dd></dl></div><div class="col col-6"><dl><dt>资源</dt><dd><a href="/zh-cn/blog/index.html" target="_self">博客</a></dd><dd><a href="/zh-cn/community/index.html" target="_self">社区</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/blogDetail.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
|
@ -1,469 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Fescar、分布式事务" />
|
||||
<meta name="description" content="seata-analysis-simple" />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>Fescar分布式事务原理解析探秘</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/blogDetail.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="blog-detail-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/zh-cn/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">En</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/zh-cn/index.html" target="_self">首页</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/docs/overview/what-is-seata.html" target="_self">文档</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/docs/developers/developers_dev.html" target="_self">开发者</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/zh-cn/blog/index.html" target="_self">博客</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/community/index.html" target="_self">社区</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/blog/download.html" target="_self">下载</a></li></ul></div></div></header><section class="blog-content markdown-body"><h1>前言</h1>
|
||||
<p>fescar发布已有时日,分布式事务一直是业界备受关注的领域,fescar发布一个月左右便受到了近5000个star足以说明其热度。当然,在fescar出来之前,
|
||||
已经有比较成熟的分布式事务的解决方案开源了,比较典型的方案如 <a href="https://github.com/codingapi/tx-lcn">LCN</a> 的2pc型无侵入事务,
|
||||
目前lcn已发展到5.0,已支持和fescar事务模型类似的TCX型事务。还有如TCC型事务实现 <a href="https://github.com/yu199195/hmily">hmily</a> <a href="https://github.com/changmingxie/tcc-transaction">tcc-transaction</a> 等。
|
||||
在微服务架构流行的当下、阿里这种开源大户背景下,fescar的发布无疑又掀起了研究分布式事务的热潮。fescar脱胎于阿里云商业分布式事务服务GTS,在线上环境提供这种公共服务其模式肯定经受了非常严苛的考验。其分布式事务模型TXC又仿于传统事务模型XA方案,主要区别在于资源管理器的定位一个在应用层一个在数据库层。博主觉得fescar的txc模型实现非常有研究的价值,所以今天我们来好好翻一翻fescar项目的代码。本文篇幅较长,浏览并理解本文大概耗时30~60分钟左右。</p>
|
||||
<h1>项目地址</h1>
|
||||
<p>fescar:<a href="https://github.com/alibaba/fescar">https://github.com/alibaba/fescar</a></p>
|
||||
<p>本博文所述代码为fescar的0.1.2-SNAPSHOT版本,根据fescar后期的迭代计划,其项目结构和模块实现都可能有很大的改变,特此说明。</p>
|
||||
<h1>fescar的TXC模型</h1>
|
||||
<p><img src="/img/blog/c45496461bca15ecd522e497d98ba954f95.jpg" alt=""></p>
|
||||
<p>上图为fescar官方针对TXC模型制作的示意图。不得不说大厂的图制作的真的不错,结合示意图我们可以看到TXC实现的全貌。TXC的实现通过三个组件来完成。也就是上图的三个深黄色部分,其作用如下:</p>
|
||||
<ol>
|
||||
<li>TM:全局事务管理器,在标注开启fescar分布式事务的服务端开启,并将全局事务发送到TC事务控制端管理</li>
|
||||
<li>TC:事务控制中心,控制全局事务的提交或者回滚。这个组件需要独立部署维护,目前只支持单机版本,后续迭代计划会有集群版本</li>
|
||||
<li>RM:资源管理器,主要负责分支事务的上报,本地事务的管理</li>
|
||||
</ol>
|
||||
<p>一段话简述其实现过程:服务起始方发起全局事务并注册到TC。在调用协同服务时,协同服务的事务分支事务会先完成阶段一的事务提交或回滚,并生成事务回滚的undo_log日志,同时注册当前协同服务到TC并上报其事务状态,归并到同一个业务的全局事务中。此时若没有问题继续下一个协同服务的调用,期间任何协同服务的分支事务回滚,都会通知到TC,TC在通知全局事务包含的所有已完成一阶段提交的分支事务回滚。如果所有分支事务都正常,最后回到全局事务发起方时,也会通知到TC,TC在通知全局事务包含的所有分支删除回滚日志。在这个过程中为了解决写隔离和度隔离的问题会涉及到TC管理的全局锁。</p>
|
||||
<p>本博文的目标是深入代码细节,探究其基本思路是如何实现的。首先会从项目的结构来简述每个模块的作用,继而结合官方自带的examples实例来探究整个分布式事务的实现过程。</p>
|
||||
<h1>项目结构解析</h1>
|
||||
<p>项目拉下来,用IDE打开后的目录结构如下,下面先大致的看下每个模块的实现</p>
|
||||
<p><img src="/img/blog/a88cf147f489f913886ef1785d94183bf09.jpg" alt=""></p>
|
||||
<ul>
|
||||
<li>common :公共组件,提供常用辅助类,静态变量、扩展机制类加载器、以及定义全局的异常等</li>
|
||||
<li>config : 配置加载解析模块,提供了配置的基础接口,目前只有文件配置实现,后续会有nacos等配置中心的实现</li>
|
||||
<li>core : 核心模块主要封装了TM、RM和TC通讯用RPC相关内容</li>
|
||||
<li>dubbo :dubbo模块主要适配dubbo通讯框架,使用dubbo的filter机制来传统全局事务的信息到分支</li>
|
||||
<li>examples :简单的演示实例模块,等下从这个模块入手探索</li>
|
||||
<li>rm-datasource :资源管理模块,比较核心的一个模块,个人认为这个模块命名为core要更合理一点。代理了JDBC的一些类,用来解析sql生成回滚日志、协调管理本地事务</li>
|
||||
<li>server : TC组件所在,主要协调管理全局事务,负责全局事务的提交或者回滚,同时管理维护全局锁。</li>
|
||||
<li>spring :和spring集成的模块,主要是aop逻辑,是整个分布式事务的入口,研究fescar的突破口</li>
|
||||
<li>tm : 全局事务事务管理模块,管理全局事务的边界,全局事务开启回滚点都在这个模块控制</li>
|
||||
</ul>
|
||||
<h1>通过【examples】模块的实例看下效果</h1>
|
||||
<p>第一步、先启动TC也就是【Server】模块,main方法直接启动就好,默认服务端口8091</p>
|
||||
<p>第二步、回到examples模块,将订单,业务,账户、仓库四个服务的配置文件配置好,主要是mysql数据源和zookeeper连接地址,这里要注意下,默认dubbo的zk注册中心依赖没有,启动的时候回抛找不到class的异常,需要添加如下的依赖:</p>
|
||||
<pre><code class="language-xml"><span class="hljs-tag"><<span class="hljs-name">dependency</span>></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">groupId</span>></span>com.101tec<span class="hljs-tag"></<span class="hljs-name">groupId</span>></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>zkclient<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">version</span>></span>0.10<span class="hljs-tag"></<span class="hljs-name">version</span>></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">exclusions</span>></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">exclusion</span>></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">artifactId</span>></span>slf4j-log4j12<span class="hljs-tag"></<span class="hljs-name">artifactId</span>></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">groupId</span>></span>org.slf4j<span class="hljs-tag"></<span class="hljs-name">groupId</span>></span>
|
||||
<span class="hljs-tag"></<span class="hljs-name">exclusion</span>></span>
|
||||
<span class="hljs-tag"></<span class="hljs-name">exclusions</span>></span>
|
||||
<span class="hljs-tag"></<span class="hljs-name">dependency</span>></span>
|
||||
</code></pre>
|
||||
<p>第三步、在BusinessServiceImpl中的模拟抛异常的地方打个断点,依次启动OrderServiceImpl、StorageServiceImpl、AccountServiceImpl、BusinessServiceImpl四个服务、等进断点后,查看数据库account_tbl表,金额已减去400元,变成了599元。然后放开断点、BusinessServiceImpl模块模拟的异常触发,全局事务回滚,account_tbl表的金额就又回滚到999元了</p>
|
||||
<p>如上,我们已经体验到fescar事务的控制能力了,下面我们具体看下它是怎么控制的。</p>
|
||||
<h1>fescar事务过程分析</h1>
|
||||
<h2>首先分析配置文件</h2>
|
||||
<p>这个是一个铁律,任何一个技术或框架要集成,配置文件肯定是一个突破口。从上面的例子我们了解到,实例模块的配置文件中配置了一个全局事务扫描器实例,如:</p>
|
||||
<pre><code class="language-xml"><span class="hljs-tag"><<span class="hljs-name">bean</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"com.alibaba.fescar.spring.annotation.GlobalTransactionScanner"</span>></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">constructor-arg</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"dubbo-demo-app"</span>/></span>
|
||||
<span class="hljs-tag"><<span class="hljs-name">constructor-arg</span> <span class="hljs-attr">value</span>=<span class="hljs-string">"my\_test\_tx_group"</span>/></span>
|
||||
<span class="hljs-tag"></<span class="hljs-name">bean</span>></span>
|
||||
</code></pre>
|
||||
<p>这个实例在项目启动时会扫描所有实例,具体实现见【spring】模块。并将标注了@GlobalTransactional注解的方法织入GlobalTransactionalInterceptor的invoke方法逻辑。同时应用启动时,会初始化TM(TmRpcClient)和RM(RmRpcClient)的实例,这个时候,服务已经和TC事务控制中心勾搭上了。在往下看就涉及到TM模块的事务模板类TransactionalTemplate。</p>
|
||||
<h2>【TM】模块启动全局事务</h2>
|
||||
<p>全局事务的开启,提交、回滚都被封装在TransactionalTemplate中完成了,代码如:</p>
|
||||
<pre><code class="language-java">
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> Object <span class="hljs-title">execute</span><span class="hljs-params">(TransactionalExecutor business)</span> <span class="hljs-keyword">throws</span> TransactionalExecutor.ExecutionException </span>{
|
||||
<span class="hljs-comment">// 1. get or create a transaction</span>
|
||||
GlobalTransaction tx = GlobalTransactionContext.getCurrentOrCreate();
|
||||
<span class="hljs-comment">// 2. begin transaction</span>
|
||||
<span class="hljs-keyword">try</span> {
|
||||
tx.begin(business.timeout(), business.name());
|
||||
} <span class="hljs-keyword">catch</span> (TransactionException txe) {
|
||||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> TransactionalExecutor.ExecutionException(tx, txe,
|
||||
TransactionalExecutor.Code.BeginFailure);
|
||||
}
|
||||
Object rs = <span class="hljs-keyword">null</span>;
|
||||
<span class="hljs-keyword">try</span> {
|
||||
<span class="hljs-comment">// Do Your Business</span>
|
||||
rs = business.execute();
|
||||
} <span class="hljs-keyword">catch</span> (Throwable ex) {
|
||||
<span class="hljs-comment">// 3. any business exception, rollback.</span>
|
||||
<span class="hljs-keyword">try</span> {
|
||||
tx.rollback();
|
||||
<span class="hljs-comment">// 3.1 Successfully rolled back</span>
|
||||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> TransactionalExecutor.ExecutionException(tx, TransactionalExecutor.Code.RollbackDone, ex);
|
||||
} <span class="hljs-keyword">catch</span> (TransactionException txe) {
|
||||
<span class="hljs-comment">// 3.2 Failed to rollback</span>
|
||||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> TransactionalExecutor.ExecutionException(tx, txe,
|
||||
TransactionalExecutor.Code.RollbackFailure, ex);
|
||||
}
|
||||
}
|
||||
<span class="hljs-comment">// 4. everything is fine, commit.</span>
|
||||
<span class="hljs-keyword">try</span> {
|
||||
tx.commit();
|
||||
} <span class="hljs-keyword">catch</span> (TransactionException txe) {
|
||||
<span class="hljs-comment">// 4.1 Failed to commit</span>
|
||||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> TransactionalExecutor.ExecutionException(tx, txe,
|
||||
TransactionalExecutor.Code.CommitFailure);
|
||||
}
|
||||
<span class="hljs-keyword">return</span> rs;
|
||||
}
|
||||
</code></pre>
|
||||
<p>更详细的实现在【TM】模块中被分成了两个Class实现,如下:</p>
|
||||
<p>DefaultGlobalTransaction :全局事务具体的开启,提交、回滚动作</p>
|
||||
<p>DefaultTransactionManager :负责使用TmRpcClient向TC控制中心发送指令,如开启全局事务(GlobalBeginRequest)、提交(GlobalCommitRequest)、回滚(GlobalRollbackRequest)、查询状态(GlobalStatusRequest)等。</p>
|
||||
<p>以上是TM模块核心内容点,TM模块完成全局事务开启后,接下来就开始看看全局事务iD,xid是如何传递、RM组件是如何介入的</p>
|
||||
<h2>【dubbo】全局事务xid的传递</h2>
|
||||
<p>首先是xid的传递,目前已经实现了dubbo框架实现的微服务架构下的传递,其他的像spring cloud和motan等的想要实现也很容易,通过一般RPC通讯框架都有的filter机制,将xid从全局事务的发起节点传递到服务协从节点,从节点接收到后绑定到当前线程上线文环境中,用于在分支事务执行sql时判断是否加入全局事务。fescar的实现见【dubbo】模块如下:</p>
|
||||
<pre><code class="language-java"><span class="hljs-meta">@Activate</span>(group = { Constants.PROVIDER, Constants.CONSUMER }, order = <span class="hljs-number">100</span>)
|
||||
<span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">TransactionPropagationFilter</span> <span class="hljs-keyword">implements</span> <span class="hljs-title">Filter</span> </span>{
|
||||
|
||||
<span class="hljs-keyword">private</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">final</span> Logger LOGGER = LoggerFactory.getLogger(TransactionPropagationFilter<span class="hljs-class">.<span class="hljs-keyword">class</span>)</span>;
|
||||
|
||||
<span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> Result <span class="hljs-title">invoke</span><span class="hljs-params">(Invoker<?> invoker, Invocation invocation)</span> <span class="hljs-keyword">throws</span> RpcException </span>{
|
||||
String xid = RootContext.getXID();
|
||||
String rpcXid = RpcContext.getContext().getAttachment(RootContext.KEY_XID);
|
||||
<span class="hljs-keyword">if</span> (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(<span class="hljs-string">"xid in RootContext\["</span> + xid + <span class="hljs-string">"\] xid in RpcContext\["</span> + rpcXid + <span class="hljs-string">"\]"</span>);
|
||||
}
|
||||
<span class="hljs-keyword">boolean</span> bind = <span class="hljs-keyword">false</span>;
|
||||
<span class="hljs-keyword">if</span> (xid != <span class="hljs-keyword">null</span>) {
|
||||
RpcContext.getContext().setAttachment(RootContext.KEY_XID, xid);
|
||||
} <span class="hljs-keyword">else</span> {
|
||||
<span class="hljs-keyword">if</span> (rpcXid != <span class="hljs-keyword">null</span>) {
|
||||
RootContext.bind(rpcXid);
|
||||
bind = <span class="hljs-keyword">true</span>;
|
||||
<span class="hljs-keyword">if</span> (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(<span class="hljs-string">"bind\["</span> + rpcXid + <span class="hljs-string">"\] to RootContext"</span>);
|
||||
}
|
||||
}
|
||||
}
|
||||
<span class="hljs-keyword">try</span> {
|
||||
<span class="hljs-keyword">return</span> invoker.invoke(invocation);
|
||||
|
||||
} <span class="hljs-keyword">finally</span> {
|
||||
<span class="hljs-keyword">if</span> (bind) {
|
||||
String unbindXid = RootContext.unbind();
|
||||
<span class="hljs-keyword">if</span> (LOGGER.isDebugEnabled()) {
|
||||
LOGGER.debug(<span class="hljs-string">"unbind\["</span> + unbindXid + <span class="hljs-string">"\] from RootContext"</span>);
|
||||
}
|
||||
<span class="hljs-keyword">if</span> (!rpcXid.equalsIgnoreCase(unbindXid)) {
|
||||
LOGGER.warn(<span class="hljs-string">"xid in change during RPC from "</span> + rpcXid + <span class="hljs-string">" to "</span> + unbindXid);
|
||||
<span class="hljs-keyword">if</span> (unbindXid != <span class="hljs-keyword">null</span>) {
|
||||
RootContext.bind(unbindXid);
|
||||
LOGGER.warn(<span class="hljs-string">"bind \["</span> + unbindXid + <span class="hljs-string">"\] back to RootContext"</span>);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<p>上面代码rpcXid不为空时,就加入到了RootContext的ContextCore中,这里稍微深入讲下。ContextCore是一个可扩展实现的接口,目前默认的实现是ThreadLocalContextCore,基于ThreadLocal来保存维护当前的xid。这里fescar提供了可扩展的机制,实现在【common】模块中,通过一个自定义的类加载器EnhancedServiceLoader加载需要扩展的服务类,这样只需要在扩展类加上@LoadLevel注解。标记order属性声明高优先级别,就可以达到扩展实现的目的。</p>
|
||||
<h2>【RM】模块本地资源管理的介入</h2>
|
||||
<p>fescar针对本地事务相关的接口,通过代理机制都实现了一遍代理类,如数据源(DataSourceProxy)、ConnectionProxy、StatementProxy等。这个在配置文件中也可以看出来,也就是说,我们要使用fescar分布式事务,一定要配置fescar提供的代理数据源。如:</p>
|
||||
<p><img src="/img/blog/af317255c71a5c1bf46f7140387acf365f8.jpg" alt=""></p>
|
||||
<p>配置好代理数据源后,从DataSourceProxy出发,本地针对数据库的所有操作过程我们就可以随意控制了。从上面xid传递,已经知道了xid被保存在RootContext中了,那么请看下面的代码,就非常清楚了:</p>
|
||||
<p>首先看StatementProxy的一段代码</p>
|
||||
<p><img src="/img/blog/17896deea47b9aee518812b039c39101d8f.jpg" alt=""></p>
|
||||
<p>在看ExecuteTemplate中的代码</p>
|
||||
<p><img src="/img/blog/04488a2745a5d564498462ed64c506174d2.jpg" alt=""></p>
|
||||
<p>和【TM】模块中的事务管理模板类TransactionlTemplate类似,这里非常关键的逻辑代理也被封装在了ExecuteTemplate模板类中。因重写了Statement有了StatementProxy实现,在执行原JDBC的executeUpdate方法时,会调用到ExecuteTemplate的execute逻辑。在sql真正执行前,会判断RootCOntext当前上下文中是否包含xid,也就是判断当前是否是全局分布式事务。如果不是,就直接使用本地事务,如果是,这里RM就会增加一些分布式事务相关的逻辑了。这里根据sql的不同的类型,fescar封装了五个不同的执行器来处理,分别是UpdateExecutor、DeleteExecutor、InsertExecutor、SelectForUpdateExecutor、PlainExecutor,结构如下图:</p>
|
||||
<p><img src="/img/blog/bb9a2f07054f19bc21adc332671de4f7b75.jpg" alt=""></p>
|
||||
<h3>PlainExecutor:</h3>
|
||||
<p>原生的JDBC接口实现,未做任何处理,提供给全局事务中的普通的select查询使用</p>
|
||||
<h3>UpdateExecutor、DeleteExecutor、InsertExecutor:</h3>
|
||||
<p>三个DML增删改执行器实现,主要在sql执行的前后对sql语句进行了解析,实现了如下两个抽象接口方法:</p>
|
||||
<pre><code class="language-java"><span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">abstract</span> TableRecords <span class="hljs-title">beforeImage</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> SQLException</span>;
|
||||
|
||||
<span class="hljs-function"><span class="hljs-keyword">protected</span> <span class="hljs-keyword">abstract</span> TableRecords <span class="hljs-title">afterImage</span><span class="hljs-params">(TableRecords beforeImage)</span> <span class="hljs-keyword">throws</span> SQLException</span>;
|
||||
</code></pre>
|
||||
<p>在这个过程中通过解析sql生成了提供回滚操作的undo_log日志,日志目前是保存在msyql中的,和业务sql操作共用同一个事务。表的结构如下:</p>
|
||||
<p><img src="/img/blog/fd5c423815d3b84bdbc70d7efeb9cd16757.jpg" alt=""></p>
|
||||
<p>rollback_info保存的undo_log详细信息,是longblob类型的,结构如下:</p>
|
||||
<pre><code class="language-json">{
|
||||
<span class="hljs-attr">"branchId"</span>:<span class="hljs-number">3958194</span>,
|
||||
<span class="hljs-attr">"sqlUndoLogs"</span>:[
|
||||
{
|
||||
<span class="hljs-attr">"afterImage"</span>:{
|
||||
<span class="hljs-attr">"rows"</span>:[
|
||||
{
|
||||
<span class="hljs-attr">"fields"</span>:[
|
||||
{
|
||||
<span class="hljs-attr">"keyType"</span>:<span class="hljs-string">"PrimaryKey"</span>,
|
||||
<span class="hljs-attr">"name"</span>:<span class="hljs-string">"ID"</span>,
|
||||
<span class="hljs-attr">"type"</span>:<span class="hljs-number">4</span>,
|
||||
<span class="hljs-attr">"value"</span>:<span class="hljs-number">10</span>
|
||||
},
|
||||
{
|
||||
<span class="hljs-attr">"keyType"</span>:<span class="hljs-string">"NULL"</span>,
|
||||
<span class="hljs-attr">"name"</span>:<span class="hljs-string">"COUNT"</span>,
|
||||
<span class="hljs-attr">"type"</span>:<span class="hljs-number">4</span>,
|
||||
<span class="hljs-attr">"value"</span>:<span class="hljs-number">98</span>
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
<span class="hljs-attr">"tableName"</span>:<span class="hljs-string">"storage_tbl"</span>
|
||||
},
|
||||
<span class="hljs-attr">"beforeImage"</span>:{
|
||||
<span class="hljs-attr">"rows"</span>:[
|
||||
{
|
||||
<span class="hljs-attr">"fields"</span>:[
|
||||
{
|
||||
<span class="hljs-attr">"keyType"</span>:<span class="hljs-string">"PrimaryKey"</span>,
|
||||
<span class="hljs-attr">"name"</span>:<span class="hljs-string">"ID"</span>,
|
||||
<span class="hljs-attr">"type"</span>:<span class="hljs-number">4</span>,
|
||||
<span class="hljs-attr">"value"</span>:<span class="hljs-number">10</span>
|
||||
},
|
||||
{
|
||||
<span class="hljs-attr">"keyType"</span>:<span class="hljs-string">"NULL"</span>,
|
||||
<span class="hljs-attr">"name"</span>:<span class="hljs-string">"COUNT"</span>,
|
||||
<span class="hljs-attr">"type"</span>:<span class="hljs-number">4</span>,
|
||||
<span class="hljs-attr">"value"</span>:<span class="hljs-number">100</span>
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
<span class="hljs-attr">"tableName"</span>:<span class="hljs-string">"storage_tbl"</span>
|
||||
},
|
||||
<span class="hljs-attr">"sqlType"</span>:<span class="hljs-string">"UPDATE"</span>,
|
||||
<span class="hljs-attr">"tableName"</span>:<span class="hljs-string">"storage_tbl"</span>
|
||||
}
|
||||
],
|
||||
<span class="hljs-attr">"xid"</span>:<span class="hljs-string">"192.168.7.77:8091:3958193"</span>
|
||||
}
|
||||
|
||||
|
||||
</code></pre>
|
||||
<p>这里贴的是一个update的操作,undo_log记录的非常的详细,通过全局事务xid关联branchid,记录数据操作的表名,操作字段名,以及sql执行前后的记录数,如这个记录,表名=storage_tbl,sql执行前ID=10,count=100,sql执行后id=10,count=98。如果整个全局事务失败,需要回滚的时候就可以生成:</p>
|
||||
<pre><code class="language-sql"><span class="hljs-keyword">update</span> storage_tbl <span class="hljs-keyword">set</span> <span class="hljs-keyword">count</span> = <span class="hljs-number">100</span> <span class="hljs-keyword">where</span> <span class="hljs-keyword">id</span> = <span class="hljs-number">10</span>;
|
||||
</code></pre>
|
||||
<p>这样的回滚sql语句执行了。</p>
|
||||
<h3>SelectForUpdateExecutor:</h3>
|
||||
<p>fescar的AT模式在本地事务之上默认支持读未提交的隔离级别,但是通过SelectForUpdateExecutor执行器,可以支持读已提交的隔离级别。代码如:</p>
|
||||
<pre><code class="language-java"><span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> Object <span class="hljs-title">doExecute</span><span class="hljs-params">(Object... args)</span> <span class="hljs-keyword">throws</span> Throwable </span>{
|
||||
SQLSelectRecognizer recognizer = (SQLSelectRecognizer) sqlRecognizer;
|
||||
|
||||
Connection conn = statementProxy.getConnection();
|
||||
ResultSet rs = <span class="hljs-keyword">null</span>;
|
||||
Savepoint sp = <span class="hljs-keyword">null</span>;
|
||||
LockRetryController lockRetryController = <span class="hljs-keyword">new</span> LockRetryController();
|
||||
<span class="hljs-keyword">boolean</span> originalAutoCommit = conn.getAutoCommit();
|
||||
|
||||
StringBuffer selectSQLAppender = <span class="hljs-keyword">new</span> StringBuffer(<span class="hljs-string">"SELECT "</span>);
|
||||
selectSQLAppender.append(getTableMeta().getPkName());
|
||||
selectSQLAppender.append(<span class="hljs-string">" FROM "</span> + getTableMeta().getTableName());
|
||||
String whereCondition = <span class="hljs-keyword">null</span>;
|
||||
ArrayList<Object> paramAppender = <span class="hljs-keyword">new</span> ArrayList<>();
|
||||
<span class="hljs-keyword">if</span> (statementProxy <span class="hljs-keyword">instanceof</span> ParametersHolder) {
|
||||
whereCondition = recognizer.getWhereCondition((ParametersHolder) statementProxy, paramAppender);
|
||||
} <span class="hljs-keyword">else</span> {
|
||||
whereCondition = recognizer.getWhereCondition();
|
||||
}
|
||||
<span class="hljs-keyword">if</span> (!StringUtils.isEmpty(whereCondition)) {
|
||||
selectSQLAppender.append(<span class="hljs-string">" WHERE "</span> + whereCondition);
|
||||
}
|
||||
selectSQLAppender.append(<span class="hljs-string">" FOR UPDATE"</span>);
|
||||
String selectPKSQL = selectSQLAppender.toString();
|
||||
|
||||
<span class="hljs-keyword">try</span> {
|
||||
<span class="hljs-keyword">if</span> (originalAutoCommit) {
|
||||
conn.setAutoCommit(<span class="hljs-keyword">false</span>);
|
||||
}
|
||||
sp = conn.setSavepoint();
|
||||
rs = statementCallback.execute(statementProxy.getTargetStatement(), args);
|
||||
|
||||
<span class="hljs-keyword">while</span> (<span class="hljs-keyword">true</span>) {
|
||||
<span class="hljs-comment">// Try to get global lock of those rows selected</span>
|
||||
Statement stPK = <span class="hljs-keyword">null</span>;
|
||||
PreparedStatement pstPK = <span class="hljs-keyword">null</span>;
|
||||
ResultSet rsPK = <span class="hljs-keyword">null</span>;
|
||||
<span class="hljs-keyword">try</span> {
|
||||
<span class="hljs-keyword">if</span> (paramAppender.isEmpty()) {
|
||||
stPK = statementProxy.getConnection().createStatement();
|
||||
rsPK = stPK.executeQuery(selectPKSQL);
|
||||
} <span class="hljs-keyword">else</span> {
|
||||
pstPK = statementProxy.getConnection().prepareStatement(selectPKSQL);
|
||||
<span class="hljs-keyword">for</span> (<span class="hljs-keyword">int</span> i = <span class="hljs-number">0</span>; i < paramAppender.size(); i++) {
|
||||
pstPK.setObject(i + <span class="hljs-number">1</span>, paramAppender.get(i));
|
||||
}
|
||||
rsPK = pstPK.executeQuery();
|
||||
}
|
||||
|
||||
TableRecords selectPKRows = TableRecords.buildRecords(getTableMeta(), rsPK);
|
||||
statementProxy.getConnectionProxy().checkLock(selectPKRows);
|
||||
<span class="hljs-keyword">break</span>;
|
||||
|
||||
} <span class="hljs-keyword">catch</span> (LockConflictException lce) {
|
||||
conn.rollback(sp);
|
||||
lockRetryController.sleep(lce);
|
||||
|
||||
} <span class="hljs-keyword">finally</span> {
|
||||
<span class="hljs-keyword">if</span> (rsPK != <span class="hljs-keyword">null</span>) {
|
||||
rsPK.close();
|
||||
}
|
||||
<span class="hljs-keyword">if</span> (stPK != <span class="hljs-keyword">null</span>) {
|
||||
stPK.close();
|
||||
}
|
||||
<span class="hljs-keyword">if</span> (pstPK != <span class="hljs-keyword">null</span>) {
|
||||
pstPK.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} <span class="hljs-keyword">finally</span> {
|
||||
<span class="hljs-keyword">if</span> (sp != <span class="hljs-keyword">null</span>) {
|
||||
conn.releaseSavepoint(sp);
|
||||
}
|
||||
<span class="hljs-keyword">if</span> (originalAutoCommit) {
|
||||
conn.setAutoCommit(<span class="hljs-keyword">true</span>);
|
||||
}
|
||||
}
|
||||
<span class="hljs-keyword">return</span> rs;
|
||||
}
|
||||
</code></pre>
|
||||
<p>关键代码见:</p>
|
||||
<pre><code class="language-java">TableRecords selectPKRows = TableRecords.buildRecords(getTableMeta(), rsPK);
|
||||
statementProxy.getConnectionProxy().checkLock(selectPKRows);
|
||||
</code></pre>
|
||||
<p>通过selectPKRows表操作记录拿到lockKeys,然后到TC控制器端查询是否被全局锁定了,如果被锁定了,就重新尝试,直到锁释放返回查询结果。</p>
|
||||
<h2>分支事务的注册和上报</h2>
|
||||
<p>在本地事务提交前,fescar会注册和上报分支事务相关的信息,见ConnectionProxy类的commit部分代码:</p>
|
||||
<pre><code class="language-java"><span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">commit</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> SQLException </span>{
|
||||
<span class="hljs-keyword">if</span> (context.inGlobalTransaction()) {
|
||||
<span class="hljs-keyword">try</span> {
|
||||
register();
|
||||
} <span class="hljs-keyword">catch</span> (TransactionException e) {
|
||||
recognizeLockKeyConflictException(e);
|
||||
}
|
||||
|
||||
<span class="hljs-keyword">try</span> {
|
||||
<span class="hljs-keyword">if</span> (context.hasUndoLog()) {
|
||||
UndoLogManager.flushUndoLogs(<span class="hljs-keyword">this</span>);
|
||||
}
|
||||
targetConnection.commit();
|
||||
} <span class="hljs-keyword">catch</span> (Throwable ex) {
|
||||
report(<span class="hljs-keyword">false</span>);
|
||||
<span class="hljs-keyword">if</span> (ex <span class="hljs-keyword">instanceof</span> SQLException) {
|
||||
<span class="hljs-keyword">throw</span> (SQLException) ex;
|
||||
} <span class="hljs-keyword">else</span> {
|
||||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> SQLException(ex);
|
||||
}
|
||||
}
|
||||
report(<span class="hljs-keyword">true</span>);
|
||||
context.reset();
|
||||
|
||||
} <span class="hljs-keyword">else</span> {
|
||||
targetConnection.commit();
|
||||
}
|
||||
}
|
||||
</code></pre>
|
||||
<p>从这段代码我们可以看到,首先是判断是了是否是全局事务,如果不是,就直接提交了,如果是,就先向TC控制器注册分支事务,为了写隔离,在TC端会涉及到全局锁的获取。然后保存了用于回滚操作的undo_log日志,继而真正提交本地事务,最后向TC控制器上报事务状态。此时,阶段一的本地事务已完成了。</p>
|
||||
<h2>【server】模块协调全局</h2>
|
||||
<p>关于server模块,我们可以聚焦在DefaultCoordinator这个类,这个是AbstractTCInboundHandler控制处理器默认实现。主要实现了全局事务开启,提交,回滚,状态查询,分支事务注册,上报,锁检查等接口,如:</p>
|
||||
<p><img src="/img/blog/3da6fd82debb9470eb4a5feb1eecac6d6a2.jpg" alt=""></p>
|
||||
<p>回到一开始的TransactionlTemplate,如果整个分布式事务失败需要回滚了,首先是TM向TC发起回滚的指令,然后TC接收到后,解析请求后会被路由到默认控制器类的doGlobalRollback方法内,最终在TC控制器端执行的代码如下:</p>
|
||||
<pre><code class="language-java"><span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">doGlobalRollback</span><span class="hljs-params">(GlobalSession globalSession, <span class="hljs-keyword">boolean</span> retrying)</span> <span class="hljs-keyword">throws</span> TransactionException </span>{
|
||||
<span class="hljs-keyword">for</span> (BranchSession branchSession : globalSession.getReverseSortedBranches()) {
|
||||
BranchStatus currentBranchStatus = branchSession.getStatus();
|
||||
<span class="hljs-keyword">if</span> (currentBranchStatus == BranchStatus.PhaseOne_Failed) {
|
||||
<span class="hljs-keyword">continue</span>;
|
||||
}
|
||||
<span class="hljs-keyword">try</span> {
|
||||
BranchStatus branchStatus = resourceManagerInbound.branchRollback(XID.generateXID(branchSession.getTransactionId()), branchSession.getBranchId(),
|
||||
branchSession.getResourceId(), branchSession.getApplicationData());
|
||||
|
||||
<span class="hljs-keyword">switch</span> (branchStatus) {
|
||||
<span class="hljs-keyword">case</span> PhaseTwo_Rollbacked:
|
||||
globalSession.removeBranch(branchSession);
|
||||
LOGGER.error(<span class="hljs-string">"Successfully rolled back branch "</span> + branchSession);
|
||||
<span class="hljs-keyword">continue</span>;
|
||||
<span class="hljs-keyword">case</span> PhaseTwo\_RollbackFailed\_Unretryable:
|
||||
GlobalStatus currentStatus = globalSession.getStatus();
|
||||
<span class="hljs-keyword">if</span> (currentStatus.name().startsWith(<span class="hljs-string">"Timeout"</span>)) {
|
||||
globalSession.changeStatus(GlobalStatus.TimeoutRollbackFailed);
|
||||
} <span class="hljs-keyword">else</span> {
|
||||
globalSession.changeStatus(GlobalStatus.RollbackFailed);
|
||||
}
|
||||
globalSession.end();
|
||||
LOGGER.error(<span class="hljs-string">"Failed to rollback global\["</span> + globalSession.getTransactionId() + <span class="hljs-string">"\] since branch\["</span> + branchSession.getBranchId() + <span class="hljs-string">"\] rollback failed"</span>);
|
||||
<span class="hljs-keyword">return</span>;
|
||||
<span class="hljs-keyword">default</span>:
|
||||
LOGGER.info(<span class="hljs-string">"Failed to rollback branch "</span> + branchSession);
|
||||
<span class="hljs-keyword">if</span> (!retrying) {
|
||||
queueToRetryRollback(globalSession);
|
||||
}
|
||||
<span class="hljs-keyword">return</span>;
|
||||
|
||||
}
|
||||
} <span class="hljs-keyword">catch</span> (Exception ex) {
|
||||
LOGGER.info(<span class="hljs-string">"Exception rollbacking branch "</span> + branchSession, ex);
|
||||
<span class="hljs-keyword">if</span> (!retrying) {
|
||||
queueToRetryRollback(globalSession);
|
||||
<span class="hljs-keyword">if</span> (ex <span class="hljs-keyword">instanceof</span> TransactionException) {
|
||||
<span class="hljs-keyword">throw</span> (TransactionException) ex;
|
||||
} <span class="hljs-keyword">else</span> {
|
||||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> TransactionException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
GlobalStatus currentStatus = globalSession.getStatus();
|
||||
<span class="hljs-keyword">if</span> (currentStatus.name().startsWith(<span class="hljs-string">"Timeout"</span>)) {
|
||||
globalSession.changeStatus(GlobalStatus.TimeoutRollbacked);
|
||||
} <span class="hljs-keyword">else</span> {
|
||||
globalSession.changeStatus(GlobalStatus.Rollbacked);
|
||||
}
|
||||
globalSession.end();
|
||||
}
|
||||
</code></pre>
|
||||
<p>如上代码可以看到,回滚时从全局事务会话中迭代每个分支事务,然后通知每个分支事务回滚。分支服务接收到请求后,首先会被路由到RMHandlerAT中的doBranchRollback方法,继而调用了RM中的branchRollback方法,代码如下:</p>
|
||||
<pre><code class="language-java"><span class="hljs-meta">@Override</span>
|
||||
<span class="hljs-function"><span class="hljs-keyword">public</span> BranchStatus <span class="hljs-title">branchRollback</span><span class="hljs-params">(String xid, <span class="hljs-keyword">long</span> branchId, String resourceId, String applicationData)</span> <span class="hljs-keyword">throws</span> TransactionException </span>{
|
||||
DataSourceProxy dataSourceProxy = get(resourceId);
|
||||
<span class="hljs-keyword">if</span> (dataSourceProxy == <span class="hljs-keyword">null</span>) {
|
||||
<span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> ShouldNeverHappenException();
|
||||
}
|
||||
<span class="hljs-keyword">try</span> {
|
||||
UndoLogManager.undo(dataSourceProxy, xid, branchId);
|
||||
} <span class="hljs-keyword">catch</span> (TransactionException te) {
|
||||
<span class="hljs-keyword">if</span> (te.getCode() == TransactionExceptionCode.BranchRollbackFailed_Unretriable) {
|
||||
<span class="hljs-keyword">return</span> BranchStatus.PhaseTwo\_RollbackFailed\_Unretryable;
|
||||
} <span class="hljs-keyword">else</span> {
|
||||
<span class="hljs-keyword">return</span> BranchStatus.PhaseTwo\_RollbackFailed\_Retryable;
|
||||
}
|
||||
}
|
||||
<span class="hljs-keyword">return</span> BranchStatus.PhaseTwo_Rollbacked;
|
||||
}
|
||||
</code></pre>
|
||||
<p>RM分支事务端最后执行的是UndoLogManager的undo方法,通过xid和branchid从数据库查询出回滚日志,完成数据回滚操作,整个过程都是同步完成的。如果全局事务是成功的,TC也会有类似的上述协调过程,只不过是异步的将本次全局事务相关的undo_log清除了而已。至此,就完成了2阶段的提交或回滚,也就完成了完整的全局事务事务的控制。</p>
|
||||
<h1>结语</h1>
|
||||
<p>如果你看到这里,那么非常感谢你,在繁忙工作之余耐心的花时间来学习。同时,我相信花的时间没白费,完整的浏览理解估计对fescar实现的大致流程了解的十之八九了。本文从构思立题到完成大概耗时1人天左右,博主在这个过程中,对fescar的实现也有了更加深入的了解。由于篇幅原因,并没有面面俱到的对每个实现的细节去深究,如sql是如何解析的等,更多的是在fescar的TXC模型的实现过程的关键点做了详细阐述。本文已校对,但由于个人知识水平及精力有限,文中不免出现错误或理解不当的地方,欢迎指正。</p>
|
||||
<h3>作者简介:</h3>
|
||||
<p>陈凯玲,2016年5月加入凯京科技。曾任职高级研发和项目经理,现任凯京科技研发中心架构&运维部负责人。pmp项目管理认证,阿里云MVP。热爱开源,先后开源过多个热门项目。热爱分享技术点滴,独立博客KL博客(<a href="http://www.kailing.pub/">http://www.kailing.pub</a>)博主。</p>
|
||||
</section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>愿景</h3><p>Seata 是一款阿里巴巴开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。</p></div><div class="col col-6"><dl><dt>文档</dt><dd><a href="/zh-cn/docs/overview/what-is-seata.html" target="_self">Seata 是什么?</a></dd><dd><a href="/zh-cn/docs/user/quickstart.html" target="_self">快速开始</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">报告文档问题</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">在Github上编辑此文档</a></dd></dl></div><div class="col col-6"><dl><dt>资源</dt><dd><a href="/zh-cn/blog/index.html" target="_self">博客</a></dd><dd><a href="/zh-cn/community/index.html" target="_self">社区</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/blogDetail.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
|
@ -1,92 +0,0 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<meta name="keywords" content="Seata、分布式事务、AT模式" />
|
||||
<meta name="description" content="AT 模式设计原理" />
|
||||
<!-- 网页标签标题 -->
|
||||
<title>分布式事务中间件 Seata 的设计原理</title>
|
||||
<link rel="shortcut icon" href="/img/seata_logo_small.jpeg"/>
|
||||
<link rel="stylesheet" href="/build/blogDetail.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"><div class="blog-detail-page" data-reactroot=""><header class="header-container header-container-normal"><div class="header-body"><a href="/zh-cn/index.html"><img class="logo" src="/img/seata_logo.png"/></a><div class="search search-normal"><span class="icon-search"></span></div><span class="language-switch language-switch-normal">En</span><div class="header-menu"><img class="header-menu-toggle" src="/img/system/menu_gray.png"/><ul><li class="menu-item menu-item-normal"><a href="/zh-cn/index.html" target="_self">首页</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/docs/overview/what-is-seata.html" target="_self">文档</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/docs/developers/developers_dev.html" target="_self">开发者</a></li><li class="menu-item menu-item-normal menu-item-normal-active"><a href="/zh-cn/blog/index.html" target="_self">博客</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/community/index.html" target="_self">社区</a></li><li class="menu-item menu-item-normal"><a href="/zh-cn/blog/download.html" target="_self">下载</a></li></ul></div></div></header><section class="blog-content markdown-body"><h1>前言</h1>
|
||||
<p>在微服务架构体系下,我们可以按照业务模块分层设计,单独部署,减轻了服务部署压力,也解耦了业务的耦合,避免了应用逐渐变成一个庞然怪物,从而可以轻松扩展,在某些服务出现故障时也不会影响其它服务的正常运行。总之,微服务在业务的高速发展中带给我们越来越多的优势,但是微服务并不是十全十美,因此不能盲目过度滥用,它有很多不足,而且会给系统带来一定的复杂度,其中伴随而来的分布式事务问题,是微服务架构体系下必然需要处理的一个痛点,也是业界一直关注的一个领域,因此也出现了诸如 CAP 和 BASE 等理论。</p>
|
||||
<p>在今年年初,阿里开源了一个分布式事务中间件,起初起名为 Fescar,后改名为 Seata,在它开源之初,我就知道它肯定要火,因为这是一个解决痛点的开源项目,Seata 一开始就是冲着对业务无侵入与高性能方向走,这正是我们对解决分布式事务问题迫切的需求。因为待过的几家公司,用的都是微服务架构,但是在解决分布式事务的问题上都不太优雅,所以我也在一直关注 Seata 的发展,今天就简要说说它的一些设计上的原理,后续我将会对它的各个模块进行深入源码分析,感兴趣的可以持续关注我的公众号或者博客,不要跟丢。</p>
|
||||
<h1>分布式事务解决的方案有哪些?</h1>
|
||||
<p>目前分布式事务解决的方案主要有对业务无入侵和有入侵的方案,无入侵方案主要有基于数据库 XA 协议的两段式提交(2PC)方案,它的优点是对业务代码无入侵,但是它的缺点也是很明显:必须要求数据库对 XA 协议的支持,且由于 XA 协议自身的特点,它会造成事务资源长时间得不到释放,锁定周期长,而且在应用层上面无法干预,因此它性能很差,它的存在相当于七伤拳那样“伤人七分,损己三分”,因此在互联网项目中并不是很流行这种解决方案。</p>
|
||||
<p>为了这个弥补这种方案带来性能低的问题,大佬们又想出了很多种方案来解决,但这无一例外都需要通过在应用层做手脚,即入侵业务的方式,比如很出名的 TCC 方案,基于 TCC 也有很多成熟的框架,如 ByteTCC、tcc-transaction 等。以及基于可靠消息的最终一致性来实现,如 RocketMQ 的事务消息。</p>
|
||||
<p>入侵代码的方案是基于现有情形“迫不得已”才推出的解决方案,实际上它们实现起来非常不优雅,一个事务的调用通常伴随而来的是对该事务接口增加一系列的反向操作,比如 TCC 三段式提交,提交逻辑必然伴随着回滚的逻辑,这样的代码会使得项目非常臃肿,维护成本高。</p>
|
||||
<h1>Seata 各模块之间的关系</h1>
|
||||
<p>针对上面所说的分布式事务解决方案的痛点,那很显然,我们理想的分布式事务解决方案肯定是性能要好而且要对业务无入侵,业务层上无需关心分布式事务机制的约束,Seata 正是往这个方向发展的,因此它非常值得期待,它将给我们的微服务架构带来质的提升。</p>
|
||||
<p>那 Seata 是怎么做到的呢?下面说说它的各个模块之间的关系。</p>
|
||||
<p>Seata 的设计思路是将一个分布式事务可以理解成一个全局事务,下面挂了若干个分支事务,而一个分支事务是一个满足 ACID 的本地事务,因此我们可以操作分布式事务像操作本地事务一样。</p>
|
||||
<p>Seata 内部定义了 3个模块来处理全局事务和分支事务的关系和处理过程,这三个组件分别是:</p>
|
||||
<ul>
|
||||
<li>Transaction Coordinator (TC): 事务协调器,维护全局事务的运行状态,负责协调并驱动全局事务的提交或回滚。</li>
|
||||
<li>Transaction Manager (TM): 控制全局事务的边界,负责开启一个全局事务,并最终发起全局提交或全局回滚的决议。</li>
|
||||
<li>Resource Manager (RM): 控制分支事务,负责分支注册、状态汇报,并接收事务协调器的指令,驱动分支(本地)事务的提交和回滚。</li>
|
||||
</ul>
|
||||
<p><img src="https://raw.githubusercontent.com/objcoding/objcoding.github.io/master/images/seata.png" alt=""></p>
|
||||
<p>简要说说整个全局事务的执行步骤:</p>
|
||||
<ol>
|
||||
<li>TM 向 TC 申请开启一个全局事务,TC 创建全局事务后返回全局唯一的 XID,XID 会在全局事务的上下文中传播;</li>
|
||||
<li>RM 向 TC 注册分支事务,该分支事务归属于拥有相同 XID 的全局事务;</li>
|
||||
<li>TM 向 TC 发起全局提交或回滚;</li>
|
||||
<li>TC 调度 XID 下的分支事务完成提交或者回滚。</li>
|
||||
</ol>
|
||||
<h1>与 XA 方案有什么不同?</h1>
|
||||
<p>Seata 的事务提交方式跟 XA 协议的两段式提交在总体上来说基本是一致的,那它们之间有什么不同呢?</p>
|
||||
<p>我们都知道 XA 协议它依赖的是数据库层面来保障事务的一致性,也即是说 XA 的各个分支事务是在数据库层面上驱动的,由于 XA 的各个分支事务需要有 XA 的驱动程序,一方面会导致数据库与 XA 驱动耦合,另一方面它会导致各个分支的事务资源锁定周期长,这也是它没有在互联网公司流行的重要因素。</p>
|
||||
<p>基于 XA 协议以上的问题,Seata 另辟蹊径,既然在依赖数据库层会导致这么多问题,那我就从应用层做手脚,这还得从 Seata 的 RM 模块说起,前面也说过 RM 的主要作用了,其实 RM 在内部做了对数据库操作的代理层,如下:</p>
|
||||
<p><img src="https://raw.githubusercontent.com/objcoding/objcoding.github.io/master/images/seata5.png" alt=""></p>
|
||||
<p>Seata 在数据源做了一层代理层,所以我们使用 Seata 时,我们使用的数据源实际上用的是 Seata 自带的数据源代理 DataSourceProxy,Seata 在这层代理中加入了很多逻辑,主要是解析 SQL,把业务数据在更新前后的数据镜像组织成回滚日志,并将 undo log 日志插入 undo_log 表中,保证每条更新数据的业务 sql 都有对应的回滚日志存在。</p>
|
||||
<p>这样做的好处就是,本地事务执行完可以立即释放本地事务锁定的资源,然后向 TC 上报分支状态。当 TM 决议全局提交时,就不需要同步协调处理了,TC 会异步调度各个 RM 分支事务删除对应的 undo log 日志即可,这个步骤非常快速地可以完成;当 TM 决议全局回滚时,RM 收到 TC 发送的回滚请求,RM 通过 XID 找到对应的 undo log 回滚日志,然后执行回滚日志完成回滚操作。</p>
|
||||
<p><img src="https://raw.githubusercontent.com/objcoding/objcoding.github.io/master/images/seata6.png" alt=""></p>
|
||||
<p>如上图所示,XA 方案的 RM 是放在数据库层的,它依赖了数据库的 XA 驱动程序。</p>
|
||||
<p><img src="https://raw.githubusercontent.com/objcoding/objcoding.github.io/master/images/Seata7.png" alt=""></p>
|
||||
<p>如上图所示,Seata 的 RM 实际上是已中间件的形式放在应用层,不用依赖数据库对协议的支持,完全剥离了分布式事务方案对数据库在协议支持上的要求。</p>
|
||||
<h1>分支事务如何提交和回滚?</h1>
|
||||
<p>下面详细说说分支事务是如何提交和回滚的:</p>
|
||||
<ul>
|
||||
<li>第一阶段:</li>
|
||||
</ul>
|
||||
<p>分支事务利用 RM 模块中对 JDBC 数据源代理,加入了若干流程,对业务 SQL 进行解释,把业务数据在更新前后的数据镜像组织成回滚日志,并生成 undo log 日志,对全局事务锁的检查以及分支事务的注册等,利用本地事务 ACID 特性,将业务 SQL 和 undo log 写入同一个事物中一同提交到数据库中,保证业务 SQL 必定存在相应的回滚日志,最后对分支事务状态向 TC 进行上报。</p>
|
||||
<p><img src="https://raw.githubusercontent.com/objcoding/objcoding.github.io/master/images/seata2.png" alt=""></p>
|
||||
<ul>
|
||||
<li>第二阶段:</li>
|
||||
</ul>
|
||||
<p>TM决议全局提交:</p>
|
||||
<p>当 TM 决议提交时,就不需要同步协调处理了,TC 会异步调度各个 RM 分支事务删除对应的 undo log 日志即可,这个步骤非常快速地可以完成。这个机制对于性能提升非常关键,我们知道正常的业务运行过程中,事务执行的成功率是非常高的,因此可以直接在本地事务中提交,这步对于提升性能非常显著。</p>
|
||||
<p><img src="https://raw.githubusercontent.com/objcoding/objcoding.github.io/master/images/seata3.png" alt=""></p>
|
||||
<p>TM决议全局回滚:</p>
|
||||
<p>当 TM 决议回滚时,RM 收到 TC 发送的回滚请求,RM 通过 XID 找到对应的 undo log 回滚日志,然后利用本地事务 ACID 特性,执行回滚日志完成回滚操作并删除 undo log 日志,最后向 TC 进行回滚结果上报。</p>
|
||||
<p><img src="https://raw.githubusercontent.com/objcoding/objcoding.github.io/master/images/seata4.png" alt=""></p>
|
||||
<p>业务对以上所有的流程都无感知,业务完全不关心全局事务的具体提交和回滚,而且最重要的一点是 Seata 将两段式提交的同步协调分解到各个分支事务中了,分支事务与普通的本地事务无任何差异,这意味着我们使用 Seata 后,分布式事务就像使用本地事务一样,完全将数据库层的事务协调机制交给了中间件层 Seata 去做了,这样虽然事务协调搬到应用层了,但是依然可以做到对业务的零侵入,从而剥离了分布式事务方案对数据库在协议支持上的要求,且 Seata 在分支事务完成之后直接释放资源,极大减少了分支事务对资源的锁定时间,完美避免了 XA 协议需要同步协调导致资源锁定时间过长的问题。</p>
|
||||
<h1>其它方案的补充</h1>
|
||||
<p>上面说的其实是 Seata 的默认模式,也叫 AT 模式,它是类似于 XA 方案的两段式提交方案,并且是对业务无侵入,但是这种机制依然是需要依赖数据库本地事务的 ACID 特性,有没有发现,我在上面的图中都强调了必须是支持 ACID 特性的关系型数据库,那么问题就来了,非关系型或者不支持 ACID 的数据库就无法使用 Seata 了,别慌,Seata 现阶段为我们准备了另外一种模式,叫 MT 模式,它是一种对业务有入侵的方案,提交回滚等操作需要我们自行定义,业务逻辑需要被分解为 Prepare/Commit/Rollback 3 部分,形成一个 MT 分支,加入全局事务,它存在的意义是为 Seata 触达更多的场景。</p>
|
||||
<p><img src="https://raw.githubusercontent.com/objcoding/objcoding.github.io/master/images/seata8.png" alt=""></p>
|
||||
<p>只不过,它不是 Seata “主打”的模式,它的存在仅仅作为补充的方案,从以上官方的发展远景就可以看出来,Seata 的目标是始终是对业务无入侵的方案。</p>
|
||||
<p><em>注:本文图片设计参考Seata官方图</em></p>
|
||||
<h1>作者简介:</h1>
|
||||
<p>张乘辉,目前就职于中通科技信息中心技术平台部,担任 Java 工程师,主要负责中通消息平台与全链路压测项目的研发,热爱分享技术,微信公众号「后端进阶」作者,技术博客(<a href="https://objcoding.com/">https://objcoding.com/</a>)博主,Seata Contributor,GitHub ID:objcoding。</p>
|
||||
</section><footer class="footer-container"><div class="footer-body"><img src="/img/seata_logo_gray.png"/><p class="docsite-power">website powered by docsite</p><div class="cols-container"><div class="col col-12"><h3>愿景</h3><p>Seata 是一款阿里巴巴开源的分布式事务解决方案,致力于在微服务架构下提供高性能和简单易用的分布式事务服务。</p></div><div class="col col-6"><dl><dt>文档</dt><dd><a href="/zh-cn/docs/overview/what-is-seata.html" target="_self">Seata 是什么?</a></dd><dd><a href="/zh-cn/docs/user/quickstart.html" target="_self">快速开始</a></dd><dd><a href="https://github.com/seata/seata.github.io/issues/new" target="_self">报告文档问题</a></dd><dd><a href="https://github.com/seata/seata.github.io" target="_self">在Github上编辑此文档</a></dd></dl></div><div class="col col-6"><dl><dt>资源</dt><dd><a href="/zh-cn/blog/index.html" target="_self">博客</a></dd><dd><a href="/zh-cn/community/index.html" target="_self">社区</a></dd></dl></div></div><div class="copyright"><span>Copyright © 2019 Seata</span></div></div></footer></div></div>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-with-addons.min.js"></script>
|
||||
<script src="https://f.alicdn.com/react/15.4.1/react-dom.min.js"></script>
|
||||
<script>
|
||||
window.rootPath = '';
|
||||
</script>
|
||||
<script src="/build/blogDetail.js"></script>
|
||||
<script>
|
||||
var _hmt = _hmt || [];
|
||||
(function() {
|
||||
var hm = document.createElement("script");
|
||||
hm.src = "https://hm.baidu.com/hm.js?104e73ef0c18b416b27abb23757ed8ee";
|
||||
var s = document.getElementsByTagName("script")[0];
|
||||
s.parentNode.insertBefore(hm, s);
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue