ServiceComb_day01

本文深入解析ServiceComb微服务框架,强调其在分布式事务处理上的优势,对比SpringCloud。涵盖快速开发流程,从环境搭建到代码实现,包括负载均衡、限流及熔断机制。通过Provider与Consumer实例演示REST通信模型。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ServiceComb
1.ServiceCombo介绍:
	ServiceCombo是Apache下的一款微服务框架,它的前身是华为云服务引擎(Cloud Service Engine);
ServiceCombo在微服务开发上比起SpringCloud更胜一筹(ServiceCombo提供了分布式事务解决方案);官
网:http://servicecomb.incubator.apache.org/
2.ServiceCombo设计思想:
	ServiceCombo主要由编程模型,运行模型和通信模型组成;由这三者的不同组合来形成完整的ServiceCombo
3.ServiceCombo快速开发脚手架:
	http://start.servicecomb.io/
4.ServiceComb运行模型:(直接使用脚手架生成)
* 负载均衡(LoadBalance): ServiceComb内置基于Ribbon的负载均衡
* 限流(FlowControl): ServiceComb基于Zuul网关实现限流
* 熔断机制(CircuitBroker): 使用熔断机制解决雪崩效应

在这里插入图片描述

ServiceCombo入门Demo–rest通信模型
1.编写公共接口
public interface RestService{
	String satHello(String name);
}

2.编写Provider
2.1编写引导类,在引导类上加@EnableServiceComb注解
@EnableServiceComb		//开启对ServiceCom的支持
@SpringBootApplication
public class ProviderApplication{
    public static void main(String[] args){
        SpringApplication.run(ProviderApplication.class);
    }
}
2.2编写提供者实现类
//将这个类发布到cse注册中心并扫描到spring容器(@Component),schemaId不重复即可
@RestSchema(schemaId = "restServiceImpl")
@RequestMapping("/say")
public class RestServiceImpl implements RestService{
	@GetMapping("/hello")	 //consumer访问provider也是基于rest风格,因此需要请求映射注解
    public String satHello(String name){
		return "Hello " + name;
    }
}
2.3编写microservice.yaml,固定名称
APPLICATION_ID: start.servicecomb.io	#应用名称任意,但是provider和consumer必须保持一致
service_description:
  name: myProvider	#微服务名称,供consumer引用
  version: 0.0.1
servicecomb:
  handler:
    chain:
      Provider: {}
  rest:
    address: 0.0.0.0:8888	#consumer访问provider引用的IP和端口
  service:
    registry:
      address: http://127.0.0.1:30100	#cse注册中心的IP和端口
      autodiscovery: false

3.编写consumer
3.1编写引导类
@EnableServiceComb		//开启对ServiceCom的支持
@SpringBootApplication
public class ConsumerApplication{
    public static void main(String[] args){
        SpringApplication.run(ConsumerApplication.class);
    } 
    @Bean
    public RestTemplate restTemplate(){
    	//org.apache.servicecomb.provider.springmvc.reference.RestTemplateBuilder
    	return RestTemplateBuilder.create();
    }
}
3.2编写provider调用者,注意跟真正Provider的区别
@Service
public class RestServiceInvoker implements RestService{
	@Autowired
	private RestTemplate restTemplate;
	
	public String satHello(String name){
		String providerName = "myProvider";	 //跟service_description.name对应
		//url: cse协议 + 提供者名称 + 提供者的rest访问方式
		String url = "cse://" + providerName + "/say/hello?name=" + name;
    }
}
3.3编写controller
@RestSchema( schemaId = "restController")
@RequestMapping("/test")
public class RestController{
	@Autowired
	private RestServiceInvoker restServiceInvoker;
    
    @ResponseBody	//可以省略
    @GetMapping("/testSay")
    public String sayHello(String name){
        return restServiceInvoker.satHello(name);
    }
}
3.4编写microservice.yaml
APPLICATION_ID: start.servicecomb.io	
service_description:
  name: myConsumer	#微服务名称
  version: 0.0.1
servicecomb:
  handler:
    chain:
      Provider: {}
  rest:
    address: 0.0.0.0:9999	#consumer供浏览器访问的IP端口
  service:
    registry:
      address: http://127.0.0.1:30100	#cse注册中心的IP和端口
      autodiscovery: false
          
测试:
	先打开cse注册中心,双击service-center.exe(在官网下载);
	启动provider,consumer(顺序无所谓,consumer是在真正调用provider时才去注册中心发现服务)
    localhost:9999/test/testSay,在这种模式下,service也可以直接被浏览器访问  

注意:
	1.controller类上也必须使用@RestSchema注解
	2.RestTemplate必须使用ServiceComb提供的实现   
pom.xml
  <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.12.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>1.8</java.version>
    </properties>

    <!--1.实现pom文件导入-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.apache.servicecomb</groupId>
                <artifactId>java-chassis-dependencies</artifactId>
                <version>1.0.0-m2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
	<dependencies>
        <!--hibernate校验规则-->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
        </dependency>

        <!--rest支持-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-rest</artifactId>
        </dependency>

        <!--ServiceComb提供的支持-->
        <dependency>
            <groupId>org.apache.servicecomb</groupId>
            <artifactId>spring-boot-starter-provider</artifactId>
        </dependency>
        <!--springboot与web整合-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!--service-interface-->
        <dependency>
            <groupId>com.baidu</groupId>
            <artifactId>service-interface</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

注意:在install接口工程时,需要先将spring-boot-maven-plugin注释掉,否则install时需要依赖引导类,而接口工程是没有引导类的
<think>我们遇到两个错误:1.`Image.select:Bandpattern'LST_Day_1km'didnotmatchanybands`:说明在数据集中找不到名为'LST_Day_1km'的波段。我们需要检查数据集中的波段名称。2.`geometry.bufferisnotafunction`:说明`geometry`不是一个Geometry对象,可能是一个FeatureCollection或者未定义。另外,用户要求添加质量控制波段(QC_Day和QC_Night)来过滤低质量像元。根据MODIS/061/MOD21C3数据集的文档(在GEE数据目录中可查):-该数据集包含的波段有:'LST_Day_CMG','QC_Day','LST_Night_CMG','QC_Night','Emis_20',...等-注意:月合成产品的温度波段名称是'LST_Day_CMG'和'LST_Night_CMG',而不是'LST_Day_1km'(1km分辨率的日产品才是用1km后缀)因此,我们修正:1.将波段名称改为'LST_Day_CMG'2.同时,我们也可以选择夜间的波段'LST_Night_CMG',但用户问题只要求白天的年平均温度,所以我们先处理白天的。质量控制:根据产品文档,QC_Day波段是一个16位的整数,其中第0-1位表示数据质量:00:高质量(好数据)01:一般质量(其他质量,可能是可用的)10:较差11:数据缺失我们只保留高质量(00)的像素。但注意:月产品已经经过合成,可能每个像元由多个观测合成,所以QC_Day表示的是这个月内该像元的质量情况。我们定义质量掩膜函数:-使用位运算提取最低两位,然后判断是否为0(00)。单位转换:原始值的比例因子为0.02,将开尔文转换为摄氏度:$T(°C)=T(K)\times0.02-273.15$关于`geometry`错误,用户之前定义的geometry是一个点,但后来使用了`.buffer(100000).bounds()`,所以我们需要确保geometry是几何对象(Geometry)。如果用户想使用自己的研究区域,可以导入一个特征集合(FeatureCollection),但我们这里示例中仍然使用点,然后缓存成面。但注意,点对象可以直接使用buffer,而特征集合则需要先转换为几何(比如取几何的并集)。如果用户希望使用自己的研究区域,我们可以通过导入资产等方式。这里我们假设用户已经定义了一个几何区域,为了代码的健壮性,我们可以检查geometry的类型,并确保它是几何对象。修正步骤:1.修改波段名称为'LST_Day_CMG'2.添加QC_Day波段用于掩膜3.定义质量掩膜函数4.在年合成之前,先对每个月的数据进行质量掩膜,然后计算月平均(实际上月数据已经是月平均,但需要掩膜)注意:由于我们使用的是月产品,所以每个月的图像已经是一个月内每天观测的平均值(或插补值)。我们只需在年合成时,对12个月取平均(需要考虑到每个月有效像素的数量,但简单平均可能可行,或者使用加权平均,这里先简单平均)5.由于质量掩膜会去掉部分像素,在计算年平均时,我们只对有效像素进行平均。GEE的`mean()`方法会自动处理NoData(如果某个月没有有效数据,则该像素年平均值也将没有数据)6.处理geometry:我们之前定义的是一个点,所以可以直接使用。但为了避免错误,我们确保geometry是几何对象,并且将点的处理改为使用`ee.Geometry.Point`。另外,我们之前代码中使用的是月数据集的日温度波段,现在改名为'LST_Day_CMG'。同时,我们要选择QC_Day波段,用于质量控制。步骤细化:a.加载数据集时,同时选择'LST_Day_CMG'和'QC_Day'波段。b.定义一个函数,对每个图像应用质量掩膜,并转换单位为摄氏度。c.在计算年平均时,我们先将一年中的月数据集合起来,然后对有效像素求平均(注意:由于使用了掩膜,无效像素会被跳过)。质量掩膜函数:```javascriptvarapplyQaMask=function(image){//获取QC_Day波段varqaDay=image.select('QC_Day');//提取最低两位varqaMask=qaDay.bitwiseAnd(3).eq(0);//00表示最高质量returnimage.updateMask(qaMask);//只保留高质量像元};```然后,在单位转换函数之前先应用质量掩膜。注意:每个月的图像我们应用掩膜,这样每个月只有高质量像元保留下来,然后再进行年平均。由于年合成是对12个月进行平均,所以即使某个月有部分像元被掩膜,平均计算也会基于剩下的月份(如果某个月全被掩膜了,那年平均也会有空白,这是合理的)。修正后的代码:```javascript//步骤1:加载MOD21C3.061数据集,选择需要的波段vardataset=ee.ImageCollection('MODIS/061/MOD21C3').select(['LST_Day_CMG','QC_Day']);//同时选择温度和质量波段//步骤2:定义时间范围和感兴趣区域varstartYear=2001;varendYear=2020;//定义一个点(北京)作为示例区域,并转换为几何区域vargeometry=ee.Geometry.Point([116.41,39.90]);//步骤3:定义质量控制函数varapplyQaMask=function(image){//提取QC_Day波段的最低两位varqa=image.select('QC_Day');varqaMask=qa.bitwiseAnd(3).eq(0);//00表示最高质量returnimage.updateMask(qaMask).select('LST_Day_CMG');//掩膜后只保留温度波段(后续处理需要)};//步骤4:单位转换函数(开尔文转摄氏度)vartoCelsius=function(image){//原始值缩放(比例因子0.02),然后减去273.15varcelsius=image.multiply(0.02).subtract(273.15);returncelsius.rename('LST_Celsius');};//步骤5:计算逐年年平均温度varannualMeans=ee.ImageCollection(ee.List.sequence(startYear,endYear).map(function(year){varstart=ee.Date.fromYMD(year,1,1);varend=start.advance(1,'year');varyearCollection=dataset.filterDate(start,end).map(applyQaMask)//应用质量掩膜.map(toCelsius);//转换为摄氏度//计算年平均:这里对12个月进行平均,如果没有有效数据则忽略varannualMean=yearCollection.mean();returnannualMean.set('year',year);}));//步骤6:可视化参数varvisParams={min:-20,max:40,palette:['blue','yellow','red']};//设置地图中心Map.centerObject(geometry,3);//添加第一年的年平均温度图层Map.addLayer(annualMeans.first(),visParams,'FirstYearMeanTemp(Day)');//步骤7:打印结果print('AnnualMeanTemperatureCollection',annualMeans);//步骤8:导出数据(示例导出2020年数据)//注意:geometry现在是一个点,我们将其转换成一个100km半径的圆,然后获取其边界矩形作为区域varexportRegion=geometry.buffer(100000).bounds();Export.image.toDrive({image:annualMeans.filter(ee.Filter.eq('year',2020)).first(),description:'MOD21C3_2020_AnnualTemp_Day',scale:5000,//5km分辨率region:exportRegion,maxPixels:1e13,fileFormat:'GeoTIFF',formatOptions:{cloudOptimized:true}});```说明:1.质量控制函数中,我们先应用掩膜,然后只保留温度波段(因为质量波段在后续不需要)。2.在单位转换函数中,我们只处理温度波段。3.在年合成时,使用`mean()`方法对12个月进行平均。注意:月产品中每个图像代表一个月,所以我们收集12个月数据后求平均即可得年平均。然而,这种平均没有考虑每个月的天数差异(比如1月31天,2月28天等),但由于月数据已经是月平均,即这个月的日平均温度的平均值,所以直接平均相当于各月等权重,这可能会导致偏差(因为不同月份天数不同)。但月产品已经是对每天观测的平均,所以再对12个月平均实际上就是全年日平均的近似(数学上:年平均温度=全年每天温度的和/365。而月平均温度=该月每天温度的和/该月天数。那么12个月的月平均的简单平均并不等于年平均,因为分母不同)。因此,更精确的做法是根据每月的天数加权平均:$$\text{年平均温度}=\frac{\sum_{i=1}^{12}(\text{月平均温度}_i\times\text{该月的天数})}{\sum_{i=1}^{12}\text{该月的天数}}$$但是,由于我们使用月产品,并不知道每个月内有多少天有效(已经被掩膜的部分),所以严格加权比较复杂。考虑到简单性,我们仍使用简单平均。如果用户要求高精度,则需使用日产品(MOD21A1或MOD21A2)进行加权平均。这里我们遵循月产品的处理惯例,使用简单平均。修正了波段的代码应该可以运行,并且geometry的错误也解决了(因为geometry是Geometry.Point,它有buffer方法)。如果用户想使用自己的区域(例如上传的资产),可以将geometry替换为导入的资产:```javascriptvargeometry=ee.FeatureCollection("用户资产路径").geometry();//或者直接使用特征集合的并集几何//vargeometry=ee.FeatureCollection("用户资产路径").union().geometry();```最后,关于质量控制,我们只使用了最高质量(00)。如果用户想要保留更多数据,可以调整掩膜条件,例如包括01(一般质量)。这可以通过修改掩膜条件来实现:```javascript//保留最高质量和一般质量varqaMask=qa.bitwiseAnd(3).lte(1);//00或01```但注意,一般质量的数据可能受云污染等影响,需要根据研究目的谨慎选择。上述代码已经修正了两个错误并添加了质量控制。如果用户没有其他要求,就可以运行了。相关问题:1.如何根据每月的天数加权计算更精确的年平均温度?2.如何使用夜间地表温度数据?3.如何同时处理白天和夜间的数据并进行对比?4.如何将质量控制扩展到包含一般质量的数据?5.如何处理长时间序列中部分年份数据缺失的问题?</think> ### 修正后的GEE代码解决方案 以下是针对您需求的完整修正代码,解决了波段名称错误和geometry错误,并添加了质量控制(QC)波段: ```javascript // 步骤1: 加载MOD21C3.061数据集并选择所需波段 var dataset = ee.ImageCollection('MODIS/061/MOD21C3') .select(['LST_Day_CMG', 'QC_Day']); // 修正波段名称并添加QC波段 // 步骤2: 定义时间范围和感兴趣区域 var startYear = 2001; var endYear = 2020; var region = ee.Geometry.Point([116.41, 39.90]) // 修正geometry定义 .buffer(100000) // 为点创建缓冲区 .bounds(); // 获取边界框 // 步骤3: 定义质量控制函数 var applyQaMask = function(image) { // 提取QC_Day波段并创建掩膜 var qcDay = image.select('QC_Day'); // QC_Day的含义(16位整数): // 位0-1: 数据质量标志(00=最高质量, 01=一般质量, 10=较差, 11=数据缺失) var qaMask = qcDay.bitwiseAnd(3).eq(0); // 仅保留最高质量数据(00) return image.updateMask(qaMask); // 应用质量掩膜 }; // 步骤4: 单位转换函数 var toCelsius = function(image) { // 原始值缩放因子为0.02: $T(K) = \text{原始值} \times 0.02$ var tempK = image.select('LST_Day_CMG').multiply(0.02); // K→℃转换: $T(℃) = T(K) - 273.15$ var tempC = tempK.subtract(273.15).rename('LST_Celsius'); return image.addBands(tempC); }; // 步骤5: 计算逐年平均温度 var annualMeans = ee.ImageCollection( ee.List.sequence(startYear, endYear).map(function(year) { var start = ee.Date.fromYMD(year, 1, 1); var end = start.advance(1, 'year'); return dataset .filterDate(start, end) .map(applyQaMask) // 应用质量掩膜 .map(toCelsius) // 单位转换 .select('LST_Celsius') // 选择温度波段 .mean() // 计算年平均 .set('year', year); // 设置年份属性 }) ); // 步骤6: 可视化参数 var visParams = { bands: ['LST_Celsius'], min: -20, max: 40, palette: ['blue', 'yellow', 'red'] }; // 步骤7: 地图显示 Map.centerObject(region, 4); Map.addLayer(annualMeans.first(), visParams, '年平均温度(℃)'); // 步骤8: 导出数据(示例导出2020年) Export.image.toDrive({ image: annualMeans.filter(ee.Filter.eq('year', 2020)).first(), description: 'MOD21C3_2020_AnnualTemp', scale: 5600, // MODIS CMG产品实际分辨率为5600米 region: region, maxPixels: 1e13 }); print('年平均值集合', annualMeans); ``` ### 关键修正说明 1. **波段名称修正**: - 原代码使用`'LST_Day_1km'`但实际波段名称为`'LST_Day_CMG'` - 添加质量控制波段`'QC_Day'`用于数据筛选 2. **Geometry处理修正**: - 直接使用`ee.Geometry.Point`创建几何对象 - 使用`.buffer()`方法创建缓冲区后获取边界框 ```javascript var region = ee.Geometry.Point([116.41, 39.90]) .buffer(100000) .bounds(); ``` 3. **质量控制逻辑**: - QC_Day为16位整数,我们使用位操作获取质量标志: $$ \text{质量标志} = \text{QC_Day} \& 3 $$ - 仅保留最高质量数据(质量标志=00) 4. **温度转换公式**: 原始数据值$V$转换为开尔文温度:$T(K) = V \times 0.02$ 开尔文转摄氏度:$T(℃) = T(K) - 273.15$ 5. **分辨率修正**: MOD21C3产品的实际分辨率为0.05度(约5600米),修正导出代码中的`scale`参数 ### 质量标志详细解释[^1] | QC值(二进制) | 含义 | 处理方式 | |--------------|------|----------| | 00 | 最高质量数据 | 保留 | | 01 | 一般质量 | 过滤(可选保留) | | 10 | 较差质量 | 过滤 | | 11 | 数据缺失 | 过滤 | ### 高级扩展建议 若要包含一般质量数据,修改质量掩膜: ```javascript // 保留最高质量和一般质量数据 var qaMask = qcDay.bitwiseAnd(3).lte(1); // 00或01 ``` [^1]: MODIS Land Surface Temperature Quality Control Documentation: https://lpdaac.usgs.gov/products/mod21v061/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值