前言

针对一个秒杀系统,可能会有百万级别的用户进行抢购,但实际的商品数量可能只有几百或者几十,远远小于用户数量。如果这些请求都进行入队操作或查询缓存,对于最终的结果没有任何的意义。因此,为了减少资源浪费,减轻后端压力,我们需要对秒杀进行限流,保障部分用户服务正常即可。

在开发高并发系统时,有三把利器用来保护系统:缓存降级限流

缓存:缓存的目的是提升系统访问速度和增大系统处理容量

降级:降级是当服务器压力剧增的情况下,根据当前业务情况及流量对一些服务和页面有策略地进行降级,以此释放服务器资源以保证核心任务的正常运行。

限流:限流的目的是通过对并发访问/请求进行限速,或者对一个时间窗口内的请求进行限速来保护系统,一旦达到限制速率则可以拒绝服务、排队

限流方法

限流可分为单机限流分布式限流

单机限流工具:

  • AtomicInterger
  • RateLimiter
  • Semaphore

分布式限流工具:

  • Nginx + Lua
  • redis + Lua

Read More

之前java中的语法糖一文使用过jd-gui来完成我们的反编译,它和javap的反编译不同,javap不是生成java文件,而是生成字节码。

编译和反编译的基本概念

在正式介绍工具之前,还是得过一遍基础,介绍啰嗦一下编译和反编译。

编译:将便于人编写、阅读、维护的高级计算机语言所写作的源代码程序,翻译为计算机能解读、运行的低阶机器语言的程序的过程就是编译。负责这一过程的处理的工具叫做编译器。编译给我们带来就是编出来的代码可读性更强,出了错也方便及时定位和修改。

反编译:反编译的过程与编译刚好相反,就是将已编译好的编程语言还原到未编译的状态,也就是找出程序语言的源代码。就是将机器看得懂的语言转换成程序员可以看得懂的语言。Java语言中的反编译一般指将class文件转换成java文件。而反编译给我们带来的就是在使用各种语法糖带来的好处时,方便我们探究代码底层的原理。

Read More

版本

操作系统:OS X 10.10.3

JDK版本: 1.8

zookeeper版本:zookeeper-3.5.9

kafka版本:1.0.0

包依赖

1
2
3
4
5
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>0.11.0.1</version>
</dependency>

启动zookeeper和kafka

zookeeper

1
./bin/zkServer.sh start

kafka

1
2
sh bin/kafka-server-start.sh  
config/server.properties &

Read More

什么情况使用连接池

对于一个简单的数据库应用,由于对于数据库的访问不是很频繁。这时可以简单地在需要访问数据库时,就新创建一个连接,用完后就关闭它,这样做也不会带来什么明显的性能上的开销。但是对于一个复杂的数据库应用,情况就完全不同了。频繁的建立、关闭连接,会极大的减低系统的性能,因为对于连接的使用成了系统性能的瓶颈。

使用连接池的好处

  1. 连接复用。通过建立一个数据库连接池以及一套连接使用管理策略,使得一个数据库连接可以得到高效、安全的复用,避免了数据库连接频繁建立、关闭的开销。
  2. 对于共享资源,有一个很著名的设计模式:资源池。该模式正是为了解决资源频繁分配、释放所造成的问题的。把该模式应用到数据库连接管理领域,就是建立一个数据库连接池,提供一套高效的连接分配、使用策略,最终目标是实现连接的高效、安全的复用。

Read More

语法糖可以看做编译器实现的一些「小把戏」,这些「小把戏」用得好,可能会使得代码效率提升喔

自动装箱的陷阱

先来看看《深入理解JVM虚拟机》的一道题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class testInteger {
public static void main(String[] args) {
Integer a = 1;
Integer b = 2;
Integer c = 3;
Integer d = 3;
Integer e = 321;
Integer f = 321;
Long g = 3L;
Long h = 3L;


System.out.println(c == d);
System.out.println(e == f);
System.out.println(e.equals(f));
System.out.println(c == (a + b));
System.out.println(c.equals(a + b));
System.out.println(g == (a + b));
System.out.println(g.equals(a + b));
System.out.println(g.equals(a + h));
}
}

Read More

代理模式(Proxy Pattern):给某个对象提供一个代理,并由代理对象控制对原对象的引用

用通俗一点的话来说就是当前对象不愿意干的,没法干的东西委托给别的对象来做,我只要做好本职工作就好了!

按照代理类的创建时期,代理类分为两种:

  • 静态代理类:由程序员创建或者由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。
  • 动态代理类:在程序运行时,运用反射机制动态创建而成。

Read More

@Slf4j注解的正确使用

  1. 对于一个Maven项目,首先要在pom.xml中加入以下依赖项:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>1.7.5</version>
    </dependency>
    <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
    <version>1.7.5</version>
    </dependency>
    <dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
    </dependency>

    <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.18</version>
    <scope>provided</scope>
    </dependency>
  • slf4j就是众多接口的集合,它不负责具体的日志实现,只在编译时负责寻找合适的日志系统进行绑定。具体有哪些接口,全部都定义在slf4j-api中。
  • slf4j-log4j12是链接slf4j-api和log4j中间的适配器。它实现了slf4j-apiz中StaticLoggerBinder接口,从而使得在编译时绑定的是slf4j-log4j12的getSingleton()方法。
  • log4j是具体的日志系统。通过slf4j-log4j12初始化Log4j,达到最终的日志输出。
  • lombok:一个插件,封装了log的get和set,可以直接使用log来输出日志信息。

Read More

池化最核心的思想就是把宝贵的资源放到池子里,每次使用都从里面获取,用完之后又放回池子供其他人使用。

线程池的好处:

  1. 消除了频繁创建和消亡线程的系统资源开销
  2. 面对过量任务的提交能够平缓地劣化,提高响应速度
  3. 提高线程的可管理性

《Java开发手册》也有这么一条:

以下源码为jdk1.8.0_171

Read More