Spring Cloud微服务开发笔记5——Ribbon负载均衡策略规则定制
上一篇文章单独介绍了Ribbon框架的使用,及其如何实现客户端对服务访问的负载均衡,但只是单独从Ribbon框架实现,没有涉及spring cloud。本文着力介绍Ribbon的负载均衡机制,下一篇文章再在spring中继承Ribbon。
Ribbon负载均衡器
上一篇文章我们已经实现了一个客户端负载均衡请求web服务的示例。
当时,我们留了一个伏笔,其中的负载均衡的规则策略可以定制,那么本文着重研究策略定制这部分内容,其他的ribbon客户端的构建和请求方法请参见上一篇文章。
ribbon的负载均衡的策略规则是独立的,即这部分功能可以独立于时间的客户端构造和请求发送。我们需要做的是,实现一个IRule接口的对象,对象里面当然会有一些需要你去覆盖实现的方法,这些方法中需要用代码实现你定制的服务器选择策略,但不包括实际的网络请求操作。
除了可以自己定制,Ribbon已经为我们设计了几个现成的规则策略,分别对应于多个不同IRule实现类。我们只需要将这些类对象传给负载均衡器ILoadBalancer的chooseServer()就可以了。其中,默认情况下,BaseLoadBalancer会选择轮询各个server的策略方式,叫做RoundRobinRule。源码如下:
public class BaseLoadBalancer extends AbstractLoadBalancer implements
PrimeConnections.PrimeConnectionListener, IClientConfigAware {
private static Logger logger = LoggerFactory
.getLogger(BaseLoadBalancer.class);
private final static IRule DEFAULT_RULE = new RoundRobinRule();
private final static SerialPingStrategy DEFAULT_PING_STRATEGY = new SerialPingStrategy();
private static final String DEFAULT_NAME = "default";
private static final String PREFIX = "LoadBalancer_";
protected IRule rule = DEFAULT_RULE;
protected IPingStrategy pingStrategy = DEFAULT_PING_STRATEGY;
protected IPing ping = null;
@Monitor(name = PREFIX + "AllServerList", type = DataSourceType.INFORMATIONAL)
protected volatile List<Server> allServerList = Collections
.synchronizedList(new ArrayList<Server>());
@Monitor(name = PREFIX + "UpServerList", type = DataSourceType.INFORMATIONAL)
protected volatile List<Server> upServerList = Collections
.synchronizedList(new ArrayList<Server>());
好,先说到这里,我们来实验一下默认的规则策略:
第一步,我们先构建一个负载均衡器,类型BaseLoadBalancer,它是ILoadBalancer的实现类。
负载均衡器,需要配置两样东西:
1、服务地址列表——谁来参选?
2、选择策略规则——怎么选?
第二步,按照服务方的地址端口列表,配置一个Server的List。添加给负载均衡器。
第三步,构造或选择一个IRule实现类,通过ConfigurationMannager来配置【客户端名称】.ribbon.NFLoadBalancerRuleClassName属性,将配置键赋予一个规则类。这里我们不操作,使用默认的。
package com.happybks.invokers;
import java.util.ArrayList;
import java.util.List;
import com.netflix.loadbalancer.BaseLoadBalancer;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.Server;
public class BalancerApplication {
public static void main(String[] args) {
ILoadBalancer balancer=new BaseLoadBalancer();
List<Server> servers = new ArrayList<Server>();
servers.add(new Server("127.0.0.1",8091));
servers.add(new Server("127.0.0.1",8092));
balancer.addServers(servers);
for(int i=0;i<10;i++) {
Server choosedServer = balancer.chooseServer(null);
System.out.println(choosedServer);
}
}
}
默认策略,就用BaseLoadBalancer类默认初始化定义好的,chooseServer方法会为我们选择已有的RoundRobinRule。
(本文出自ochina博主happBKs的博文:https://my.oschina.net/happyBKs/blog/1787825)
源码如下:
private final static IRule DEFAULT_RULE = new RoundRobinRule();
/*
* Get the alive server dedicated to key
*
* @return the dedicated server
*/
public Server chooseServer(Object key) {
if (counter == null) {
counter = createCounter();
}
counter.increment();
if (rule == null) {
return null;
} else {
try {
return rule.choose(key);
} catch (Exception e) {
logger.warn("LoadBalancer [{}]: Error choosing server for key {}", name, key, e);
return null;
}
}
}
我们运行代码:10次选择server的结果打印如下:
16:41:10.754 [main] WARN com.netflix.config.sources.URLConfigurationSource - No URLs will be polled as dynamic configuration sources.
16:41:10.758 [main] INFO com.netflix.config.sources.URLConfigurationSource - To enable URLs as dynamic configuration sources, define System property archaius.configurationSource.additionalUrls or make config.properties available on classpath.
16:41:10.766 [main] INFO com.netflix.config.DynamicPropertyFactory - DynamicPropertyFactory is initialized with configuration sources: com.netflix.config.ConcurrentCompositeConfiguration@75bd9247
16:41:10.818 [main] DEBUG com.netflix.loadbalancer.BaseLoadBalancer - LoadBalancer [default]: clearing server list (SET op)
16:41:10.819 [main] DEBUG com.netflix.loadbalancer.BaseLoadBalancer - LoadBalancer [default]: addServer [127.0.0.1:8091]
16:41:10.819 [main] DEBUG com.netflix.loadbalancer.BaseLoadBalancer - LoadBalancer [default]: addServer [127.0.0.1:8092]
127.0.0.1:8092
127.0.0.1:8091
127.0.0.1:8092
127.0.0.1:8091
127.0.0.1:8092
127.0.0.1:8091
127.0.0.1:8092
127.0.0.1:8091
127.0.0.1:8092
127.0.0.1:8091
关于负载均衡相关的四个配置项
这些配置项的前缀是【客户端名称】.ribbon
The supported properties are listed below and should be prefixed by <clientName>.ribbon.
:
NFLoadBalancerClassName
: should implementILoadBalancer
NFLoadBalancerRuleClassName
: should implementIRule
NFLoadBalancerPingClassName
: should implementIPing
NIWSServerListClassName
: should implementServerList
NIWSServerListFilterClassName
should implementServerListFilter
其中比较重要的是NFLoadBalancerRuleClassName
,我们可以通过这个配置项定制需要的负载均衡规则,可以是ribbon提供的原生的几种规则类,也可以是自己实现的规则类,这些类都实现了IRule接口。
NFLoadBalancerPingClassName
用于配置查看服务器是否存活。
NFLoadBalancerRuleClassName
指定负载均衡器的实现类。当然,可以设置自己实现的负载均衡器。
NIWSServerListClassName
是服务器列表的处理类,用来维护服务器列表的。Ribbon已经实现了动态服务器列表。
NIWSServerListFilterClassName
是服务器的拦截类。
负载均衡的两种配置方法:
一种直接调用ConfigurationManager获取配置实例,然后设置配置属性;一种是在application.yml中配置。
自定义策略规则:
下面我们以一个示例来构建一个自己的负载均衡规则。
示例:构建一个60%的概率选择8091,40%概率选择8092的规则
我们构建一个实现IRule接口的实现类:
package com.happybks.invokers;
import java.util.List;
import java.util.Random;
import com.netflix.loadbalancer.BaseLoadBalancer;
import com.netflix.loadbalancer.ILoadBalancer;
import com.netflix.loadbalancer.IRule;
import com.netflix.loadbalancer.Server;
public class MyProbabilityRandomRule implements IRule {
ILoadBalancer balancer = new BaseLoadBalancer();
@Override
public Server choose(Object key) {
List<Server> allServers = balancer.getAllServers();
Random random = new Random();
final int number = random.nextInt(10);
if (number < 7) {
return findServer(allServers,8091);
}
return findServer(allServers,8092);
}
private Server findServer(List<Server> allServers, int port) {
for (Server server : allServers) {
if (server.getPort() == port) {
return server;
}
}
System.out.println("NULL port="+port);
return null;
}
@Override
public void setLoadBalancer(ILoadBalancer lb) {
this.balancer = lb;
}
@Override
public ILoadBalancer getLoadBalancer() {
return this.balancer;
}
}
客户端的请求程序这里我们还是直接在一个普通的main方法中实现
我们首先需要配置请求服务器列表,这个上篇文章已经介绍过。
之后我们对对应的客户端配置它的ribbon.NFLoadBalancerRuleClassName配置为我们刚才定义的那个实现了IRule的实现类的类名全名,注意:是IRule实现类的全名,一个字符串,不是class。
package com.happybks.invokers;
import com.netflix.client.ClientException;
import com.netflix.client.ClientFactory;
import com.netflix.client.http.HttpRequest;
import com.netflix.client.http.HttpResponse;
import com.netflix.config.ConfigurationManager;
import com.netflix.niws.client.http.RestClient;
public class MyRuleClientApplication {
public static void main(String[] args) throws Exception {
// 1、设置请求的服务器
ConfigurationManager.getConfigInstance().setProperty("happybks-client.ribbon.listOfServers",
"localhost:8091,localhost:8092"); // 1
// 2、 配置规则处理类
//本示例略,先默认使用其默认负载均衡策略规则
ConfigurationManager.getConfigInstance().setProperty("happybks-client.ribbon.NFLoadBalancerRuleClassName",MyProbabilityRandomRule.class.getName());
// 3、获取 REST 请求客户端
RestClient client = (RestClient) ClientFactory.getNamedClient("happybks-client");
// 4、创建请求实例
HttpRequest request = HttpRequest.newBuilder().uri("/carsInfo/onsale").build();
// 5、发 送 10 次请求到服务器中
for (int i = 0; i < 10; i++) {
System.out.println("the "+(i+1)+"th: ");
HttpResponse response = client.executeWithLoadBalancer(request);
String result = response.getEntity(String.class);
System.out.println(result);
}
}
}
响应请求的服务方程序请参见之前的文章,我们不再累述。然后我们看看运行结果:
22:52:27.695 [main] WARN com.netflix.config.sources.URLConfigurationSource - No URLs will be polled as dynamic configuration sources.
22:52:27.701 [main] INFO com.netflix.config.sources.URLConfigurationSource - To enable URLs as dynamic configuration sources, define System property archaius.configurationSource.additionalUrls or make config.properties available on classpath.
22:52:27.834 [main] INFO com.netflix.config.DynamicPropertyFactory - DynamicPropertyFactory is initialized with configuration sources: com.netflix.config.ConcurrentCompositeConfiguration@97e1986
22:52:28.787 [main] INFO com.netflix.http4.ConnectionPoolCleaner - Initializing ConnectionPoolCleaner for NFHttpClient:happybks-client
22:52:28.798 [Connection pool clean up thread] DEBUG com.netflix.http4.ConnectionPoolCleaner - Connection pool clean up started for client happybks-client
22:52:28.799 [Connection pool clean up thread] DEBUG com.netflix.http4.MonitoredConnectionManager - Closing expired connections
22:52:28.799 [Connection pool clean up thread] DEBUG com.netflix.http4.NamedConnectionPool - Closing expired connections
22:52:28.799 [Connection pool clean up thread] DEBUG com.netflix.http4.MonitoredConnectionManager - Closing connections idle longer than 30000 MILLISECONDS
22:52:28.800 [Connection pool clean up thread] DEBUG com.netflix.http4.NamedConnectionPool - Closing connections idle longer than 30000 MILLISECONDS
22:52:29.032 [main] WARN com.netflix.client.ClientFactory - Class com.happybks.invokers.MyProbabilityRandomRule neither implements IClientConfigAware nor provides a constructor with IClientConfig as the parameter. Only default constructor will be used.
22:52:29.035 [main] INFO com.netflix.loadbalancer.BaseLoadBalancer - Client: happybks-client instantiated a LoadBalancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=happybks-client,current list of Servers=[],Load balancer stats=Zone stats: {},Server stats: []}ServerList:null
22:52:29.111 [main] INFO com.netflix.loadbalancer.DynamicServerListLoadBalancer - Using serverListUpdater PollingServerListUpdater
22:52:29.145 [main] WARN com.netflix.client.ClientFactory - Class com.happybks.invokers.MyProbabilityRandomRule neither implements IClientConfigAware nor provides a constructor with IClientConfig as the parameter. Only default constructor will be used.
22:52:29.165 [main] INFO com.netflix.loadbalancer.DynamicServerListLoadBalancer - DynamicServerListLoadBalancer for client happybks-client initialized: DynamicServerListLoadBalancer:{NFLoadBalancer:name=happybks-client,current list of Servers=[localhost:8091, localhost:8092],Load balancer stats=Zone stats: {unknown=[Zone:unknown; Instance count:2; Active connections count: 0; Circuit breaker tripped count: 0; Active connections per server: 0.0;]
},Server stats: [[Server:localhost:8092; Zone:UNKNOWN; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 08:00:00 GMT+08:00 1970; First connection made: Thu Jan 01 08:00:00 GMT+08:00 1970; Active Connections:0; total failure count in last (1000) msecs:0; average resp time:0.0; 90 percentile resp time:0.0; 95 percentile resp time:0.0; min resp time:0.0; max resp time:0.0; stddev resp time:0.0]
, [Server:localhost:8091; Zone:UNKNOWN; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 08:00:00 GMT+08:00 1970; First connection made: Thu Jan 01 08:00:00 GMT+08:00 1970; Active Connections:0; total failure count in last (1000) msecs:0; average resp time:0.0; 90 percentile resp time:0.0; 95 percentile resp time:0.0; min resp time:0.0; max resp time:0.0; stddev resp time:0.0]
]}ServerList:com.netflix.loadbalancer.ConfigurationBasedServerList@152aa092
22:52:29.165 [main] INFO com.netflix.client.ClientFactory - Client: happybks-client instantiated a LoadBalancer: DynamicServerListLoadBalancer:{NFLoadBalancer:name=happybks-client,current list of Servers=[localhost:8091, localhost:8092],Load balancer stats=Zone stats: {unknown=[Zone:unknown; Instance count:2; Active connections count: 0; Circuit breaker tripped count: 0; Active connections per server: 0.0;]
},Server stats: [[Server:localhost:8092; Zone:UNKNOWN; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 08:00:00 GMT+08:00 1970; First connection made: Thu Jan 01 08:00:00 GMT+08:00 1970; Active Connections:0; total failure count in last (1000) msecs:0; average resp time:0.0; 90 percentile resp time:0.0; 95 percentile resp time:0.0; min resp time:0.0; max resp time:0.0; stddev resp time:0.0]
, [Server:localhost:8091; Zone:UNKNOWN; Total Requests:0; Successive connection failure:0; Total blackout seconds:0; Last connection made:Thu Jan 01 08:00:00 GMT+08:00 1970; First connection made: Thu Jan 01 08:00:00 GMT+08:00 1970; Active Connections:0; total failure count in last (1000) msecs:0; average resp time:0.0; 90 percentile resp time:0.0; 95 percentile resp time:0.0; min resp time:0.0; max resp time:0.0; stddev resp time:0.0]
]}ServerList:com.netflix.loadbalancer.ConfigurationBasedServerList@152aa092
22:52:29.167 [main] INFO com.netflix.client.ClientFactory - Client Registered:com.netflix.niws.client.http.RestClient@44a7bfbc
the 1th:
22:52:30.115 [PollingServerListUpdater-0] DEBUG com.netflix.loadbalancer.DynamicServerListLoadBalancer - List of Servers for happybks-client obtained from Discovery client: [localhost:8091, localhost:8092]
22:52:30.115 [PollingServerListUpdater-0] DEBUG com.netflix.loadbalancer.DynamicServerListLoadBalancer - Filtered List of Servers for happybks-client obtained from Discovery client: [localhost:8091, localhost:8092]
22:52:30.115 [PollingServerListUpdater-0] DEBUG com.netflix.loadbalancer.BaseLoadBalancer - LoadBalancer [happybks-client]: clearing server list (SET op)
22:52:30.115 [PollingServerListUpdater-0] DEBUG com.netflix.loadbalancer.BaseLoadBalancer - LoadBalancer [happybks-client]: addServer [localhost:8091]
22:52:30.115 [PollingServerListUpdater-0] DEBUG com.netflix.loadbalancer.BaseLoadBalancer - LoadBalancer [happybks-client]: addServer [localhost:8092]
22:52:30.115 [PollingServerListUpdater-0] DEBUG com.netflix.loadbalancer.DynamicServerListLoadBalancer - Setting server list for zones: {unknown=[localhost:8091, localhost:8092]}
22:52:30.115 [PollingServerListUpdater-0] DEBUG com.netflix.loadbalancer.BaseLoadBalancer - LoadBalancer [happybks-client_unknown]: clearing server list (SET op)
22:52:30.115 [PollingServerListUpdater-0] DEBUG com.netflix.loadbalancer.BaseLoadBalancer - LoadBalancer [happybks-client_unknown]: addServer [localhost:8091]
22:52:30.115 [PollingServerListUpdater-0] DEBUG com.netflix.loadbalancer.BaseLoadBalancer - LoadBalancer [happybks-client_unknown]: addServer [localhost:8092]
{"brandName":"Volvo","price":536000.0,"serviceUrl":"http://localhost:8092/carsInfo/onsale"}
the 2th:
{"brandName":"Volvo","price":536000.0,"serviceUrl":"http://localhost:8091/carsInfo/onsale"}
the 3th:
{"brandName":"Volvo","price":536000.0,"serviceUrl":"http://localhost:8091/carsInfo/onsale"}
the 4th:
{"brandName":"Volvo","price":536000.0,"serviceUrl":"http://localhost:8091/carsInfo/onsale"}
the 5th:
andName":"Volvo","price":536000.0,"serviceUrl":"http://localhost:8091/carsInfo/onsale"}
the 6th:
{"brandName":"Volvo","price":536000.0,"serviceUrl":"http://localhost:8092/carsInfo/onsale"}
the 7th:
andName":"Volvo","price":536000.0,"serviceUrl":"http://localhost:8092/carsInfo/onsale"}
the 8th:
{"brandName":"Volvo","price":536000.0,"serviceUrl":"http://localhost:8091/carsInfo/onsale"}
the 9th:
{"brandName":"Volvo","price":536000.0,"serviceUrl":"http://localhost:8092/carsInfo/onsale"}
the 10th:
{"brandName":"Volvo","price":536000.0,"serviceUrl":"http://localhost:8091/carsInfo/onsale"}
22:52:30.889 [Thread-2] INFO com.netflix.loadbalancer.PollingServerListUpdater - Shutting down the Executor Pool for PollingServerListUpdater
从上面的结果可以看出,有6个请求为8091,剩下4个为8092,我们自己定义的规则的功能就实现了。
Ribbon内置负载均衡规则
Ribbon框架按照不同需求,已经为我们实现了许多实现了IRule接口的实现类,适用于常用的负载均衡规则。以下规则能够实现大部分负载均衡需求的应用场景,如果有更复杂的需求,可以自己实现IRule。
内置负载均衡规则类 | 规则描述 |
RoundRobinRule | 简单轮询服务列表来选择服务器。它是Ribbon默认的负载均衡规则。 |
AvailabilityFilteringRule |
对以下两种服务器进行忽略: (1)在默认情况下,这台服务器如果3次连接失败,这台服务器就会被设置为“短路”状态。短路状态将持续30秒,如果再次连接失败,短路的持续时间就会几何级地增加。 注意:可以通过修改配置loadbalancer.<clientName>.connectionFailureCountThreshold来修改连接失败多少次之后被设置为短路状态。默认是3次。 (2)并发数过高的服务器。如果一个服务器的并发连接数过高,配置了AvailabilityFilteringRule规则的客户端也会将其忽略。并发连接数的上线,可以由客户端的<clientName>.<clientConfigNameSpace>.ActiveConnectionsLimit属性进行配置。 |
WeightedResponseTimeRule |
为每一个服务器赋予一个权重值。服务器响应时间越长,这个服务器的权重就越小。这个规则会随机选择服务器,这个权重值会影响服务器的选择。 |
ZoneAvoidanceRule | 以区域可用的服务器为基础进行服务器的选择。使用Zone对服务器进行分类,这个Zone可以理解为一个机房、一个机架等。 |
BestAvailableRule | 忽略哪些短路的服务器,并选择并发数较低的服务器。 |
RandomRule | 随机选择一个可用的服务器。 |
Retry | 重试机制的选择逻辑 |
附录:AvailabilityFilteringRule的三个默认配置
# successive connection failures threshold to put the server in circuit tripped state, default 3
niws.loadbalancer.<clientName>.connectionFailureCountThreshold
# Maximal period that an instance can remain in "unusable" state regardless of the exponential increase, default 30
niws.loadbalancer.<clientName>.circuitTripMaxTimeoutSeconds
# threshold of concurrent connections count to skip the server, default is Integer.MAX_INT
<clientName>.<clientConfigNameSpace>.ActiveConnectionsLimit
Spring Cloud微服务开发笔记5——Ribbon负载均衡策略规则定制的更多相关文章
- Spring Cloud微服务学习笔记
Spring Cloud微服务学习笔记 SOA->Dubbo 微服务架构->Spring Cloud提供了一个一站式的微服务解决方案 第一部分 微服务架构 1 互联网应用架构发展 那些迫使 ...
- Spring Cloud 微服务开发系列整理
Spring Boot 系列精选 Spring Boot 自定义 starter Spring Boot 整合 mybatis-plus Spring Boot 整合 spring cache Spr ...
- Spring cloud微服务安全实战-6-10sentinel之热点和系统规则
热点规则 热点就是经常访问的数据.很多时候我们希望争对某一些热点数据,然后来进行限制.比如说商品的信息这个服务,我们给它做一个限流,qps是100,某一天我想做一个秒杀活动,可能会有很大的流量,这个时 ...
- Spring cloud微服务安全实战_汇总
Spring cloud微服务安全实战 https://coding.imooc.com/class/chapter/379.html#Anchor Spring Cloud微服务安全实战-1-1 课 ...
- Spring Cloud微服务Sentinel+Apollo限流、熔断实战总结
在Spring Cloud微服务体系中,由于限流熔断组件Hystrix开源版本不在维护,因此国内不少有类似需求的公司已经将眼光转向阿里开源的Sentinel框架.而以下要介绍的正是作者最近两个月的真实 ...
- Spring Cloud微服务限流之Sentinel+Apollo生产实践
Sentinel概述 在基于Spring Cloud构建的微服务体系中,服务之间的调用链路会随着系统的演进变得越来越长,这无疑会增加了整个系统的不可靠因素.在并发流量比较高的情况下,由于网络调用之间存 ...
- Spring Cloud微服务笔记(四)客户端负载均衡:Spring Cloud Ribbon
客户端负载均衡:Spring Cloud Ribbon 一.负载均衡概念 负载均衡在系统架构中是一个非常重要,并且是不得不去实施的内容.因为负载均衡对系统的高可用性. 网络压力的缓解和处理能力的扩容的 ...
- 在阿里云容器服务上开发基于Docker的Spring Cloud微服务应用
本文为阿里云容器服务Spring Cloud应用开发系列文章的第一篇. 一.在阿里云容器服务上开发Spring Cloud微服务应用(本文) 二.部署Spring Cloud应用示例 三.服务发现 四 ...
- Spring Cloud 微服务
https://mp.weixin.qq.com/s?__biz=MzU0OTE4MzYzMw==&mid=2247486301&idx=2&sn=f6d45860269b61 ...
随机推荐
- 8 -- 深入使用Spring -- 7... Spring 整合 Struts 2
8.7 Spring 整合 Struts2 8.7.1 启动Spring 容器 8.7.2 MVC框架与Spring整合的思考 8.7.3 让Spring管理控制器 8.7.4 使用自动装配
- HttpClient(一)-- HelloWorld
一.简介 HttpClient 是Apache Jakarta Common 下的子项目,可以用来提供高效的.最新的.功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP 协议最新的 ...
- JSON调试找不到 net.sf.ezmorph.Morpher
JSON中,java.lang.NoClassDefFoundError: net/sf/ezmorph/Morpher问题解决 使用JSON,在SERVLET或者STRUTS的ACTION中取得数据 ...
- 【Spring Boot&& Spring Cloud系列】单点登录SSO概述
概念 单点登录(Singleton Sign On),简称为SSO,是目前比较流行的企业业务整合的解决方案之一.SSO的定义是在多个应用系统中,用户只需要登录一次就能访问所有相互信任的应用系统. 也就 ...
- 使用 CSS MARK 改变 SVG 背景色
CSS masks -webkit-mask 这个属性是相当强大的,详细的介绍请到这里查看,它非常值得深入研究. -webkit-mask 让为一个元素添加蒙板成为可能,从而你可以创建任意形状的花样. ...
- Android NDK学习(3)使用Javah命令生成JNI头文件 .
转:http://www.cnblogs.com/fww330666557/archive/2012/12/14/2817387.html 第一步: 在Eclipse中创建android项目,并声明N ...
- Oracle 学习之触发器
1. 触发器简介 触发器是存储在数据库服务器中的程序单元,当一个表或一个视图被改变,或者数据库发生某些事件时,Oracle会自动触发触发器,并执行触发器中的代码.只有在触发器中定义的事件发生时,触发器 ...
- oracle IMP-00085: 为无界导出文件指定了多个输入文件
导入按表导出的数据的时候,提示为无界导出文件指定了多个输入文件 命令如下: imp user/user@database file=e:\test.dmp 提示信息: Import: Release ...
- Elasticsearch学习之深入搜索一 --- 提高查询的精准度
1. 为帖子增加标题字段 POST /forum/article/_bulk { "} } { "doc" : {"title" : "th ...
- LeetCode 17 Letter Combinations of a Phone Number (电话号码字符组合)
题目链接 https://leetcode.com/problems/letter-combinations-of-a-phone-number/?tab=Description HashMap< ...