1 Star 0 Fork 7

ye367 / seckill

forked from Jerusalem / seckill 
加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
Apache-2.0

聚焦Java性能优化,打造亿级流量秒杀系统

部署生产环境

  1. 本地在项目根目录下使用mvn clean package打包生成seckill-1.0.0-SNAPSHOT.jar文件

  2. 将jar包服务上传到服务端上并编写额外的application.properties配置文件

  3. 编写deploy.sh脚本文件启动对应的项目

    source /etc/profile;		//使java环境生效
    nohup java -Xms2048m -Xmx2048m  -XX:NewSize=1024m -XX:MaxNewSize=1024m -jar seckill-1.0.0-SNAPSHOT.jar --spring.config.addition-location=/usr/local/seckill/application.properties
  4. 授权并执行使用

    chmod 777 deploy.sh
    
    ./deploy.sh &

    启动应用程序

    查看日志

    tail -f nohup.out
  5. 打开阿里云的网络安全组配置,将80端口开放给外网可访问

参数说明

  • nohup:以非停止方式运行程序,这样即便控制台退出了程序也不会停止
  • java:java命令启动,设置jvm初始和最大内存为2048m,2个g大小,设置jvm中初始新生代和最大新生代大小为1024m,设置成一样的目的是为了减少扩展jvm内存池过程中向操作系统索要内存分配的消耗
  • –-spring.config.addtion-location=:指定额外的配置文件地址

性能压测 ApacheJMeter

1. 前置知识
2. 组件
  • 线程组
  • Http请求
  • 察看结果树
  • 聚合报告
3. 常用操作命令
查看服务器性能
top -H

查看某个进程
ps -ef | grep java

通过端口查看进程
netstat -anp | grep 5240

查看某进程的线程
pstree -p [progressId] wc -l

统计某进程的线程数量
pstree -p [progressId] wc -l

杀死进程
kill 5240

1. 解决容量问题

1.1 服务端并发容量上不去

1.1.1 修改Spring Boot内嵌Tomcat默认配置(spring-configuration-metadata.json )
server.tomcat.accept-count:等待队列长度,默认100 
server.tomcat.max-connections:最大可被连接数,默认10000 
server.tomcat.max-threads:最大工作线程数,默认200 
server.tomcat.min-spare-threads:最小工作线程数,默认10

默认配置下,链接超10000后出现拒绝链接情况 
默认配置下,发出的请求超过200+100后拒绝处理

修改配置如下

server.tomcat.accept-count: 1000
server.tomcat.max-connections: 10000 
server.tomcat.max-threads: 800
server.tomcat.min-spare-threads: 10000

对4核8G的服务器来说,经验上最好的max-threads是800
1.1.2 定制化内嵌Tomcat配置定制化内嵌Tomcat配置
@Component
public class WebServerConfiguration implements WebServerFactoryCustomizer<ConfigurableWebServerFactory> {
    @Override
    public void customize(ConfigurableWebServerFactory configurableWebServerFactory) {
         //使用对应工厂类提供给我们的接口定制化我们的tomcat connector
        ((TomcatServletWebServerFactory)configurableWebServerFactory).addConnectorCustomizers(new TomcatConnectorCustomizer() {
            @Override
            public void customize(Connector connector) {
                Http11NioProtocol protocol = (Http11NioProtocol) connector.getProtocolHandler();
                //定制化keepalivetimeout(设置30秒内没有请求则服务端自动断开keepalive链接)
                protocol.setKeepAliveTimeout(30000);
                //当客户端发送超过10000个请求则自动断开keepalive链接
                protocol.setMaxKeepAliveRequests(10000);
            }
        });
    }
}

说明:

  • keepAliveTimeOut:多少毫秒后不响应就断开keepAlive
  • maxKeepAliveRequests:多少次请求后keepAlive断开失效
  • KeepAlive :建立长连接,保护系统不受客户端连接的拖累,减少网络消耗

1.2 响应时间长,TPS上不去

1.2.1 单web容器上限
  • 线程数量:4核8G的单进程调度线程数最好是800,超过1000后即花费巨大的时间在cpu调度上
  • 等待队列长度:队列做缓冲池用,但不能无限长,消耗内存,出对入队消耗cpu(一般1000-2000)
1.2.2 Mysql数据库QPS容量问题
  • 主键查询:千万级别数据 = 1-10毫秒。
  • 唯一索引查询: 千万级别数据= 10-100毫秒
  • 非唯一索引查询: 千万级别数据= 100-1000毫秒
  • 无索引: 百万条数据= 1000毫秒 +

数据库查询尽量使用到主键查询和唯一索引查询,如果非唯一索引查询在数据达到一定数量级后,则要进行分表分库来优化。

1.2.3 单机容量问题
  • 表象:单机cpu使用率增高,memory占用增加,网络带宽使用增加
  • cpu us:用户空间的Cpu使用情况
  • cpu sy:内核空间的cpu使用情况
  • load average:1,5,15分钟load平均值,跟着核数系数,0代表通常,1代表打满,1+代表阻塞
  • memory:free空闲内存,used使用内存

2. 分布式扩展(服务端水平对称部署)

2.1 引入Nginx实现反向代理、负载均衡

2.1.1 部署使用OpenResty作为Nginx框架

如果对Nginx开发有特殊要求或者OpenResty的Nginx达不到我们的需求,可以到Nginx官网下载,操作之后得到所需的Nginx替换掉openResty/sbin目录下的nginx即可。

1.先行条件,需要在linux安装pcre,openssl,gcc,curl等
apt install PCRE
apt install pcre-devel openssl-devel gcc curl

2.下载openresty 下载页面 http://openresty.org/cn/download.html

3.上传并解压
tar -xvzf openresty**.tar.gz

4.解压后执行如下命令
./configure
make
make install
安装完成,nginx默认安装在 /usr/local/openresty/nginx目录下
修改本地和阿里云服务器的host路径,以便于统一访问
2.1.2 将Nginx作为Web服务器
  • location节点path:指定url映射key
  • location节点内容:root指定location path后对应的根路径,index指定默认的访问页
  • sbin/nginx -c conf/nginx.conf启动
  • 修改配置后直接sbin/nginx -s reload无缝重启
1.静态资源部署
进入nginx根目录下的html下,新建resources目录用于存放前端静态资源
设置指向resources目录下的location可以访问对应的html下的静态资源文件

2.1.3 将Nginx作为动静分离服务器
  • location节点path特定resources:静态资源路径
  • location节点其他路径:动态请求
2.1.4 将Nginx作为反向代理服务器
  • 设置upStream sserver

    反向代理配置,配置一个backend server,可以用于指向后端不同的server集群,配置内容为server集群的局域网ip,以及轮训的权重值,并且配置一个location,当访问规则命中location任何一个规则的时候则可以进入反向代理规则

    upstream backend_server{
        server 192.168.75.180 weight=1;
        server 192.168.75.181 weight=1;
    }
  • 设置动态请求location为proxy pass路径
    location / {
         proxy_pass http://backend_server;
         #设置请求头
         proxy_set_header Host $http_host:$proxy_port;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
  • 开启tomcat access log认证
#日志开关
server.tomcat.accesslog.enabled=true
#日志格式
server.tomcat.accesslog.pattern=%h %l %u %t "%r" %s %b %D
server.tomcat.accesslog.directory=/usr/local/seckill/logs
  • 设置Nginx与应用服务器的长连接
    upstream backend_server{
        server 192.168.75.180 weight=1;
        server 192.168.75.181 weight=1;
        keepalive_timeout 30;			//添加此行
    }
    location / {
         proxy_pass http://backend_server;
         #设置请求头
         proxy_set_header Host $http_host:$proxy_port;
         proxy_set_header X-Real-IP $remote_addr;
         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
         # 添加如下两行
         proxy_http_version 1.1;
         #允许重新定义或追加字段到传递给代理服务器的请求头信息(默认是close)
         proxy_set_header Connection "";
    }
2.1.5 Nginx高性能原因
  • epoll多路复用

    • java bio模型 - 阻塞式进程
    • linux select模型 - 变更触发轮询查找,有1024数量上限
    • epoll模型 - 变更触发回调直接读取,理论上无上限
  • master-worker进程模型

  • 协程机制
    • 依附于线程的内存模型,切换开销小
    • 遇阻塞及归还执行权,代码同步
    • 无需加锁

2.2 引入Redis实现分布式会话管理存储

2.2.1 基于cookie传输sessionid(不适用于移动端【安卓、IOS、微信小程序】)
  • 引入依赖

        <dependency>
          <groupId>org.springframework.boot</groupId>
          <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <dependency>
          <groupId>org.springframework.session</groupId>
          <artifactId>spring-session-data-redis</artifactId>
          <version>2.0.5.RELEASE</version>
        </dependency>
  • 配置类

    @Component
    @EnableRedisHttpSession(maxInactiveIntervalInSeconds = 3600)
    public class RedisSessionConfig {
        
    }
2.2.2 基于token传输类似sessionid(推荐)
  • 修改后端代码
        //生成登录凭证token,UUID
        String uuidToken = UUID.randomUUID().toString();
        uuidToken = uuidToken.replace("-","");
        //建议token和用户登陆态之间的联系
        redisTemplate.opsForValue().set(uuidToken,userModel);
        redisTemplate.expire(uuidToken,1, TimeUnit.HOURS);
        //下发token
        return CommonReturnType.create(uuidToken);
  • 修改前端代码

3. 查询性能优化 - 实现多级缓存

缓存设计原则

  • 用快速存取设备,用内存
  • 将缓存推到离用户最近的地方
  • 脏缓存清理

3.1 Redis缓存

3.1.1 单机版
//存入Redis
redisTemplate.opsForValue().set("item_"+id,itemModel);
redisTemplate.expire("item_"+id,10, TimeUnit.MINUTES);
//序列化
public class JodaDateTimeJsonSerializer extends JsonSerializer<DateTime> {
    @Override
    public void serialize(DateTime dateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
        jsonGenerator.writeString(dateTime.toString("yyyy-MM-dd HH:mm:ss"));
    }
}
//反序列化
public class JodaDateTimeJsonDeserializer extends JsonDeserializer<DateTime> {
    @Override
    public DateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
        String dateString =jsonParser.readValueAs(String.class);
        DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss");
        return DateTime.parse(dateString,formatter);
    }
}
//自定义RedisTemplates
@Component
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 3600)
public class RedisSessionConfig {

    @Bean
    public RedisTemplate redisTemplate(RedisConnectionFactory redisConnectionFactory){
        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        //解决key的序列化方式 -> String
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringRedisSerializer);
        //解决value的序列化方式 -> Json
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper objectMapper =  new ObjectMapper();
        SimpleModule simpleModule = new SimpleModule();
        simpleModule.addSerializer(DateTime.class,new JodaDateTimeJsonSerializer());
        simpleModule.addDeserializer(DateTime.class,new JodaDateTimeJsonDeserializer());
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        objectMapper.registerModule(simpleModule);
        jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        return redisTemplate;
    }
}
3.1.2 Sentinal哨兵模式
3.1.3 集群cluster模式

3.2 本地热点缓存

3.2.1 特点
  • 热点数据
  • 脏读非常不敏感
  • 内存可控
3.2.2 解决方案 - Guava cache
  • 可控制的大小和超时时间
  • 可配置的lru策略(达到存储上限后,最近最少被访问的key优先被淘汰)
  • 线程安全

3.3 nginx+lua 缓存

3.3.1 原理解析
  • lua协程机制

    • 依附于线程的内存模型,切换开销小
    • 遇阻塞及归还执行权,代码同步
    • 无需加锁
  • nginx协程机制

    • nginx每个工作进程创建一个lua虚拟机
    • 工作进程内的所有协程共享同一个VM
    • 每个外部请求由一个lua协程处理,之间数据隔离
    • lua代码调用io等异步接口时,协程被挂起,上下文数据保持不变
    • 自动保存,不阻塞工作进程
    • io异步操作完成后还原协程上下文,代码继续执行

    Nginx处理阶段:

  • nginx lua插载点

    • init_by_lua:系统启动时调用
    • init_worker_by_lua:worker进程启动时调用
    • set_by_lua:nginx变量用复杂lua return
    • rewrite_by_lua:重写url规则
    • access_by_lua:权限验证阶段
    • content_by_lua:内容输出节点

  • OpenResty
    • OpenResty由Nginx核心和很多第三方模块组成,默认集成了lua开发环境,使Nginx可以作为一个Web Server使用
    • 借助于Nginx的事件驱动模型和非阻塞IO,可以实现高性能的Web应用程序
    • OpenResty提供了大量组件,如Mysql,Redis,Memcached等,使在Nginx上开发Web应用程序更方便更简单
3.3.2 方式一: share dic 共享内存字典(存在脏读问题)
  • 编写lua脚本 - itemsharedic.lua
function get_from_cache(key)
        local cache_ngx = ngx.shared.my_cache
        local value = cache_ngx:get(key)
        return value
end

function set_to_cache(key,value,exptime)
        if not exptime then
                exptime = 0
        end
        local cache_ngx = ngx.shared.my_cache
        local succ,err,forcible = cache_ngx:set(key,value,exptime)
        return succ
end

local args = ngx.req.get_uri_args()
local id = args["id"]
local item_model = get_from_cache("item_"..id)
if item_model == nil then
        local resp = ngx.location.capture("/item/get?id="..id)
        item_model = resp.body
        set_to_cache("item_"..id,item_model,1*60)
end
ngx.say(item_model)
  • 配置nginx.conf

加入shared dictionary的扩展,声明128m的共享字典的访问内存

lua_shared_dict my_cache 128m;
  • 设置location用来访问shared dict的lua文件
location /itemlua/get {
		default_type 'application/json';
		content_by_lua_file '/usr/local/openresty/lua/itemsharedic.lua';
}

**适用场景:**更新较少,热点数据

3.3.3 方式二:Redis的支持
  • 编写lua脚本 - itemredis.lua
local args = ngx.req.get_uri_args()
local id = args[ "id"]
local redis= require "resty.redis"
local cache= redis:new()
local ok,err = cache:connect("192.168.75.140",6379)   //连接只读Redis,只读操作
local item_model= cache:get("item_"..id)
if item_model == ngx.null or item_model = nil then
       local resp = ngx.location.capture("/item/get?id="..id) 
       item_model= resp.body
end
ngx.say(item_model)
  • 配置nginx.conf
location /itemlua/get {
		default_type 'application/json';
		content_by_lua_file '/usr/local/openresty/lua/itemredis.lua';
}

**适用场景:**更新较多,非热点数据

3.4 nginx proxy cache 缓存(不推荐)

3.4.1 前置条件
  • Nginx反向代理
  • 依靠文件系统存索引级的文件
  • 依靠内存缓存文件地址
3.4.2 配置步骤
  1. 申明一个cache缓存节点的路径

    proxy_cache_path /usr/local/openresty/nginx/cache_temp levels=1:2 keys_zone=tmp_cache:100m inactive=7d max_size=100g;

    参数说明:

    • /usr/local/openresty/nginx/cache_temp:设置缓存文件路径
    • levels:目录设置两层结构用来缓存
    • keys_zone:指定了一个叫tmp_cache的缓存区,并且设置了100m的内存用来存储缓存key到文件路径的位置
    • inactive:缓存文件超过7天后自动释放淘汰
    • max_size:缓存文件总大小超过100g后自动释放淘汰
  2. location内加入

    proxy_cache tmp_cache;   //缓存节点名称
    proxy_cache_valid 200 206 304 302 7d;		//只缓存指定的状态码的请求
    proxy_cache_key $request_uri;			//将请求uri作为缓存的key
3.4.3 发现问题 - 效果反而下降:

​ 这种缓存方法读取的Nginx的本地文件,并没有将文件缓存到Nginx的内存中,所以效果并不好,不推荐。

总结:

  • 在大型的应用集群中若对Redis访问过度依赖,会因为应用服务器到Redis之间的网络带宽产生瓶颈

    针对读请求导致的性能瓶颈,只需要在数据写入过程中复制一份,数据就变成两份,数据读能力就扩展了一倍。 针对写请求,redis是key-value存储结构,通过对写请求key做sharding,分散到不同的master实例上,解决写的瓶颈问题。

  • 架构的越顶层性能越高,占用的系统资源越昂贵,更新机制越难

  • 架构的底层更容易集中式的存储数据,但是性能最差

所以,无通用的解决方案,结合场景选择合适的架构

4. 查询性能优化 - 页面静态化

4.1 实现静态资源CDN及其原理解析

  • DNS用CNAME解析到源站
  • 回源缓存设置
  • 强推失效
4.1.1 cache-control响应头
  • private:客户端可以缓存
  • publlic:客户端和代理服务器都可以缓存
  • max-age=xxx:缓存的内容将在XXX秒后失效
  • no-cache:强制向服务端再验证一次
  • no-store:不缓存请求的任何返回内容
4.1.2 有效性判断
  • ETag:资源唯一标识
  • If-None-Match:客户端发送的匹配ETag标识符
  • Last-modified:资源最后被修改的时间
  • If-Modified-Since:客户端发送的匹配资源最后修改时间的标识符

协商机制:比较Last-modified和ETag到服务端,若服务端判断没变化则304不返回数据,否则200返回数据

4.1.3 浏览器的刷新方式
  • 回车刷新或a链接

  • F5刷新或command+R刷新

  • ctrl+F5或command+shift+R刷新

4.1.4 CDN自定缓存策略
  • 可自定义目录过期时间
  • 可自定义后缀名过期时间
  • 可自定义对应策略权重
  • 可通过界面或api强制cdn对应目录刷新(非保成功)
4.1.5 静态资源部署策略

(一)

  • css,js,img等元素使用版本号部署(不便利,维护困难)

  • css,js,img等元素使用带摘要部署(存在先部署html还是先部署资源的覆盖问题)

  • css,js,img等元素使用摘要做文件名部署,新老版本并存且可回滚,资源部署完后在部署html(推荐)

(二)

  • 对应静态资源保持生命周期内不会变,max-age可设置的很长,无视失效更新周期
  • html文件设置no-cache或较短max-age,以便于更新
  • html文件仍然设置较长的mac-age,依靠动态的获取版本号请求发送到后端,异步下载最新的版本号的html后展示渲染在前端

(三)

  • 动态请求也可以静态化成json资源推送到cdn上
  • 依靠异步请求获取后端节点对应的资源状态做紧急下架处理
  • 可通过跑批紧急推送cdn内容以使其下架等操作

4.2 全页面静态化(*)

4.2.1 概念

在服务端完成html,css,甚至js的load渲染成纯html文件后,直接以静态资源的方式部署到cdn上。

4.2.2 phantomjs应用 - 无头浏览器
  • 修改需要全页面静态化的实现,采用initView和hasInit方式防止多次初始化
  • 编写对应轮询生成内容方式
  • 将全静态化页面生成后推送到cdn

5. 交易性能优化 - 缓存库存

交易性能瓶颈

  • 交易验证完全依赖于数据库
  • 库存行锁
  • 后置处理逻辑

5.1 优化交易验证

  • 用户风控策略优化:策略缓存模型化

  • 活动校验策略优化:引入活动发布流程,模型缓存化,紧急下线功能

    具体实现见代码优化

5.2 优化库存行锁

5.2.1 解决方案
  • 扣减库存缓存化

  • 异步同步数据库

  • 库存数据库最终一致性保证

    具体实现见代码优化

5.2.2 部署RocketMq
  • docker-compose
version: '3.3'
services:
  rmqnamesrv:
    image: foxiswho/rocketmq:server
    container_name: rmqnamesrv
    ports:
      - 9876:9876
    volumes:
      - ./data/logs:/opt/logs
      - ./data/store:/opt/store
    networks:
        rmq:
          aliases:
            - rmqnamesrv
  
  rmqbroker:
    image: foxiswho/rocketmq:broker
    container_name: rmqbroker
    ports:
      - 10909:10909
      - 10911:10911
    volumes:
      - ./data/logs:/opt/logs
      - ./data/store:/opt/store
      - ./data/brokerconf/broker.conf:/etc/rocketmq/broker.conf
    environment:
        NAMESRV_ADDR: "rmqnamesrv:9876"
        JAVA_OPTS: " -Duser.home=/opt"
        JAVA_OPT_EXT: "-server -Xms128m -Xmx128m -Xmn128m"
    command: mqbroker -c /etc/rocketmq/broker.conf
    depends_on:
      - rmqnamesrv
    networks:
      rmq:
        aliases:
          - rmqbroker

  rmqconsole:
    image: styletang/rocketmq-console-ng
    container_name: rmqconsole
    ports:
    	- 8080:8080
    environment:
        JAVA_OPTS: "-Drocketmq.namesrv.addr=rmqnamesrv:9876 -Dcom.rocketmq.sendMessageWithVIPChannel=false"
    depends_on:
        - rmqnamesrv
    networks:
        rmq:
          aliases:
            - rmqconsole

networks:
    rmq:
        driver: bridge
docker update --restart=always XXX

具体实现见代码优化

5.2.3 问题
  • 异步消息发送失败
  • 扣减操作执行失败
  • 下单失败无法正确回滚库存

6. 交易性能优化 - 事务型消息

  • 事务型消息应用
  • 库存流水状态
  • 库存售罄处理方案

7. 流量削峰技术

7.1 秒杀令牌

7.1.1 原理
  • 秒杀接口需要依靠令牌才能进入
  • 秒杀的令牌由秒杀活动模块负责生成
  • 秒杀活动模块对秒杀令牌生成全权处理,逻辑收口
  • 秒杀下单前需要先获取秒杀令牌

7.2 秒杀大闸

7.2.1 原理
  • 依靠秒杀令牌的授权原理定制化发牌逻辑,做到大闸功能
  • 根据秒杀商品初始库存颁发对应数量令牌,控制大闸流量
  • 用户风控策略前置到秒杀令牌发放中
  • 库存售罄判断前置到秒杀令牌发放中

7.3 队列泄洪

7.3.1 原理
  • 依靠排队去限制并发流量
  • 依靠排队和下游拥塞窗口程度调整队列释放流量大小
  • 典型案例:支付宝银行网关队列
7.3.2 代码实现
  • 本地:将队列维护在本地内存中
    private ExecutorService executorService;

    /***
     * 同步调用线程池的submit方法
     * 拥塞窗口为20的等待队列,实现队列泄洪
     */
    @PostConstruct
    public void init(){
        executorService = Executors.newFixedThreadPool(20);
    }
  • 分布式:将队列设置到外部redis中

8. 防刷限流

8.1 验证码生成与验证技术 - 错峰

  • 包装秒杀令牌前置,验证码错峰
  • 数学公式验证码生成器

8.2 限流原理与实现

8.2.1 方案
  • 限并发
  • 令牌桶算法(可以应对突发流量)
  • 漏桶算法(固定速率)
8.2.2 实现
    /***
     * 限流
     */
    @PostConstruct
    public void init(){
        orderCreateRateLimiter = RateLimiter.create(300);
    }

8.3 防黄牛技术

8.3.1 传统防刷
  • 限制一个会话在一定时间内接口调用次数(无法解决多会话接入的问题)

  • 限制一个ip在一定时间内接口调用次数(不好控制,容易误伤)

8.3.2 设备指纹
8.3.3 凭证系统

缓存、并发等高阶Java性能技术持续更新中.....

友情链接

Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.

简介

聚焦Java性能优化,打造亿级流量秒杀系统。详解分布式、多级缓存、交易泄压、流量错峰、防刷限流、性能压测等核心秒杀问题。 展开 收起
Java
Apache-2.0
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
Java
1
https://gitee.com/yerongli367/seckill.git
git@gitee.com:yerongli367/seckill.git
yerongli367
seckill
seckill
master

搜索帮助