首页 > 其他分享 >第二章-Nacos服务注册中心

第二章-Nacos服务注册中心

时间:2024-03-14 20:48:23浏览次数:22  
标签:depart Nacos nacos 实例 注册 provider 服务 第二章

第二章 Nacos 服务注册与发现

在上一章中实现了微服务拆分,并且通过HTTP请求(RestTemplate)实现了跨微服务的远程调用,不过这种手动发起HTTP请求的方式存在问题:

@Service
@RequiredArgsConstructor
public class CartServiceImpl extends ServiceImpl<CartMapper, Cart> implements ICartService {

    //private final IItemService itemService;
    private final RestTemplate restTemplate;

    ...

    private void handleCartItems(List<CartVO> vos) {
        // 1.获取商品id
        Set<Long> itemIds = vos.stream().map(CartVO::getItemId).collect(Collectors.toSet());
        // 2.查询商品
        String itemUrl = "http://localhost:8081/items?ids={ids}";
        ResponseEntity<List<ItemDTO>> response = restTemplate.exchange(
                itemUrl,//请求路径
                HttpMethod.GET,//请求方式
                null,//请求实体
                new ParameterizedTypeReference<List<ItemDTO>>() {
                },//响应数据类型
                Map.of("ids", CollUtils.join(itemIds, ","))//请求参数
        );
        List<ItemDTO> items = null;
        if (response.getStatusCode().is2xxSuccessful()) {
            items = response.getBody();
        }
        if (CollUtils.isEmpty(items)) {
            return;
        }
        // 3.转为 id 到 item的map
        Map<Long, ItemDTO> itemMap = items.stream()
								        .collect(Collectors.toMap(ItemDTO::getId, Function.identity()));
        // 4.写入vo
        for (CartVO v : vos) {
            ItemDTO item = itemMap.get(v.getItemId());
            if (item == null) {
                continue;
            }
            v.setNewPrice(item.getPrice());
            v.setStatus(item.getStatus());
            v.setStock(item.getStock());
        }
    }
   ...
}

在查询商品的时候,URL地址是写死的:String itemUrl = "http://localhost:8081/items?ids={ids}

如果商品服务是热点接口,为了应对更高的并发/避免单点故障,进行多实例部署

image-20240105171039026

每一个item-service实例的IP或者端口号是不同的,此时就会出现问题:

  • item-service多实例,服务调用者cart-service如何知道每一个实例的地址?

  • HTTP请求需要指定URL地址,此时服务调用者cart-service到底调用哪一个实例?

  • 如果某一个item-service实例宕机,cart-service仍然在调用怎么办?

  • 并发量过高,item-service临时部署多台,cart-service如何知道最新的实例地址?

为了解决这些问题,必须引入服务注册中心的概念。

注册中心原理

在微服务的远程调用中有两个角色:

  • 服务提供者:item-service
  • 服务调用者:cart-service

在大型微服务项目中,服务提供者的数量会非常多,为了管理这些微服务引入了注册中心。注册中心、服务提供者、服务消费者之间的关系:

image.png | 550

流程如下

  • 服务启动时将自己的服务信息(服务名称、IP、端口号、版本)写入服务注册中心服务注册表中,服务注册表保存了所有的服务

任何一个微服务都可能是调用者/提供者

  • 服务调用者需要调用微服务时,首先在注册中心订阅需要的服务,将服务注册表下载到本地

  • 根据调用的微服务名称在服务注册表中获取对应的服务提供者集合

  • 调用者自身对服务提供者负载均衡,根据调用者本地的负载均衡策略挑选一个实例进行调用

服务提供者实例宕机或启动新实例

  • 服务提供者定期向注册中心发送请求,报告自己的健康状态(心跳请求)

  • 注册中心如果长时间收不到服务提供者的心跳请求,认为该实例宕机,将其从服务注册表中删除

  • 每当服务有新实例启动时,会发送注册请求,信息会被记录在注册中心的服务注册表中。

  • 注册中心的服务注册表变更后,主动通知微服务,更新本地的服务注册表

注册中心产品

目前开源的注册中心有很多,比较常见的有:

  • Eureka:Netflix公司出品,目前集成在Spring Cloud应用中,一般用于Java语言
  • Nacos:Alibaba公司出品,目前被集成在Spring Cloud Alibaba中,一般用于Java语言
  • Consul:HashiCorp公司出品,目前集成在Spring Cloud中,不限制微服务语言

这三种注册中心都遵循Spring Cloud的API规范,在业务开发上没有太大差异,Spring Cloud Alibaba使用的注册中心是Nacos

Nacos简介

Nacos的两个重要功能:服务发现与配置管理

image-20240105171935295 | 650

云原生:微服务 + DevOps + CI/CD + 容器化

Nacos架构:

1561217892717-1418fb9b-7faa-4324-87b9-f1740329f564.jpeg

Nacos client:Java语言编写的客户端

  • sidecar:多语言异构模块,通过这个模块可以让其他语言使用nacos

  • Name Server:命名服务,支持的服务:dns、vip、address-server

  • OpenAPI:客户端(Provider/Consumer)通过API接口就可以访问服务端(Nacos)的 Naming Service(服务发现)和 Config Service(配置管理),客户端和服务端通信协议支持http/dns/udp/tls

  • Consistency Protocol:集群之间的一致性协议,priv-raft(Naming Service)、sync renew、rdbms based(Config Service)

Nacos下载与配置

Windows环境

Nacos官网找到最新稳定版本 ,目前的Spring Cloud Alibaba版本是 2022.0.0.0-RC2,对应的Nacos版本是2.2.1。

image.png

对于2.2.0.1和2.2.1版本,需要修改conf下application.properties文件:

设置其中的nacos.core.auth.plugin.nacos.token.secret.key值(https://nacos.io/docs/v2/guide/user/auth/)

参数名 默认值 启止版本 说明
nacos.core.auth.enabled false 1.2.0 ~ latest 是否开启鉴权功能
nacos.core.auth.system.type nacos 1.2.0 ~ latest 鉴权类型
nacos.core.auth.plugin.nacos.token.secret.key SecretKey012345678901234567890123456789012345678901234567890123456789(2.2.0.1后无默认值) 2.1.0 ~ latest 默认鉴权插件用于生成用户登陆临时accessToken所使用的密钥,使用默认值有安全风险
nacos.core.auth.plugin.nacos.token.expire.seconds 18000 2.1.0 ~ latest 用户登陆临时accessToken的过期时间
nacos.core.auth.enable.userAgentAuthWhite false 1.4.1 ~ latest 是否使用useragent白名单,主要用于适配老版本升级,置为true时有安全风险
nacos.core.auth.server.identity.key serverIdentity(2.2.1后无默认值) 1.4.1 ~ latest 用于替换useragent白名单的身份识别key,使用默认值有安全风险
nacos.core.auth.server.identity.value security(2.2.1后无默认值) 1.4.1 ~ latest 用于替换useragent白名单的身份识别value,使用默认值有安全风险
nacos.core.auth.default.token.secret.key SecretKey012345678901234567890123456789012345678901234567890123456789 1.2.0 ~ 2.0.4 nacos.core.auth.plugin.nacos.token.secret.key
nacos.core.auth.default.token.expire.seconds 18000

修改配置文件:

image.png

启动Nacos:

startup.cmd -m standalone

默认是集群启动,需要指定为单机启动

生态融合

参照Nacos官网-生态融合 -> 服务发现

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>

官网说明的使用方式:

server.port=8081
spring.application.name=nacos-producer
spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
management.endpoints.web.exposure.include=*

要求指定服务名称nacos地址

注册provider

spring:  
  # 微服务名称  
  application:  
    name: depart-provider  
  #nacos注册中心地址  
  cloud:  
    nacos:  
	  discovery:
	      server-addr: 127.0.0.1:8848  
	      username: nacos  
	      password: nacos

在2.2.1版本中,不加username和password会报错:user not found,某些版本加了反而可能会报错

在2.1.0版本中,不需要指定

注册consumer

spring:  
  application:  
    name: depart-consumer  
  cloud:  
    nacos:  
      server-addr: 127.0.0.1:8848  
      username: nacos  
      password: nacos

注册完毕后在nacos控制台 127.0.0.1/nacos 中就可以看到这两个服务

改造案例一:简单consumer、provider

在案例一中,我们进行远程调用使用的是RestTemplate的简单直连方式:

@RestController  
@RequestMapping("/consumer/depart")  
public class DepartController {  
    @Resource  
    private RestTemplate restTemplate;  
  
    public static final String SERVICE_PROVIDER = "http://localhost:8081/provider/depart";  
  
    @PostMapping  
    public ResponseResult<Boolean> saveHandle(@RequestBody Depart depart){  
  
        ResponseResult<Boolean> responseResult = restTemplate.postForObject(SERVICE_PROVIDER, depart,
			         ResponseResult.class);  
        return responseResult;  
    }  
  
    @GetMapping("/{id}")  
    public ResponseResult<Depart> getHandler(@PathVariable Long id){  
        String url = SERVICE_PROVIDER + "/" + id;  
        ResponseResult<Depart> result = restTemplate.getForObject(url, ResponseResult.class, id);  
        return result;  
    }  
    @GetMapping("/list")  
    public ResponseResult<List<Depart>> listHandler(){  
        String url = SERVICE_PROVIDER + "/list";  
        ResponseResult<List<Depart>> result = restTemplate.getForObject(url, ResponseResult.class);  
        return result;  
    }  
}

在调用时使用的地址:public static final String SERVICE_PROVIDER = "http://localhost:8081/provider/depart"

使用微服务方式:

@RestController  
@RequestMapping("/consumer/depart")  
public class DepartController {  
    @Resource  
    private RestTemplate restTemplate;  
  
    //直连方式  
    //public static final String SERVICE_PROVIDER = "http://localhost:8081/provider/depart";  
  
    //微服务方式  
    public static final String SERVICE_PROVIDER = "http://depart-provider/provider/depart";  
  
  
    @PostMapping  
    public ResponseResult<Boolean> saveHandle(@RequestBody Depart depart){  
  
        ResponseResult<Boolean> responseResult = restTemplate.postForObject(SERVICE_PROVIDER, depart, ResponseResult.class);  
        return responseResult;  
    }  
  
    @GetMapping("/{id}")  
    public ResponseResult<Depart> getHandler(@PathVariable Long id){  
        String url = SERVICE_PROVIDER + "/" + id;  
        ResponseResult<Depart> result = restTemplate.getForObject(url, ResponseResult.class, id);  
        return result;  
    }  
    @GetMapping("/list")  
    public ResponseResult<List<Depart>> listHandler(){  
        String url = SERVICE_PROVIDER + "/list";  
        ResponseResult<List<Depart>> result = restTemplate.getForObject(url, ResponseResult.class);  
        return result;  
    }  
}

并且要指明RestTemplate以负载均衡方式调用:

@Configuration  
public class RestTemplateConfig {  
  
    //以负载均衡的方式调用服务  
    @LoadBalanced  
    @Bean    
    public RestTemplate restTemplate(){  
        return new RestTemplate();  
    }  
}

但是这样启动会报错:

java.net.UnknownHostException: depart-provider

因为新版的Spring Cloud不再支持Ribbon了,老版本Spring Cloud默认使用Ribbon做负载均衡,需要增加依赖:

<!--负载均衡-->  
<dependency>  
    <groupId>org.springframework.cloud</groupId>  
    <artifactId>spring-cloud-starter-loadbalancer</artifactId>  
</dependency>

获取服务注册表信息

通过DiscoveryClient获取到服务注册表信息

@Autowired  
private DiscoveryClient discoveryClient;  
  
@GetMapping("/discovery")  
public ResponseResult<List<String>> discoveryHandler(){  
    //获取注册中心所有服务名称  
    List<String> services = discoveryClient.getServices();  
    for (String service : services) {  
        //获取指定服务名称对应的所有服务实例  
        List<ServiceInstance> instances = discoveryClient.getInstances(service);  
        for (ServiceInstance instance : instances) {  
            //获取实例对应的信息  
            HashMap<String, Object> hashMap = new HashMap<>() {{  
                put("serviceName",service);  
                put("serviceID",instance.getServiceId());  
                put("serviceHost",instance.getHost());  
                put("servicePort",instance.getPort());  
                put("serviceURI",instance.getUri());  
            }};  
  
            System.out.println(hashMap);  
        }  
    }  
    return ResponseResult.success(services);  
}

请求得到的服务名称列表:

{

    "code": 200,

    "data": [

        "depart-consumer",

        "depart-provider"

    ],

    "message": null

}

服务对应的实例信息:

{
	serviceHost=192.168.11.1, 
	serviceURI=http://192.168.11.1:8081, 
	servicePort=8081, 
	serviceName=depart-provider, 
	serviceID=depart-provider
}

改造案例二的RestTemplate调用方式

在案例二中,发起远程调用:

    //微服务方式  
    public static final String SERVICE_PROVIDER = "http://depart-provider/provider/depart";  

这种方式是通过RestTemplate自己的负载均衡策略调用,常用的负载均衡算法有:

  • 随机
  • 轮询
  • IP的hash
  • LRU

我们可以根据需要调用服务的名称通过DiscoveryClient获取到对应的服务实例列表,自定义负载均衡策略,获取到URL进行访问

@Autowired  
private DiscoveryClient discoveryClient;  
  
private String getLoadBalancedServerAddress() {  
    List<ServiceInstance> instances = discoveryClient.getInstances("depart-provider");  
    Collections.shuffle(instances);  
    String URL = instances.get(0).getUri().toString() + "/provider/depart";  
    System.out.println(URL);  
    return URL;  
}  
  
  
@PostMapping  
public ResponseResult<Boolean> saveHandle(@RequestBody Depart depart) {  
  
    ResponseResult<Boolean> responseResult = 
			restTemplate.postForObject(getLoadBalancedServerAddress(), depart, ResponseResult.class);  
    return responseResult;  
}  
  
  
@GetMapping("/{id}")  
public ResponseResult<Depart> getHandler(@PathVariable Long id) {  
    String url = getLoadBalancedServerAddress() + "/" + id;  
    ResponseResult<Depart> result = restTemplate.getForObject(url, ResponseResult.class, id);  
    return result;  
}  
  
@GetMapping("/list")  
public ResponseResult<List<Depart>> listHandler() {  
    String url = getLoadBalancedServerAddress() + "/list";  
    ResponseResult<List<Depart>> result = restTemplate.getForObject(url, ResponseResult.class);  
    return result;  
}

注册表缓存

如果此时停止Nacos,consumer还是可以正常访问provider的。

服务启动后,发生调用时会自动从Nacos注册中心下载并缓存注册表到本地。所以,即使Nacos宕机,consumer仍然可以调用provider,只是此时不能有新服务进行注册了,服务缓存中的注册表信息无法更新。

但是如果服务启动后,没有发生调用Nacos就宕机,consumer就获取不到服务注册表信息,自然也无法调用provider

临时实例与持久实例

临时实例和持久实例的存储位置健康检测机制是不同的:

  • 临时实例:默认情况下,仅会注册在Nacos内存,不会持久化到Nacos磁盘,其健康检测机制为Client模式,即Client主动向Server上报健康状态。默认心跳间隔为5秒,在15秒内Server未收到Client心跳,就会将其标记为 不健康 状态;30秒内收到了Client心跳,则重新恢复到 健康 状态,否则将Client从Server端内存清除。

  • 持久实例:服务实例不仅会注册到Nacos内存,也会持久化到Nacos磁盘。健康检测机制为Server模式,Server主动检测Client的健康状态,默认20s检测一次,检测失败后标记为 不健康 状态,但不会被清除,因为这是持久化到磁盘的。

大多数情况下都是临时实例,因为互联网项目存在突发流量暴增的情况,Alibaba是云原生的,可以充分利用云端的弹性,流量下降就清除临时实例。持久实例销毁是很麻烦的。

创建持久实例

默认的实例是临时实例(ephemeral为true),设置为true后尝试重启:

spring:  
  # 微服务名称  
  application:  
    name: depart-provider  
  #nacos注册中心地址  
  cloud:  
    nacos:  
      discovery:  
        server-addr: 127.0.0.1:8848  
        username: nacos  
        password: nacos  
        # 注册为持久实例
        ephemeral: false

重启:

Caused by: com.alibaba.nacos.api.exception.NacosException: 
failed to req API:/nacos/v1/ns/instance after all servers([127.0.0.1:8848]) tried: caused: errCode: 400, errMsg: Current service DEFAULT_GROUP@@depart-provider is ephemeral service, can't register persistent instance. ;

临时实例depart-provider不能被注册为持久实例,因为实例一旦被注册过为临时实例,就不能再次注册为持久实例了。

注册为持久实例:更改spring.application.name

spring:  
  # 微服务名称  
  application:  
    name: depart-provider-persistent  
  #nacos注册中心地址  
  cloud:  
    nacos:  
      discovery:  
        server-addr: 127.0.0.1:8848  
        username: nacos  
        password: nacos  
        ephemeral: false

image.png

此时depart-provider-persistent就被注册为持久实例

注销持久实例

此时是无法删除临时实例和持久实例的:

image.png

停机后:

image.png

临时实例下线,持久实例还是不能删除。

删除持久实例需要参照Nacos官网-OpenAPI指南

请求方式

DELETE

Content-Type:application/x-www-form-urlencoded

请求地址

/nacos/v2/ns/instance

请求Body

参数名 参数类型 是否必填 描述说明
namespaceId String 命名空间Id,默认为public
groupName String 分组名,默认为DEFAULT_GROUP
serviceName String 服务名
ip String IP地址
port int 端口号
clusterName String 集群名称,默认为DEFAULT
healthy boolean 是否只查找健康实例,默认为true
weight double 实例权重,默认为1.0
enabled boolean 是否可用,默认为true
metadata JSON格式String 实例元数据
ephemeral boolean 是否为临时实例

返回值

参数名 参数类型 描述
data boolean 是否执行成功

请求实例

curl -d 'serviceName=test_service' \
  -d 'ip=127.0.0.1' \
  -d 'port=8090' \
  -d 'weight=0.9' \
  -d 'ephemeral=true' \
  -X DELETE 'http://127.0.0.1:8848/nacos/v2/ns/instance'

IP和端口号在Nacos控制台可以看到,ephemeral为false:

curl -d 'serviceName=depart-provider-persistent' \
  -d 'ip=192.168.11.1' \
  -d 'port=8081' \
  -d 'ephemeral=false' \
  -d 'username=nacos' \
  -d 'password=nacos' \
  -X DELETE 'http://127.0.0.1:8848/nacos/v2/ns/instance'
http://localhost:8848/nacos/v2/ns/instance?serviceName=serviceName=depart-provider-persistent&ip=192.168.11.1&port=8081&weight=1&groupName=DEFAULT_GROUP&namespaceId=public&ephemeral=false&clusterName=DEFAULT&username=nacos&password=nacos

外置数据持久化

在启动Nacos时,控制台输出:

Nacos started successfully in stand alone mode. use embedded storage

使用了内嵌的数据库,在nacos/data/derby-data下可以看到。

Nacos官网-单机模式支持mysql中说明,在0.7版本之前,在单机模式时nacos使用嵌入式数据库实现数据的存储,不方便观察数据存储的基本情况。0.7版本增加了支持mysql数据源能力,具体的操作步骤:

  • 1.安装数据库,版本要求:5.6.5+

  • 2.初始化mysql数据库,数据库初始化文件:mysql-schema.sql

  • 3.修改nacos/conf/application.properties文件,增加支持mysql数据源配置(目前只支持mysql),添加mysql数据源的url、用户名和密码。

spring.datasource.platform=mysql

db.num=1
db.url.0=jdbc:mysql://11.162.196.16:3306/nacos_devtest?characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true
db.user=nacos_devtest
db.password=youdontknow

再次以单机模式启动nacos,nacos将所有写入derby的数据都写入了mysql

在Nacos架构图中:

1561217892717-1418fb9b-7faa-4324-87b9-f1740329f564.jpeg

mysql-schema.sql

该sql脚本在nacos\conf\mysql-schema.sql位置。其中只有建表语句,没有创建数据库语句

其中建议数据库名为 nacos_config

运行脚本,创建了12张表。

修改application.properties

修改nacos/conf/application.properties:

image.png

启动nacos

控制台提示:

Nacos started successfully in stand alone mode. use external storage

Nacos集群

Nacos单节点宕机会导致系统故障,创建Nacos集群。

配置Nacos集群

复制nacos文件夹到nacos-cluster,在该文件夹下以集群方式启动nacos。

nacos8849的配置

修改conf/cluster.conf:

#it is ip
#example
192.168.11.1:8849
192.168.11.1:8851
192.168.11.1:8853

注意:此处必须填写真实ip地址,并且端口号必须间隔一个

同时修改conf/application.properties的端口号:

server.port=8849

nacos8851的配置

复制nacos8849文件夹,改名为nacos8851,只需要修改application.properties的端口号

server.port=8851

nacos8853的配置

和上文相同

启动nacos集群

在上文我们的启动是通过命令:startup.cmd -m standalone 因为我们是单机启动,而nacos默认以集群方式启动。

此时我们配置了nacos集群,直接双击启动即可。

Nacos started successfully in cluster mode. use external storage

image.png

连接Nacos集群

修改provider/consumer的application.yml配置文件:

# 微服务名称  
application:  
  name: depart-provider  
#nacos注册中心地址  
cloud:  
  nacos:  
    discovery:  
      server-addr: 127.0.0.1:8851,127.0.0.1:8853  
      username: nacos  
      password: nacos

此时在8851和8853控制台都能看到相同的内容:

image.png

但是这样做实际上是不安全的,nacos节点的地址都暴露给了客户端,可以使用nginx进行反向代理。

Nacos服务隔离

数据模型

Nacos 数据模型 Key 由三元组唯一确定, Namespace默认是空串,公共命名空间(public),分组默认是 DEFAULT_GROUP。

1561217857314-95ab332c-acfb-40b2-957a-aae26c2b5d71.jpeg | 450

Nacos中的服务是由三元组唯一确定的:namespace、group、serviceName。

namespace和group的作用是相同的,用于划分不同的区域范围,隔离服务。不同的是,namespace的范围更大,不同的namespace可以包含相同的group,不同的group可以包含相同的service。

namespace默认是public(空字符串),group默认是DEFAULT_GROUP

服务隔离

服务隔离:微服务只能在同一个三元组之间互相调用

启动三个 02-provider-8081实例,不同的是namespace、group、port:

  • public + DEFAULT_GROUP + 8081
  • public + MY_GROUP + 8082
  • hello + MY_GROUP + 8083

自定义hello命名空间

image.png

配置服务注册的namespace、group

spring:  
  # 微服务名称  
  application:  
    name: depart-provider  
  #nacos注册中心地址  
  cloud:  
    nacos:  
      discovery:  
        server-addr: 127.0.0.1:8848  
        username: nacos  
        password: nacos  
        # 可以在此处配置namespace和group
        namespace:  
        group:

使用行内参数的方式启动3个服务:

  1. 默认启动的就是 public DEFAULT_GROUP 8081

  2. 启动public + MY_GROUP + 8083

-Dserver.port=8083 -Dspring.cloud.nacos.discovery.group=MY_GROUP

 public registering service depart-provider,nacos registry, MY_GROUP depart-provider 192.168.11.1:8083 register finished
  1. 启动hello + MY_GROUP + 8085
-Dserver.port=8085 -Dspring.cloud.nacos.discovery.group=MY_GROUP -Dspring.cloud.nacos.discovery.namespace=hello

hello registering service depart-provider,nacos registry, MY_GROUP depart-provider 192.168.11.1:8085 register finished

虽然不会报错,但是在nacos控制台是看不到这个服务的,需要指定为namespace的ID:

-Dserver.port=8085  
-Dspring.cloud.nacos.discovery.group=MY_GROUP  
-Dspring.cloud.nacos.discovery.namespace=679c3195-e967-47f7-9925-3c1aa6165a03

679c3195-e967-47f7-9925-3c1aa6165a03 registering service depart-provider
nacos registry, MY_GROUP depart-provider 192.168.11.1:8085 register finished

打开控制台就能看到三个provider实例,启动consumer,consumer当前的配置:

# consumer的配置文件
cloud:  
  nacos:  
    server-addr: 127.0.0.1:8848  
    username: nacos  
    password: nacos

consumer进行接口调用,当前的consumer在public DEFAULT_GROUP下,只能调用相同三元组中的服务,也就是8081

标签:depart,Nacos,nacos,实例,注册,provider,服务,第二章
From: https://www.cnblogs.com/euneirophran/p/18073894

相关文章

  • 2024年最新港区Apple ID注册教程
    大家都知道,许多海外应用在国内并不能直接下载,例如,TikTok在国内用不了,对跨境电商和海外社媒营销人员来说,如何有效地接触和利用各个国家或地区的在线资源,尤其是对于海外应用程序的接入是很重要的。不过许多做TikTok跨境电商的卖家会将Apple ID切换到港区,下载香港地区可用的TikT......
  • 第二章投资技术《第五节 背离》
    1.走势晴雨表背离(也叫背驰):背道而驰股价与下方的指标背道而驰2.背离形态2.1顶背离走势上行,指标下行,上涨力度减弱,构成顶背离出现时机:上涨过程达到阶段性新高不破不立:股价创阶段性新高的过程中,没有出现顶背离,下跌趋势就不会确立,就可以一直持股2.2底背离走势下行,指标上行,下......
  • 服务平滑迁移:eureka迁移到nacos。无法注册双中心的问题解决
    迁移的文档:https://www.alibabacloud.com/help/zh/edas/developer-reference/smoothly-migrate-a-spring-cloud-cluster-that-contains-multiple-applications-to-edas其中遇到的问题未配置排除配置项时(exclude={RibbonEurekaAutoConfiguration.class}),ribbonServerList不是......
  • 第二章操作系统进程与线程
    一、进程的概念组成特征    程序的概念:静态的,存放在磁盘内的可执行文件,一系列的指令集合        进程的概念:动态的,程序的执行过程    进程创建时,会被操作系统分配一个唯一的、不重复的编号                进程实体(进程映像)的组成......
  • PING命令 获取的TTL值 注册表位置
    对TTL进行伪装或隐藏是一种网络欺骗技术,通常用于隐匿数据包的传输路径或减少网络攻击的暴露。以下是一种可能的方法和基础技术原理:使用代理服务器:通过设置代理服务器来修改数据包的TTL值,然后再将其发送到目标服务器。代理服务器会在转发数据包时更改TTL的值,使得接收方无......
  • 使用Julia语言展示几何平均值与算数平均值在实际应用中的差别(采用注册计量师考试试题
    理论部分在注册计量师考试中有一道试题,大体内容为:现在有一块砝码在等臂天平上进行测量,第一次测得值是19.6g,调换两边位置后的测得值是19.7g,天平最终测得检测样品的重量为多少? 个别同事可能会将算数平均值作为这个砝码的最终测量值,但实际应当使用几何平均值的方式计算,算数......
  • 第二章投资技术《第四节 让走势画地为牢(分型,笔)》
    1.零部件大大小小的零部件组装一起变成机器股市中,对应到其中就是“关节”-》转折,连接的地方,关节两头的表现形式肯定不一样,甚至是相反的找到关节,分析规律与方式,才能游刃有余2.关节故事里的关节,就是分型指数不再创新高或新低,那么最高或者最低这根k与前后两根k组成了顶分型和底......
  • seata nacos spring cloud
    目录概述实践seata-server所需表seata-server修改配置seata原理问题项目表构建seata配置正常下单order日志product日志account日志库存不足余额不足问题结束概述seata1.8.0版本,针对springcloudalibabafeign应用。实践seata-server所需表建ry-......
  • docker-compose 部署nacos
    version:'3'services:#模拟一个正常的mysql数据库mysql8:image:mysql:5.7restart:alwayscontainer_name:mysqlports:-3306:3306volumes:-./databases/mysql/logs:/var/log/mysql-./databases/mysql/data:/v......
  • 老虎/TiggerRamDisk注册/下载/官网 绕过激活锁,屏幕锁隐藏工具,支持最新iOS17系统
    支持的版本:iOS12.0~17.3支持的型号:iPhone66s、6sp、SE、7、7P、8、8P、XiPadAir2WiFi(A1566)iPadAir24G(A1567)iPadMini4WiFi(A1538)iPadMini44G(A1550)iPad52017WiFi(A1822)iPad520174G(A1823)iPad62018WiFi(A1893)iPad620184G......