SpringCloud与Hystrix断路器
问题
复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免地失败。
服务雪崩
多个微服务之间调用的时候,假设微服务A调用微服务B和微服务C,微服务B和微服务C又调用其它的微服务,这就是所谓的“扇出”。如果扇出的链路上某个微服务的调用响应时间过长或者不可用,对微服务A的调用就会占用越来越多的系统资源,进而引起系统崩溃,所谓的“雪崩效应”.
对于高流量的应用来说,单一的后端依赖可能会导致所有服务器上的所有资源都在几秒钟内饱和。比失败更糟糕的是,这些应用程序还可能导致服务之间的延迟增加,备份队列,线程和其他系统资源紧张,导致整个系统发生更多的级联故障。这些都表示需要对故障和延迟进行隔离和管理,以便单个依赖关系的失败,不能取消整个应用程序或系统。
备注:一般情况对于服务依赖的保护主要有3中解决方案:
- 熔断模式:这种模式主要是参考电路熔断,如果一条线路电压过高,保险丝会熔断,防止火灾。放到我们的系统中,如果某个目标服务调用慢或者有大量超时,此时,熔断该服务的调用,对于后续调用请求,不在继续调用目标服务,直接返回,快速释放资源。如果目标服务情况好转则恢复调用。
- 隔离模式:这种模式就像对系统请求按类型划分成一个个小岛的一样,当某个小岛被火少光了,不会影响到其他的小岛。例如可以对不同类型的请求使用线程池来资源隔离,每种类型的请求互不影响,如果一种类型的请求线程资源耗尽,则对后续的该类型请求直接返回,不再调用后续资源。这种模式使用场景非常多,例如将一个服务拆开,对于重要的服务使用单独服务器来部署,再或者公司最近推广的多中心。
- 限流模式:上述的熔断模式和隔离模式都属于出错后的容错处理机制,而限流模式则可以称为预防模式。限流模式主要是提前对各个类型的请求设置最高的QPS阈值,若高于设置的阈值则对该请求直接返回,不再调用后续资源。这种模式不能解决服务依赖的问题,只能解决系统整体资源分配问题,因为没有被限流的请求依然有可能造成雪崩效应。
Hystrix解决之道
服务降级
Hystrix服务降级,其实就是线程池中单个线程障处理,防止单个线程请求时间太长,导致资源长期被占有而得不到释放,从而导致线程池被快速占用完,导致服务崩溃。
Hystrix能解决如下问题:
1.请求超时降级,线程资源不足降级,降级之后可以返回自定义数据
2.线程池隔离降级,分布式服务可以针对不同的服务使用不同的线程池,从而互不影响
3.自动触发降级与恢复
4.实现请求缓存和请求合并
服务熔断
熔断模式:这种模式主要是参考电路熔断,如果一条线路电压过高,保险丝会熔断,防止火灾。放到我们的系统中,如果某个目标服务调用慢或者有大量超时,此时,熔断该服务的调用,对于后续调用请求,不在继续调用目标服务,直接返回,快速释放资源。如果目标服务情况好转则恢复调用。
服务限流
限流模式主要是提前对各个类型的请求设置最高的QPS阈值,若高于设置的阈值则对该请求直接返回,不再调用后续资源。这种模式不能解决服务依赖的问题,只能解决系统整体资源分配问题,因为没有被限流的请求依然有可能造成雪崩效应。
近实时监控
HystrixCommand和HystrixObservableCommand在执行时,会生成执行结果和运行指标,比如每秒执行的请求数、成功数等,这些监控数据对分析应用系统的状态很有用。使用Hystrix的模块 hystrix-metrics-event-stream ,就可将这些监控的指标信息以 text/event-stream 的格式暴露给外部系统。spring-cloud-starter-hystrix包含该模块,在此基础上,只须为项目添加spring-boot-starter-actuator,就可使用 /hystrix.stream 端点获取Hystrix的监控信息了。
官方资料 https://github.com/Netflix/Hystrix/wiki/How-To-Use#Hello-World
服务熔断
熔断机制是应对雪崩效应的一种微服务链路保护机制。当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回”错误”的响应信息。当检测到该节点微服务调用响应正常后恢复调用链路。在SpringCloud框架里熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况,当失败的调用到一定阈值,缺省是5秒内20次调用失败就会启动熔断机制。熔断机制的注解是@HystrixCommand。
步骤
创建microservicecloud-provider-dept-hystrix-8001
我们需要参考microservicecloud-provider-dept-8001
pom.xml
pom文件修改为这样的
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081 |
<?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"> <parent> <artifactId>microservicecloud</artifactId> <groupId>com.hph.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>microservicecloud-provider-dept-hystrix-8001</artifactId> <dependencies> <!-- hystrix --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> </dependency> <!-- 引入自己定义的api通用包,可以使用Dept部门Entity --> <dependency> <groupId>com.hph.springcloud</groupId> <artifactId>microservicecloud-api</artifactId> <version>${project.version}</version> </dependency> <!-- 将微服务provider侧注册进eureka --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <!-- actuator监控信息完善 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <!-- 修改后立即生效,热部署 --> <dependency> <groupId>org.springframework</groupId> <artifactId>springloaded</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> </dependencies></project> |
application.yml
12345678910111213141516171819202122232425262728293031323334353637 |
server: port: 8001 mybatis: config-location: classpath:mybatis/mybatis.cfg.xml #mybatis所在路径 type-aliases-package: com.hph.springcloud.entities #entity别名类 mapper-locations: - classpath:mybatis/mapper/**/*.xml #mapper映射文件 spring: application: name: microservicecloud-dept datasource: type: com.alibaba.druid.pool.DruidDataSource driver-class-name: org.gjt.mm.mysql.Driver url: jdbc:mysql://192.168.1.110:3306/cloudDB01 username: root password: 123456 dbcp2: min-idle: 5 initial-size: 5 max-total: 5 max-wait-millis: 200 eureka: client: #客户端注册进eureka服务列表内 service-url: defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ instance: instance-id: microservicecloud-dept8001-hystrix #自定义hystrix相关的服务名称信息 prefer-ip-address: true #访问路径可以显示IP地址 info: app.name: hph-microservicecloud company.name: www.hphblog.cn build.artifactId: ${project.artifactId} build.version: ${project.version} |
DeptMapper.xml
123456789101112131415 |
<?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"> <mapper namespace="com.hph.springcloud.dao.DeptDao"> <select id="findById" resultType="Dept" parameterType="Long"> select deptno,dname,db_source from dept where deptno=#{deptno}; </select> <select id="findAll" resultType="Dept"> select deptno,dname,db_source from dept; </select> <insert id="addDept" parameterType="Dept"> INSERT INTO dept(dname,db_source) VALUES(#{dname},DATABASE()); </insert></mapper> |
mybatis.cfg.xml
123456789101112 |
<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <settings> <setting name="cacheEnabled" value="true" /><!-- 二级缓存开启 --> </settings> </configuration> |
修改DeptController
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172 |
package com.hph.springcloud.controller; import org.springframework.beans.factory.annotation.Autowired;import org.springframework.cloud.client.ServiceInstance;import org.springframework.cloud.client.discovery.DiscoveryClient;import org.springframework.web.bind.annotation.*; import com.hph.springcloud.entities.Dept;import com.hph.springcloud.service.DeptService;import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; import java.util.List; @RestControllerpublic class DeptController{ @Autowired private DeptService service = null; @Autowired private DiscoveryClient client; @RequestMapping(value = "/dept/get/{id}", method = RequestMethod.GET) //一旦调用服务方法失败并抛出了错误信息后,会自动调用@HystrixCommand标注好的fallbackMethod调用类中的指定方法 @HystrixCommand(fallbackMethod = "processHystrix_Get") public Dept get(@PathVariable("id") Long id) { Dept dept = this.service.get(id); if (null == dept) { throw new RuntimeException("该ID:" + id + "没有没有对应的信息"); } return dept; } public Dept processHystrix_Get(@PathVariable("id") Long id) { return new Dept().setDeptno(id).setDname("该ID:" + id + "没有没有对应的信息,null--@HystrixCommand") .setDb_source("no this database in MySQL"); } @RequestMapping(value = "/dept/add", method = RequestMethod.POST) public boolean add(@RequestBody Dept dept) { return service.add(dept); } @RequestMapping(value = "/dept/list", method = RequestMethod.GET) public List<Dept> list() { return service.list(); } // @Autowired// private DiscoveryClient client; @RequestMapping(value = "/dept/discovery", method = RequestMethod.GET) public Object discovery() { List<String> list = client.getServices(); System.out.println("**********" + list); List<ServiceInstance> srvList = client.getInstances("MICROSERVICECLOUD-DEPT"); for (ServiceInstance element : srvList) { System.out.println(element.getServiceId() + "\t" + element.getHost() + "\t" + element.getPort() + "\t" + element.getUri()); } return this.client; }} |
修改主启动类DeptProvider8001_Hystrix_App
添加新注解@EnableCircuitBreake
12345678910111213141516171819 |
package com.hph.springcloud; import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;import org.springframework.cloud.client.discovery.EnableDiscoveryClient;import org.springframework.cloud.netflix.eureka.EnableEurekaClient; @SpringBootApplication@EnableEurekaClient //本服务启动后会自动注册进eureka服务中@EnableDiscoveryClient //服务发现@EnableCircuitBreaker//对hystrixR熔断机制的支持public class DeptProvider8001_Hystrix_App{ public static void main(String[] args) { SpringApplication.run(DeptProvider8001_Hystrix_App.class, args); }} |
测试
- 首先启动3个eurekaserver
- 启动微服务microservicecloud-provider-dept-8001
- 启动microservicecloud-consumer-dept-80
- 访问http://localhost/consumer/dept/get/2048
不足
这样写耦合度太高,我们需要对它进行解耦
服务降级
整体资源快不够了,将某些服务先关掉,待渡过难关,再开启回来。服务降级处理是在客户端实现完成的,与服务端没有关系
修改microservicecloud-api 内容
根据已经有的DeptClientService接口新建一个实现FallbackFactory接口的类DeptClientServiceFallbackFactory
1234567891011121314151617181920212223242526272829303132333435363738 |
package com.hph.springcloud.service; import java.util.List; import org.springframework.stereotype.Component;import com.hph.springcloud.entities.Dept;import feign.hystrix.FallbackFactory; @Component//这个注解比较重要不要忘记添加public class DeptClientServiceFallbackFactory implements FallbackFactory<DeptClientService>{ @Override public DeptClientService create(Throwable throwable) { return new DeptClientService() { @Override public Dept get(long id) { return new Dept().setDeptno(id) .setDname("该ID:"+id+"没有没有对应的信息,Consumer客户端提供的降级信息,此刻服务Provider已经关闭") .setDb_source("no this database in MySQL"); } @Override public List<Dept> list() { return null; } @Override public boolean add(Dept dept) { return false; } }; }} |
DeptClientService
12345678910111213141516171819202122 |
package com.hph.springcloud.service; import com.hph.springcloud.entities.Dept;import org.springframework.cloud.netflix.feign.FeignClient;import org.springframework.web.bind.annotation.PathVariable;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod; import java.util.List; @FeignClient(value = "MICROSERVICECLOUD-DEPT",fallbackFactory=DeptClientServiceFallbackFactory.class)public interface DeptClientService { @RequestMapping(value = "/dept/get/{id}",method = RequestMethod.GET) public Dept get(@PathVariable("id") long id); @RequestMapping(value = "/dept/list",method = RequestMethod.GET) public List<Dept> list(); @RequestMapping(value = "/dept/add",method = RequestMethod.POST) public boolean add(Dept dept); } |
我们首先mvn clean一下 然后mvn install一下更新一下Maven中的api包为修改后的包
修改microservicecloud-consumer-dept-feign
application.yml
123456789101112 |
server: port: 80 feign: hystrix: enabled: true eureka: client: register-with-eureka: false service-url: defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/,http://eureka7003.com:7003/eureka/ |
测试
首先启动3个eurekaserver
启动微服务microservicecloud-provider-dept-8001
启动microservicecloud-consumer-dept-80
访问http://localhost/consumer/dept/get/1
5.高并发请求下模拟访问
此时服务端provider已经down了,但是我们做了服务降级处理,让客户端在服务端不可用时也会获得提示信息而不会挂起耗死服务器。这次我们使用的工具时apache的ab -是发送请求的数量 -c是并发数。我们可以看到服务被临时被降级了。
服务监控
除了隔离依赖服务的调用以外,Hystrix还提供了准实时的调用监控(Hystrix Dashboard),Hystrix会持续地记录所有通过Hystrix发起的请求的执行信息,并以统计报表和图形的形式展示给用户,包括每秒执行多少请求多少成功,多少失败等。Netflix通过hystrix-metrics-event-stream项目实现了对以上指标的监控。Spring Cloud也提供了Hystrix Dashboard的整合,对监控内容转化成可视化界面。
microservicecloud-consumer-hystrix-dashboard
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182 |
<?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"> <parent> <artifactId>microservicecloud</artifactId> <groupId>com.hph.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>microservicecloud-provider-dept-hystrix-8001</artifactId> <dependencies> <!-- hystrix --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-hystrix</artifactId> </dependency> <!-- 引入自己定义的api通用包,可以使用Dept部门Entity --> <dependency> <groupId>com.hph.springcloud</groupId> <artifactId>microservicecloud-api</artifactId> <version>${project.version}</version> </dependency> <!-- 将微服务provider侧注册进eureka --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-eureka</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency> <!-- actuator监控信息完善 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-core</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <!-- 修改后立即生效,热部署 --> <dependency> <groupId>org.springframework</groupId> <artifactId>springloaded</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> </dependencies> </project> |
application.ym
12 |
server: port: 9001 |
DeptConsumer_DashBoard_App
123456789101112131415 |
package com.hph.springcloud; import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.cloud.netflix.hystrix.dashboard.EnableHystrixDashboard; @SpringBootApplication@EnableHystrixDashboardpublic class DeptConsumer_DashBoard_App{ public static void main(String[] args) { SpringApplication.run(DeptConsumer_DashBoard_App.class,args); }} |
所有Provider微服务提供类(8001/8002/8003)都需要监控依赖配置
12345 |
<!-- actuator监控信息完善 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> |
测试
启动microservicecloud-consumer-hystrix-dashboard访问http://localhost:9001/hystrix
启动3个eurekaserver
启动microservicecloud-provider-dept-hystrix-8001
访问http://localhost:8001/dept/get/1
访问http://localhost:8001/hystrix.stream
这种访问不是很友好我们可以试一下其他的方法。
将http://localhost:8001/hystrix.stream填入地址栏
如何观察
其中颜色在右上角代表着不同的信息。
实心圆:共有两种含义。它通过颜色的变化代表了实例的健康程度,它的健康度从绿色<黄色<橙色<红色递减。
该实心圆除了颜色的变化之外,它的大小也会根据实例的请求流量发生变化,流量越大该实心圆就越大。所以通过该实心圆的展示,就可以在大量的实例中快速的发现故障实例和高压力实例。
曲线:用来记录2分钟内流量的相对变化,可以通过它来观察到流量的上升和下降趋势。
动态图展示监控 我们用ab模拟访问。
完整代码
Github: https://github.com/bigdataxiaohan/microservicecloud/tree/master/Hystrix
SpringCloud与Hystrix断路器相关推荐
- 【SpringCloud】Hystrix断路器【五】
1. Hystrix理解 1.1 概述 1.2 背景 1.3 雪崩效应常见场景 1.4 雪崩效应应对策略 1.5 初探Hystrix 1.6 Hystrix流程图 2. 构建问题项目 2.2 构建cl ...
- SpringCloud中 Feign结合Hystrix断路器开发。
Feign结合Hystrix断路器开发: 转载于:https://www.cnblogs.com/longdb/p/10468371.html
- 五、Hystrix断路器
Hystrix断路器 概述 分布式系统面临的问题 复杂分布式体系结构中的应用程序有数十个依赖关系,每一个依赖关系在某些时候将不可避免的失败. 服务雪崩 多个微服务之间调用的时候,假如微服务A调用微服务 ...
- Hystrix断路器原理及实现(服务降级、熔断、限流)
Hystrix断路器原理及实现(服务降级.熔断.限流) 分布式系统面临的问题 Hystrix重要概念(面试常考) Hystrix案例 Hystrix 服务提供者 Hystrix 服务消费者 原因与解决 ...
- 微服务——Hystrix断路器(豪猪哥)
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 概述 分布式系统面临的问题 是什么 能干嘛 Hystrix重要概念 服务降级(fallback) 哪些情况会触发降级 服务熔 ...
- SpringCloud07 - Hystrix 断路器
扯淡: 服务与服务之间有业务关联就需要调用,当被调用的服务发生故障(上线后多半是由于网路原因导致连接超时),必然会波及到服务调用者.通俗讲,断路器就是在低层级的服务发生故障时将服务间的连接断开. 个人 ...
- SpringClound——Hystrix断路器
SpringCloud学习资料汇总超级棒的 如上是我在看文章时忽然看到的一个很好的学习SpringCloud的网站 SpringClound--微服务概述--史上最烂 SpringClound--Sp ...
- Hystrix断路器入门1
Hystrix断路器入门1 1.分布式系统面临的问题 复杂分布式体系结构中的应用程序有数十个依赖关系,每个依赖关系在某些时候将不可避免地失败. 服务雪崩 多个微服务之间调用的时候,假设微服务A调用微服 ...
- Spring Cloud构建微服务架构:服务容错保护(Hystrix断路器)【Dalston版】
前言 在前两篇<Spring Cloud构建微服务架构:服务容错保护(Hystrix服务降级)>和<Spring Cloud构建微服务架构:服务容错保护(Hystrix依赖隔离)&g ...
最新文章
- ERR_PTR PTR_ERR IS_ERR ERROR
- 家用笔记本电脑什么牌子好_家用直饮水机什么牌子好 家用直饮水机品牌排名...
- CephFS管理命令
- C++ 中常用数学函数
- 微软 Mozilla高管评Safari Windows版
- VTK:几何对象之OpenVRCylinder
- 向linux内核加入系统调用新老内核比較
- 千难万险 —— goroutine 从生到死(六)
- 日志中的秘密:Windows登录类型
- 《消息队列》函数讲解
- confirm的意思中文翻译_confirm的中文意思
- 为用户提供出游指南,抖音发起“抖音美好打卡地”文旅认证品牌
- android核心系列--1,组件生命周期
- XMPP中文 XEP-0045: 多用户聊天(一)
- 2020年全球锂电池电芯产值将超过3400亿元
- C++刷题知识点总结2
- 爱看小说手机网源码全站带3w数据带采集,ThinkPHP内核小说网站源码带听书等全部插件
- Matlab模拟钢琴识别琴谱GUI
- 振弦传感器不同线制分类
- R语言中如何进行PCA分析?利用ggplot和prcomp绘制基因表达量分析图
热门文章
- log4j记录不同的日志_Spring boot中使用log4j记录日志
- #3120. 「CTS2019 | CTSC2019」珍珠
- Centos-检查文件系统并尝试修复-fsck
- Deploy简单配置记录
- 贪心算法(Greedy Algorithm)
- 【Python】Python中的引用和赋值
- 第三章 续:时间控件(TimePicker)
- C/C++排序算法(6)堆排序
- C语言课后习题(64)
- java一致性hash api_一致性哈希算法学习及JAVA代码实现分析