1.使用IP註冊服務java
a) 修改服務提供者和服務消費者的yml配置文件git
eureka: instance: hostname: localhost prefer-ip-address: true #使用IP地址註冊到註冊中心 instance-id: PROVIDER-NAME #註冊到註冊中心的名稱 client: service-url: defaultZone: http://localhost:7001/eureka
b) prefer-ip-address: true 使用IP地址註冊到註冊中心
在訪問Eureka註冊中心的時候,註冊到註冊中心的服務的訪問的IP就不會是127.0.0.1和localhost,而是192.168.xx.xweb
2.服務之間的調用(通訊)算法
a) 創建服務提供者和消費者的公共模塊spring
b) 在消費者和提供者添加對公共服務模塊的依賴json
c) 在服務提供者模塊定義接口(Controller層)bootstrap
d) 在服務消費者定義controller調用服務提供者controller緩存
i. 經過restFul風格SpringMVC提供的遠程調用工具RestTemplete實現,在主配置類裏面配置RestTemplete這個bean交給Spring管理,而後在Controller注入RestTemplete對象.調用服務.安全
3.Eureka集羣:解決單節點故障springboot
a) 修改hosts文件: C:\Windows\System32\drivers\etc\hosts
添加兩個服務註冊的本地IP域名
127.0.0.1 eureka-7001.com
127.0.0.1 eureka-7002.com
b) 修改Eurake配置文件配置
spring: application: name: spring-cloud-eureka server: port: 7001 eureka: instance: hostname: eureka-7001.com client: #不向Eureka註冊本身 register-with-eureka: false #不檢查其餘的EurekaServer節點 fetch-registry: false service-url: #設置eureka服務器所在的地址,查詢服務和註冊服務程序都註冊到這個地址(服務暴露的地址) defaultZone: http://eureka-7002.com:7002/eureka/
c) 搭建另外一個註冊中心,修改yml配置文件
spring: application: name: spring-cloud-eureka server: port: 7002 eureka: instance: hostname: eureka-7002.com client: #不向Eureka註冊本身 register-with-eureka: false #不檢查其餘的EurekaServer節點 fetch-registry: false service-url: #設置eureka服務器所在的地址,查詢服務和註冊服務程序都註冊到這個地址(服務暴露的地址) defaultZone: http://eureka-7001.com:7001/eureka/
d) 修改客戶端註冊到Eurake的路徑
spring: application: name: SPRING-CLOUD-USER //若是服務提供者作了集羣的時候這裏的name必須相同 server: port: 8001 //服務提供者 eureka: instance: hostname: localhost prefer-ip-address: true #使用IP地址註冊到註冊中心 instance-id: USER-CLIENT// 若是服務提供者作集羣的時候這個instance-id 必定不能相同
client: service-url: #設置eureka服務器所在的地址,查詢服務和註冊服務程序都註冊到這個地址(服務暴露的地址)
#defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/
defaultZone: http://peer1:7001/eureka,http://peer2:7002/eureka //向兩個註冊中心註冊服務
4.負載均衡的實現
負載均衡:下降服務提供者的壓力,對服務提供者作集羣,防止服務崩潰
a) 負載均衡的算法
1)輪詢算法,隨機算法,按照權重,按照響應權重,iphash
b)ribbon實現負載均衡
1)新建了一個公共模塊,服務消費者和提供者在pom裏面依賴這個模塊,用於服務提供者和消費者的調用
a)domain
package cn.itsource.domian; public class Employee { private Long id; private String name; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Employee{" + "id=" + id + ", name='" + name + '\'' + '}'; } public Employee() { } public Employee(Long id, String name) { this.id = id; this.name = name; } }
b)向前臺返回的json數據
package cn.itsource.utils; public class JsonResult { private boolean success = true; private String message; private Object data; // 返回當前對象 public static JsonResult me(){ return new JsonResult(); } public String getMessage() { return message; } public JsonResult setMessage(String message) { this.message = message; return this; } public Object getData() { return data; } public JsonResult setData(Object data) { this.data = data; return this; } public boolean isSuccess() { return success; } public JsonResult setSuccess(boolean success) { this.success = success; return this; } }
2)引入springboot與ribbon集成的jar包
<!--客戶端負載均衡實現 ribbon-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
3)對服務提供者作集羣,對服務者壓力大的作集羣,集羣時必定要修改yml配置文件的instance-id的名字爲不一樣,若是不修改就會將前一個服務覆蓋掉
spring: application: name: SPRING-CLOUD-USER server: port: 8001 //其中的一個yml配置文件 eureka: instance: hostname: localhost prefer-ip-address: true #使用IP地址註冊到註冊中心 instance-id: USER-CLIENT client: service-url: #設置eureka服務器所在的地址,查詢服務和註冊服務程序都註冊到這個地址(服務暴露的地址) # defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ defaultZone: http://peer1:7001/eureka,http://peer2:7002/eureka
spring: application: name: SPRING-CLOUD-USER server: port: 8002 //另外一個yml配置文件 eureka: instance: hostname: localhost prefer-ip-address: true #使用IP地址註冊到註冊中心 instance-id: USER-CLIENT01 client: service-url: #設置eureka服務器所在的地址,查詢服務和註冊服務程序都註冊到這個地址(服務暴露的地址) # defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ defaultZone: http://peer1:7001/eureka,http://peer2:7002/eureka
4)自定義一個配置類配置RestTemplate這個bean交給Spring管理,在這個bean上打上@loadBalanced註解,就賦予了負載均衡的能力了
@Configuration public class RestTemplateConfigBean { @Bean @LoadBalanced //開啓負載均衡器 public RestTemplate restTemplate(){ return new RestTemplate(); } }
5)在消費者調用的時候用服務提供者yml配置文件的服務服務名進行通訊
@RestController public class EmployeeController { @Autowired private RestTemplate restTemplate; @RequestMapping("/consumer/{id}") public JsonResult getEmployee(@PathVariable("id") Long id){ System.out.println("EmployeeController.getEmployee被調用了......"); //調用遠程服務 http請求 String url = "http://SPRING-CLOUD-USER/employee/"+id; //這裏的服務名要與服務提供者的服務名對應上 Employee employee = restTemplate.getForObject(url, Employee.class); return JsonResult.me().setData(employee); } }
6) 總結:微服務之間的通訊是服務消費者經過http協議(即封裝的TCP協議)向服務提供者發送HTTP請求獲取數據
c)feign實現負載均衡:Feign的底層仍是Ribbon,它只是對Ribbon作了封裝
1.前3步和ribbon的步驟同樣,惟一不一樣的就是第2步引入的jar包不一樣
<!--feign的支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
2.在主配置類上打上一個註解@EnableFeignClients就開啓了feign
package cn.itsource; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication @EnableEurekaClient @EnableFeignClients //開啓feign負載均衡的支持 //@ImportResource("RestTemplateConfigBean.class")//可寫可不寫,@SpringBootApplication能夠掃到這個配置類 public class SpringBootApplicationConfig_8088 { public static void main(String[] args) { SpringApplication.run(SpringBootApplicationConfig_8088.class,args); } }
3.定義一個接口client.EmployeeFeignClient:用於消費者調用提供者的接口,在這個接口上面打上@FeignClient(「用戶服務提供者的服務名」)
注意在消費端接口調用服務端接口的方法要與服務提供端的方法如出一轍.
package cn.itsource.client; import cn.itsource.domian.Employee; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; /** * 實現負載均衡的接口,SPRING-CLOUD-USER表示要調用提供者的服務名
*/
@FeignClient(value = "SPRING-CLOUD-USER")
public interface EmployeeFeignClient {
@RequestMapping("/employee/{id}")
Employee getById(@PathVariable("id") Long id); //注意這個方法要與服務提供端控制層的方法如出一轍
}
5.斷路器的實現
a)雪崩現象:其中一個微服務發生故障,其餘調用這個微服務的服務都發生故障,致使整個服務不可用
b)爲了解決這個雪崩現象,咱們可使用斷路器(Hystrix)來實現
c)斷路器的做用:資源隔離,熔斷,服務降級,緩存
a) 資源隔離模式
i. 線程池隔離模式:給定的線程數所有都在使用時,沒有空閒的線程就會對消費者發送的請求進行隔離
ii. 信號量隔離模式:計數器(默認是100個),當型號量達到一百個的時候,就會對消費者發送的請求進行隔離
2.熔斷:屢次請求微服務超時就標記該微服務爲短路狀態,其餘服務不會再調用該短路的服務,咱們一般在yml配置文件裏面開啓熔斷,當服務在yml配置的規定的時間內沒有恢復服務,斷路器就會將該服務標記爲熔斷,之後消費者發送的請求都不會在調用這個服務了
3.降級:爲了保證微服務中主要的服務不出問題,會人爲的關掉(或者是服務死掉的時候)一些可有可無的服務,而後返回一個拖底數據,給用戶一個友好的提示
4.緩存:Hystrix內部會將請求作緩存
d)ribbon實現Hystrix
1.導入Hystrix的包
<!--開啓器短路器的依賴--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
2. 在主配置類打上@EnableCircuitBreaker//開啓Hystrix
@SpringBootApplication @EnableEurekaClient @EnableCircuitBreaker //開啓斷路器 //@ImportResource("RestTemplateConfigBean.class")//可寫可不寫,@SpringBootApplication能夠掃到這個配置類 public class SpringBootApplicationConfig_8080 { public static void main(String[] args) { SpringApplication.run(SpringBootApplicationConfig_8080.class,args); } }
3.在服務消費者的controller層方法上打上 @HystrixCommand(fallBackMethod=」方法名」)註解,而後在Controller添加fallBackMethod=」方法名」這個方法.
@RestController public class EmployeeController { @Autowired private RestTemplate restTemplate; @RequestMapping("/consumer/{id}") @HystrixCommand(fallbackMethod = "getEmployeeFallBack")//託底方法必定要與拖底的方法名對應 public JsonResult getEmployee(@PathVariable("id") Long id){ System.out.println("EmployeeController.getEmployee被調用了......"); //調用遠程服務 http請求 String url = "http://SPRING-CLOUD-USER/employee/"+id; Employee employee = restTemplate.getForObject(url, Employee.class); return JsonResult.me().setData(employee); } public JsonResult getEmployeeFallBack(@PathVariable("id") Long id){//這個參數必須與消費者調用服務提供者方法參數一致 //當該服務提供者出現問題就調用這個拖地方法\ return JsonResult.me().setSuccess(false).setMessage("服務展現不可用,請一下子重試[服務降級]"); } }
e) feign與Hystrix的實現
1.在yml開啓Hystrix的配置
feign: hystrix: enabled: true #開啓熔斷支持,當在規定的時間服務沒有恢復,熔斷器就會將這個服務熔斷,再也不被調用 client: config: remote-service: #服務名,填寫default爲全部服務 connectTimeout: 30000 readTimeout: 30000 hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 30000 #表示,某個沒法調用的服務超過這個時間就會對這個服務開啓熔斷
2.自定義的負載均衡的接口的實現類交給spring管理
@Component public class EmployeeClientHystrixFallback implements EmployeeFeignClient { @Override public Employee getById(Long id) { System.out.println("執行託底數據的方法"); return new Employee(-1L,"託底數據"); } }
3.在feign集成的負載均衡的接口中打了@EnableFeignClients中加上fallback=這個接口的實現類的字節碼對象
/** * 實現負載均衡的接口 */ @FeignClient(value = "SPRING-CLOUD-USER",fallback = EmployeeClientHystrixFallback.class) public interface EmployeeFeignClient { @RequestMapping("/employee/{id}") Employee getById(@PathVariable("id") Long id); }
f)SpringCloud Zuul:服務網關,微服務的入口(網路關卡)
1.做用:實現能夠對請求分發,鑑權,限流.負載均衡
2.導入Zuul集成的jar包
<!--服務網關的支持--> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency>
3.在主配置類上打上@EnableZuulProxy開啓網關
@SpringBootApplication @EnableEurekaClient @EnableZuulProxy public class SpringBootApplicationZuul_6001 { public static void main(String[] args) { SpringApplication.run(SpringBootApplicationZuul_6001.class,args); } }
4.修改yml配置文件,爲了安全,不使用服務名訪問,配置禁止服務名訪問,配置zuul訪問路徑
spring: application: name: ZUUL-SERVER server: port: 6001 eureka: instance: hostname: localhost prefer-ip-address: true #使用IP地址註冊到註冊中心 instance-id: ZUUL-SERVIER client: service-url: #設置eureka服務器所在的地址,查詢服務和註冊服務程序都註冊到這個地址(服務暴露的地址) # defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/ defaultZone: http://peer1:7001/eureka,http://peer2:7002/eureka zuul: ignored-services: '*' routes: SPRING-CLOUD-USER: /employee/**
5.Zuul實現原理:Filter,分爲三個階段:前置過濾,路由過濾器,後置過濾器
package com.example.zuul.filter; import com.alibaba.fastjson.JSON; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import com.netflix.zuul.exception.ZuulException; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.HashMap; @Component //交給Spring管理 public class SpringCloudZuulFilter extends ZuulFilter { @Override public String filterType() { // 登陸校驗,確定是在前置攔截 return "pre"; } @Override public int filterOrder() { // 順序設置爲1 return 1; } @Override public boolean shouldFilter() { // 返回true,表明過濾器生效。 // 獲取請求對象 HttpServletRequest request = RequestContext.getCurrentContext().getRequest(); // 判斷訪問的路徑 if (request.getRequestURI().contains("login")) { return false; //返回false表示要不去調用run方法 } return true; //返回true表示要去調用run方法,表示尚未登陸,須要進行驗證 } // 攔截方法 @Override public Object run() throws ZuulException { // 登陸校驗邏輯。 // 1)獲取Zuul提供的請求上下文對象 RequestContext ctx = RequestContext.getCurrentContext(); // 2) 從上下文中獲取request對象 HttpServletRequest req = ctx.getRequest(); // 3) 從請求中獲取token String token = req.getParameter("access-token"); // 4) 判斷 if (token == null || "".equals(token.trim())) { // 獲取響應對象 HttpServletResponse response = ctx.getResponse(); response.setContentType("text/json;charset=utf-8"); HashMap<String, Object> map = new HashMap(); map.put("success", false); map.put("message", "兄弟你沒有權限"); String string = JSON.toJSONString(map);//json對象轉字符串 try { response.getWriter().write(string);//向頁面作一個響應 } catch (IOException e) { e.printStackTrace(); } // 沒有token,登陸校驗失敗,攔截,阻止放行 ctx.setSendZuulResponse(false); // 返回401狀態碼。也能夠考慮重定向到登陸頁。 ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value()); } // 校驗經過,能夠考慮把用戶信息放入上下文,繼續向後執行 return null; } }
g).SpringCloud分佈式配置中心
1.新建模塊導包config服務端的依賴包
<!--Config服務依賴-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
2.打一個開啓配置服務的標籤(主配置類上)
@SpringBootApplication @EnableEurekaClient @EnableConfigServer public class SpringConfigServer_2000 { public static void main(String[] args) { SpringApplication.run(SpringConfigServer_2000.class,args); } }
3. 在yml配置在GitHub上建立的倉庫地址和GitHub上面的用戶名和密碼(前提是倉庫爲私有的時候),倉庫是共有的就不用配置用戶名和密碼
server: port: 2000 spring: application: name: CONFIG-SERVER #在註冊中心生成的服務的名稱 cloud: config: uri: server: git: username: 1806274414@qq.com password: Lihuibin123456 uri: https://gitee.com/li_hui_bin/springcloud.git #遠程配置中心的倉庫地址 eureka: instance: hostname: localhost prefer-ip-address: true #使用IP地址註冊到註冊中心 instance-id: CONFIG-SERVER client: service-url: defaultZone: http://peer1:7001/eureka,http://peer2:7002/eureka
4.遠程倉庫新建消費者的yml配置文件,遠程倉庫新建的文件名: application-employee-dev.yml
server: port: 8088 spring: application: name: DEPTPROVIDER #在註冊中心生成的服務的名稱 eureka: instance: hostname: localhost prefer-ip-address: true #使用IP地址註冊到註冊中心 instance-id: PROVIDER-NAME01 client: service-url: defaultZone: http://peer1:7001/eureka,http://peer2:7002/eureka feign: hystrix: enabled: true #開啓熔斷支持 client: config: remote-service: #服務名,填寫default爲全部服務 connectTimeout: 30000 readTimeout: 30000 hystrix: command: default: execution: isolation: thread: timeoutInMilliseconds: 30000
5.修改服務消費者的配置文件:將以前的application.yml文件改成bootstrap.yml
a)導入config的客戶端依賴包
<!--config客戶端的支持-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
</dependency>
b)在消費者的bootstrop.yml配置文件中配置遠程配置中心的地址和遠程倉庫的文件.
spring: cloud: config: uri: http://localhost:2000 #遠程倉庫中心去拿消費者的配置文件的訪問地址 name: application-employee profile: dev #注意這裏必定要與遠程倉庫的配置文件對應上
label: master