上文已经完成了一个简单的 浏览器 到 Client 到CSDN端的通路
我们的架构是每个博客网址为一个单独的组件, 这里为了方便直接先用CSDN 那个组件复制下
我这里改成 SDN 修改下 application.properties 端口记得改
eureka.client.serviceUrl.defaultZone=http://localhost:8761/eureka/
spring.application.name=sdn
server.port=8983
下面是TOMCAT 和 eureka server运行的截图
好了 有两个搜索端了,我这里把CSDN SDN 叫做搜索端了 , 下面修改下 Client端 让他能分别调用2个组件
我修改了下github上的配置 把我们新建的serviceID加入进去
我们会回到Client项目的 ClientService 多了个SDN,需要修改下代码,能让程序自动加载多个HOST(这里只是简单介绍,如果搜索端好几个肯定得改进)
@Service public class ClientService {@Autowired RestTemplate restTemplate;@Autowiredprivate EurekaClient discoveryClient;@Value("${serviceIds}")public String serviceIds;public String search(String key,String page) {StringBuffer sb =new StringBuffer();if(serviceIds.contains(",")) {String[] ids = serviceIds.split(",");for(int i=0;i<ids.length;i++) {sb.append(searchDetail(key, page, ids[i]));}}else {sb.append(searchDetail(key, page,serviceIds));}return sb.toString();}public String searchDetail(String key,String page,String serviceId) {HashMap<String, String> map = new HashMap<>();map.put("key", key);map.put("page", page);String str= restTemplate.getForObject(serviceUrl(serviceId)+"/search?key={key}&page={page}",String.class,map);return str;}@BeanRestTemplate restTemplate() {return new RestTemplate();}public String serviceUrl(String serviceId) {InstanceInfo instance = discoveryClient.getNextServerFromEureka(serviceId, false);return instance.getHomePageUrl();} }
因为数据比较多 我把两个搜索端直接改成返回一个字符串了
@RestController public class CsdnController {Gson gson = new Gson();@RequestMapping(value = "/search")public String search(@RequestParam("key") String key, @RequestParam("page") String page) {System.out.println("search");ArrayList<HashMap<String, String>> result;try { // result = SearchUtil.search(key, "blog", page); // return gson.toJson(result);return "i am csdn 1";} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}return null;} }
public class CsdnController {Gson gson = new Gson();@RequestMapping(value = "/search")public String search(@RequestParam("key") String key, @RequestParam("page") String page) {System.out.println("search");ArrayList<HashMap<String, String>> result;try { // result = SearchUtil.search(key, "blog", page); // return gson.toJson(result);return "i am sdn 1";} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}return null;} }
这下有两个端了,搜索时间也延长了2倍, 但万一个端有异常 另外一个端良好 怎么办 这时候就需要断路由 hystrix
在client pom里面导入下
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId></dependency>
POM 代码
<?xml version="1.0" encoding="UTF-8"?> <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>tsearch_web</groupId><artifactId>springtest-client</artifactId><version>0.0.1</version><packaging>jar</packaging><name>springtest-client</name><description>Note Server catch</description><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.1.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><spring-cloud.version>Greenwich.M3</spring-cloud.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-freemarker</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-config</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix</artifactId></dependency></dependencies><dependencyManagement><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>Finchley.RELEASE</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build><repositories><repository><id>spring-milestones</id><name>Spring Milestones</name><url>https://repo.spring.io/milestone</url><snapshots><enabled>false</enabled></snapshots></repository></repositories></project>
修改下application
@EnableEurekaClient
@SpringBootApplication
@EnableCircuitBreaker
public class SpringtestClientApplication {public static void main(String[] args) {SpringApplication.run(SpringtestClientApplication.class, args);}
}
新增个SearchUtil 类
@Component public class SearchUtil { @AutowiredRestTemplate restTemplate;@Autowiredprivate EurekaClient discoveryClient;@HystrixCommand(groupKey = "searchDetail1", commandKey = "searchDetail1",fallbackMethod = "stubMyService")public String searchDetail1(String key, String page, String serviceId) {System.out.println("come="+serviceId);HashMap<String, String> map = new HashMap<>();map.put("key", key);map.put("page", page);String str = restTemplate.getForObject(serviceUrl(serviceId) + "/search?key={key}&page={page}", String.class,map);return str;}@HystrixCommand(groupKey = "searchDetail2", commandKey = "searchDetail2",fallbackMethod = "stubMyService")public String searchDetail2(String key, String page, String serviceId) {System.out.println("come="+serviceId);HashMap<String, String> map = new HashMap<>();map.put("key", key);map.put("page", page);String str = restTemplate.getForObject(serviceUrl(serviceId) + "/search?key={key}&page={page}", String.class,map);return str;}public String stubMyService(String key, String page, String serviceId) {return "error";}@BeanRestTemplate restTemplate() {return new RestTemplate();}public String serviceUrl(String serviceId) {InstanceInfo instance = discoveryClient.getNextServerFromEureka(serviceId, false);return instance.getHomePageUrl();} }
修改下 ClientService
@Service
public class ClientService {@AutowiredSearchUtil sc;@Value("${serviceIds}")public String serviceIds;public String search(String key, String page) {StringBuffer sb = new StringBuffer();if (serviceIds.contains(",")) {String[] ids = serviceIds.split(",");sb.append(sc.searchDetail1(key, page, ids[0]));sb.append(sc.searchDetail2(key, page, ids[1]));}else {sb.append(sc.searchDetail1(key, page, serviceIds));}return sb.toString();}}
不断刷新 浏览器 好像没啥区别
给CSDN的Client加个超载
@RestController public class CsdnController {Gson gson = new Gson();@RequestMapping(value = "/search")public String search(@RequestParam("key") String key, @RequestParam("page") String page) {System.out.println("search");ArrayList<HashMap<String, String>> result;try { // result = SearchUtil.search(key, "blog", page); // return gson.toJson(result);Thread.sleep(5000);return "i am csdn 1";} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}return null;} }
继续刷新
然后看下控制台 不是说好的垄断吗 为啥 还是进来了 虽然时间减少了
用Hystrix的时候要注意一点 Hystrix的 超时时间一点要大于resttemplete 或者你用 ribbon
Hystrix 的默认值全在 com.netflix.hystrix.HystrixCommandProperties
这个就是出错次数 private static final Integer default_circuitBreakerRequestVolumeThreshold = 20;// default => statisticalWindowVolumeThreshold: 20 requests in 10 seconds must occur before statistics matter
我们改下 SearchUtil
@Component public class SearchUtil { @AutowiredRestTemplate restTemplate;@Autowiredprivate EurekaClient discoveryClient;@HystrixCommand(groupKey = "searchDetail1", commandKey = "searchDetail1",fallbackMethod = "stubMyService",commandProperties = {@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold",value = "5")})public String searchDetail1(String key, String page, String serviceId) {System.out.println("come="+serviceId);HashMap<String, String> map = new HashMap<>();map.put("key", key);map.put("page", page);String str = restTemplate.getForObject(serviceUrl(serviceId) + "/search?key={key}&page={page}", String.class,map);return str;}@HystrixCommand(groupKey = "searchDetail2", commandKey = "searchDetail2",fallbackMethod = "stubMyService")public String searchDetail2(String key, String page, String serviceId) {System.out.println("come="+serviceId);HashMap<String, String> map = new HashMap<>();map.put("key", key);map.put("page", page);String str = restTemplate.getForObject(serviceUrl(serviceId) + "/search?key={key}&page={page}", String.class,map);return str;}public String stubMyService(String key, String page, String serviceId) {return "error";}@BeanRestTemplate restTemplate() {return new RestTemplate();}public String serviceUrl(String serviceId) {InstanceInfo instance = discoveryClient.getNextServerFromEureka(serviceId, false);return instance.getHomePageUrl();} }
重启下 不断刷新浏览器 发现 searchDetail1方法不执行了 好了 垄断完成
我们需要知道组件的当前状态 这时候就需要hystrix的dashbox
POM 中引入
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-hystrix-dashboard</artifactId></dependency>
修改下ClientApplication 加入dashboard注释
@EnableEurekaClient
@SpringBootApplication
@EnableCircuitBreaker
@EnableHystrixDashboard
public class SpringtestClientApplication {public static void main(String[] args) {SpringApplication.run(SpringtestClientApplication.class, args);}@Beanpublic ServletRegistrationBean getServlet() {HystrixMetricsStreamServlet streamServlet = new HystrixMetricsStreamServlet();ServletRegistrationBean registrationBean = new ServletRegistrationBean(streamServlet);registrationBean.setLoadOnStartup(1);registrationBean.addUrlMappings("/hystrix.stream");registrationBean.setName("HystrixMetricsStreamServlet");return registrationBean;}
}
在浏览器输入http://localhost:8881/hystrix 就能看到界面
按上面的填写好 点击Monitor Stream就能进入统计页面
写个函数拼命跑 会发现数字多有变化 鼠标放上去可以看到具体说明
public class TestHystic {public static void main(String[] args) {long time1=System.currentTimeMillis();String b ="";System.out.println(b.length());for(int i=0;i<100;i++) {try {getData();System.out.println("usertime="+(System.currentTimeMillis()-time1));time1=System.currentTimeMillis();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}}}public static void getData() throws Exception {URL serverUrl = new URL("http://localhost:8881/search?key=spring&page=1");HttpURLConnection conn = (HttpURLConnection) serverUrl.openConnection();InputStream in = conn.getInputStream();BufferedReader br =new BufferedReader(new InputStreamReader(in, "UTF-8"));StringBuffer sb= new StringBuffer();String line;while((line=br.readLine())!=null) {sb.append(line);}System.out.println(sb.toString());in.close();} }