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;
}
}

  

最新文章

  1. Java调优知识汇总
  2. sql-按周输出每月的周日期范围
  3. CentOS 安装ftp
  4. 清除SVN获取文件的所有.svn文件夹
  5. Linux下编译安装mysql-5.0.45.tar.gz
  6. Arrays.asList的使用及异常问题
  7. 跨平台的游戏客户端Socket封装,调整
  8. WPF的依赖属性
  9. Apache Maven 入门篇(下)
  10. js数字验证
  11. 身份证识别OCR,开启视频模式扫一扫即可识别身份证信息
  12. JavaScript 经典之一 闭包
  13. .NET自带缓存机制实例
  14. 2017-06-23(chmod whoami chown)
  15. C# 给一个控件去掉焦点
  16. git revert 还有这个坑?
  17. hdoj:2050
  18. jquery 请求返回的几种方式
  19. c# DataTable 序列化json
  20. ASP.NET应用技巧:非托管COM组件的使用

热门文章

  1. 微服务实战系列(四)-注册中心springcloud alibaba nacos
  2. 报错: Failed to establish a new connection: [WinError 10061] 由于目标计算机积极拒绝,无法连接。&#39;))
  3. pandas读取MySql/SqlServer数据
  4. 使用JWT登录生成token
  5. Solr常见异常
  6. LRU Cache &amp; Bloom Filter
  7. macOS使用ABP.vNext Core开发CMS系统(一) 让程序跑起来
  8. Arduino Mega 2560
  9. frp内网穿透
  10. 手把手教你AspNetCore WebApi:数据验证