当前位置:首页 > Java技术 > java高并发处理

java高并发处理

2022年08月06日 17:05:55Java技术14

      在java web项目开发者,最难解决的是高并发问题,我为搞并发解决方案,想出了一个解决方案。

     a.应用层面:读写分离、缓存、队列、集群、令牌、系统拆分、隔离、系统升级(可水平扩容方向)。

     b.时间换空间:降低单次请求时间,这样在单位时间内系统并发就会提升。

     c.空间换时间:拉长整体处理业务时间,换取后台系统容量空间。

      1.使用缓存服务器

      使用Redis作为缓存服务器的,刚开始的时候会满足需要,随着项目的增大缓存数据的增多就会查询和插入更慢这时就要考虑Redis集群方案了

使用Redis分布式要保证数据都能能够平均的缓存到每一台机器,首先想到的做法是对数据进行分片,因为Redis是key-value存储的,首先想到的是Hash分片,可能的做法是对key进行哈希运算,得到一个long值对分布式的数量取模会得到一个一个对应数据库的一个映射,没有读取就可以定位到这台数据库,那么速度但然会提升了。

但是取模的hash算法是有问题的如果集群数量不变的话没有什么问题,一旦增加一台机器或者一台机器挂掉,导致机器数量变化,就会导致计算的出的数据库映射乱掉,不能正确存取数据了。

因为这个问题引入我们说的一致性哈希算法,这个哈希算法具有的特征

1.均衡性:也有人把它定义为平衡性,是指哈希的结果能够尽可能分布到所有的节点中去,这样可以有效的利用每个节点上的资源。

2.单调性:对于单调性有很多翻译让我非常的不解,而我想要的是当节点数量变化时哈希的结果应尽可能的保护已分配的内容不会被重新分派到新的节点。

3.分散性和负载:这两个其实是差不多的意思,就是要求一致性哈希算法对 key 哈希应尽可能的避免重复。

一致性哈希就数据结构是创建一个排序的环形数据结构,有许多个区域,先让每一台服务器都分布环上,取每一个服务器的特效做哈希运行,得到的值放进环中,进行排序这样就能根据哈希特征找到对应的真是服务器,能够让把服务器平均的分布到环上。



第一个特征均衡性:就是尽量的让数据平均的分部到每一个服务器,不让某台机器压力特别打,或者干脆没活干,因为这个原因,我们的每一个服务器都添加几个虚拟服务器,比如真是服务器叫node1那么第一个服务器的虚拟服务器就叫node1-1,node1-2...,根据这些特征进行哈希运算也分布到环中,这样就能把服务器平均的分布到环中。


第二个特征单调性:因为服务器都在环中,数据的key进行哈希运算得到一个值,跟环中的服务器的哈希值进行比较,取离当前值最接近的哈希值对象的服务器,这样就是获取服务器的原理了,我们是做了一个偷懒的工作,服务器哈希进行排序,以顺时针方式得到一个刚好大于key哈希的服务器。
单调性是在不管添加节点还是删除节点,原来对应的服务器不变,因为这个环很大,服务器是零星分布的,这样增加或者删除一个节点只有受影响的都是当前节点,但是key对应的数据库是不变的,也不能说不变,是把变化变得尽可能的小。

第三个特征分散性和负载:指服务器在环中尽可能的分散,尽可能的让数据平均分布到不同的服务器,我们就是使用虚拟节点的方式解决的。

public final class MurmurHash {    
    
    public MurmurHash() {    
    
    }    
    
    private byte[] toBytesWithoutEncoding(String str) {    
    
        int len = str.length();    
        int pos = 0;    
        byte[] buf = new byte[len << 1];    
        for (int i = 0; i < len; i++) {    
    
            char c = str.charAt(i);    
            buf[pos++] = (byte) (c & 0xFF);    
            buf[pos++] = (byte) (c >> 8);    
        }    
        return buf;    
    }    
    
    public int hashcode(String str) {    
        byte[] bytes = toBytesWithoutEncoding(str);    
        return hash32(bytes, bytes.length);    
    }    
    
    /**  
     *  * Generates 32 bit hash from byte array of the given length and  * seed.  
     *  *  * @param data byte array to hash  * @param length length of the array  
     * to hash  * @param seed initial seed value  * @return 32 bit hash of the  
     * given array    
     */    
    public int hash32(final byte[] data, int length, int seed) {    
        // 'm' and 'r' are mixing constants generated offline.    
        // They're not really 'magic', they just happen to work well.    
        final int m = 0x5bd1e995;    
        final int r = 24;    
        // Initialize the hash to a random value    
        int h = seed ^ length;    
        int length4 = length / 4;    
        for (int i = 0; i < length4; i++) {    
            final int i4 = i * 4;    
            int k = (data[i4 + 0] & 0xff) + ((data[i4 + 1] & 0xff) << 8)    
                    + ((data[i4 + 2] & 0xff) << 16)    
                    + ((data[i4 + 3] & 0xff) << 24);    
            k *= m;    
            k ^= k >>> r;    
            k *= m;    
            h *= m;    
            h ^= k;    
        }    
        // Handle the last few bytes of the input array    
        switch (length % 4) {    
        case 3:    
            h ^= (data[(length & ~3) + 2] & 0xff) << 16;    
        case 2:    
            h ^= (data[(length & ~3) + 1] & 0xff) << 8;    
        case 1:    
            h ^= (data[length & ~3] & 0xff);    
            h *= m;    
        }    
        h ^= h >>> 13;    
        h *= m;    
        h ^= h >>> 15;    
        return h;    
    }    
    
    /**  
     *  * Generates 32 bit hash from byte array with default seed value.  *  * @param  
     * data byte array to hash  * @param length length of the array to hash  * @return  
     * 32 bit hash of the given array    
     */    
    public int hash32(final byte[] data, int length) {    
        return hash32(data, length, 0x9747b28c);    
    }    
        
    public int hash32(final String data) {    
        byte[] bytes = toBytesWithoutEncoding(data);    
        return hash32(bytes, bytes.length, 0x9747b28c);    
    }    
    
    /**  
     *  * Generates 64 bit hash from byte array of the given length and seed.  *  
     *  * @param data byte array to hash  * @param length length of the array to  
     * hash  * @param seed initial seed value  * @return 64 bit hash of the  
     * given array    
     */    
    public long hash64(final byte[] data, int length, int seed) {    
        final long m = 0xc6a4a7935bd1e995L;    
        final int r = 47;    
        long h = (seed & 0xffffffffl) ^ (length * m);    
        int length8 = length / 8;    
        for (int i = 0; i < length8; i++) {    
            final int i8 = i * 8;    
            long k = ((long) data[i8 + 0] & 0xff)    
                    + (((long) data[i8 + 1] & 0xff) << 8)    
                    + (((long) data[i8 + 2] & 0xff) << 16)    
                    + (((long) data[i8 + 3] & 0xff) << 24)    
                    + (((long) data[i8 + 4] & 0xff) << 32)    
                    + (((long) data[i8 + 5] & 0xff) << 40)    
                    + (((long) data[i8 + 6] & 0xff) << 48)    
                    + (((long) data[i8 + 7] & 0xff) << 56);    
            k *= m;    
            k ^= k >>> r;    
            k *= m;    
            h ^= k;    
            h *= m;    
        }    
        switch (length % 8) {    
        case 7:    
            h ^= (long) (data[(length & ~7) + 6] & 0xff) << 48;    
        case 6:    
            h ^= (long) (data[(length & ~7) + 5] & 0xff) << 40;    
        case 5:    
            h ^= (long) (data[(length & ~7) + 4] & 0xff) << 32;    
        case 4:    
            h ^= (long) (data[(length & ~7) + 3] & 0xff) << 24;    
        case 3:    
            h ^= (long) (data[(length & ~7) + 2] & 0xff) << 16;    
        case 2:    
            h ^= (long) (data[(length & ~7) + 1] & 0xff) << 8;    
        case 1:    
            h ^= (long) (data[length & ~7] & 0xff);    
            h *= m;    
        }    
        ;    
        h ^= h >>> r;    
        h *= m;    
        h ^= h >>> r;    
        return h;    
    }    
    
    /**  
     *  * Generates 64 bit hash from byte array with default seed value.  *  * @param  
     * data byte array to hash  * @param length length of the array to hash  * @return  
     * 64 bit hash of the given string    
     */    
    public long hash64(final byte[] data, int length) {    
        return hash64(data, length, 0xe17a1465);    
    }    
        
        
    public long hash64(final String data) {    
        byte[] bytes = toBytesWithoutEncoding(data);    
        return hash64(bytes, bytes.length);    
    }    
}    


2.动静态资源分离,缓解tomcat服务器压力

 nginx 这个轻量级、高性能的 web server 主要可以干两件事情:

  〉直接作为http server(代替apache,对PHP需要FastCGI处理器支持);
  〉另外一个功能就是作为反向代理服务器实现负载均衡

  以下我们就来举例说明如何使用 nginx 实现负载均衡。因为nginx在处理并发方面的优势,现在这个应用非常常见。当然了Apache的 mod_proxy和mod_cache结合使用也可以实现对多台app server的反向代理和负载均衡,但是在并发处理方面apache还是没有 nginx擅长。

  1)环境:

  a. 我们本地是Windows系统,然后使用VirutalBox安装一个虚拟的Linux系统。
  在本地的Windows系统上分别安装nginx(侦听8080端口)和apache(侦听80端口)。在虚拟的Linux系统上安装apache(侦听80端口)。
  这样我们相当于拥有了1台nginx在前端作为反向代理服务器;后面有2台apache作为应用程序服务器(可以看作是小型的server cluster。;-) );

  b. nginx用来作为反向代理服务器,放置到两台apache之前,作为用户访问的入口;
  nginx仅仅处理静态页面,动态的页面(php请求)统统都交付给后台的两台apache来处理。
  也就是说,可以把我们网站的静态页面或者文件放置到nginx的目录下;动态的页面和数据库访问都保留到后台的apache服务器上。

  c. 如下介绍两种方法实现server cluster的负载均衡。
  我们假设前端nginx(为127.0.0.1:80)仅仅包含一个静态页面index.html;
  后台的两个apache服务器(分别为localhost:80和158.37.70.143:80),一台根目录放置phpMyAdmin文件夹和test.php(里面测试代码为print “server1“;),另一台根目录仅仅放置一个test.php(里面测试代码为 print “server2“;)。

  2)针对不同请求 的负载均衡:

  a. 在最简单地构建反向代理的时候 (nginx仅仅处理静态不处理动态内容,动态内容交给后台的apache server来处理),我们具体的设置为:在nginx.conf中修改:
  复制代码 代码如下:

  location ~ \.php$ {
  proxy_pass 158.37.70.143:80 ;
  }

  〉 这样当客户端访问localhost:8080/index.html的时候,前端的nginx会自动进行响应;
  〉当用户访问localhost:8080/test.php的时候(这个时候nginx目录下根本就没有该文件),但是通过上面的设置 location ~ \.php$(表示正则表达式匹配以.php结尾的文件,详情参看location是如何定义和匹配的 http://wiki.nginx.org/NginxHttpCoreModule) ,nginx服务器会自动pass给 158.37.70.143的apache服务器了。该服务器下的test.php就会被自动解析,然后将html的结果页面返回给nginx,然后 nginx进行显示(如果nginx使用memcached模块或者squid还可以支持缓存),输出结果为打印server2。

   服务器架构图

   java高并发处理 _ JavaClub全栈架构师技术笔记



作者:刘家大少爷10086
来源链接:https://blog.csdn.net/qq_31065001/article/details/54923254

版权声明:
1、JavaClub(https://www.javaclub.cn)以学习交流为目的,由作者投稿、网友推荐和小编整理收藏优秀的IT技术及相关内容,包括但不限于文字、图片、音频、视频、软件、程序等,其均来自互联网,本站不享有版权,版权归原作者所有。

2、本站提供的内容仅用于个人学习、研究或欣赏,以及其他非商业性或非盈利性用途,但同时应遵守著作权法及其他相关法律的规定,不得侵犯相关权利人及本网站的合法权利。
3、本网站内容原作者如不愿意在本网站刊登内容,请及时通知本站(javaclubcn@163.com),我们将第一时间核实后及时予以删除。


本文链接:https://www.javaclub.cn/java/18395.html

分享给朋友:

“java高并发处理” 的相关文章

java ftp上传文件 支持并发

package com.dl.utils; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOE...

高并发下java项目遇到的各种坑--概述篇(一)

      最近在做一个跨境电商的项目,主要是做跨境电商的企业做清关服务,将跨境电商企业订单信息生成清关报文推动海关,推送物流公司并获取物流信息,将海关回执和物流信息分别推送给电商企业和仓库系统等功能。此文章是为了记录在整个技术选型,服务器搭建部署中...

分布式高并发下全局唯一Id的生成方案

前言: 针对于单点服务器生成全局唯一Id的方案: 1、使用java.util.UUID进行全局唯一ID的生成 2、使用com.fasterxml.uuid进行全局唯一Id的生成 maven依赖: <dependency>...

如何在高并发环境下设计出无锁的数据库操作(Java版本)

  一个在线2k的游戏,每秒钟并发都吓死人。传统的hibernate直接插库基本上是不可行的。我就一步步推导出一个无锁的数据库操作。   1. 并发中如何无锁。 一个很简单的思路,把并发转化成为单线程。Java的Disruptor就是一个很好...

Java高并发至Synchronized

Synchronized的作用:   能够保证在同一时刻最多只有一个线程执行该段代码,以达到保证并发安全的效果。 并发编程的地位:   关键字,被java原生支持,实现互斥的基本手段、是研究高并发的基础。 不使用并发手段会有什么样的后果:   例如i++的...

javaweb项目高并发处理

并发是什么,之前我觉得就是对数据的一个安全性操作,这样理解也没有错,因为这是数据的并发,那么什么是并发呢? 并发,在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行,但任一个时刻点上只有一个程序在处理机上运行。...

java高并发 pdf

推荐序一 推荐序二 推荐序三 推荐序四 前言 第一部分 多线程基础 第1章 快速认识线程 1.1 线程的介绍 1.2 快速创建并启动一个线程 1.3 线程的生命周期详解 1.4 线程的sta...

Java高并发秒杀系统(二)

Java高并发秒杀系统(二)

秒杀系优化分析 1 详情页面 2系统时间 3地址暴露接口 4执行秒杀操作 秒杀系统优化实现...

JAVA高并发的三种实现

JAVA高并发的三种实现

提到锁,大家肯定想到的是sychronized关键字。是用它可以解决一切并发问题,但是,对于系统吞吐量要求更高的话,我们这提供几个小技巧。帮助大家减小锁颗粒度,提高并发能力。 初级技巧-乐观锁 乐观锁使用的场景是,读不会冲突,写会冲突。同时读的频率远大于写。 &...

《实战Java高并发程序设计》读书笔记一

《实战Java高并发程序设计》读书笔记一

第一章 走入并行世界 1、基本概念 同步:同步方法一旦开始,调用者必须等到方法调用返回后,才能继续后续操作 异步:一旦开始,方法调用就会立即返回,调用就可以继续后续操作 并发:表示两个或者多个任务一起执行,偏重于任务交替执行,而多个任务之间...

发表评论

访客

◎欢迎参与讨论,请在这里发表您的看法和观点。