learn.lianglianglee.com/专栏/SpringCloud微服务实战(完)/23 结束语.md.html
2022-05-11 18:57:05 +08:00

805 lines
19 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
<link rel="icon" href="/static/favicon.png">
<title>23 结束语.md.html</title>
<!-- Spectre.css framework -->
<link rel="stylesheet" href="/static/index.css">
<!-- theme css & js -->
<meta name="generator" content="Hexo 4.2.0">
</head>
<body>
<div class="book-container">
<div class="book-sidebar">
<div class="book-brand">
<a href="/">
<img src="/static/favicon.png">
<span>技术文章摘抄</span>
</a>
</div>
<div class="book-menu uncollapsible">
<ul class="uncollapsible">
<li><a href="/" class="current-tab">首页</a></li>
</ul>
<ul class="uncollapsible">
<li><a href="../">上一级</a></li>
</ul>
<ul class="uncollapsible">
<li>
<a href="/专栏/SpringCloud微服务实战/00 开篇导读.md.html">00 开篇导读.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/01 以真实“商场停车”业务切入——需求分析.md.html">01 以真实“商场停车”业务切入——需求分析.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/02 具象业务需求再抽象分解——系统设计.md.html">02 具象业务需求再抽象分解——系统设计.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/03 第一个 Spring Boot 子服务——会员服务.md.html">03 第一个 Spring Boot 子服务——会员服务.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/04 如何维护接口文档供外部调用——在线接口文档管理.md.html">04 如何维护接口文档供外部调用——在线接口文档管理.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/05 认识 Spring Cloud 与 Spring Cloud Alibaba 项目.md.html">05 认识 Spring Cloud 与 Spring Cloud Alibaba 项目.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/06 服务多不易管理如何破——服务注册与发现.md.html">06 服务多不易管理如何破——服务注册与发现.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/07 如何调用本业务模块外的服务——服务调用.md.html">07 如何调用本业务模块外的服务——服务调用.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/08 服务响应慢或服务不可用怎么办——快速失败与服务降级.md.html">08 服务响应慢或服务不可用怎么办——快速失败与服务降级.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/09 热更新一样更新服务的参数配置——分布式配置中心.md.html">09 热更新一样更新服务的参数配置——分布式配置中心.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/10 如何高效读取计费规则等热数据——分布式缓存.md.html">10 如何高效读取计费规则等热数据——分布式缓存.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/11 多实例下的定时任务如何避免重复执行——分布式定时任务.md.html">11 多实例下的定时任务如何避免重复执行——分布式定时任务.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/12 同一套服务如何应对不同终端的需求——服务适配.md.html">12 同一套服务如何应对不同终端的需求——服务适配.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/13 采用消息驱动方式处理扣费通知——集成消息中间件.md.html">13 采用消息驱动方式处理扣费通知——集成消息中间件.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/14 Spring Cloud 与 Dubbo 冲突吗——强强联合.md.html">14 Spring Cloud 与 Dubbo 冲突吗——强强联合.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/15 破解服务中共性问题的繁琐处理方式——接入 API 网关.md.html">15 破解服务中共性问题的繁琐处理方式——接入 API 网关.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/16 服务压力大系统响应慢如何破——网关流量控制.md.html">16 服务压力大系统响应慢如何破——网关流量控制.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/17 集成网关后怎么做安全验证——统一鉴权.md.html">17 集成网关后怎么做安全验证——统一鉴权.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/18 多模块下的接口 API 如何统一管理——聚合 API.md.html">18 多模块下的接口 API 如何统一管理——聚合 API.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/19 数据分库后如何确保数据完整性——分布式事务.md.html">19 数据分库后如何确保数据完整性——分布式事务.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/20 优惠券如何避免超兑——引入分布式锁.md.html">20 优惠券如何避免超兑——引入分布式锁.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/21 如何查看各服务的健康状况——系统应用监控.md.html">21 如何查看各服务的健康状况——系统应用监控.md.html</a>
</li>
<li>
<a href="/专栏/SpringCloud微服务实战/22 如何确定一次完整的请求过程——服务链路跟踪.md.html">22 如何确定一次完整的请求过程——服务链路跟踪.md.html</a>
</li>
<li>
<a class="current-tab" href="/专栏/SpringCloud微服务实战/23 结束语.md.html">23 结束语.md.html</a>
</li>
</ul>
</div>
</div>
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
<div class="sidebar-toggle-inner"></div>
</div>
<script>
function add_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.add('show')
}
function remove_inner() {
let inner = document.querySelector('.sidebar-toggle-inner')
inner.classList.remove('show')
}
function sidebar_toggle() {
let sidebar_toggle = document.querySelector('.sidebar-toggle')
let sidebar = document.querySelector('.book-sidebar')
let content = document.querySelector('.off-canvas-content')
if (sidebar_toggle.classList.contains('extend')) { // show
sidebar_toggle.classList.remove('extend')
sidebar.classList.remove('hide')
content.classList.remove('extend')
} else { // hide
sidebar_toggle.classList.add('extend')
sidebar.classList.add('hide')
content.classList.add('extend')
}
}
function open_sidebar() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.add('show')
overlay.classList.add('show')
}
function hide_canvas() {
let sidebar = document.querySelector('.book-sidebar')
let overlay = document.querySelector('.off-canvas-overlay')
sidebar.classList.remove('show')
overlay.classList.remove('show')
}
</script>
<div class="off-canvas-content">
<div class="columns">
<div class="column col-12 col-lg-12">
<div class="book-navbar">
<!-- For Responsive Layout -->
<header class="navbar">
<section class="navbar-section">
<a onclick="open_sidebar()">
<i class="icon icon-menu"></i>
</a>
</section>
</header>
</div>
<div class="book-content" style="max-width: 960px; margin: 0 auto;
overflow-x: auto;
overflow-y: hidden;">
<div class="book-post">
<p id="tip" align="center"></p>
<div><h1>23 结束语</h1>
<p>读到这里,相信你已经将本课程全部学完,对 Spring Cloud、Spring Cloud Alibaba 两个开源项目整体上有一个更加直观的认知,经过本次实际操作,是不是也没有想像中的那么难,一旦你将整个开发全貌有体系的接触之后,微服务思想也可以渗透到日常的开发工作中去。本篇,就带你做个简单复盘,回顾下整个课程体系。</p>
<h3>前景回顾</h3>
<p>本次实战选用的是常见的商场停车场景,旨在通过简单的场景融入微服务开发技术体系,逐步完善迭代,达到我们学习并实践微服务技术开发的目标,内容还是主要聚集于技术开发,系统运维层面涉及的内容较少,随着 DevOps 的流行,相信越来越多的公司开发与运维的边界逐渐消失,彻底融合在一起。</p>
<p>提到微服务,必然涉及到服务的拆分,拆分粒度究竟多细,业内没有统一的标准,依团队能力而异。太粗了,达不到效果,太细了管理起来繁杂冗余。服务拆分后,底层存储也涉及到拆分问题。即便是没采用微服务,在业务增长快速的情况下,分库分表也是比较常见的情况,这里涉及到垂直拆分以及水平拆分的问题。</p>
<p>垂直拆分,根据表功能不同,以近似属性划分,拆分为不同的小数据库。当库中单个表的容量超大时,就需要按不同纬度进行水平拆分,分布在形如 A<em>01、A</em>02、A_03……等不同的表中。本案例中不涉及水平拆分问题如果存储体系不变终究是遇到水平拆分的问题。</p>
<h3>技术点回顾</h3>
<p>技术是为业务服务,技术栈只有在适当的业务场景中才能发挥出应用有作用,这里列一个表格,将业务场景与技术应用对应起来。</p>
<table>
<thead>
<tr>
<th align="left">使用业务场景</th>
<th align="left">技术点</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">商场用户绑定手机号、开通月卡</td>
<td align="left">服务间调用RestTemplate、Feign、Ribbon</td>
</tr>
<tr>
<td align="left">各个子服务对外的在线 API 管理</td>
<td align="left">Spring Boot 与 Swagger 集成</td>
</tr>
<tr>
<td align="left">商场停车收费系统对外聚合 API</td>
<td align="left">Spring Cloud Gateway 与 Swagger 整合</td>
</tr>
<tr>
<td align="left">子服务模块众多时,如何管理这些服务接口</td>
<td align="left">通过 Nacos 进行服务管理</td>
</tr>
<tr>
<td align="left">特殊节日下,绑定手机号赠送积分与往日不同</td>
<td align="left">使用 Nacos 做分布式配置,供所有服务调用</td>
</tr>
<tr>
<td align="left">停车场可用车位数展现,停车计费规则</td>
<td align="left">分布式缓存 Redis</td>
</tr>
<tr>
<td align="left">定时向会员推送营销短信</td>
<td align="left">分布式定时任务,整合 Shedlock</td>
</tr>
<tr>
<td align="left">商场优惠券兑换</td>
<td align="left">分布式锁应用 Redis 整合 Redission</td>
</tr>
<tr>
<td align="left">面向不同终端的数据装配</td>
<td align="left">BFF 架构应用</td>
</tr>
<tr>
<td align="left">优惠券兑换洗车</td>
<td align="left">与 RPC 框架 Apache Dubbo 整合</td>
</tr>
<tr>
<td align="left">屏蔽内部接口,对外统一的路由控制</td>
<td align="left">Spring Cloud Gateway</td>
</tr>
<tr>
<td align="left">服务调用时,响应慢或服务不可用时,需要快速失败</td>
<td align="left">整合 Hystrix</td>
</tr>
<tr>
<td align="left">网关进行限流限制,防止流量过大</td>
<td align="left">Sentinel 设定特定规则</td>
</tr>
<tr>
<td align="left">网关鉴权,安全防护</td>
<td align="left">Spring Cloud Gateway 整合 JWT</td>
</tr>
<tr>
<td align="left">付费出场时,计费数据的完整性</td>
<td align="left">使用分布式事务,整合组件 Seata</td>
</tr>
<tr>
<td align="left">每个子服务的健康状态如何</td>
<td align="left">整合 Spring Boot Admin</td>
</tr>
<tr>
<td align="left">确定服务间调用时请求的完整链路</td>
<td align="left">Apache SkyWalking</td>
</tr>
</tbody>
</table>
<p>实践出真知,通过简短 20 几节内容,各个环节是没有办法进行深入的讲解,所以就需要大家在实际应用过中,边摸索边学习,稳扎稳打。</p>
<h3>微服务是万能的吗?</h3>
<p>近两年,微服务的一度火热,似乎成了拯救自家业务的银弹。用微服务不等于就解决了一切问题,它与公司的组织架构、技术储备、业务走向、技术投入等都有很大的关系,需要产品、开发、测试、运维等各岗位人员通力配合。在没有一个开放性的、敏捷的思维框架下,不管是初次实施微服务开发,还是基于原有业务进行微服务架构重构,都面临着很大的挑战,同时它对系统测试运维有了更高的要求,不是说开发完就结束了。在软件生命周期过程中,开发仅占了很小的一部分,大部分阶段是处于运维阶段。</p>
<p>有必要开展微服务架构吗?业务发展快速,技术起点高且团队应用成熟的情况下,可以直接从微服务架构起步。或者系统已经复杂,维护难度越来越大,时间允许的情况下,进行微服务架构重构也是可能的,但也不可直接推倒重来,只能采用绞杀模式,一步一步替代,否则上来直接重写,代价是相当高的。</p>
<p>不要瞧不上单体应用,深度挖掘潜力后,完全可以应付正常的业务使用,一般情况下,还是建议从单体应用开发起步,业务稳定后,再做进一步打算。适当的设计,才不会造成成本浪费。</p>
<h3>微服务不仅仅是开发</h3>
<p>微服务不仅仅是开发还有后期长期的运维与升级。本篇仅讲述了开发部分后期生产系统的部署运维还有很长的路要走。DevOps 时代要求开发有更多的运维技能,甚至在开发阶段就已经进入运维角色。容器化部署、自动化扩容、弹性扩展等等,微服务架构的过程还有很长的路要走,希望小伙伴们继续保持学习的劲头,再接再励。</p>
</div>
</div>
<div>
<div style="float: left">
<a href="/专栏/SpringCloud微服务实战/22 如何确定一次完整的请求过程——服务链路跟踪.md.html">上一页</a>
</div>
</div>
</div>
</div>
</div>
</div>
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
</div>
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"709975be6b6c3cfa","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
</body>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-NPSEEVD756');
var path = window.location.pathname
var cookie = getCookie("lastPath");
console.log(path)
if (path.replace("/", "") === "") {
if (cookie.replace("/", "") !== "") {
console.log(cookie)
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
}
} else {
setCookie("lastPath", path)
}
function setCookie(cname, cvalue) {
var d = new Date();
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
var expires = "expires=" + d.toGMTString();
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
}
function getCookie(cname) {
var name = cname + "=";
var ca = document.cookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i].trim();
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
}
return "";
}
</script>
</html>