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

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

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

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

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

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

import java.util.List;

import cn.hz.pojo.User;


public interface UserService {
	public List<User> find();
	public User get(Long id);
}

  UserServiceImpl.java

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测试使用)

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

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

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

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 @ 2019-06-05 15:15  蔡徐坤1987  阅读(720)  评论(0编辑  收藏  举报