2019年12月

Nginx配置文件通常位于sites-available目录中,一个网站一个配置文件。参考文档
Nginx配置文件主要分成以下几部分:

1、 main(全局设置)

配置影响nginx全局指令,一般有运行nginx服务器的用户组、nginx进程pid存放路径、日志存放路径、配置文件引入、允许生成的worker_process数等

2、 events

配置影响nginx服务器或与用户的网络连接等。

有每个进程的最大连接数,选取那种事件驱动模型处理连接请求,是否允许同事接受多个网络连接、开启多个网络连接序列化等

3、 http

可以嵌套多个server,配置代理、缓存、日志定义等绝大多数功能和第三方模块的配置。如文件引入、mime-type定义、日志自定义、连接超时时间、单连接请求数等

4、 server(主机设置)

主要用于配置虚拟主机的相关参数,如域名、IP、端口等。一个http中可以有多个server

5、 upstream(上游服务器设置,主要为反向代理、负载均衡等相关配置)

主要用于设置一系列的后端服务器

6、 location(URL匹配特定位置后的设置)

配置请求的路由对应的网页位置,以及各种网页的处理情况。比如,根目录“/”,“/images”,)

server 继承 main,location 继承 server,upstream独立(既不继承也不被继承)。
比如location的root 可以放在server中,也可以放在location中

Nginx文件结构

...              #全局块

events {         #events块
   ...
}

http      #http块
{
    ...   #http全局块
    server        #server块
    { 
        ...       #server全局块
        location [PATTERN]   #location块
        {
            ...
        }
        location [PATTERN] 
        {
            ...
        }
    }
    server
    {
      ...
    }
    ...     #http全局块
}

通用配置文件

user www www;
worker_processes 2;  
error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;  
pid logs/nginx.pid;

events {
    use epoll;
    worker_connections 2048;
}

http {

    include mime.types;
    default_type application/octet-stream;  
    #log_format main '$remote_addr - $remote_user [$time_local] "$request" '
    # '$status $body_bytes_sent "$http_referer" '
    # '"$http_user_agent" "$http_x_forwarded_for"';  
    #access_log logs/access.log main;  
    sendfile on;
    # tcp_nopush on;  
    keepalive_timeout 65;  

    # gzip压缩功能设置
    gzip on;
    gzip_min_length 1k;
    gzip_buffers 4 16k;
    gzip_http_version 1.0;
    gzip_comp_level 6;
    gzip_types text/html text/plain text/css text/javascript application/json application/javascript   application/x-javascript application/xml;
    gzip_vary on;  

    # http_proxy 设置
    client_max_body_size 10m;
    client_body_buffer_size 128k;
    proxy_connect_timeout 75;
    proxy_send_timeout 75;
    proxy_read_timeout 75;
    proxy_buffer_size 4k;
    proxy_buffers 4 32k;
    proxy_busy_buffers_size 64k;
    proxy_temp_file_write_size 64k;
    proxy_temp_path /usr/local/nginx/proxy_temp 1 2;  

    # 设定负载均衡后台服务器列表
    upstream backend {
        #ip_hash;
        server 192.168.10.100:8080 max_fails=2 fail_timeout=30s ;
        server 192.168.10.101:8080 max_fails=2 fail_timeout=30s ;
    }  

    # 很重要的虚拟主机配置
    server {
        listen 80;
        server_name itoatest.example.com;
        root /apps/oaapp;  
        charset utf-8;
        access_log logs/host.access.log main;  

        #对 / 所有做负载均衡+反向代理
    location / {
        root /apps/oaapp;
        index index.jsp index.html index.htm;  
        proxy_pass http://backend;
        proxy_redirect off;

        # 后端的Web服务器可以通过X-Forwarded-For获取用户真实IP
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504;
      }  

    #静态文件,nginx自己处理,不去backend请求tomcat
    location ~* /download/ {
        root /apps/oa/fs;
    }
    location ~ .*\.(gif|jpg|jpeg|bmp|png|ico|txt|js|css)$ {    
        root /apps/oaapp;
        expires 7d;
    }
    location /nginx_status {
        stub_status on;
        access_log off;
        allow 192.168.10.0/24;
        deny all;
    } 
    location ~ ^/(WEB-INF)/ {
        deny all;
    }
    #error_page 404 /404.html;  
    # redirect server error pages to the static page /50x.html
    #
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
    root html;
}
}  
## 其它虚拟主机,server 指令开始
}

通用指令、变量说明

map 指令是由ngx_http_map_module 模块提供的,默认情况下安装nginx都会安装
map 的作用是 创建自定义变量,通过使用nginx的内置变量,去匹配某些特定规则,如果匹配常规则将值给自定义变量。

语法:map $var1 $var2 {...}
$var1是源变量,通常为nginx的内置变量。$var2就是自定义的变量,$var2的值取决于匹配的情况
内部匹配是正则表达式,如果以"~"开头,则表明对大小写敏感,"~*"则是不敏感

例: 匹配请求的url传过来的参数。如果参数是"debug",则设置$foo=1,默认设置$foo=0

map $args $foo {
    default 0;
    debug   1;
}

解释 $args是nginx的内置变量,就是获取的请求url的参数。如果 $args 匹配到debug 那么就会将$foo的值设置为1,默认为0

2、常用指令说明

2.1 全局配置

  • worker_processes 2

在配置文件的顶级main部分,worker角色的工作进程的个数,master进程是接收并分配请求给worker处理。这个数值简单一点可以设置为cpu的核数grep ^processor /proc/cpuinfo | wc -l,也是 auto 值,如果开启了ssl和gzip更应该设置成与逻辑CPU数量一样甚至为2倍,可以减少I/O操作。如果nginx服务器还有其它服务,可以考虑适当减少。

  • worker_cpu_affinity

也是写在main部分。在高并发情况下,通过设置cpu粘性来降低由于多CPU核切换造成的寄存器等现场重建带来的性能损耗。如 worker_cpu_affinity 0001 0010 0100 1000; (四核)。

  • worker_connections 2048

写在events部分。每一个worker进程能并发处理(发起)的最大连接数(包含与客户端或后端被代理服务器间等所有连接数)。nginx作为反向代理服务器,计算公式 最大连接数 = worker_processes * worker_connections/4,所以这里客户端最大连接数是1024,这个可以增到到8192都没关系,看情况而定,但不能超过后面的worker_rlimit_nofile。当nginx作为http服务器时,计算公式里面是除以2。

  • worker_rlimit_nofile 10240

写在main部分。默认是没有设置,可以限制为操作系统最大的限制65535。

  • use epoll

写在events部分。在Linux操作系统下,nginx默认使用epoll事件模型,得益于此,nginx在Linux操作系统下效率相当高。同时Nginx在OpenBSD或FreeBSD操作系统上采用类似于epoll的高效事件模型kqueue。在操作系统不支持这些高效模型时才使用select。

2.2

3、配置WebSocket

Nginx 配置 WebSocket反向代理,可直接复制使用.


map $http_upgrade $connection_upgrade { 
    default upgrade; 
    '' close; 
} 
upstream wsbackend{ 
    server ip1:port1; 
    server ip2:port2; 
    keepalive 1000; 
} 

server { 
    listen 20038; 
    location /{ 
        proxy_http_version 1.1; 
        proxy_pass http://wsbackend; 
        proxy_redirect off; 
        proxy_set_header Host $host; 
        proxy_set_header X-Real-IP $remote_addr; 
        proxy_read_timeout 3600s; 
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
        proxy_set_header Upgrade $http_upgrade; 
        proxy_set_header Connection $connection_upgrade; 
    } 
}

详解:
http协议中,header中有个Upgrade(主要用于检测协议)
Ngin代理WebSocket的重点是设置Upgrade和Connection响应头。
配置Nginx根据Upgrade(既$http_upgrade)来设置Connection

  • 如果请求头中有Upgrade,就直接设置到响应头中,并把Connection设置为upgrade。
    因为websocket请求时header中会带上 Upgrade:websocket,Connection:Upgrade
    否则把Connection设置为close。如普通的Http请求

websocket.png

因此
第一步、

map $http_upgrade $connection_upgrade { 
    default upgrade; 
    '' close; 
}

表示的是

  1. 如果 $http_upgrade 不为 '' (空),则 $connection_upgrade 为 upgrade
  2. 如果 $http_upgrade 为 '' (空),则 $connection_upgrade 为 close

第二步、

   upstream wsbackend{ 
        server ip1:port1; 
        server ip2:port2; 
        keepalive 1000; 
    } 

表示的是 nginx负载均衡

  1. 两台服务器 (ip1:port1)和(ip2:port2)
  2. keepalive 1000 表示的是每个nginx进程中上游服务器保持的空闲连接,当空闲连接过多时,会关闭最少使用的空闲连接.当然,这不是限制连接总数的,可以想象成空闲连接池的大小.设置的值应该是上游服务器能够承受的

最后、

server { 
    listen 20038; 
    location /{ 
    proxy_http_version 1.1; 
    proxy_pass http://wsbackend; 
    proxy_redirect off; 
    proxy_set_header Host $host; 
    proxy_set_header X-Real-IP $remote_addr; 
    proxy_read_timeout 3600s; 
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 
    proxy_set_header Upgrade $http_upgrade; 
    proxy_set_header Connection $connection_upgrade; 
    } 
} 

表示的是监听的服务器的配置

  1. listen 20038 表示 nginx 监听的端口
  2. locations / 表示监听的路径(/表示所有路径,通用匹配,相当于default)
  3. proxt_http_version 1.1 表示反向代理发送的HTTP协议的版本是1.1,HTTP1.1支持长连接
  4. proxy_pass http://wsbackend; 表示反向代理的uri,这里可以使用负载均衡变量
  5. proxy_redirect off; 表示不要替换路径,其实这里如果是/则有没有都没关系,因为default也是将路径替换到proxy_pass的后边
  6. proxy_set_header Host $host; 表示传递时请求头不变, $host是nginx内置变量,表示的是当前的请求头,proxy_set_header表示设置请求头
  7. proxy_set_header X-Real-IP $remote_addr; 表示传递时来源的ip还是现在的客户端的ip
  8. proxy_read_timeout 3600s; 表的两次请求之间的间隔超过 3600s 后才关闭这个连接,默认的60s.自动关闭的元凶
  9. proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 表示X-Forwarded-For头不发生改变
  10. proxy_set_header Upgrade $http_upgrade; 表示设置Upgrade不变 11. proxy_set_header Connection $connection_upgrade; 表示如果 $http_upgrade为upgrade,则请求为upgrade(websocket),如果不是,就关闭连接

前言

记录下常用的Homestead方法,其实说是Homestead,很多时候都是Linux的常规用法

Homestead安装Swoole

流程:

  1. 通过vagrant init创建Vagrantfile文件,通常不用执行

切记,默认git的Homestead是有Vagrantfile文件的,如果删除了再执行这个代码会出现一些异常。

  1. 执行vagrant up 或者执行vagrant provision时,虚拟机进入初始化状态

Vagrant 提供的钩子,触发【Homestead脚本】,具体为 homestead.rb;
Homestead脚本】 读取Homestead.yaml文件,对sites、folders、databases进行重新初始化;
初始化 sites 时,会读取 Homestead 脚本仓库里带着的Nginx站点模板,具体为 scripts/sites-types/laravel.sh或者serve-laravel.sh

Homestead目录

目录.png

Homestead.yaml配置

ip: "192.168.10.10"   #虚拟机的IP,可以通过这个IP访问站点
memory: 2048    #内存大小
cpus: 2     #Cpu核心个数
provider: virtualbox  #虚拟机平台,用virtualbox装的一定要确认这里是virtualbox。(hyper-v、virtualbox、 vmware_fushion、  vmware_workstation、parallels)

authorize: ~/.ssh/id_rsa.pub  #ssh的公钥

keys:
    - ~/.ssh/id_rsa  #ssh的私钥,配置了ssh以后,登录虚拟机可以直接在终端输入homestead ssh进入

folders:
    - map: D:/projects
      to: /home/vagrant/projects

sites:
    - map: lsw.test
     to: /home/vagrant/projects/laravel-swoole-wechat/public

databases:
    - homestead

features:
    - mariadb: false
    - ohmyzsh: false
    - webdriver: false

# ports:
#     - send: 50000
#       to: 5000
#     - send: 7777
#       to: 777
#       protocol: udp
  • sites :配置Nginx站点

    map: homestead.test

    to: /home/vagrant/code/my-project/public #注意laravel一定是指定到public目录

    type : 站点类型,默认Laravel。

    对应的scripts/site-types目录里面的文件。可以用于创建yii、laravel、wordpress等很多框架对应的nginx配置。

    我们还可以自行根据type,在site-types里创建对应的[type].sh文件,生成其对应的nginx配置

Homestead优化

有时候需要把一些常用的命令简写化

这不是vagrant的命令,是登录到Homestead的命令

[8_4SK(E335OPC5A3)HC)F5.png

修改aliases文件,给命令加上别名
如:快速跳转到code目录

alias .code="cd ~/code"

切记修改了Homestead里的文件需要 reload 下

vagrant reload --pervision

开发相关

  • Nginx :/etc/Nginx (sites-available就是所有网站的配置)
  • php -i|grep php.ini :找到PHP.ini文件的位置
  • php -i |less 查看配置文件在哪里,编译参数
  • php -m 查看php扩展(全部显示)
  • php -m |less 查看php加载的模块 (分页查看,输入数字换页,也可以不带)
  • php -m |more 查看php加载的模块 (分页查看,更多的方式,每次多显示一个)
  • sudo service php7.1-fpm restart :重启php7.1-fpm

Linux常用知识:

  • echo $PATH :查看linux的环境变量
  • cat 文件 :查看文件的全部内容

cat log.txt

vi编辑( 通常都要以sudo的方式运行,否则会没有权限)

  • vim 目录文件 :进行编辑

按ESC键 跳出vi的编辑命令,然后:

  • gg :文件开头行
  • G :文件尾(切记一定是大写)
  • :n (n代表指定行数)跳转到指定行数

:50 跳转到50行

  • :w 保存文件但不退出vi
  • :w file 将修改另外保存到file中,不退出vi
  • :w! 强制保存,不推出vi
  • :wq 保存文件并退出vi
  • :wq! 强制保存文件,并退出vi
  • q: 不保存文件,退出vi
  • :q! 不保存文件,强制退出vi
  • :e! 放弃所有修改,从上次保存文件开始再编辑

前言

参考网站:
Homestead安装配置-中文文档
Homestead安装配置-视频讲解
记录下安装Homestead的步骤,以及需要注意的点
以下命令行均使用 git-bash

一、安装所需要的软件

1、安装下列软件,安装方法很简单就不多说了

  • git:
  • vagrant:
  • VirtualBox:一个免费的虚拟机软件

2、由于vagrant默认的工作目录是 C:\Users\用户名\.vagrant.d,如若C盘空间不足,可以将此移至其他目录如:D:\.vagrant.d,然后在环境变量中配置VAGRANT_HOME即可

VAGRANT_HOME=D:\.vagrant.d

1.png

二、下载、添加vagrant Box

1、安装Vagrant Homestead盒子,选择一个支持virtualBox的版本。查看版本

  1. vagrant box add laravel/homestead // 直接安装最新版本,但有可能不支持virtualbox
  2. vagrant box add laravel/homestead --box_version=9.1.0 // 选择对应的版本
  3. vagrant box add laravel/homestead ./virtualbox.box // 安装本地的版本

命令详解 vagrant box add 【本地box名字】 【本地box文件的名字】

  1. vagrant box add metadata.json // 通过配置文件安装

       {
       "name": "laravel/Homestead",  // 本地box名字,就是vagrant box list 是查看的名字
       "versions": [{
           "version": "9.1.0",  // 版本
           "providers": [{
               "name": "virtualbox", // 支持的是hyper-v、virtualbox等
               "url": "./CentOS-7-x86_64-Vagrant-1910_01.VirtualBox.box" // 文件的地址
           }]
       }]
       }
    

2.jpg
如果下载过慢,可以通过上图的Downloading获取到下载链接,通过其他方式下载后安装(要下载其他版本,就修改下版本和后面的virtual)

2、若使用安装最新版本,如若当时最新版本同时支持Hyper-v、virtual等,会要求您选择一个版本,输入对应的数字即可!

5.png

至此Homestead所需环境安装成功

三、安装Homestead

1、克隆Homestead

cd ~
git clone https://github.com/laravel/homestead.git Homestead

2、克隆完成后,需要检查Homestead的版本,因为 master 分支不会总是稳定版本,需要通过Github Release Page检出为release版本

cd ~/Homestead

// Clone the desired release...
git checkout v8.0.1

3、接下来,运行初始化命令来创建Homestead.yaml配置文件

// Mac/Linux...
bash init.sh  // 虽然我用的Windows,但由于是使用git-bash执行的,因此使用这个命令

// Windows...
init.bat

四、配置Homestead.yaml

打开Homestead目录内的Homestead.yaml文件

---
ip: "192.168.10.10"   #虚拟机的IP,可以通过这个IP访问站点
memory: 2048    #内存大小
cpus: 2     #Cpu核心个数
provider: virtualbox  #虚拟机平台,用virtualbox装的一定要确认这里是virtualbox。(hyper-v、virtualbox、vmware_fushion、  vmware_workstation、parallels)

authorize: ~/.ssh/id_rsa.pub  #ssh的公钥

keys:
    - ~/.ssh/id_rsa  #ssh的私钥,配置了ssh以后,登录虚拟机可以直接在终端输入homestead ssh进入

folders:
    - map: D:/projects
      to: /home/vagrant/projects

sites:
    - map: lsw.test
      to: /home/vagrant/projects/laravel-swoole-wechat/public

databases:
    - homestead

features:
    - mariadb: false
    - ohmyzsh: false
    - webdriver: false

# ports:
#     - send: 50000
#       to: 5000
#     - send: 7777
#       to: 777
#       protocol: udp
  • folders映射目录

映射的目录。map:主系统的目录,to:要映射的虚拟机目录!
随着站点数量增加,会遇到性能问题,这时应该映射每个项目到对应的vagrant文件夹

    - map: D:/projects
      to: /home/vagrant/projects

    - map: D:/code
      to: /home/vagrant/code
      type: "nfs"  # 开启nfs

     - map: ~/code
      to: /home/vagrant/code
      type: "rsync"
      options: # 通过options配置同步文件夹
          rsync__args: ["--verbose", "--archive", "--delete", "-zz"]
          rsync__exclude: ["node_modules"]
  • 配置 Nginx 站点

    sites:

    • map: homestead.test
      to: /home/vagrant/code/my-project/public #注意laravel一定是指定到public目录

五、接下来先初始化下vagrant,然后启动vagrant

vagrant init  //切记clone下来的Homestead默认有了,不用再执行一次。初始化,只有第一次时执行,就是创建个VagrantFile,已经有了就不用执行这个命令了
vagrant up 启动

六、登录vagrant,对环境进行配置

vagrant ssh:远程连接

composer config -g repo.packagist composer https://packagist.phpcomposer.com // 修改Composer全局镜像







- 阅读剩余部分 -

原理

希尔排序是插入排序的改进版本。
项目中用的比较少,不稳

  1. 先设置一个间隔(gap),以视为一组。
  2. 当这个间隔的所有组全排序好后,减少间隔,重复1.
  3. 最后以间隔为1,在排序。(其实就是最后执行次插入排序,插入排序就是间隔1的希尔排序)
    注:间隔越大,交换次数越小! 间隔越小,交换次数越多

通常间隔以h或者gap表示

举例说明

如:需要对以下数组进行排序

const arr = [8, 5, 6, 3, 11, 2, 9, 15, 13, 1, 14, 6, 9, 10]

假设间隔(gap)为4,如下图,相同颜色的为一组,执行插入排序。

希尔排序1.png

既然每个数(除去最前面的没有可比较的数以外)都会执行插入排序。那么我们就可以直接使用普通的插入排序方式来实现,只需要将默认的间隔1改为对应的gap

代码实现

我们先来看看普通的插入排序

  for (let i = 1; i < arr.length; i++) { // 以1(第0个数前面没有需要比较的)开始,直到数组跑完
    for (let k = i ; k > 0; k--) {  // 依次与前面的进行比较。如 i=1时,依次与i-1比。i>0是因为i=0时,前面没有数比较了,所以不需要
      if (arr[k] < arr[k - 1]) {
        // 交换 k和 k-1
      } else {
          break;
        }
    }
  }

前面我们也说过,插入排序也可以看做是一个间隔为1的希尔排序

// 一次间隔的排序
function shell_sort_gap(arr, gap) {
  // 普通的插入排序是以,1开始的。而希尔排序,既然以间隔分组,就相当于 0-第一个间隔是一组的,那就是以间隔排序
  for (let i = gap; i < arr.length; i++) { // 以gap开始
    for (let k = i; k > gap - 1; k -= gap) { // 依次与前面的进行比较,每次差距为gap。这里gap-1,是因为gap肯定是最小的可比较数,最前面的那几个数就不要再遍历比较了。
      if (arr[k] < arr[k - gap]) {
        // 交换 k和 k-1
        array_swap(arr, k, k - gap)
      } else {
        break;
      }
    }
  }
}

上面只是间隔为某一个数时的排序,后面需要减少间隔,直到间隔为1。
for (let gap = 4; gap > 0;) { // 这里的4,是我主观意识上取的值

shell_sort_gap(arr, gap)
gap = Math.floor(gap / 2) // 向下取整,如果是其他语言,gap类型为int,就不需要Math.floor了,JS需要不然会有小数

}

上面初次间隔的值,是主观意识上给的,对于算法来说肯定是不合适的。
因此我们改成,默认为数组的一半,然后依次将间隔/2。

  for (let gap = Math.floor(arr.length / 2); gap > 0; gap = Math.floor(gap / 2)) { 
    shell_sort_gap(arr, gap)
  }

但后续很多人发现,这种除以2的方式效率(shell发现的)不是最高的(Knuth(K不发音)发现的)。(还有一些其他的算法)

h = 1
h = 3*h+1
//当h=3h+1时,效率更高!h就是gap,通常算法里默认就是h

因此我们先以1带入h计算出最适合的h,在以公示倒推排序

function shell_sort(arr) {    
  if (arr.length < 2) {
    return
  }
  // 计算最优的gap
  let h = 1
  while (h <= arr.length / 3) { //如果大于1/3了,就超过数组长度了。因此需要小于等于1/3
    h = 3 * h + 1
  }
  for (let gap = Math.floor(h); gap > 0; gap = Math.floor((gap - 1) / 3)) { // 再以倒推的方式排序
    shell_sort_gap(arr, gap)
  }
}

由此可见,不同gap减少方式,会导致效率不同,因此希尔排序的时间复杂度不尽相同,普遍认为是O(n的1.3次方)。

实现原理

以下标1开始,向前比较,小于则交换
原理很像冒泡排序,只不过冒泡排序是两两比较,大的向后移。
而插入排序是无论什么时候,都只操作这一个数

插入排序.png

代码实现:

  for (let i = 1; i < arr.length; i++) { // 以第1(第0个数前面没有需要比较的)个数开始,直到数组跑完

    for (let k = i ; k > 0; k--) { // 依次与前面的进行比较。如 i=1时,依次与i-1比。i>0是因为i=0时,前面没有数比较了,所以不需要
      if (arr[k] < arr[k-1]) {
        array_swap(arr, k, k-1) // 交换位置
      } else {
        break;  // 由于是往前插入的,说明比当前值的都放到前面了,那么如果不比他小的值的地方是已经排好的了,所以可以直接跳出,这样才能满足最好时间复杂度O(n)
      }
      console.log('---第' + k + '次', arr)
    }
    console.log('第' + i + '次', arr)
  }
}

再优化的思路:

  1. 减少交换次数,比较大小后,记录想要插入的位置,后直接插入(不用交换)
  2. 交换使用位移运算的方式,优化数组的insert
  for (let i = 1; i < arr.length; i++) { // 以1 开始,循环
    let minPos = i // 当前数的下标
    let tmp = arr[i] // 当前数
    for (let k = i - 1; k > -1; k--) { // 遍历这个数以前的数
      if (tmp  < arr[k]) { // 用当前值去比较
        minPos = k
      } else {
        break;
      }
    }
    // 插入,前面的都往后移
    for (let j = i; j > minPos; j--) {
      arr[j] = arr[j - 1]
    }
    arr[minPos] = tmp 
  }