 服务拆解)
1 服务拆解和治理1.1 服务拆解微服务的核心就是服务拆分,将传统的大项目拆分为多个微型服务(服务或微服务),实现服务之间高内聚(微服务职责单一),低耦合(微服务功能相对独立)的目的(1) 水平(横向)拆分:先搭出拆分框架,比如【公共服务】(比如:common服务,client服务...)可以作为一层,【业务微服务】可以作为一层(2) 垂直(竖向)拆分:在水平拆分的基础上,对某一层继续拆分1.2 服务治理一旦服务做了拆分,各个服务之间就有了隔离,导致无法直接相互调用,而实现服务之间的相互调用就涉及到服务治理,服务治理包含3个角色:注册中心:记录并监控各个微服务实例状态(心跳机制),推送服务变更信息服务提供者:暴露服务接口,供其他微服务调用,当某个提供者有多个实例时,可以利用负载均衡算法,从多实例中选择一个实例提供服务服务消费者:调用其他微服务接口(提供者和消费者可以同时兼顾)2 注册中心(Nacos)它是阿里巴巴的产品,目前已加入SpringCloudAlibaba中本文介绍的是基于Docker部署的Nacos2.1 配置数据库(mysql)新建nacos数据库,nacos数据库中新建下表:/* * Copyright 1999-2018 Alibaba Group Holding Ltd. * * Licensed under the Apache License, Version 2.0 (the License); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an AS IS BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /******************************************/ /* 表名称 config_info */ /******************************************/ CREATE TABLE config_info ( id bigint(20) NOT NULL AUTO_INCREMENT COMMENT id, data_id varchar(255) NOT NULL COMMENT data_id, group_id varchar(128) DEFAULT NULL COMMENT group_id, content longtext NOT NULL COMMENT content, md5 varchar(32) DEFAULT NULL COMMENT md5, gmt_create datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, gmt_modified datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 修改时间, src_user text COMMENT source user, src_ip varchar(50) DEFAULT NULL COMMENT source ip, app_name varchar(128) DEFAULT NULL COMMENT app_name, tenant_id varchar(128) DEFAULT COMMENT 租户字段, c_desc varchar(256) DEFAULT NULL COMMENT configuration description, c_use varchar(64) DEFAULT NULL COMMENT configuration usage, effect varchar(64) DEFAULT NULL COMMENT 配置生效的描述, type varchar(64) DEFAULT NULL COMMENT 配置的类型, c_schema text COMMENT 配置的模式, encrypted_data_key varchar(1024) NOT NULL DEFAULT COMMENT 密钥, PRIMARY KEY (id), UNIQUE KEY uk_configinfo_datagrouptenant (data_id,group_id,tenant_id) ) ENGINEInnoDB DEFAULT CHARSETutf8 COLLATEutf8_bin COMMENTconfig_info; /******************************************/ /* 表名称 config_info_aggr */ /******************************************/ CREATE TABLE config_info_aggr ( id bigint(20) NOT NULL AUTO_INCREMENT COMMENT id, data_id varchar(255) NOT NULL COMMENT data_id, group_id varchar(128) NOT NULL COMMENT group_id, datum_id varchar(255) NOT NULL COMMENT datum_id, content longtext NOT NULL COMMENT 内容, gmt_modified datetime NOT NULL COMMENT 修改时间, app_name varchar(128) DEFAULT NULL COMMENT app_name, tenant_id varchar(128) DEFAULT COMMENT 租户字段, PRIMARY KEY (id), UNIQUE KEY uk_configinfoaggr_datagrouptenantdatum (data_id,group_id,tenant_id,datum_id) ) ENGINEInnoDB DEFAULT CHARSETutf8 COLLATEutf8_bin COMMENT增加租户字段; /******************************************/ /* 表名称 config_info_beta */ /******************************************/ CREATE TABLE config_info_beta ( id bigint(20) NOT NULL AUTO_INCREMENT COMMENT id, data_id varchar(255) NOT NULL COMMENT data_id, group_id varchar(128) NOT NULL COMMENT group_id, app_name varchar(128) DEFAULT NULL COMMENT app_name, content longtext NOT NULL COMMENT content, beta_ips varchar(1024) DEFAULT NULL COMMENT betaIps, md5 varchar(32) DEFAULT NULL COMMENT md5, gmt_create datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, gmt_modified datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 修改时间, src_user text COMMENT source user, src_ip varchar(50) DEFAULT NULL COMMENT source ip, tenant_id varchar(128) DEFAULT COMMENT 租户字段, encrypted_data_key varchar(1024) NOT NULL DEFAULT COMMENT 密钥, PRIMARY KEY (id), UNIQUE KEY uk_configinfobeta_datagrouptenant (data_id,group_id,tenant_id) ) ENGINEInnoDB DEFAULT CHARSETutf8 COLLATEutf8_bin COMMENTconfig_info_beta; /******************************************/ /* 表名称 config_info_tag */ /******************************************/ CREATE TABLE config_info_tag ( id bigint(20) NOT NULL AUTO_INCREMENT COMMENT id, data_id varchar(255) NOT NULL COMMENT data_id, group_id varchar(128) NOT NULL COMMENT group_id, tenant_id varchar(128) DEFAULT COMMENT tenant_id, tag_id varchar(128) NOT NULL COMMENT tag_id, app_name varchar(128) DEFAULT NULL COMMENT app_name, content longtext NOT NULL COMMENT content, md5 varchar(32) DEFAULT NULL COMMENT md5, gmt_create datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, gmt_modified datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 修改时间, src_user text COMMENT source user, src_ip varchar(50) DEFAULT NULL COMMENT source ip, PRIMARY KEY (id), UNIQUE KEY uk_configinfotag_datagrouptenanttag (data_id,group_id,tenant_id,tag_id) ) ENGINEInnoDB DEFAULT CHARSETutf8 COLLATEutf8_bin COMMENTconfig_info_tag; /******************************************/ /* 表名称 config_tags_relation */ /******************************************/ CREATE TABLE config_tags_relation ( id bigint(20) NOT NULL COMMENT id, tag_name varchar(128) NOT NULL COMMENT tag_name, tag_type varchar(64) DEFAULT NULL COMMENT tag_type, data_id varchar(255) NOT NULL COMMENT data_id, group_id varchar(128) NOT NULL COMMENT group_id, tenant_id varchar(128) DEFAULT COMMENT tenant_id, nid bigint(20) NOT NULL AUTO_INCREMENT COMMENT nid, 自增长标识, PRIMARY KEY (nid), UNIQUE KEY uk_configtagrelation_configidtag (id,tag_name,tag_type), KEY idx_tenant_id (tenant_id) ) ENGINEInnoDB DEFAULT CHARSETutf8 COLLATEutf8_bin COMMENTconfig_tag_relation; /******************************************/ /* 表名称 group_capacity */ /******************************************/ CREATE TABLE group_capacity ( id bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 主键ID, group_id varchar(128) NOT NULL DEFAULT COMMENT Group ID空字符表示整个集群, quota int(10) unsigned NOT NULL DEFAULT 0 COMMENT 配额0表示使用默认值, usage int(10) unsigned NOT NULL DEFAULT 0 COMMENT 使用量, max_size int(10) unsigned NOT NULL DEFAULT 0 COMMENT 单个配置大小上限单位为字节0表示使用默认值, max_aggr_count int(10) unsigned NOT NULL DEFAULT 0 COMMENT 聚合子配置最大个数0表示使用默认值, max_aggr_size int(10) unsigned NOT NULL DEFAULT 0 COMMENT 单个聚合数据的子配置大小上限单位为字节0表示使用默认值, max_history_count int(10) unsigned NOT NULL DEFAULT 0 COMMENT 最大变更历史数量, gmt_create datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, gmt_modified datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 修改时间, PRIMARY KEY (id), UNIQUE KEY uk_group_id (group_id) ) ENGINEInnoDB DEFAULT CHARSETutf8 COLLATEutf8_bin COMMENT集群、各Group容量信息表; /******************************************/ /* 表名称 his_config_info */ /******************************************/ CREATE TABLE his_config_info ( id bigint(20) unsigned NOT NULL COMMENT id, nid bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT nid, 自增标识, data_id varchar(255) NOT NULL COMMENT data_id, group_id varchar(128) NOT NULL COMMENT group_id, app_name varchar(128) DEFAULT NULL COMMENT app_name, content longtext NOT NULL COMMENT content, md5 varchar(32) DEFAULT NULL COMMENT md5, gmt_create datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, gmt_modified datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 修改时间, src_user text COMMENT source user, src_ip varchar(50) DEFAULT NULL COMMENT source ip, op_type char(10) DEFAULT NULL COMMENT operation type, tenant_id varchar(128) DEFAULT COMMENT 租户字段, encrypted_data_key varchar(1024) NOT NULL DEFAULT COMMENT 密钥, PRIMARY KEY (nid), KEY idx_gmt_create (gmt_create), KEY idx_gmt_modified (gmt_modified), KEY idx_did (data_id) ) ENGINEInnoDB DEFAULT CHARSETutf8 COLLATEutf8_bin COMMENT多租户改造; /******************************************/ /* 表名称 tenant_capacity */ /******************************************/ CREATE TABLE tenant_capacity ( id bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT 主键ID, tenant_id varchar(128) NOT NULL DEFAULT COMMENT Tenant ID, quota int(10) unsigned NOT NULL DEFAULT 0 COMMENT 配额0表示使用默认值, usage int(10) unsigned NOT NULL DEFAULT 0 COMMENT 使用量, max_size int(10) unsigned NOT NULL DEFAULT 0 COMMENT 单个配置大小上限单位为字节0表示使用默认值, max_aggr_count int(10) unsigned NOT NULL DEFAULT 0 COMMENT 聚合子配置最大个数, max_aggr_size int(10) unsigned NOT NULL DEFAULT 0 COMMENT 单个聚合数据的子配置大小上限单位为字节0表示使用默认值, max_history_count int(10) unsigned NOT NULL DEFAULT 0 COMMENT 最大变更历史数量, gmt_create datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 创建时间, gmt_modified datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 修改时间, PRIMARY KEY (id), UNIQUE KEY uk_tenant_id (tenant_id) ) ENGINEInnoDB DEFAULT CHARSETutf8 COLLATEutf8_bin COMMENT租户容量信息表; CREATE TABLE tenant_info ( id bigint(20) NOT NULL AUTO_INCREMENT COMMENT id, kp varchar(128) NOT NULL COMMENT kp, tenant_id varchar(128) default COMMENT tenant_id, tenant_name varchar(128) default COMMENT tenant_name, tenant_desc varchar(256) DEFAULT NULL COMMENT tenant_desc, create_source varchar(32) DEFAULT NULL COMMENT create_source, gmt_create bigint(20) NOT NULL COMMENT 创建时间, gmt_modified bigint(20) NOT NULL COMMENT 修改时间, PRIMARY KEY (id), UNIQUE KEY uk_tenant_info_kptenantid (kp,tenant_id), KEY idx_tenant_id (tenant_id) ) ENGINEInnoDB DEFAULT CHARSETutf8 COLLATEutf8_bin COMMENTtenant_info; CREATE TABLE users ( username varchar(50) NOT NULL PRIMARY KEY COMMENT username, password varchar(500) NOT NULL COMMENT password, enabled boolean NOT NULL COMMENT enabled ); CREATE TABLE roles ( username varchar(50) NOT NULL COMMENT username, role varchar(50) NOT NULL COMMENT role, UNIQUE INDEX idx_user_role (username ASC, role ASC) USING BTREE ); CREATE TABLE permissions ( role varchar(50) NOT NULL COMMENT role, resource varchar(128) NOT NULL COMMENT resource, action varchar(8) NOT NULL COMMENT action, UNIQUE INDEX uk_role_permission (role,resource,action) USING BTREE );2.2 Docker中部署Nacos2.2.1 拉取Nacos镜像docker pull nacos/nacos-server2.2.2 配置docker-compose.ymlservices: nacos: #如果是集群模式就用nacos1,nacos2,nacos3.... #云服务器内存最低选4G的 image: nacos/nacos-server container_name: nacos_container restart: always #开机自启 ports: - 8848:8848 #界面访问端口 - 9848:9848 #程序使用grpc连接的端口 - 9849:9849 # environment: MODE: standalone #standalone表示单机模式,集群模式用cluster PREFER_HOST_MODE: hostname #支持IP还是域名模式(默认ip),体现在访问地址时地址栏的显示(hostname显示会更简洁一点) #数据库用mysql SPRING_DATASOURCE_PLATFORM: mysql MYSQL_SERVICE_HOST: 123.123.123.123 MYSQL_SERVICE_PORT: 3306 MYSQL_SERVICE_DB_NAME: nacos MYSQL_SERVICE_USER: root MYSQL_SERVICE_PASSWORD: 123456 MYSQL_DB_PARAM: characterEncodingutf8connectTimeout1000socketTimeout3000autoReconnecttrueuseSSLfalseallowPublicKeyRetrievaltrueserverTimezoneAsia/Shanghai # 设置mysql的连接参数 volumes: - /root/docker_nacos/logs:/home/nacos/logs networks: - sunner_network2.2.3 生成nacos容器利用nacos镜像和docker-compose.yml生成nacos容器docker compose up -d3 服务注册服务注册是针对服务提供者的,严格来说不参与微服务之间调用的微服务不需要服务注册,但后期的调用都是统一调用的gatewaygateway再去nacos中查找注册了的服务,因此几乎所有的微服务都要做服务注册,即都得引入discovery依赖3.1 引入依赖父工程依赖管理:!--org.springframework.cloud版本管理-- dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-dependencies/artifactId version2022.0.5/version !--配合下面的import使用,表明此文件是一个pom文件,一次性引入父工程及祖工程的dependencyManagement(只是引入依赖管理,而不会真的引入jar包),这样子工程只需写groupId、artifactId即可,不需要再写版本号了-- typepom/type scopeimport/scope /dependency !--com.alibaba.cloud版本管理-- dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-alibaba-dependencies/artifactId version2023.0.1.3/version !--配合下面的import使用,表明此文件是一个pom文件,一次性引入父工程及祖工程的dependencyManagement(只是引入依赖管理,而不会真的引入jar包),这样子工程只需写groupId、artifactId即可,不需要再写版本号了-- typepom/type scopeimport/scope /dependency子项目引入依赖:!--nacos注册,发现-- dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId /dependency3.2 配置application.yamlspring: application: name: engineering #微服务名称 cloud: nacos: server-addr: 123.123.123.123:88483.3 访问nacos(8848端口)nacos是根据微服务名划分组别,因此即使多个同名的微服务部署在不同地址的服务器上,也会被nacos归为一组,当调用者调用此微服务时,nacos会根据负载均衡算法,从这组微服务中取出一个供调用者去调用4 服务发现和调用(OpenFeign)服务发现和调用是针对服务消费者的,不做OpenFeign调用的微服务无需引入OpenFeign和负载均衡依赖,只需要引入discovery依赖即可如果项目继承了common项目:①因为common引入了OpenFeign依赖,所以common的子项目都得引入OpenFeign依赖②因为common有xxxClient.java,因此common的子项目都得引入负载均衡依赖③common的子项目虽然在①和②步都是要强制引入的,但对于okhttp依赖的引入可以根据此子项目是否去OpenFeign调用,做选择性引入(需要调用就引入,不需要就不引)4.1 引入依赖!--nacos注册,发现-- dependency groupIdcom.alibaba.cloud/groupId artifactIdspring-cloud-starter-alibaba-nacos-discovery/artifactId /dependency !--OpenFeign-- dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-starter-openfeign/artifactId /dependency !--负载均衡,配合OpenFeign使用(从发现的多个目标微服务中,(利用负载均衡算法)选择其中一个微服务去调用)-- dependency groupIdorg.springframework.cloud/groupId artifactIdspring-cloud-starter-loadbalancer/artifactId !--早期用的是Ribbon-- /dependency4.2 通过EnableFeignClients注解,开启OpenFeign功能/** * 启动SpringBoot项目的主入口程序 */ MapperScan({xyz.aboluo.cloud_test.dao}) //dao接口包扫描 EnableFeignClients(xyz.aboluo.cloud_test.client) //配置包扫描,扫描不到的Client不生效,也无法通过Autowired进行注入 SpringBootApplication(scanBasePackages xyz.aboluo.cloud_test) //标记这是一个SpringBoot应用 public class MainApplication { public static void main(String[] args) { ConfigurableApplicationContext iocContext SpringApplication.run(MainApplication.class, args); // Teacher teacher iocContext.getBean(Teacher.class); } }4.3 编写FeignClient注意事项:①FeignClient只会提供从nacos中获取的某个engineering实例的IP地址端口,不会提供项目路径②需要明确注明GetMapping或PostMapping,不要使用RequestMapping③注解PostMapping需要提供项目路径接口路径,拼接后就形成IP地址端口项目路径接口路径/*FeignClient只会提供从nacos中获取的某个engineering实例的IP地址端口,不会提供项目路径*/ FeignClient(value engineering) public interface EngineeringClient { /** * 需要提供项目路径接口路径,拼接后就形成IP地址端口项目路径接口路径 * 需要明确使用GetMappingPostMapping,不要使用RequestMapping */ PostMapping(/engineering/alWindow/queryAlWindow.do) Result queryAlWindow(RequestBody AlWindow alWindow); }4.4 使用FeignClient,实现远程调用RestController RequestMapping(/test) public class EngineeringTestController { Autowired private EngineeringClient engineeringClient; RequestMapping(/callEngineering.do) public Result queryAlWindow(RequestBody AlWindow alWindow) { Result result engineeringClient.queryAlWindow(alWindow); return Result.success(result); } }4.5 OpenFeign连接池OpenFeign最终发起远程调用是通过Client,而每次调用都需要重新创建Client对象进行连接,非常消耗资源,效率低,因此需要用到连接池(可以选择Apache HttpClient或OKHttp)4.5.1 引入依赖(服务消费方引入依赖)!--ok-http连接池,配合OpenFeign时生效-- dependency groupIdio.github.openfeign/groupId artifactIdfeign-okhttp/artifactId /dependency4.5.2 开启连接池功能(服务消费方开启)spring: application: name: cloud_test #微服务名称 cloud: nacos: server-addr: 123.123.123.123:8848 openfeign: okhttp: enabled: true5 服务拆解优化给所有需要提供微服务接口暴露(服务提供者)的方法上增加FeignClient支持的注释,提醒开发者,如果此方法发生改变时,还需要去改变对应的Client5.1 微服务拆解问题假设有3个微服务A、B、C,在B和C中都需要调用A,因此在B和C中都要写一个AClient供B或C的接口调用,并且要在B和C中添加Apojo此时就有2个问题:①重复编写AClient和Apojo②一旦A中的接口或pojo发生变化,B和C中的AClient或Apojo都需要做修改,导致微服务之间的耦合度高5.2 拆解优化的2种思路5.2.1 思路1(一拆三)单体项目拆分为多个服务a、b、c......,每个服务再拆分为3个服务:①pojo服务:向其他微服务提供对象关系映射(ORM)类②client服务:向其他微服务提供调用本服务接口的Client③business服务:放置本服务的业务代码如果a是服务提供者,b、c是服务消费者,此时b和c就需要用到a中的pojo和client,此时只需要在b服务和c服务的pom.xml中引入a_pojo和a_client的依赖(此时b的子项目b_business和c的子项目c_business也同步引入了对应依赖)优点:①解决了重复编写pojo和client的问题 ②因为所有pojo和client都在a中进行维护,解决了高耦合问题5.2.2 思路2(归总)新建一个client项目:①将所有微服务的pojo都写在此项目的pojos文件夹下的对应文件夹里②将所有微服务的Client都写在此项目的clients文件夹里③微服务的pom.xml中引入client的依赖④在服务消费者的启动类上加上EnableFeignClients(xyz.aboluo.client.clients)水平拆分:水平A:公共模块作为一层水平B:业务模块作为一层垂直拆分:在水平拆分的基础上继续拆分公共模块:client模块,common模块.......业务模块:a模块、b模块、c模块......