Eureka实现注册中心

CAP原则又称CAP定理,指的是在一个分布式系统中,Consistency(一致性)、 Availability(可用性)、Partition tolerance(分区容错性),三者不可得兼。它是分布式系统中最核心最重要的理论。

分布式系统的CAP理论:理论首先把分布式系统中的三个特性进行了如下归纳:

l  一致性(C):在分布式系统中的所有数据备份,在同一时刻是否同样的值。(等同于所有节点访问同一份最新的数据副本)

l  可用性(A):在集群中一部分节点故障后,集群整体是否还能响应客户端的读写请求。(对数据更新具备高可用性)

l  分区容错性(P):以实际效果而言,分区相当于对通信的时限要求。系统如果不能在时限内达成数据一致性,就意味着发生了分区的情况,必须就当前操作在C和A之间做出选择。

 

ZooKeeper和Eureka对比

ZooKeeper基于CP,不保证高可用,如果zookeeper正在选主,或者Zookeeper集群中半数以上机器不可用,那么将无法获得数据。Eureka基于AP,能保证高可用,即使所有机器都挂了,也能拿到本地缓存的数据。作为注册中心,其实配置是不经常变动的,只有发版(发布新的版本)和机器出故障时会变。对于不经常变动的配置来说,CP是不合适的,而AP在遇到问题时可以用牺牲一致性来保证可用性,既返回旧数据,缓存数据。

所以理论上Eureka是更适合作注册中心。而现实环境中大部分项目可能会使用ZooKeeper,那是因为集群不够大,并且基本不会遇到用做注册中心的机器一半以上都挂了的情况。所以实际上也没什么大问题。

 

Eureka部署服务端、提供端、消费端(消费者整合负载均衡Ribbon,提供方整合Mybaits)

服务端:

搭建SpringBoot项目

 

pom.xml

复制代码
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>eureka.server</groupId>
    <artifactId>eureka-server</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.RELEASE</version>
        <relativePath />
    </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>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka-server</artifactId>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Dalston.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>
复制代码

application.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
security:
  basic:
    enabled: true
  user:
    name: user
    password: password123
server:
  port: 8761
eureka:
  client:
    register-with-eureka: false
    fetch-registry: false
    service-url:
      defaultZone: http://user:password123@localhost:8761/eureka
logging:
  level:
    root: INFO

  RunAppEureka.java

1
2
3
4
5
6
7
8
9
10
11
12
13
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
 
@SpringBootApplication
@EnableEurekaServer
public class RunAppEureka {
 
    public static void main(String[] args) {
        SpringApplication.run(RunAppEureka.class, args);
    }
 
}

  提供方1(加入整合SpringBoot整合Mybatis)

复制代码
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>eureka.provider</groupId>
    <artifactId>eureka-provider</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.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>

        <impala.jdbc.version>2.5.30</impala.jdbc.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.0</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.12</version>
        </dependency>
        <dependency>
            <groupId>com.oracle</groupId>
            <artifactId>ojdbc6</artifactId>
            <version>11.2.0.3</version>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Dalston.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>
复制代码

application.yml

复制代码
server:
  port: 7900
spring:
  application:
    name: provider-user
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: oracle.jdbc.OracleDriver
    url: jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)(HOST=172.24.7.177)(PORT=1521)))(CONNECT_DATA=(SERVICE_NAME=iovdb)))
    username: foton
    password: foton[zk]
mybatis:
  typeAliasesPackage: cn.hz.pojo
  mapperLocations: classpath:mappers/*.xml
eureka:
  client:
    serviceUrl:
      defaultZone: http://user:password123@localhost:8761/eureka
logging:
  level:
    root: INFO
复制代码

ProviderRunApp.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
 
@SpringBootApplication
@EnableEurekaClient
@MapperScan("cn.hz.mapper")
public class ProviderRunApp {
 
    public static void main(String[] args) {
        SpringApplication.run(ProviderRunApp.class, args);
    }
 
}

User.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import java.io.Serializable;
import java.util.Date;
 
import org.springframework.format.annotation.DateTimeFormat;
 
import com.fasterxml.jackson.annotation.JsonFormat;
 
public class User implements Serializable {
    /**
     *
     */
    private static final long serialVersionUID = 8693407369491314806L;
    /*
     * id NUMBER(19) not null, created TIMESTAMP(6), modified TIMESTAMP(6),
     * description VARCHAR2(255 CHAR), name VARCHAR2(255 CHAR),
     * cbm_mag_company_id NUMBER(19), category_id NUMBER(19), cbm_mag_user_id
     * NUMBER(19), layout CLOB
     */
    private Long id;
    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
    @JsonFormat(
            pattern = "yyyy-MM-dd HH:mm:ss"
    )
    private Date created;
    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
    @JsonFormat(
            pattern = "yyyy-MM-dd HH:mm:ss"
    )
    private Date modified;
    private String description;
    private String name;
    private int sort;
    private Long companyId;
    private Long userId;
    private Long parentId;
 
    getter setter。。。
 
    @Override
    public String toString() {
        return "User [id=" + id + ", created=" + created + ", modified=" + modified + ", description=" + description
                + ", name=" + name + ", sort=" + sort + ", companyid=" + companyId + ", userId=" + userId
                + ", parentId=" + parentId + "]";
    }

  

UserMapper.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import java.util.List;
 
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
 
import cn.hz.pojo.User;
 
//注解和xml方式混合
public interface UserMapper {
    //调用xml方式
    public List<User> find();
 
    //调用注解方式
    @Select("select id, created, modified, description, name, sort, cbm_mag_company_id as companyId, parent_id as parentId, cbm_mag_user_id as userId from IOV_DASH_CATEGORY where id=#{id}")
    public User get(@Param("id") Long id);
}

  UserService.java

1
2
3
4
5
6
7
8
9
import java.util.List;
 
import cn.hz.pojo.User;
 
 
public interface UserService {
    public List<User> find();
    public User get(Long id);
}

  UserServiceImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import java.util.List;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
 
import cn.hz.mapper.UserMapper;
import cn.hz.pojo.User;
 
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
 
public List<User> find() {
return userMapper.find();
}
 
public User get(Long id) {
return userMapper.get(id);
}
}

  UserMapper.xml

复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<!-- namespace命名空间,唯一特性 -->
<mapper namespace="cn.hz.mapper.UserMapper">
    <resultMap type="cn.hz.pojo.User" id="user">
       <id column="id" property="id" jdbcType="BIGINT"/>
       <result column="created" property="created" javaType="java.sql.Date"/>
       <result column="modified" property="modified" javaType="java.sql.Date"/>
       <result column="description" property="description" jdbcType="VARCHAR"/>
       <result column="name" property="name" jdbcType="VARCHAR"/>
       <result column="sort" property="sort" jdbcType="INTEGER"/>
       <result column="companyId" property="cbm_mag_company_id" jdbcType="BIGINT"/>
       <result column="userId" property="cbm_mag_user_id" jdbcType="BIGINT"/>
       <result column="parentId" property="parent_id" jdbcType="BIGINT"/>
    </resultMap>
    <select id="find" resultType="user">
        select id, created, modified, description, name, sort, cbm_mag_company_id as companyId, parent_id as parentId, cbm_mag_user_id as userId from IOV_DASH_CATEGORY
    </select>
</mapper>
复制代码

UserController.java (为整合MyBatis测试使用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
 
import cn.hz.pojo.User;
import cn.hz.service.UserService;
 
@RestController
@RequestMapping(value = "/user")
public class UserController {
    @Autowired
    private UserService userSerivce;
 
    @GetMapping("/{name}")
    public String getName(@PathVariable String name) {
        return "hello:" + name;
    }
 
    @GetMapping("/list")
    public String list() {
        return userSerivce.find().toString();
    }
 
    @GetMapping("/get/{id}")
    public String get(@PathVariable Long id) {
        User user = userSerivce.get(id);
        if (null == user)
            return null;
        else
            return userSerivce.get(id).toString();
    }
}  

 

提供方2和提供方1创建基本相同,此处忽略

 

消费者:(整合Ribbon调用不同的提供方)

 

1.1.1    Ribbon

 

Feign是netflix开发的声明式、模板化的http客户端,在使用时就像调用本地(服务消费者自己)的方法一般,帮助我们更加优雅的调用服务提供者的API。Feign自身支持springMVC,还整合了Eureka、Ribbon,极大的简化了Feign的使用。就整合Euraka而言,只需和普通的服务配置Eureka server的信息即可。整合Ribbon,就意味着不再需要通过标注@LoadBalanced的实例化后的RestTemplate去调用服务提供者方法了。Feign只需通过简单的定义一个接口即可实现负载均衡。

 

和nginx不同,它是客户端侧负载均衡。

 

 

 

 

pom.xml

复制代码
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>eureka.client</groupId>
    <artifactId>eureka-client</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.9.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>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-eureka</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>Dalston.SR1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>
复制代码

application.yml

复制代码
server:
  port: 8010
spring:
  application:
    name: consumer-client
eureka:
  client:
    serviceUrl:
      defaultZone: http://user:password123@localhost:8761/eureka
logging:
  level:
    root: INFO
复制代码

ClientRunApp.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.ribbon.RibbonClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
 
@SpringBootApplication
@EnableEurekaClient
@RibbonClient(name="provider-user", configuration=RibbonRuleConfig.class)
public class ClientRunApp {
 
    @Bean
    @LoadBalanced  //Ribbon负载均衡
    public RestTemplate restTemplate() {
        return new RestTemplate();
    }
 
    public static void main(String[] args) {
        SpringApplication.run(ClientRunApp.class, args);
    }
 
}

  RibbonRuleConfig.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.RandomRule;
 
/**
 *
 * 自定义Ribbon配置
 * 规定:这个类不能再@ComponentScan和@SpringBootApplication本包和子包下,否则引起@RibbonClients扫描冲突
 * 注意:随机第一次打断点进入,之后多次刷新就不进入,可能由于本地缓存原因
 */
@Configuration
public class RibbonRuleConfig {
    @Bean
    public IRule ribbonRule(){
        return new RandomRule();
    }
}

  UserController.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
 
@RestController
public class UserController {
    @Autowired
    private RestTemplate restTemplate;
     
      @GetMapping("/user/{id}")
      @ResponseBody
      public String getName(@PathVariable String id) {
          //String url = "http://localhost:7900/user/"+ name;
        //provider-user就是Eureka中提供服务
            String url = "http://provider-user/user/get/"+id;
          return "client:" + this.restTemplate.getForObject(url, String.class);
          //return url;
      }
}

  

 

posted @   蔡徐坤1987  阅读(721)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示