How to improve the throughput of web applications

This blog by means of optimization is cited for the more traditional project , but want to improve the throughput of the system is now fashionable technology or unseparated those front and rear end, as a static resource use nginx proxy server to our static resources

Who limits Throughput?

When we conduct a stress test on a traditional project, it is a container found, Throughput system is tightly restricted database (mysql), although the code does not seem wrong, there is no logical error, but too many requests was beaten to the database, open the database from a large number of IO operations, such a large load even make a whole load Linux system suddenly soared, but the other hand, the throughput of our system, huh, huh ...

Eyeing cache

Since the compressive strength mysql limits of our system, then the data cached, do everything possible to reduce the number of direct contact between the user and the database, so that the throughput of our system, at the same time be able to request the number of processors will naturally rise up

Many caching techniques available in the market, is relatively popular two Memcache cache database and Redis,

The difference Redis and Memcahe

  • Redis supports not only key-value data type of the key, and also supports list, set, hash data structures, etc.
  • Redis support data backup, that backup cluster master-slaver mode
  • Redis is to support data persistence, it can save the data in memory on disk, supports two kinds of RDB and persistent forms of AOF

Of the pressure-sensing Redis

# 挨个测试redis中的命令
# 每个数据包大小是3字节
# 100个并发, 发起10万次请求
redis-benchmark -h 127.0.0.1 -p 6379 -c 100 -n 100000

[root@139 ~]# redis-benchmark -h 127.0.0.1 -p 9997 -c 100 -n 100000
====== PING_INLINE ======
  100000 requests completed in 1.04 seconds
  100 parallel clients
  3 bytes payload
  keep alive: 1

98.68% <= 1 milliseconds // 百分之98.68的请求在1秒内完成了
99.98% <= 2 milliseconds 
100.00% <= 2 milliseconds
96525.09 requests per second  // 每秒完成的请求数在9万六左右


-d  指定数据包的大小,看下面redis的性能还是很强大的
-q  简化输出的参数
[root@139 ~]# redis-benchmark -h 127.0.0.1 -p 9997 -q -d 100 -c 100 -n 100000
PING_INLINE: 98619.32 requests per second
PING_BULK: 95877.28 requests per second
SET: 96153.85 requests per second
GET: 95147.48 requests per second
INCR: 95238.10 requests per second
LPUSH: 95328.88 requests per second
RPUSH: 95877.28 requests per second
LPOP: 95328.88 requests per second
RPOP: 97276.27 requests per second
SADD: 96339.12 requests per second
HSET: 98231.83 requests per second
SPOP: 94607.38 requests per second
LPUSH (needed to benchmark LRANGE): 92165.90 requests per second
LRANGE_100 (first 100 elements): 97181.73 requests per second
LRANGE_300 (first 300 elements): 96153.85 requests per second
LRANGE_500 (first 450 elements): 94428.70 requests per second
LRANGE_600 (first 600 elements): 95969.28 requests per second
MSET (10 keys): 98231.83 requests per second

只测试 指定的命令
-t 跟多个命令参数
[root@139 ~]# redis-benchmark -p 9997 -t set,get -q -n 100000 -c 100 
SET: 97276.27 requests per second
GET: 98135.42 requests per second

From the above stress test, you can see, the performance of Redis is an absolute strength, very powerful, and not an order of magnitude compared to mysql, so the obvious conclusion is that, if we add a layer redis key in user and mysql to do cache the system throughput to natural meeting

So in order to improve the compressive strength of the system, we will gradually shift from the pressure to redis in mysql

Page Caching

Before saying the page cache, we first talk about in a traditional project, a request lifecycle is probably this: sent from the browser to the server, the server queries the database to obtain results, then the results data to the Template Engine the data rendered into the html page

Want to improve the speed of this process, we can do this, the page cache, the name suggests is the html page cache to cache database

Examples are as follows:

At first we will first try to have the rendered html source in response to the client, the response format get out of the buffer by @ResponseBody和producescontrol of property that tells the browser that they will return to it the text html

Advantages: The pressure is transferred from the requesting user mysql to redis, this strength is not a matter for stand-alone redis

Disadvantages: It is clear that the request to expand the page level, data consistency will inevitably be affected, which is using the page cache have to consider the fact

Feature 1: strictly control the caching of time, do not forget to add expiration time ...

Feature 2: Let thymeleaf original is automatically rendering data now, then obviously we manually in rendering data

for example

    @RequestMapping(value = "/to_list",produces = "text/html;charset=UTF-8")
    @ResponseBody
    public String toLogin(Model model, User user, HttpServletResponse response, HttpServletRequest request) {

        // 先从redis缓存中获取数据
        String html = redisService.get(GoodsKey.goodsList, "", String.class);
        if (html != null)
            return html;

        // 查询商品列表
        List<GoodsVo> goodsList = goodsService.getGoodsList();
        model.addAttribute("goodsList", goodsList);

        // 使用Thymeleaf模板引擎手动渲染数据
        WebContext springWebContext = new WebContext(request,response,request.getServletContext(),request.getLocale(),model.asMap());
        String goods_list = thymeleafViewResolver.getTemplateEngine().process("goods_list", springWebContext);

        // 存入redis
        if (goods_list!=null){
            redisService.set(GoodsKey.goodsList,"",goods_list);
        }
        return goods_list;
    }

Since they stop here, it went on to say also how to play ...

You see, by the above api manual control template engine has been rendered even get a good html source code, what is already rendering good it means that I write in the front end:? Th $ {user}, such placeholders has now been replaced with thymeleaf Joe Smith ... (enough said direct it)

Got already rendered good source code, we can through the IO operation, this file is written to a directory system up, do not know if you ever noticed that when the mortar Jingdong Taobao visiting a product page, you will find url It is like this www.jjdd.com/aguydg/ahdioa/1235345.html

The suffix 123145.html high probability illustrate the use of technology Jingdong static pages, it was too bright, the face of such a huge amount of product information suffix represented by numbers are good, but speed is not faster?

How to achieve this effect?

Is above that, through these IO data written to the Linux source code in one directory, file name is the URL above the final figure by doing a static resource server Nginx xxx.html these agents together, users access and then withdrew this static page, the same does not contact the database, but nginx supports zero-copy, not the number of concurrent 50,000 thing ...
also, the suffix array at best Freeze write, item id would be better used directly, after all click merchandise is to get to the id, then go to the static page

Object Caching

Java objects in the cache, such as the user's information into the redis persistent, check their information each time a user start redis query, any direct return, if not go to query the database, so to achieve the same user and database adding a layer between a plurality of caches, may greatly improve the system throughput

Generally how to play with?

for example

The user's request before querying the database to try to obtain information from the object in redis, redis does not exist, then went to the database query, the query results after the completion of this result change deposit into redis

// todo 使用redis做缓存,减少和数据库的接触次数
public Label findById(Long labelId) {

    // 先尝试从缓存中查询当前对象
    Label label = (Label) redisTemplate.opsForValue().get("label_id" + labelId);

    if (label==null){
        Optional<Label> byId = labelRepository.findById(labelId);
        if (!byId.isPresent()) {
            // todo 异常
        }
        label = byId.get();

        // 将查出的结果存进缓存中
        redisTemplate.opsForValue().set("label_id"+label.getId(),label);
    }
    return label;
}

When users update data, to update the database, and then delete / update the cache in response redis

public void update(Long labelId, Label label) {
    label.setId(labelId);
    Label save = labelRepository.save(label);

    // todo 数据库修改成功后, 将缓存删除
    redisTemplate.delete("label_id"+save.getId());
    }

When you delete data, delete data in the database, and then delete the cache redis

public void delete(Long labelId) {
    labelRepository.deleteById(labelId);

    // todo 数据库修改成功后, 将缓存删除
    redisTemplate.delete("label_id"+labelId);
}

Vue imitate achieve static pages

We are talking about static pages, it really that magical? In fact, not so magical, to say it plainly, the data on the traditional web page is rendered up through the template engine (such as JSP or that kind of template thymeleaf engine), made a static rendering the data pages by js completed, and the project pages and static resources such as js, css files in such a directory, the status and the same common static resources, as well as advantage is that the browser to welfare , because browsers cache static resources are there, and if you are good, you will find sometimes repeat requests a page, the page displayed, but the request status code is 304 ... We will still reach the server, but the server will tell the browser it wants to access the page actually does not change, then the browser will use to find local cache

Nowadays the most popular play static pages among the most popular technique is Angular.js and Vue.js, also really easy to use, a few months ago I wrote notes about vue, interested students can go and see click to see my the vue notes

In this blog in just right is useless to VUE, but the realization of ideas and vue static pages is the big bad not bad, the same is achieved by static pages js code

  • First, that the back-end code how to write?

Well separated front and rear ends, naturally json interaction, through the rear end @ResponseBodyreturns to the front end json object control, and, also recommend a VO is integral with the variety of objects VO data package together, it is returned to the front end of disposable so it seems, the back-end is really simple and that is to return a json objects

  • How to write the front end of it?

The first thing is to lower html files from the template folder move to the static folder, make this html file and js / css files fraternizing

Then to the xxx.html the name, why you want to change one directory? Because SpringBoot is greater than the agreed-coded, in what directory the file is what, in addition Thymeleaf part of the default configuration information is as follows

@ConfigurationProperties(prefix = "spring.thymeleaf")
public class ThymeleafProperties {

    private static final Charset DEFAULT_ENCODING = StandardCharsets.UTF_8;

    public static final String DEFAULT_PREFIX = "classpath:/templates/";

    public static final String DEFAULT_SUFFIX = ".html";

No way, the configuration information default templates considered under the classpath files are xxx.html

The second thing is the introduction of similar thymeleaf html tag in this namespace are removed, does not require a static page

<!DOCTYPE HTML>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>商品列表</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
    <!-- jquery -->
    <!--<script type="text/javascript" th:src="@{/js/jquery.min.js}"></script>-->
    <script type="text/javascript" th:src="js/jquery.min.js"></script>

The third thing to write a ajax, when the page is loaded on a hair trigger a request to the back-end, data acquisition, data rendering to complete the operation by each node jQuery

Three-shore call it a day, a fancy is not very complicated, but our page is a static page has become, since she will be cached browser, as long as this page does not fluctuate, the browser has been using its own cache, data traffic on the network how interesting their own brain supplement, the system RT absolutely soared several orders of magnitude

Optimization means of static resources

Talk about optimization techniques common market, it's static resources:

  • Compression and Optimization js / css reduce traffic
  • A plurality js / css together, reducing the number of connections
  • Tengine technology
  • webPack, use vue development, it will set a vue depends packed js a html file, would not Shuangwai?
  • CDN acceleration technology, many manufacturers have to provide cloud services, and the price is not expensive, the large size of static resources on accelerating CDN is a good choice
  • Nginx do use static resource agent, and Nginx to support zero-copy, also supports file compression after the data transmitted over the network, its concurrency is also very powerful, when static resource server it is definitely the best choice, believe me, you will love it

In addition, when multiple users concurrent modification inventory, inventory modifications will become even negative, the database engine itself using innodb is the presence of row-level locking, we just change our sql plus on the line condition and stock_number> 0

In order to prevent the same user to send two requests, the occasional spike to the case of multiple goods, we went miaosha_user table to establish a unique index, a unique index will establish userId does not allow the same userId appears twice, in order to avoid the above Happening

Verification code technology

  • benefit

Allowing users to enter a verification code has a lot of benefits, in addition to verify the user's identity information, the most obvious benefit is dispersed user stress on the system, if you do not add a picture front-end verification may need to carry 10,000 concurrent code in the system 1s but added image verification code, these can be distributed to 10,000 concurrent 10 seconds or less, even more

  • The whole idea:

    Image verification code is just a image, so that the front end want to show it will certainly require a img tag, a relatively poor think the place is Shane? Is this image of path, src = what's the problem, how can we do it? Can Controller imge generated path to the src written directly through this rear end, each refresh the page, it will initiate a request to the path, to generate an Image of the Controller, the HttpServletResponse acquired by the output stream, generated pictures will be sent using the browser streams, plus he is the img tag, which is not to ok?

Baidu how to generate the authentication code of a class of technology, really really a lot, I will not put code, interested students on their own Baidu, a piece of code

  • Click on the picture how to achieve complete refresh does it?

Because this picture is a static resource, if you do not disable the cache, this image will be cached, in order to implement each click picture to replace the verification code words, refer to the following js achieve, add a timestamp

   function refreshImageCode() {
        $("#verifyCodeImg").attr("src","/path/verifyCode?goodsId="+$("#goodsId").val()+"&timestamp="+new Date());
    }

Interface limiting technology

  • What is the interface limiting?

For example: If we want to say in one minute limit single user visits a method of A Controller can not exceed 30 times, which is actually a need for an interface to limit the flow, can effectively prevent malicious users access

  • How to implement the interface limiting it?

In fact, it is not binding cache to achieve a difficult task, for example, I will use the example above:? Not think of a method of limiting it we add the following logic in a method

Pseudo-code as follows:

public void a(User user){
    // 校验user合法性
    // 限流
   Integer count = redis.get(user.getId());
    if(count!=null&&count>15)
      return ; // 到达了指定的阕值,直接返回不允许继续访问
    if(count==null){
        redis.set(user.getId(),30,1); // 表示当前用户访问了1次, 当前key的有效时间为30s
    }else{
        redis.incr(user.getId());
    }
}
  • How business logic code may prevent infection limiting it

We can use the technology to intercept, if we rewrite the interceptor preHandler()method, it will call back before performing the Controller methods, coupled with custom annotation technology behind it is simply to ...

Example:

@Component
public class AccessIntercepter extends HandlerInterceptorAdapter {
    // 在方法执行之前进行拦截
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (handler instanceof HandlerMethod){
            HandlerMethod hd = (HandlerMethod) handler;
            LimitAccess methodAnnotation = hd.getMethodAnnotation(LimitAccess.class);
            if (methodAnnotation==null)
                return true;

            // 解析注解
            int maxCount = methodAnnotation.maxCount();
            boolean needLogin = methodAnnotation.needLogin();
            int second = methodAnnotation.second();
            // todo
        }
        return true;
    }
}

Conclusion: recently I went to the exam week, and this Saturday, next Wednesday test operations research ... wish I could weather the ...

I bloger give me daydreaming, welcome thumbs up support

Guess you like

Origin www.cnblogs.com/ZhuChangwu/p/11872124.html
Recommended