Skip to content

曾海峰作业 #1092

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added java/doc/性能压测/压测_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added java/doc/性能压测/压测_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added java/doc/性能压测/压测_3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
16 changes: 16 additions & 0 deletions java/doc/性能压测/压测计划
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
《获取短域名》性能压测计划
1.压测目标
1.1 在系统性能正常指标下,系统QPS峰值。
正常指标定义:P95耗时10ms内,错误率为0

2.压测环境
2.1 服务器环境 macos 版本12.2.1 芯片:M1 Pro
2.2 Jvm内存设置:-Xms4096m -Xmx4096m
2.2 压测工具 JMeter

3.压测方案
3.1 长域名通过固定前缀 + 随机数
3.2 初始线程数100,每轮增加20线程数,每轮压测持续180s,直到达到压测目标

4.压测结果
吞吐量在27000 - 30000之间
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added java/doc/测试覆盖率.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
61 changes: 61 additions & 0 deletions java/doc/长域名转短域名服务设计文档
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
长域名转短域名服务设计文档
1.需求
1.1 短域名存储接口:接受长域名信息,返回短域名信息
1.2 短域名读取接口:接受短域名信息,返回长域名信息
1.3 限制
1.3.1 短域名长度最大为 8 个字符
1.3.2 映射数据存储在JVM内存即可,防止内存溢出
1.3.3 采用SpringBoot,集成Swagger API文档
1.3.4 JUnit编写单元测试, 使用Jacoco生成测试报告(行覆盖率和分支覆盖率85%+)
2.设计方案
2.1 首先为短域名生成长域名后缀字符,方案可采用哈希算法或者ID自增生成器
2.2 为使域名字符长度不超过8个且合法,需要转化成62进制
2.3 将生成好的短域名放入缓存,通过key-value方式存储,提高查询检索效率
2.4 通过短域名返回长域名时,从缓存中获取
2.5 为防止恶意查询攻击和提高查询检索效率,引入布隆过滤器,查询时从布隆过滤器判断是否存在。

3.流程图
见 《短域名获取长域名流程图.png》《长域名生成短域名流程图.png》

4.接口文档
4.1 长域名生成短域名
入参:
{
"longUrl":"" // 长域名

}

出参:
{
"code":200, // 响应码 200:成功,400:参数格式错误,500:服务存在异常
"desc":"success",//响应描述
"urlData":"" // 响应值

}

4.2 根据短域名获取长域名
入参:
{
"shortUrl":"" //短域名

}

出参:
{
"code":200, // 响应码 200:成功,400:参数格式错误,500:服务存在异常,600:长域名不存在,或已过期
"desc":"success",//响应描述
"urlData":"" //响应值
}

5. 方案说明
5.1 短域名字符生成方案
5.1.1 哈希算法:需要解决哈希冲突问题,同时因为有哈希计算,一定程度上会影响性能
5.1.2 ID生成器:本次采用AtomicLong自增生成,存在缺点是对于同一个URL会生成不同的短域名
5.1.3 ID生成器生产环境:mysql自增 | redis 自增 | ZK | 雪花算法。生产环境可以增加多个发号器提高性能。
5.2 缓存选择
5.2.1 内存缓存:可选择性有ConcurrentHashMap、Guava Cache、Caffeine。根据要求需要控制内存,则需要过期策略,选择性能更高的caffeine
5.2.2 生产环境:可以使用分布式缓存,如redis来实现




113 changes: 113 additions & 0 deletions java/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
<?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>com.neo</groupId>
<artifactId>spring-boot-url</artifactId>
<version>1.0.0-SNAPSHOT</version>
<packaging>jar</packaging>

<name>spring-boot-url</name>
<description>Demo project for Spring Boot</description>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<java.version>1.8</java.version>
</properties>

<dependencies>
<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>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>RELEASE</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.2-android</version>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8.1</version>
</dependency>
<!-- swagger依赖 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>

<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>

<dependency>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.7</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${project.parent.version}</version>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
<version>0.8.7</version>
<executions>
<execution>
<id>default-prepare-agent</id>
<goals>
<goal>prepare-agent</goal>
</goals>
</execution>
<execution>
<id>default-report</id>
<goals>
<goal>report</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
12 changes: 12 additions & 0 deletions java/src/main/java/com/url/Application.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.url;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application {

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
54 changes: 54 additions & 0 deletions java/src/main/java/com/url/bean/UrlResultBean.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package com.url.bean;

import com.url.error.BusinessCode;
import java.io.Serializable;

/**
* 结果封装类
* @Author jeckzeng
* @Date 2022/4/30
* @Version 1.0
*/
public class UrlResultBean implements Serializable {

private Integer code;

private String desc;

private String urlData;

public Integer getCode() {
return code;
}

public void setCode(Integer code) {
this.code = code;
}

public String getDesc() {
return desc;
}

public void setDesc(String desc) {
this.desc = desc;
}

public void setUrlData(String urlData) {
this.urlData = urlData;
}

public String getUrlData() {
return urlData;
}

public UrlResultBean() {

}

public UrlResultBean(BusinessCode businessCode,String urlData){
this.code = businessCode.code();
this.desc = businessCode.msg();
this.urlData = urlData;
}

}
47 changes: 47 additions & 0 deletions java/src/main/java/com/url/config/SwaggerConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package com.url.config;

import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

/**
* 开启对Swagger2的支持
* @Author jeckzeng
* @Date 2022/4/30
* @Version 1.0
*/
@EnableSwagger2
@Configuration
public class SwaggerConfig {

@Value("${swagger.enable}")
private Boolean swaggerEnable;

@Bean
public Docket docket() {
return new Docket(DocumentationType.SWAGGER_2)
.enable(swaggerEnable)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.paths(PathSelectors.any())
.build();
}

private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("长域名生成短域名服务接口文档")
.description("长域名生成短域名服务 RESTful APIs")
.version("1.0.0")
.build();
}
}
34 changes: 34 additions & 0 deletions java/src/main/java/com/url/config/UrlBloomConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.url.config;

import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.embedded.tomcat.TomcatConnectorCustomizer;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.nio.charset.Charset;

/**
* 布隆过滤器配置
* @Author jeckzeng
* @Date 2022/4/30
* @Version 1.0
*/
@Slf4j
@Configuration
public class UrlBloomConfig {

@Value("${url-bloom-filter.insertion}")
private long insertion;

@Value("${url-bloom-filter.fpp}")
private double fpp;

@Bean
public BloomFilter<String> createBloomFilter(){
return BloomFilter.create(Funnels.stringFunnel(Charset.defaultCharset()),insertion,fpp);
}
}
34 changes: 34 additions & 0 deletions java/src/main/java/com/url/config/UrlCacheConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.url.config;

import com.github.benmanes.caffeine.cache.Cache;
import com.github.benmanes.caffeine.cache.Caffeine;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.concurrent.TimeUnit;

/**
* 缓存配置类
* @Author jeckzeng
* @Date 2022/4/30
* @Version 1.0
*/
@Slf4j
@Configuration
public class UrlCacheConfig {

@Value("${cache.maximumSize}")
private long maximumSize;

@Value(("${cache.expireTime}"))
private long expireTime;

@Bean
public Cache<String,String> createUrlCache(){
return Caffeine.newBuilder()
.maximumSize(maximumSize)
.expireAfterAccess(expireTime,TimeUnit.MINUTES)
.build();
}
}
Loading