当前位置: 首页 > news >正文

【业务功能109】微服务-springcloud-springboot-Skywalking-链路追踪-监控

Skywalking

skywalking是一个apm系统,包含监控,追踪,并拥有故障诊断能力的 分布式系统

一、Skywalking介绍

1.什么是SkyWalking

  Skywalking是由国内开源爱好者吴晟开源并提交到Apache孵化器的产品,它同时吸收了Zipkin /Pinpoint /CAT 的设计思路。特点是:支持多种插件,UI功能较强,支持非侵入式埋点。目前使用厂商最多,版本更新较快。

  数据存储支持:Elasticsearch、MySQL、H2、TiDB。默认是H2,而且是存到内存。实际我们一般将其存到ES。

主页:http://skywalking.apache.org/
下载:https://skywalking.apache.org/downloads/
github:https://github.com/apache/skywalking
文档:https://github.com/apache/skywalking/tree/master/docs
配置:https://github.com/apache/skywalking/tree/master/docs/en/setup/backend

2.APM

  APM全称Application Performance Management应用性能管理,目的是通过各种探针采集数据,收集关键指标,同时搭配数据呈现以实现对应用程序性能管理和故障管理的系统化解决方案.

  Zabbix、Premetheus、open-falcon等监控系统主要关注服务器硬件指标与系统服务运行状态等,而APM系统则更重视程序内部执行过程指标和服务之间链路调用情况的监控,APM更有利于深入代码找到请求响应“慢”的根本问题,与Zabbix之类的监控是互补关系 目前市面上开源的APM系统主要有CAT、Zipkin、Pinpoint、SkyWalking,大都是参考Google的 Dapper实现的.

3.链路追踪工具对比

链路追踪工具一般要有如下功能:

  • 心跳检测(确定应用是否还在运行)
  • 记录请求的执行流程、执行时间
  • 资源监控(CPU、内存、带宽、磁盘)
  • 告警功能(监控执行时间、成功率等通过邮件、钉钉、短信、微信等进行通知)
  • 可视化页面

常用的工具有:

Zipkin
  Twitter开源的调用链分析工具,目前基于springcloud sleuth得到了广泛的使用,特点是轻量,使用部署简单。
Pinpoint
  韩国人开源的基于字节码注入的调用链分析,以及应用监控分析工具。特点是支持多种插件,UI功能强大,接入端无代码侵入。
SkyWalking
  本土开源的基于字节码注入的调用链分析,以及应用监控分析工具。特点是支持多种插件,UI功能较强,接入端无代码侵入。目前已加入Apache孵化器。
CAT
  大众点评开源的基于编码和配置的调用链分析,应用监控分析,日志采集,监控报警等一系列的监控平台工具。

各维度对比

对比项ZipkinPinpointSkyWalkingCat
实现方式拦截请求,发送(Http,MQ)数据到Zipkin服务Java探针,字节码增强Java探针,字节码增强代码埋点(拦截器,注解,过滤器等)
接入方式基于linkerd或者sleuth方式javaagent字节码javaagent字节码代码侵入
agent到collector协议http,MQthriftgRPChttp/tcp
OpenTracing支持不支持支持不支持
颗粒度接口级方法级方法级代码级
全局调用统计不支持支持支持支持
traceid查询支持不支持支持不支持
报警不支持支持支持支持
JVM监控不支持不支持支持支持
UI功能支持支持支持支持
数据存储ES、MySQL等HBaseES/H2/MySQLMySQL/HDFS

性能对比图

image.png

4.SkyWalking的功能特性

  1. 多种监控手段,通过语言探针和Service mesh 获得监控的数据
  2. 支持多种语言自动探针,包括 Java, .NET Core 和 Node.js
  3. 轻量高效,无需大数据平台和大量的服务器资源
  4. 模块化,UI,存储,集群管理都有多种机制可选
  5. 支持报警,告警
  6. 优秀的可视化解决方案

二、SkyWalking环境搭建

1.Skywalking结构

  先来看看Skywalking的结构图

image.png

说明:

  • Skywalking agent 和业务系统绑定在一起,负责收集各种监控数据
  • Skywalking oapservice负责处理监控数据,比如接受Skywalking agent的监控数据,并且存储在数据库中,接受Skywalking webapp前端的请求,从数据库查询数据,并返回给前端,Skywalking oapservice通常会以集群的方式搭建
  • Skywalking webapp ,UI服务,用于可视化展示数据
  • 用户持久化监控数据的数据库,可以选用ElasticSearch、MySQL等

2.Skywalking部署

  从官网提供的下载地址下载安装文件,我们先通过windows操作来演示下:https://skywalking.apache.org/downloads/

image.png

点击对应的下载链接下载即可

image.png

启动服务:

image.png

启动成功后会启动两个服务,一个是Skywalking-oap-server,一个是Skywalking-web-ui:8080

Skywalking-oap-server服务启动后会暴露11800和12800两个端口,分别为收集监控数据的端口11800和接收前端请求的端口12800,修改端口可以修改config/application.yml

image.png

默认端口8080,访问效果如下:

image.png

3.Java Agent

  在新版本中Agent是需要单独下载的。

image.png

下载后解压出来放在了前面Skywalking的解压目录中

image.png

三、服务接入

  然后我们就可以把我们的微服务接入到Skywalking中来监控链路的执行。

1.开发环境的配置

  首先来看看在开发环境中的配置,因为Skywalking是无侵入式的。我们只需要在启动的时候 idea中的启动类配置中的 VM options 设置参数配置即可

# skywalking-agent.jar 的路径位置
-javaagent:d:\xxx\skywalking-agent.jar
# 在Skywalking中显示的服务名称
-DSW_AGENT_NAME=xxx-skywalking-service
# Skywalking的collector服务的IP及端口
-DSW_AGENT_COLLECTOR_BACKEND_SERVICES=localhost:11800

注意:-DSW_AGENT_COLLECTOR_BACKEND_SERVICES 可以指定远程服务,但是 -javaagent必须是本地的jar包.

2.gateway服务

  然后我们接入gateway的服务。在启动时设置对应的参数

image.png

启动服务后,我们进入Skywalking的UI服务中查看

image.png

可以看到有对应的服务信息,但是没有相关的链路信息,主要是因为默认Skywalking中是不支持Gateway的,我们需要显示的添加对应的gateway插件支持

image.png

从我们下载的agent包中的 optional-plugins中把gateway的jar拷贝的对应的plugins中即可

image.png

重启服务测试即可

image.png

3.对接多个服务

  接下来我们就可以把商城系统中的各个服务都对接到Skywalking中,给每个服务添加对应的配置

-Xmx512m
-javaagent:D:\software\apache-skywalking-apm-bin\skywalking-agent\skywalking-agent.jar
-DSW_AGENT_NAME=mall-product
-DSW_AGENT_COLLECTOR_BACKEND_SERVICES=localhost:11800

分别启动

image.png

image.png

四、Skywalking持久化

  持久化数据到MySQL中。修改下config/application.yml配置,把原来默认的H2修改为MySQL就可以了。

image.png

mysql://localhost:3306/swtest?rewriteBatchedStatements=true&serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8

然后还需要把MySQL的驱动包拷贝到对应的目录中 oap-libs

image.png

然后重启服务即可,对应的数据库会自动生成表结构

image.png

五、自定义SkyWalking链路

  在默认情况下Skywalking是没有记录我们的业务方法的,只会追踪到controller层接口,如果需要添加业务方法的链路监控我们就需要添加如下的依赖

<dependency><groupId>org.apache.skywalking</groupId><artifactId>apm-toolkit-trace</artifactId><version>8.8.0</version>
</dependency>

然后在业务方法上添加@Trace注解。那么该方法就会被监控

image.png

重启服务并访问:

image.png

但是查看这个方法的详情中没有返回信息和参数

image.png

这时我们可以通过@Tags和@Tag来解决这个问题

@Trace@Tags({@Tag(key = "getCatelog2JSON",value = "returnedObj"),@Tag(key = "param",value = "arg[0]")})

key:方法名 value = returnedObj:是指定返回值

arg[0]:参数

重启测试

image.png

六、集成日志框架

  将微服务的日志框架去集成SkyWalking,我们希望在我们微服务中日志中,能够记录当前调用链路的id,然后我们再根据这个id去SkyWalking的前端界面中进行搜索找到对应的调用链路记录。

  因为springboot默认实现的日志框架是logback,这里也就拿logback举例,使得调用链路的id可以显示在控制台,每当请求接口时,控制台就会输出对应的id,拿到id就可以在skywalking客户端去检索对应的链路,比较方便快速的找到。

在微服务中导入maven坐标

<!-- skywalking 日志记录  -->
<dependency><groupId>org.apache.skywalking</groupId><artifactId>apm-toolkit-logback-1.x</artifactId><version>8.5.0</version>
</dependency>

在项目中 resources目录下创建 logback-spring.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<configuration><appender name="console" class="ch.qos.logback.core.ConsoleAppender"><encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"><layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout"><pattern>%d{HH:mm:ss.SSS} [%thread] %-5level logger_name:%logger{36} - [%tid] - message:%msg%n</pattern></layout></encoder></appender><root level="INFO"><appender-ref ref="console" /></root></configuration>

在Skywalking UI的日志菜单中显示日志信息,那么就需要再配置文件中再增加一个日志配置信息

<?xml version="1.0" encoding="UTF-8"?>
<configuration><!--  控制台日志输出的格式中添加tid  --><appender name="console" class="ch.qos.logback.core.ConsoleAppender"><encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"><layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.TraceIdPatternLogbackLayout"><pattern>%d{HH:mm:ss.SSS} [%thread] %-5level logger_name:%logger{36} - [%tid] - message:%msg%n</pattern></layout></encoder></appender><!-- skywalking grpc 日志收集 8.4.0版本开始支持 --><appender name="grpc-log" class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.log.GRPCLogClientAppender"><encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder"><layout class="org.apache.skywalking.apm.toolkit.log.logback.v1.x.mdc.TraceIdMDCPatternLogbackLayout"><Pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%tid] [%thread] %-5level %logger{36} -%msg%n</Pattern></layout></encoder></appender><root level="INFO"><appender-ref ref="console" /><appender-ref ref="grpc-log" /></root></configuration>

前面的部署环境是在windows下,一般实际上我们都是安装在linux服务器上通过docker容器安装,那么这里还需要注意下,需要在前面安装下载出来的 skywalking-agent文件下 ->> conf ->> agent.config文件,添加以下的配置信息即可,server_host的ip换成所在的服务器ip即可

plugin.toolkit.log.grpc.reporter.server_host=${SW_GRPC_LOG_SERVER_HOST:127.0.0.1}
plugin.toolkit.log.grpc.reporter.server_port=${SW_GRPC_LOG_SERVER_PORT:11800}
plugin.toolkit.log.grpc.reporter.max_message_size=${SW_GRPC_LOG_MAX_MESSAGE_SIZE:10485760}
plugin.toolkit.log.grpc.reporter.upstream_timeout=${SW_GRPC_LOG_GRPC_UPSTREAM_TIMEOUT:30}

image.png

七、告警信息&信息推送

  • 在skywalking客户端上,有告警栏目,当我们请求接口时长过长时,会显示对应接口信息,而告警规则是在前面安装的 skywalking-apm-bin\config\alarm-settings.yml 配置文件中,默认响应配置了一些告警规则,比如10分钟内有多少次接口请求超过1s那么就会显示告警信息在页面上,提供用户查看
  • 而页面上看之外,我们也还可能将告警信息通知到我们的项目中,可以通过配置网络钩子,使得告警信息可以通过指定的接口请求返回给我们。webhooks:- http://127.0.0.1:8087/notify 地址就是指定的微服务的请求地址,如果有符合告警规则的请求场景,配置了这个网络钩子指定的接口,那么就会去自动发起请求接口,那么我们指定的接口,就可以用Object做参数,接收告警信息,接着在方法中做相关的信息推送比如发送邮件,短信等提醒推送功能

   @RestController
public class Api Controller {@PostMapping("/notify")public String getCurrentSeckillSessionSkus(@ResponseBody Object obj){System.out.println("obj="+ obj);return "Skywalking warning notify";}

相关文章:

【业务功能109】微服务-springcloud-springboot-Skywalking-链路追踪-监控

Skywalking skywalking是一个apm系统&#xff0c;包含监控&#xff0c;追踪&#xff0c;并拥有故障诊断能力的 分布式系统 一、Skywalking介绍 1.什么是SkyWalking Skywalking是由国内开源爱好者吴晟开源并提交到Apache孵化器的产品&#xff0c;它同时吸收了Zipkin /Pinpoint …...

《向量数据库指南》——AI原生向量数据库Milvus Cloud 2.3架构升级

架构升级 GPU 支持 早在 Milvus 1.x 版本,我们就曾经支持过 GPU,但在 2.x 版本中由于切换成了分布式架构,同时出于对于成本方面的考虑,暂时未加入 GPU 支持。在 Milvus 2.0 发布后的一年多时间里,Milvus 社区对 GPU 的呼声越来越高,再加上 NVIDIA 工程师的大力配合——为…...

Flutter中实现交互式Webview的方法

前言&#xff1a; Flutter是一款强大的跨平台移动应用开发框架&#xff0c;而Webview则是在应用中展示Web内容的重要组件。本文将介绍如何在Flutter应用中实现交互式的Webview&#xff0c;以便为用户提供更加丰富的内容和功能。 1. 引入webview_flutter插件 要在Flutter应用中…...

【Java Web】用Redis优化登陆模块

使用Redis存储验证码 验证码需要频繁访问和封信&#xff0c;对性能要求高&#xff1b;验证码不需要永久保存&#xff0c;通常在很短时间内失效&#xff1b;分布式部署&#xff0c;存在Session共享问题&#xff1b; 使用Redis存储登陆凭证 处理每次请求时&#xff0c;都要查询用…...

华为云云耀云服务器L实例评测|docker私有仓库部署手册

【软件安装版本】【集群安装&#xff08;是&#xff09;&#xff08;否&#xff09;】 版本号 文档编写 文档审核 创建日期 修改日期 1.0 jzg jzg 2023.9.13 一. 部署规划与架构 1. 规划&#xff1a;&#xff08;集群&#xff1a;网络规划&…...

JAVA-3DES对称加解密工具(不依赖第三方库)

import javax.crypto.Cipher; import javax.crypto.spec.SecretKeySpec; import java.nio.charset.StandardCharsets; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException;public class EncryptUtil {// 密钥public static final String ENCR…...

基于Matlab卡尔曼滤波的IMU和GPS组合导航数据融合(附上源码+数据)

本文介绍了如何使用Matlab实现惯性测量单元&#xff08;IMU&#xff09;和全球定位系统&#xff08;GPS&#xff09;组合导航数据融合的卡尔曼滤波算法。通过将IMU和GPS的测量数据进行融合&#xff0c;可以提高导航系统的精度和鲁棒性。我们将详细介绍卡尔曼滤波的原理和实现步…...

net自动排课系统完整源码(适合智慧校园)

目录 1 net自动排课系统完整源码(适合智慧校园) 1.1 后台管理admin 1.1.1 菜单 1.1.2 教学计划 net自动排课系统完整源码(适合智慧校园) 后台管理admin<%@ Page Language="C#" AutoEventWireup="true" CodeBehind=&...

Matlab匿名函数教程

Matlab匿名函数是一种方便、简洁的函数定义方式&#xff0c;可以在不使用函数文件的情况下&#xff0c;直接在命令行或脚本中定义函数。本文将介绍Matlab匿名函数的基本语法和用法。 匿名函数的基本语法如下&#xff1a; function_handle (input_variables) expression其中&…...

【Vue】一文让你进入Vue的大门

Vue简介 官网 ● 英文官网 ● 中文官网 介绍与描述 Vue历史 Vue 是一套用来动态构建用户界面的渐进式JS框架 构建用户界面&#xff1a;把数据通过某种办法变成用户界面 渐进式&#xff1a;Vue可以自底向上逐层的应用&#xff0c;简单应用只需要一个轻量小巧的核心库&#xff0c…...

Linux mmap读/写触发共享文件页生命周期

概述 Linux的mm内存子系统的核心功能就要要管理各种类型的page,确保能高效分配和释放,让物理内存得以最大化使用。初识内存系统往往关注的是page的申请和管理流程,容易忽略page的释放回收流程,其实理解mm中的内存回收和释放也是最核心的机制。 Linux内核为了支持各种场景…...

linux 用户、组操作

一、创建用户并设置密码 #创建用户 duoergun useradd duoergun #设置用户 duoergun 密码 passwd duoergun二、创建组 #创建组 qingdynasty groupadd qingdynasty三、用户添加到组&#xff0c;用户从组删除 #添加用户duoergun到组qingdynasty usermod -aG qingdynasty duoer…...

MySQL报错this is incompatible withsal mode=only full group by处理办法

问题说明 报这个错误是指&#xff0c;在查询分组时展示了非分组字段。举例&#xff1a; select id , user_name from user group by user_name;上述语句查询id和user_name字段&#xff0c;其中user_name进行了分组&#xff0c;id并没有分组&#xff0c;这时候mysql就会报上述…...

Mybatis 动态语言 - mybatis-freemarker

前面我们介绍了Mybatis动态SQL的使用&#xff1b;本篇我们介绍使用mybatis- freemarker动态语言生成动态SQL。 如果您对Mybatis动态SQL不太了解&#xff0c;建议您先进行了解后再阅读本篇&#xff0c;可以参考&#xff1a; Mybatis 动态SQL – 使用if,where标签动态生成条件语…...

软件源码开发,网络中的“摄像头”:运维监控系统

在日常生活中&#xff0c;我们不管是在大街小巷&#xff0c;还是在商场大厦都可以见到一个圆形或是方形带有镜片的“小盒子”&#xff0c;这个“小盒子”就是摄像头&#xff0c;摄像头作为一个能实时录制记录它能照到范围内的视频图像的工具&#xff0c;可以在丢失物品、抓捕坏…...

ping命令

打开运行窗口 首先&#xff0c;我们需要打开运行窗口&#xff0c;可以通过按下WinR组合键打开。然后&#xff0c;在窗口中输入cmd&#xff0c;进入dos命令。 在命令行中输入ping命令 在dos命令行中&#xff0c;我们可以通过输入ping命令来检测网络连接。例如&#xff0c;我们…...

MFC:程序的托盘显示

介绍 关键技术&#xff0c;API函数Shell_NotifyIcon&#xff0c;具体查看msdn吧 实现的主要代码 #define MY_TRAY_ICON_ID (1)/ //其他代码&#xff1a;略BEGIN_MESSAGE_MAP(CTestShowTrayDlg, CDialogEx)//...ON_MESSAGE(WM_MY_TRAY_ICON, &CTestShowTrayDlg::OnMessag…...

AI绘画:StableDiffusion实操教程-斗破苍穹-云韵-婚服(附高清图下载)

大家好&#xff0c;我是小梦&#xff0c;最近一直研究AI绘画。 不久前&#xff0c;我与大家分享了StableDiffusion的全面教程&#xff1a;“AI绘画&#xff1a;Stable Diffusion 终极宝典&#xff1a;从入门到精通 ” 然而&#xff0c;仍有些读者提出&#xff0c;虽然他们已经…...

JS装饰器的介绍

装饰器的基本介绍 装饰器是一种特殊类型的声明&#xff0c;它能够被附加到类声明&#xff0c;方法&#xff0c;访问符&#xff0c;属性或参数上。 装饰器使用expression这种形式&#xff0c;expression求值后必须为一个函数&#xff0c;它会在运行时被调用&#xff0c;被装饰的…...

微信小程序(原生)使用Swiper实现(商品详情)视频和图片轮播(仿京东/淘宝商品详情头部视频+图片轮播)

一、需求 1、如果第一是视频&#xff0c;不进行自动轮播 2、可以手动滑动切换 3、点击播放视频&#xff0c;也可以手动滑动切换 4、视频播放完后&#xff0c;自动轮播 5、视频可以点击暂停和全屏播放二、最终效果 三、源码 播放icon使用了TDesign组件库 1、wxml <swiper c…...

Lombok 的 @Data 注解失效,未生成 getter/setter 方法引发的HTTP 406 错误

HTTP 状态码 406 (Not Acceptable) 和 500 (Internal Server Error) 是两类完全不同的错误&#xff0c;它们的含义、原因和解决方法都有显著区别。以下是详细对比&#xff1a; 1. HTTP 406 (Not Acceptable) 含义&#xff1a; 客户端请求的内容类型与服务器支持的内容类型不匹…...

脑机新手指南(八):OpenBCI_GUI:从环境搭建到数据可视化(下)

一、数据处理与分析实战 &#xff08;一&#xff09;实时滤波与参数调整 基础滤波操作 60Hz 工频滤波&#xff1a;勾选界面右侧 “60Hz” 复选框&#xff0c;可有效抑制电网干扰&#xff08;适用于北美地区&#xff0c;欧洲用户可调整为 50Hz&#xff09;。 平滑处理&…...

Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例

使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件&#xff0c;常用于在两个集合之间进行数据转移&#xff0c;如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model&#xff1a;绑定右侧列表的值&…...

iPhone密码忘记了办?iPhoneUnlocker,iPhone解锁工具Aiseesoft iPhone Unlocker 高级注册版​分享

平时用 iPhone 的时候&#xff0c;难免会碰到解锁的麻烦事。比如密码忘了、人脸识别 / 指纹识别突然不灵&#xff0c;或者买了二手 iPhone 却被原来的 iCloud 账号锁住&#xff0c;这时候就需要靠谱的解锁工具来帮忙了。Aiseesoft iPhone Unlocker 就是专门解决这些问题的软件&…...

为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?

在建筑行业&#xff0c;项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升&#xff0c;传统的管理模式已经难以满足现代工程的需求。过去&#xff0c;许多企业依赖手工记录、口头沟通和分散的信息管理&#xff0c;导致效率低下、成本失控、风险频发。例如&#…...

HTML 列表、表格、表单

1 列表标签 作用&#xff1a;布局内容排列整齐的区域 列表分类&#xff1a;无序列表、有序列表、定义列表。 例如&#xff1a; 1.1 无序列表 标签&#xff1a;ul 嵌套 li&#xff0c;ul是无序列表&#xff0c;li是列表条目。 注意事项&#xff1a; ul 标签里面只能包裹 li…...

在WSL2的Ubuntu镜像中安装Docker

Docker官网链接: https://docs.docker.com/engine/install/ubuntu/ 1、运行以下命令卸载所有冲突的软件包&#xff1a; for pkg in docker.io docker-doc docker-compose docker-compose-v2 podman-docker containerd runc; do sudo apt-get remove $pkg; done2、设置Docker…...

Android 之 kotlin 语言学习笔记三(Kotlin-Java 互操作)

参考官方文档&#xff1a;https://developer.android.google.cn/kotlin/interop?hlzh-cn 一、Java&#xff08;供 Kotlin 使用&#xff09; 1、不得使用硬关键字 不要使用 Kotlin 的任何硬关键字作为方法的名称 或字段。允许使用 Kotlin 的软关键字、修饰符关键字和特殊标识…...

JVM虚拟机:内存结构、垃圾回收、性能优化

1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...

招商蛇口 | 执笔CID,启幕低密生活新境

作为中国城市生长的力量&#xff0c;招商蛇口以“美好生活承载者”为使命&#xff0c;深耕全球111座城市&#xff0c;以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子&#xff0c;招商蛇口始终与城市发展同频共振&#xff0c;以建筑诠释对土地与生活的…...