分类: 开源工具

  • 针对 jar 和 vue 的一键自动化部署工具,界面友好,操作简单(已开源)

    前言

    easy-jenkins是一款对vue和jar的部署工具,操作简单,实行一键部署,内部结构采用流水线形式架构,每次部署,时时提供部署过程,部署记录,界面友好简洁,使用方便,符合用户常规操作

    easy-jenkins面向分支形式,无需登录,默认分支为jenkins,每个分支可以配置多个数据源,切换不同分支可以管理不同数据源

    easy-jenkins采用本地存储的结构无需配置数据库,简单易上手

    提示:以下是本篇文章正文内容,下面案例可供参考

    一、项目地址

    开源地址:

    • https://gitee.com/susantyp/easy-jenkins

    二、使用步骤

    先把代码拉入你的本地

    1.项目结构

    2.启动主类 EasyJenkinsApplication

    3.安装

    启动后弹出当前窗体 点击下一步

    来到这里后,填写相应的信息

    • 安装路径
    • maven路径 打包需要
    • 以及项目端口的启动,避免不要和本地端口冲突,我们可以设置 8332 8899 9900 等端口

    点击安装并启动, 点击确认 等待几秒,项目自动启动

    4.项目启动图

    三、功能点介绍

    • 部署列表
    • 部署记录
    • 数据分支
    • 基本设置

    1.部署列表

    部署列表主要显示我们的连接信息

    1.添加连接(部署jar)

    我们点击按钮,添加连接

    添加本地项目地址

    添加本地项目地址后,它下面的文本款会根据本地项目地址自动生成,如图

    在这边需要确保:

    • 你的本地项目地址是正确的
    • jar名称正确的
    • pom.xml文件是正确的

    我部署项目的端口为8080

    根据你自己的项目设置端口

    添加服务器相关信息

    在我们的右边填写我们的服务器信息

    • 服务器ip
    • 账号
    • 密码
    • 端口

    上传的位置 后面不需要带 /

    上传的位置 默认生成一个命令

    如果上传位置是 /home/springboot

    则生成如下

    nohup java -jar /home/springboot/wall.jar & tailf /home/springboot/nohup.out

    可以修改为你自己需要运行的命令

    或者直接使用当前命令

    2.部署jar

    我们点击部署按钮即可

    部署过程效果图

    后台会实时返回部署的消息,返回给前端显示

    3.部署成功

    部署成功返回:Successfully deployed

    4.删除

    点击table 直接删除

    5.编辑

    编辑小伙伴可以自己玩一下

    2.部署记录

    部署记录主要记录了,最近部署的情况和统计信息

    3.数据分支

    easy-jenkins 是面向分支的

    不同分支存储不同的连接,默认分支为jenkins

    1.创建分支

    创建一个root的分支

    2.切换分支

    切换完成后,可以查看当前分支的状态

    当前我们就是root分支的环境下

    我们点击部署记录

    部署记录此时为空的,刚刚创建分支下面是没有连接数据的,需要重新添加连接

    我们切换为jenkins分支后,前面我们在jenkins添加了一条连接数据,下面就显示数据了,同时上面会标注当前的环境为jenkins

    注意了,正在使用的分支是不可以删除

    4.基本设置

    • 安装路径
    • maven路径
    • 项目端口号

    当前这三个值,是我们最初刚刚开始安装的时候的需要录入的值,我们可以点击编辑操作

    5.启动

    • 第一次启动会启动安装向导程序
    • 第二次启动直接启动浏览器,则不再启动安装向导程序

    6.如何部署vue

    dist 是vue项目默认build的位置

    同样 后面 不需要 ‘/’

    需要注意

    上传位置名字保持跟本地相同的名字,如图:

    然后填写你相应的服务器信息即可

    7.exe启动项目

    在我们exe文件夹下面,有一个easy-jenkins.exe文件

    可以将他拷贝到桌面,直接点击它运行即可,不需要每次启动springboot程序

    总结

    此部署工具主要针对于个人本地的部署

    针对于小型项目的部署,轻量级的,一键部署,操作简单

    作者:来自上海的这位朋友

    来源:blog.csdn.net/Susan003/article/

    details/128223343

  • 为什么 Nginx 比 Apache 更牛叉?

    快乐分享,Java干货及时送达👇

    来源:codebay.cn/post/8557.html

    • 一、Apache三种工作模式
      • 1、prefork的工作原理
      • 2、worker的工作原理
      • 3、event 基于事件机制的特性
    • 二、如何提高Web服务器的并发连接处理能力
    • 三、Nginx优异之处
    • 四、Nginx 工作原理
    • 五、Nginx 的诞生主要解决C10K问题
      • 1、select模型:(apache使用,由于受模块等限制,用的不多);
      • 2、poll:poll是unix沿用select自己重新实现了一遍,唯一解决的问题是poll 没有最大文件描述符数量的限制;
      • 3、epoll模型:(Nginx使用)

    Nginx才短短几年,就拿下了Web服务器大壁江山,众所周知,Nginx在处理大并发静态请求方面,效率明显高于Httpd,甚至能轻松解决C10K问题。

    在高并发连接的情况下,Nginx是Apache服务器不错的替代品。Nginx同时也可以作为7层负载均衡服务器来使用。根据我的测试结果,Nginx + PHP(FastCGI) 可以承受3万以上的并发连接数,相当于同等环境下Apache的10倍。

    一般来说,4GB内存的服务器+Apache(prefork模式)一般只能处理3000个并发连接,因为它们将占用3GB以上的内存,还得为系统预留1GB的内存。我曾经就有两台Apache服务器,因为在配置文件中设置的MaxClients为4000,当Apache并发连接数达到3800时,导致服务器内存和Swap空间用满而崩溃。

    而这台 Nginx + PHP(FastCGI) 服务器在3万并发连接下,开启的10个Nginx进程消耗150M内存(15M*10=150M),开启的64个php-cgi进程消耗1280M内存(20M*64=1280M),加上系统自身消耗的内存,总共消耗不到2GB内存。如果服务器内存较小,完全可以只开启25个php-cgi进程,这样php-cgi消耗的总内存数才500M。

    在3万并发连接下,访问Nginx+ PHP(FastCGI) 服务器的PHP程序,仍然速度飞快。

    为什么Nginx在处理高并发方面要优于httpd,我们先从两种web服务器的工作原理以及工作模式说起。

    一、Apache三种工作模式

    我们都知道Apache有三种工作模块,分别为:prefork、worker、event。

    • prefork: 多进程,每个请求用一个进程响应,这个过程会用到select机制来通知。
    • worker: 多线程,一个进程可以生成多个线程,每个线程响应一个请求,但通知机制还是select不过可以接受更多的请求。
    • event: 基于异步I/O模型,一个进程或线程,每个进程或线程响应多个用户请求,它是基于事件驱动(也就是epoll机制)实现的。

    1、prefork的工作原理

    如果不用“–with-mpm”显式指定某种MPM,prefork就是Unix平台上缺省的MPM。它所采用的预派生子进程方式也是 Apache1.3中采用的模式。prefork本身并没有使用到线程,2.0版使用它是为了与1.3版保持兼容性;另一方面,prefork用单独的子进程来处理不同的请求,进程之间是彼此独立的,这也使其成为最稳定的MPM之一。

    2、worker的工作原理

    相对于prefork,worker是2.0版中全新的支持多线程和多进程混合模型的MPM。由于使用线程来处理,所以可以处理相对海量的请求,而系统资源的开销要小于基于进程的服务器。但是,worker也使用了多进程,每个进程又生成多个线程,以获得基于进程服务器的稳定性,这种MPM的工作方 式将是Apache2.0的发展趋势。

    3、event 基于事件机制的特性

    一个进程响应多个用户请求,利用callback机制,让套接字复用,请求过来后进程并不处理请求,而是直接交由其他机制来处理,通过epoll机制来通知请求是否完成;在这个过程中,进程本身一直处于空闲状态,可以一直接收用户请求。可以实现一个进程程响应多个用户请求。支持持海量并发连接数,消耗更少的资源。

    二、如何提高Web服务器的并发连接处理能力

    有几个基本条件:

    1、基于线程,即一个进程生成多个线程,每个线程响应用户的每个请求。

    2、基于事件的模型,一个进程处理多个请求,并且通过epoll机制来通知用户请求完成。

    3、基于磁盘的AIO(异步I/O)

    4、支持mmap内存映射,mmap传统的web服务器,进行页面输入时,都是将磁盘的页面先输入到内核缓存中,再由内核缓存中复制一份到web服务器上,mmap机制就是让内核缓存与磁盘进行映射,web服务器,直接复制页面内容即可。不需要先把磁盘的上的页面先输入到内核缓存去。

    刚好,Nginx 支持以上所有特性。所以Nginx官网上说,Nginx支持50000并发,是有依据的。

    三、Nginx优异之处

    传统上基于进程或线程模型架构的Web服务通过每进程或每线程处理并发连接请求,这势必会在网络和I/O操作时产生阻塞,其另一个必然结果则是对内存或CPU的利用率低下。

    生成一个新的进程/线程需要事先备好其运行时环境,这包括为其分配堆内存和栈内存,以及为其创建新的执行上下文等。这些操作都需要占用CPU,而且过多的进程/线程还会带来线程抖动或频繁的上下文切换,系统性能也会由此进一步下降。

    另一种高性能web服务器/Web服务器反向代理:Nginx,Nginx的主要着眼点就是其高性能以及对物理计算资源的高密度利用,因此其采用了不同的架构模型。受启发于多种操作系统设计中基于“事件”的高级处理机制,Nginx采用了模块化、事件驱动、异步、单线程及非阻塞的架构,并大量采用了多路复用及事件通知机制。

    在Nginx中,连接请求由为数不多的几个仅包含一个线程的进程Worker以高效的回环(run-loop)机制进行处理,而每个Worker可以并行处理数千个的并发连接及请求。

    四、Nginx 工作原理

    Nginx会按需同时运行多个进程:一个主进程(master)和几个工作进程(worker),配置了缓存时还会有缓存加载器进程(cache loader)和缓存管理器进程(cache manager)等。所有进程均是仅含有一个线程,并主要通过“共享内存”的机制实现进程间通信。主进程以root用户身份运行,而worker、cache loader和cache manager均应以非特权用户身份运行。

    在高连接并发的情况下,Nginx是Apache服务器不错的替代品。

    Nginx 安装非常的简单 , 配置文件非常简洁(还能够支持perl语法),Bugs 非常少的服务器: Nginx 启动特别容易, 并且几乎可以做到7*24不间断运行,即使运行数个月也不需要重新启动. 你还能够 不间断服务的情况下进行软件版本的升级 。

    五、Nginx 的诞生主要解决C10K问题

    最后我们从各自使用的多路复用IO模型来分析:

    1、select模型:(apache使用,由于受模块等限制,用的不多);

    单个进程能够 监视的文件描述符的数量存在最大限制;

    select()所维护的 存储大量文件描述符的数据结构 ,随着文件描述符数量的增长,其在用户态和内核的地址空间的复制所引发的开销也会线性增长;

    由于网络响应时间的延迟使得大量TCP连接处于非活跃状态,但调用select()还是会对 所有的socket进行一次线性扫描 ,会造成一定的开销;

    2、poll:poll是unix沿用select自己重新实现了一遍,唯一解决的问题是poll 没有最大文件描述符数量的限制;

    3、epoll模型:(Nginx使用)

    epoll带来了两个优势,大幅度提升了性能:

    (1)基于事件的就绪通知方式 ,select/poll方式,进程只有在调用一定的方法后,内核才会对所有监视的文件描述符进行扫描,而epoll事件通过epoll_ctl()注册一个文件描述符,一旦某个文件描述符就绪时,内核会采用类似call back的回调机制,迅速激活这个文件描述符,epoll_wait()便会得到通知

    (2)调用一次epoll_wait()获得就绪文件描述符时,返回的并不是实际的描述符,而是一个代表就绪描述符数量的值,拿到这些值去epoll指定的一个数组中依次取得相应数量的文件描述符即可,这里使用内存映射(mmap)技术, 避免了复制大量文件描述符带来的开销

    (3)当然epoll也有一定的局限性, epoll只有Linux2.6才有实现 ,而其他平台都没有,这和apache这种优秀的跨平台服务器,显然是有些背道而驰了。

    (4)简单来说epoll是select的升级版,单进程管理的文件描述符没有最大限制。但epoll只有linux平台可使用。作为跨平台的Apache没有使用

    
    

  • 太牛了,前后端完全开源,快速搭建简约美观的在线可互动的教室,星标4.5k!

    快乐分享,Java干货及时送达👇

    Agora Flat开源教室是一款高效实用且专业的互动课堂软件,Agora Flat开源教室能够帮助用户快速搭建简约的互动教室,实现网上学习和授课等功能,提高教学效率。

    Agora Flat开源教室客户端支持大小课班和一对一的模式,用户可以多情景灵便转换,进行优质课堂教学。

    特性

    • 实时交互:多功能互动白板,实时音视频(RTC)通讯,即时消息(RTM)聊天
    • 登录方式:微信,GitHub
    • 房间管理:加入、创建、预定房间,支持周期性房间
    • 课堂录制回放:白板信令回放,音视频云录制回放,群聊信令回放
    • 多媒体课件云盘
    • 屏幕共享

    功能

    轻松创建丰富多样的在线教室

    • 大班课

    适用于大型课堂授课,知识传递效率更高。学生可举手发言参与在线互动。

    • 小班课

    适用于 1 名教师和 2~16 名学生进行在线教学,互动性更及时,趣味性更高,提高教学效率的同时保证质量。

    • 一对一

    适用于 1 名老师对 1 名学生,沉浸式的个性化课堂教学,学习效果更加明显。

    支持自定义主题和 UI

    场景插件:无限的组合,无限的可能

    安装运行

    快速上手

    你可以在没有服务端的情况下构建并运行 Flat 客户端。此仓库包含以下项目:

    Flat Electron 客户端

    https://github.com/netless-io/flat/tree/main/desktop

    Flat Web 客户端

    https://github.com/netless-io/flat/tree/main/web

    安装

    如果你还没有安装 pnpm:

    npm i -g pnpm

    Clone 或者 fork 这个项目,在根目录执行:

    pnpm i

    构建并运行 Flat Electron 客户端

    在仓库根目录运行以下命令:

    pnpm start

    你可以运行以下命令将项目打包成可执行文件:

    • 项目根目录执行 pnpm ship 将根据当前系统打包。
    • 或者项目根目录执行 pnpm ship:macpnpm ship:win 可针对指定的系统打包。

    如果你因为网络问题导致无法下载 electron,可在项目目录新建: .npmrc 文件,并写入 ELECTRON_MIRROR=" https://npmmirror.com/mirrors/electron/" 内容。重新执行 pnpm i 即可。

    构建并运行 Flat Web 客户端

    在仓库根目录运行以下任意一个命令:

    pnpm start:web
    cd ./web/flat-web/ && pnpm start

    在 Flat 中 UI 逻辑与业务逻辑分开开发。可以通过 Storybook 快速查看与开发部分 UI。在项目根目录执行 pnpm storybook 在本地运行 Storybook。

    相关项目

    Flat 安卓客户端

    • https://github.com/netless-io/flat-android

    Flat 服务端

    • https://github.com/netless-io/flat-server

    Flat 主页

    • https://flat.whiteboard.agora.io/#download

    传送门

    • 开源地址:https://github.com/netless-io/flat

    整理:骑猪看星星

    来源:开源技术专栏

  • 牛逼哄哄的 BitMap,到底牛逼在哪?

    快乐分享,Java干货及时送达👇

    文章来源:https://www.cnblogs.com/cjsblog/p/11613708.html


    BitMap


    Bit-map的基本思想就是用一个bit位来标记某个元素对应的Value,而Key即是该元素。由于采用了Bit为单位来存储数据,因此在存储空间方面,可以大大节省。(PS:划重点 节省存储空间 )

    假设有这样一个需求:在20亿个随机整数中找出某个数m是否存在其中,并假设32位操作系统,4G内存

    在Java中,int占4字节,1字节=8位(1 byte = 8 bit)

    如果每个数字用int存储,那就是20亿个int,因而占用的空间约为 (2000000000*4/1024/1024/1024)≈7.45 G

    如果按位存储就不一样了,20亿个数就是20亿位,占用空间约为 (2000000000/8/1024/1024/1024)≈0.233 G

    高下立判,无需多言

    那么,问题来了,如何表示一个数呢?

    刚才说了,每一位表示一个数,0表示不存在,1表示存在,这正符合二进制

    这样我们可以很容易表示{1,2,4,6}这几个数:

    计算机内存分配的最小单位是字节,也就是8位,那如果要表示{12,13,15}怎么办呢?

    当然是在另一个8位上表示了:

    图片

    这样的话,好像变成一个二维数组了

    1个int占32位,那么我们只需要申请一个int数组长度为 int tmp[1+N/32] 即可存储,其中N表示要存储的这些数中的最大值,于是乎:

    tmp[0]:可以表示0~31

    tmp[1]:可以表示32~63

    tmp[2]:可以表示64~95

    。。。

    如此一来,给定任意整数M,那么M/32就得到下标,M%32就知道它在此下标的哪个位置


    添加


    这里有个问题,我们怎么把一个数放进去呢?例如,想把5这个数字放进去,怎么做呢?

    首先,5/32=0,5%32=5,也是说它应该在tmp[0]的第5个位置,那我们把1向左移动5位,然后按位或

    换成二进制就是

    这就相当于 86 | 32 = 118

    86 | (1

    b[0] = b[0] | (1

    也就是说,要想插入一个数,将1左移带代表该数字的那一位,然后与原数进行按位或操作

    化简一下,就是 86 + (5/8) | (1

    因此,公式可以概括为:p + (i/8)|(1


    清除


    以上是添加,那如果要清除该怎么做呢?

    还是上面的例子,假设我们要6移除,该怎么做呢?

    从图上看,只需将该数所在的位置为0即可

    1左移6位,就到达6这个数字所代表的位,然后按位取反,最后与原数按位与,这样就把该位置为0了

    b[0] = b[0] & (~(1

    b[0] = b[0] & (~(1


    查找


    前面我们也说了,每一位代表一个数字,1表示有(或者说存在),0表示无(或者说不存在)。通过把该为置为1或者0来达到添加和清除的小伙,那么判断一个数存不存在就是判断该数所在的位是0还是1

    假设,我们想知道3在不在,那么只需判断 b[0] & (1


    Bitmap有什么用


    量数据的快速排序、查找、去重



    快速排序


    假设我们要对0-7内的5个元素(4,7,2,5,3)排序(这里假设这些元素没有重复),我们就可以采用Bit-map的方法来达到排序的目的。

    要表示8个数,我们就只需要8个Bit(1Bytes),首先我们开辟1Byte的空间,将这些空间的所有Bit位都置为0,然后将对应位置为1。

    最后,遍历一遍Bit区域,将该位是一的位的编号输出(2,3,4,5,7),这样就达到了排序的目的,时间复杂度O(n)。

    优点:

    • 运算效率高,不需要进行比较和移位;
    • 占用内存少,比如N=10000000;只需占用内存为N/8=1250000Byte=1.25M

    缺点:

    • 所有的数据不能重复。即不可对重复的数据进行排序和查找。
    • 只有当数据比较密集时才有优势

    快速去重


    20亿个整数中找出不重复的整数的个数,内存不足以容纳这20亿个整数。

    首先,根据“内存空间不足以容纳这05亿个整数”我们可以快速的联想到Bit-map。下边关键的问题就是怎么设计我们的Bit-map来表示这20亿个数字的状态了。其实这个问题很简单,一个数字的状态只有三种,分别为不存在,只有一个,有重复。因此,我们只需要2bits就可以对一个数字的状态进行存储了,假设我们设定一个数字不存在为00,存在一次01,存在两次及其以上为11。那我们大概需要存储空间2G左右。

    接下来的任务就是把这20亿个数字放进去(存储),如果对应的状态位为00,则将其变为01,表示存在一次;如果对应的状态位为01,则将其变为11,表示已经有一个了,即出现多次;如果为11,则对应的状态位保持不变,仍表示出现多次。

    最后,统计状态位为01的个数,就得到了不重复的数字个数,时间复杂度为O(n)。

    快速查找


    这就是我们前面所说的了,int数组中的一个元素是4字节占32位,那么除以32就知道元素的下标,对32求余数(%32)就知道它在哪一位,如果该位是1,则表示存在。



    小结&回顾


    Bitmap主要用于快速检索关键字状态,通常要求关键字是一个连续的序列(或者关键字是一个连续序列中的大部分), 最基本的情况,使用1bit表示一个关键字的状态(可标示两种状态),但根据需要也可以使用2bit(表示4种状态),3bit(表示8种状态)。

    Bitmap的主要应用场合:表示连续(或接近连续,即大部分会出现)的关键字序列的状态(状态数/关键字个数 越小越好)。

    32位机器上,对于一个整型数,比如int a=1 在内存中占32bit位,这是为了方便计算机的运算。但是对于某些应用场景而言,这属于一种巨大的浪费,因为我们可以用对应的32bit位对应存储十进制的0-31个数,而这就是Bit-map的基本思想。Bit-map算法利用这种思想处理大量数据的排序、查询以及去重。

    补充1


    在数字没有溢出的前提下,对于正数和负数,左移一位都相当于乘以2的1次方,左移n位就相当于乘以2的n次方,右移一位相当于除2,右移n位相当于除以2的n次方。

    >> 右移,相当于除以2的n次方,例如:64>>3 相当于64÷8=8

    ^ 异或,相当于求余数,例如:48^32 相当于 48%32=16

    补充2


    不使用第三方变量,交换两个变量的值

    // 方式一
    a = a + b;
    b = a - b;
    a = a - b;

    // 方式二
    a = a ^ b;
    b = a ^ b;
    a = a ^ b;


    BitSet


    BitSet实现了一个位向量,它可以根据需要增长。每一位都有一个布尔值。一个BitSet的位可以被非负整数索引(PS:意思就是每一位都可以表示一个非负整数)。可以查找、设置、清除某一位。通过逻辑运算符可以修改另一个BitSet的内容。默认情况下,所有的位都有一个默认值false。

    图片
    图片
    图片
    图片
    图片

    可以看到,跟我们前面想的差不多

    用一个long数组来存储,初始长度64,set值的时候首先右移6位(相当于除以64)计算在数组的什么位置,然后更改状态位

    别的看不懂不要紧,看懂这两句就够了:

    int wordIndex = wordIndex(bitIndex);
    words[wordIndex] |= (1L 


    Bloom Filters


    图片

    Bloom filter 是一个数据结构,它可以用来判断某个元素是否在集合内,具有运行快速,内存占用小的特点。

    而高效插入和查询的代价就是,Bloom Filter 是一个基于概率的数据结构:它只能告诉我们一个元素绝对不在集合内或可能在集合内。

    Bloom filter 的基础数据结构是一个 比特向量(可理解为数组)。

    主要应用于大规模数据下不需要精确过滤的场景,如检查垃圾邮件地址,爬虫URL地址去重,解决缓存穿透问题等

    如果想判断一个元素是不是在一个集合里,一般想到的是将集合中所有元素保存起来,然后通过比较确定。链表、树、散列表(哈希表)等等数据结构都是这种思路,但是随着集合中元素的增加,需要的存储空间越来越大;同时检索速度也越来越慢,检索时间复杂度分别是O(n)、O(log n)、O(1)。

    布隆过滤器的原理是,当一个元素被加入集合时,通过 K 个散列函数将这个元素映射成一个位数组(Bit array)中的 K 个点,把它们置为 1 。检索时,只要看看这些点是不是都是1就知道元素是否在集合中;如果这些点有任何一个 0,则被检元素一定不在;如果都是1,则被检元素很可能在(之所以说“可能”是误差的存在)。


    BloomFilter 流程

    1、 首先需要 k 个 hash 函数,每个函数可以把 key 散列成为 1 个整数;

    2、初始化时,需要一个长度为 n 比特的数组,每个比特位初始化为 0;

    3、某个 key 加入集合时,用 k 个 hash 函数计算出 k 个散列值,并把数组中对应的比特位置为 1;

    4、判断某个 key 是否在集合时,用 k 个 hash 函数计算出 k 个散列值,并查询数组中对应的比特位,如果所有的比特位都是1,认为在集合中。

    dependency>
        groupId>com.google.guavagroupId>
        artifactId>guavaartifactId>
        version>28.1-jreversion>
    dependency>