【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>
问题背景
zipkin原生提供的采样率设置,仅能针对全局进行设置,无法做到精细化设置,比如,有些接口我们觉得比较重要,所以想采样率高一点,有些接口很简单,我们希望不采集或者采集率设置低一点,原生是没办法做到的,需要完成这个功能,需要我们重写他的采样率计算器。
配置重写
下面的是他原生的配置,由于它是使用了@ConditionalOnMissingBean注解的,也就是容器中不存在这个Bean的时候,才初始化他自己默认的配置,因此我们可以重写他的配置。
@Bean
@ConditionalOnMissingBean
public Sampler defaultTraceSampler(SamplerProperties config) {
return new PercentageBasedSampler(config);
}
重写配置如下
@Bean
Sampler percentageLocalSampler(SamplerLocalProperties samplerLocalProperties){
return new PercentageLocalSampler(samplerLocalProperties);
}
1
2
3
4
5
在Config类上面添加@EnableConfigurationProperties(SamplerLocalProperties.class) 用来创建我们自己的配置属性对象
代码书写
创建SamplerLocalProperties属性类
/**
* @Author 张云和
* @Date 2018/8/14
* @Time 17:13
*/
@ConfigurationProperties("spring.sleuth.sampler")
@Data
public class SamplerLocalProperties {
private List<UriSampleProperties> uriSample = new ArrayList<>(0);
private float percentage = 0.1f;
}
创建UriSampleProperties类
/**
* @Author 张云和
* @Date 2018/8/14
* @Time 17:39
*/
@Data
public class UriSampleProperties {
/**
* 自定义的采样率的接口uri正则表达式
*/
private String uriRegex;
private float uriPercentage = 0.1f;
}
编写percentageLocalSampler
public class PercentageLocalSampler implements Sampler {
private final Map<String, BitSet> sampleDecisionsMap;
private final SamplerLocalProperties configuration;
private final String all = "all";
private final Map<String, AtomicInteger> concurrentSampleCount;
public Map<String, AtomicInteger> getConcurrentSampleCount(){
return this.concurrentSampleCount;
}
public PercentageLocalSampler(SamplerLocalProperties configuration) {
this.configuration = configuration;
sampleDecisionsMap = buildRandomBit();
concurrentSampleCount = new ConcurrentHashMap<>();
// 设置全局的上报次数
concurrentSampleCount.put(all, new AtomicInteger(0));
}
@Override
public boolean isSampled(Span currentSpan) {
if (currentSpan == null) {
return false;
}
String uri = currentSpan.getName(); // 获取span中的请求uri
uri = uri.replace("http://", "");
AtomicInteger count = this.concurrentSampleCount.get(all); // 获取全局的访问率
BitSet bitSet = this.sampleDecisionsMap.get(all); // 获取全局的bitSet
float percentage = this.configuration.getPercentage(); // 获取全局的采样率
for (UriSampleProperties sampleProperties : configuration.getUriSample()) {
if (uri.matches(sampleProperties.getUriRegex())) { // 正则匹配
//匹配上了自定义采样率的正则
synchronized (this){ // 多个线程会有并发问题,这里加个局部锁
if (!concurrentSampleCount.containsKey(uri)) { // 判断当前uri是否在map中
concurrentSampleCount.put(uri, new AtomicInteger(0));
}
}
count = concurrentSampleCount.get(uri); // 获取当前URI对应的访问次数
bitSet = sampleDecisionsMap.get(sampleProperties.getUriRegex()); // 获取当前URI对应的bitSet
percentage = sampleProperties.getUriPercentage(); // 获取当前URI对应的采样率
}
}
if(percentage == 0.0f){ // 如果采样率是0 ,直接返回false
return false;
}else if (percentage == 1.0f){ // 如果采样率是1 ,那么直接返回true
return true;
}
synchronized (this) {
final int i = count.getAndIncrement(); // f访问次数加1
boolean result = bitSet.get(i); // 判断当前的访问 次数是否在 bitSet中,存在则返回true
if (i == 99) { // 等于99的时候,重新设置为0
count.set(0);
}
return result;
}
}
/**
* Reservoir sampling algorithm borrowed from Stack Overflow.
* <p>
* http://stackoverflow.com/questions/12817946/generate-a-random-bitset-with-n-1s
*/
static BitSet randomBitSet(int size, int cardinality, Random rnd) {
BitSet result = new BitSet(size);
int[] chosen = new int[cardinality];
int i;
for (i = 0; i < cardinality; ++i) {
chosen[i] = i;
result.set(i);
}
for (; i < size; ++i) {
int j = rnd.nextInt(i + 1);
if (j < cardinality) {
result.clear(chosen[j]);
result.set(i);
chosen[j] = i;
}
}
return result;
}
private Map<String, BitSet> buildRandomBit() {
Map<String, BitSet> map = new ConcurrentHashMap<>();
// 设置全局的采样率
int outOf100 = (int) (configuration.getPercentage() * 100.0f);
map.put(all, randomBitSet(100, outOf100, new Random()));
if (CollectionUtils.isNotEmpty(configuration.getUriSample())) {
for (UriSampleProperties sampleProperties : configuration.getUriSample()) {
// 设置个性化的采样率
map.put(sampleProperties.getUriRegex(), randomBitSet(100,
(int) (sampleProperties.getUriPercentage() * 100.0f), new Random()));
}
}
return map;
}
}
客户端接入
spring
sleuth:
sampler:
percentage: 1 # 全局采样率
uri-sample:
- uri-regex: "test|consumer" # 正则匹配
uri-percentage: 0.1 #个性化采样率
————————————————
来源:oschina
链接:https://my.oschina.net/xiaominmin/blog/3146805