centos 安装solr

1.安装jdk

下载安装包(也可以使用其他下载文件方式),因为认证问题,不能直接wget, 打开此页面 ,在Java SE Development Kit 8u161勾上Accept License Agreement,然后点击jdk-8u161-linux-x64.rpm,在下载页面获取文件下载地址,比如我本次的是http://download.oracle.com/otn-pub/java/jdk/8u161-b12/2f38c3b165be4555a1fa6e98c45e0808/jdk-8u161-linux-x64.rpm?AuthParam=1519538436_f233fa0ab4a9cba466bec47d360db37a,然后在/down目录下wget此地址。然后再重命名文件 mv jdk-8u161-linux-x64.rpm?AuthParam=1519538436_f233fa0ab4a9cba466bec47d360db37a jdk-8u161-linux-x64.rpm

安装 rpm -ivh jdk-8u161-linux-x64.rpm

配置系统环境变量,在/etc/profile里追加

JAVA_HOME=/usr/java/jdk1.8.0_161
JRE_HOME=$JAVA_HOME/jre
CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JRE_HOME/lib
PATH=$JAVA_HOME/bin:$JRE_HOME/bin:$PATH
export PATH JAVA_HOME CLASSPATH

生效配置,并检验结果

source /etc/profile
java -version

2.安装solr

安装前检测rng-tools及lsof是否正确安装(安装成功输入命令后显示版本号)

rpm -qa |grep rng-tools
rpm -qa |grep lsof

若未安装,设备能够联网的情况下,可使用如下命令安装,否则自行下载安装包安装

yum install rng-tools
yum install lsof

配置rng-tools

echo 'EXTRAOPTIONS="--rng-device /dev/urandom"' >/etc/sysconfig/rngd
service rngd start
chkconfig rngd on

在down目录下创建solr,下载solr安装包,下载apache-tomcat安装包(如果找不到页面,则在浏览器打开https://tomcat.apache.org/download-80.cgi查看有的版本号,然后修改版本号),然后使用tar -zxvf命令解压两个文件

#下载solr安装包
wget http://mirror.bit.edu.cn/apache/lucene/solr/6.6.2/solr-6.6.2.tgz
#下载apache-tomcat安装包(如果找不到页面,则在浏览器打开https://tomcat.apache.org/download-80.cgi查看有的版>本号,然后修改版本号)
wget http://mirror.bit.edu.cn/apache/tomcat/tomcat-8/v8.0.50/bin/apache-tomcat-8.0.50.tar.gz

3.配置solr

使用tar -zxvf命令解压刚刚下载的solr安装包和下载apache-tomcat安装包

tar -zxvf solr-6.6.2.tgz
tar -zxvf apache-tomcat-8.0.50.tar.gz

在solr-6.6.2目录下拷贝dataimporthandler的jar包

cp dist/solr-dataimporthandler-* server/solr-webapp/webapp/WEB-INF/lib/

在/down/solr目录下载mysql-connector-java-5.1.45安装包

wget https://dev.mysql.com/get/Downloads/Connector-J/mysql-connector-java-5.1.45.tar.gz

解压mysql-connector-java-5.1.45.tar.gz

tar -zxvf mysql-connector-java-5.1.45.tar.gz

拷贝mysql-connector-java

cp mysql-connector-java-5.1.45/mysql-connector-java-5.1.45-bin.jar solr-6.6.2/server/solr-webapp/webapp/WEB-INF/lib/

在/down/solr目录下载ikanalyzer安装包

wget https://github.com/zxiaofan/ik-analyzer-solr6/releases/download/6.6.0/ikanalyzer-6.6.0.jar

解压ikanalyzer

jar -xvf ikanalyzer-6.6.0.jar

拷贝ikanalyzer

cp ikanalyzer-6.6.* solr-6.6.2/server/solr-webapp/webapp/WEB-INF/lib/

在/down/solr目录下载pinyin4j

wget https://github.com/zxiaofan/ik-analyzer-solr6/releases/download/6.6.0/pinyin4j_IKconfig.zip

复制文件

unzip pinyin4j_IKconfig.zip -d pinyin4j
cp pinyin4j/pinyin*.jar solr-6.6.2/server/solr-webapp/webapp/WEB-INF/lib/
mkdir solr-6.6.2/server/solr-webapp/webapp/WEB-INF/classes
cp pinyin4j/ext.dic solr-6.6.2/server/solr-webapp/webapp/WEB-INF/classes/
cp pinyin4j/IKAnalyzer.cfg.xml solr-6.6.2/server/solr-webapp/webapp/WEB-INF/classes/
cp pinyin4j/stopword.dic solr-6.6.2/server/solr-webapp/webapp/WEB-INF/classes/

修改配置solr-6.6.2/server/solr-webapp/webapp/WEB-INF/classes/IKAnalyzer.cfg.xml加入新的内容

<!--词典动态更新时间间隔[首次延时,时间间隔](格式:正整数,单位:分钟)-->
<entry key="dic_updateMin">1,1</entry>

<!--禁用内置主词典main2012.dic(默认false)-->
<!--<entry key="dicInner_disable">true</entry> -->

修改时区,修改solr-6.6.2/bin/solr.in.sh中的SOLR_TIMEZONE="UTC+8"

4.创建core并配置

进入solr-6.6.2目录,执行创建名称为goods的core,如果无法确定实例端口,加上-p 端口号,如果在root用户下启动solr存在风险,要么换个账号,要么加上 -force

bin/solr create -c goods -p 8983 -force

修改配置:修改server/solr/goods/conf目录下的solrconfig.xml,data-config.xml,managed-schema的文件,没有就新建

#solrconfig.xml添加内容(在</config>之前)
<requestHandler name="/dataimport" class="org.apache.solr.handler.dataimport.DataImportHandler">
  <lst name="defaults">
      <str name="config">data-config.xml</str>
  </lst>
</requestHandler>

#data-config.xml添加内容
<?xml version="1.0" encoding="UTF-8"?>
<dataConfig>
  <dataSource
      name="dbSource"
      type="JdbcDataSource"
      driver="com.mysql.jdbc.Driver"
      url="jdbc:mysql://数据库地址:端口号/数据库名称"
      batchSize="-1"
      user="用户名"
      password="密码"
      readOnly="true"
      autoCommit="true"
      netTimeoutForStreamingResults="0"
      />
  <document>
      <entity name="goods" dataSource="dbSource" onError="skip" pk="id" query="select id,address-detail,create_time from lab_model_address"
          deltaImportQuery="select id,address-detail,create_time from lab_model_address where id = '${dih.delta.id}'"
          deltaQuery="select id,address-detail,create_time from lab_model_address where create_time > unix_timestamp('${dataimporter.last_index_time}')">
          <field column="id" name="id" />
          <field column="address-detail" name="address-detail" />
          <field column="create_time" name="create_time" />
      </entity>
  </document>
</dataConfig>

#managed-schema添加内容(在<field name="id" ... />之后)
<field name="address-detail" type="text_ik" indexed="true" stored="true"/>
  <fieldType name="text_pinyin" class="solr.TextField" positionIncrementGap="0">
      <analyzer type="index">
          <tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory"/>
          <filter class="solr.SynonymGraphFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true" />
          <filter class="com.shentong.search.analyzers.PinyinTransformTokenFilterFactory" minTermLenght="2" />
          <filter class="com.shentong.search.analyzers.PinyinNGramTokenFilterFactory" minGram="1" maxGram="20" />
      </analyzer>
      <analyzer type="query">
          <tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory"/>
          <filter class="solr.SynonymGraphFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true" />
          <filter class="solr.LowerCaseFilterFactory" />
      </analyzer>
  </fieldType>
  <fieldType name="text_ik" class="solr.TextField">
      <analyzer type="index" useSmart="false" isMaxWordLength="false" >
          <tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory"/>
          <filter class="solr.SynonymGraphFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/>
      </analyzer>
      <analyzer type="query" useSmart="true" isMaxWordLength="true" >
          <tokenizer class="org.wltea.analyzer.lucene.IKTokenizerFactory"/>
          <filter class="solr.SynonymGraphFilterFactory" synonyms="synonyms.txt" ignoreCase="true" expand="true"/>
      </analyzer>
  </fieldType>
  <field name="title_ik" type="text_ik" indexed="true" required="true" stored="true"/>
  <copyField source="address-detail" dest="title_ik"/>
  <field name="create_time" type="int" indexed="true" stored="true"/>
  <field name="pinyin" type="text_pinyin" indexed="true" stored="true"/>
  <copyField source="address-detail" dest="pinyin"/>

5.启动,停止,重启solr

bin/solr stop -all
bin/solr start -force
bin/solr stop -all; bin/solr start -force

6.导入数据

浏览器中访问http://IP:8983/, 查看CoreAdmin中是否存在创建的core:goods Core Selector选择新建的core(如goods),选择Dataimport,Command选择full-import,Start, Rows选择合理值,点击Excute执行数据导入

7.验证数据是否导入:接上一步中选择Query,直接点击Execute Query查看结果

8.验证分词是否可用:接上一步中选择Analysis,输入值,类型选择text_ik,查看分词结果(需要分词的数据类型在managed-schema中field的type为text_ik类型。

9.添加批处理任务(apache-solr-dataimporthandler-.jar可以在 我的GitHub下载 )

将apache-solr-dataimporthandler-.jar放到solr-6.6.2/server/solr-webapp/webapp/WEB-INF/lib/ 在solr-6.6.2/server/solr-webapp/webapp/WEB-INF/web.xml中的</web-app>之前加入下面代码

<listener>
 <listener-class>org.apache.solr.handler.dataimport.scheduler.ApplicationListener</listener-class>
</listener>

在solr-6.6.2/server/solr/conf中新建dataimport.properties,文件夹不存在时新建
#################################################
#                                               #
#       dataimport scheduler properties         #
#                                               #
#################################################

#  to sync or not to sync
#  1 - active; anything else - inactive
syncEnabled=1

#  which cores to schedule
#  in a multi-core environment you can decide which cores you want syncronized
#  leave empty or comment it out if using single-core deployment
syncCores=goods,goods-test

#  solr server name or IP address
#  [defaults to localhost if empty]
server=localhost

#  solr server port
#  [defaults to 80 if empty]
port=8983

#  application name/context
#  [defaults to current ServletContextListener's context (app) name]
webapp=solr

#  URL params [mandatory]
#  remainder of URL
#增量
params=/dataimport?command=delta-import&clean=false&commit=true&optimize=false&wt=json&indent=true&entity=goods&verbose=false&debug=false

#  schedule interval
#  number of minutes between two runs
#  [defaults to 30 if empty]
interval=20

#  重做索引的时间间隔,单位分钟,默认7200,即1天;
#  为空,为0,或者注释掉:表示永不重做索引
reBuildIndexInterval=7200

#  重做索引的参数
reBuildIndexParams=/dataimport?command=full-import&clean=true&commit=true&optimize=true&wt=json&indent=true&entity=goods&verbose=false&debug=false

#  重做索引时间间隔的计时开始时间,第一次真正执行的时间=reBuildIndexBeginTime+reBuildIndexInterval*60*1000;
#  两种格式:2012-04-11 03:10:00 或者  03:10:00,后一种会自动补全日期部分为服务启动时的日期
reBuildIndexBeginTime=09:00:00

10.重启solr

git操作

复制

git checkout master

git pull

git checkout -b 新分支名

git push origin 新分支名

删除分支
git push origin --delete 20180829
push后回退

git revert 版本号 git push origin 分支名

合并某分支到当前分支:git merge <name> 在这里书写你的文章。

ssl

http传输是明文的,可以拦截进行修改等等的操作,及其不安全。ssl对http进行包裹,让别人不容易拦截偷窥,组合成https

在进行数据传输前,进行相关的验证生成相应的密钥,验证后面的相互请求是否可靠。

密钥使用的算法有对称加密和非对称加密,对称加密更快,非对称加密更复杂且更慢

https因为在http上做了一层ssl操作,所以要慢一点。

php处理大文件

普通的处理文件是要全部吧文件内容读入内存,但是有内存和时间限制,可以修改php.ini,但是还和电脑的内存大小有关系;

<?php
   ini_set('memory_limit', '-1');
   $file = 'access.log';
   $data = file($file);
   $line = $data[count($data) - 1];
   echo $line;
?>

还有一个方法就是使用fseek读取,通过指针操作,不用一次性全部读入内存,可以一行一行的读取。

<?php
  $fp = fopen($file, "r");
  $line = 10;
  $pos = -2;
  $t = " ";
  $data = "";
  while ($line > 0)
  {
      while ($t != "\n")
      {
          fseek($fp, $pos, SEEK_END);
          $t = fgetc($fp);
          $pos--;
      }
      $t = " ";
      $data .= fgets($fp);
      $line--;
  }
  fclose($fp);
  echo $data
  ?>

或者一段一段的读取

<?php
  $fp = fopen($file, "r");
  $num = 10;
  $chunk = 4096;
  $fs = sprintf("%u", filesize($file));
  $max = (intval($fs) == PHP_INT_MAX) ? PHP_INT_MAX : filesize($file);
  for ($len = 0; $len < $max; $len += $chunk)
  {
      $seekSize = ($max - $len > $chunk) ? $chunk : $max - $len;
      fseek($fp, ($len + $seekSize) * -1, SEEK_END);
      $readData = fread($fp, $seekSize) . $readData;
      if (substr_count($readData, "\n") >= $num + 1)
      {
          preg_match("!(.*?\n){" . ($num) . "}$!", $readData, $match);
          $data = $match[0];
          break;
      }
  }
  fclose($fp);
  echo $data;
  ?>

平时统计相关文件比如nginx的accesslog,可以使用系统命令awk或者grep或者tail等等,效率是很快的

统计每小时的请求数,top100的时间点(精确到小时)

awk '{print $4}' access.log |cut -c 14-15|sort|uniq -c|sort -nr|head -n 100

统计蜘蛛抓取次数

grep 'Baiduspider' access.log |wc -l

tail

<?php
   $file = 'access.log';
   $file = escapeshellarg($file); // 对命令行参数进行安全转义
   $line = `tail -n 1 $file`;
   echo $line;
?>

rand和mt_rand

rand默认使用libc生成器,具有一些不确定和未知的弹性而慢;而mt_rand使用Mersener Twister算法生成随机数,速度比rand快4倍。

设计模式

创建型

  • 简单工厂模式
优点:
操作者不用管具体实例化哪个对象,工厂类通过参数去决定实例化对象;降低耦合
缺点:
编译期间就定好了有哪些类,如果有新需求,需要修改工厂类
uml图
<?php
/**
* Created by PhpStorm.
* User: wky
* Date: 2018/10/30
* Time: 10:16
*/
namespace Simple\Factory;

/**
* Class ArchitectureFactory 工厂类
* @package Simple\Factory
*/
class ArchitectureFactory{

   protected $typeList;

   public function __construct()
   {
       //需要实例化的对象的数组
       $this->typeList = [
           'officeBuilding'=>__NAMESPACE__.'\OfficeBuilding',//造写字楼
           'school'=>__NAMESPACE__.'\School',//造学校
       ];
   }

   public function getExample($type){
       if(!isset($this->typeList[$type])){
           //todo 提示类不存在
       }
       return new $this->typeList[$type]();
   }
}

ArchitectureInterFace

<?php
/**
* Created by PhpStorm.
* User: wky
* Date: 2018/10/30
* Time: 10:16
*/
namespace Simple\Factory;

/**
* Interface ArchitectureInterFace 造写字楼和学校需要的设计图
* @package Simple\Factory
*/
interface ArchitectureInterFace{

   public function designChart();
}

OfficeBuilding

<?php
/**
* Created by PhpStorm.
* User: wky
* Date: 2018/10/30
* Time: 10:16
*/
namespace Simple\Factory;

/**
* Class OfficeBuilding 造写字楼
* @package Simple\Factory
*/
class OfficeBuilding implements ArchitectureInterFace{

   public function designChart(){
       return '造写字楼的图纸';
   }
}

School

<?php
/**
* Created by PhpStorm.
* User: wky
* Date: 2018/10/30
* Time: 10:22
*/
namespace Simple\Factory;

/**
* Class School 造学校
* @package Simple\Factory
*/
class School implements ArchitectureInterFace{

   public function designChart(){
       return '造学校的图纸';
   }
}

Test

<?php
/**
* Created by PhpStorm.
* User: wky
* Date: 2018/10/30
* Time: 10:24
*/
namespace Simple\Factory;

/**
* Class Test
* @package Simple\Factory
*/
class Test{

   public function test(){
       $architecture = ['officeBuilding', 'school'];
       $factory = new ArchitectureFactory();
       foreach ($architecture as $type){
           $factory->getExample($type);
       }
   }
}
  • 工厂方法模式

和简单工厂方法模式的区别是工厂方法实例化在子类

  • 抽象工厂模式

和工厂方法模式的区别是抽象工厂一个产品一个实现类,有新需求不用改原来的代码

  • 静态工厂模式

和简单工厂的区别是静态工厂是在工厂类中的静态方法实例化对象

  • 建造者模式

和抽象工厂的区别就是,建造者模式构建对象由导演类构建,而抽象工厂由工厂类构造;建造者模式更适用于复杂的对象的构建

  • 多例模式

需要多个对象,比如各种数据库的链接

  • 单例模式

保证整个生命周期只有一个实例对象。比如一种数据库链接、锁定文件等等

  • 对象池模式

对象用完归还对象池类,而不是销毁,适用于实例化代价比较大的前景,因为对象放着也是需要消耗内存的

  • 原型模式

通过类的克隆方法创建对象,而不是new,但是类的克隆方法是私有的就无法克隆了;使用场景是需要的类不是最初的类,而是运行中某一种状态下的类

结构型

  • 适配器模式
  • 桥梁模式
  • 组合模式
  • 数据映射模式
  • 装饰模式
  • 依赖注入模式
  • 门面模式
  • 流接口模式
  • 代理模式
  • 注册模式

行为型

  • 责任链模式
  • 命令行模式
  • 迭代器模式
  • 中介者模式
  • 备忘录模式
  • 空对象模式
  • 观察者模式
  • 规格模式
  • 状态模式
  • 策略模式
  • 模板方法模式
  • 访问者模式

其他

  • 委托模式
  • 服务定位模式
  • 资源模式

参考地址:https://laravelacademy.org/post/2465.html

php实现经典算法

冒泡:

function bub_sort($array){
      $n = count($array);
            for($i=0; $i<$n; $i++){
                    for($j=$i+1; $j<$n; $j++){
                            if($array[$i]>$array[$j]){
                                    $temp = $array[$i];
                                    $array[$i] = $array[$j];
                                    $array[$j] = $temp;
                            }
                    }
            }
            var_dump($array);
    }
    bub_sort([3,2,1,5,7,3]);

直接插入排序:

function ins_sort($array){
             $len = count($array);
             for($i=1;$i<$len;$i++){
                     $temp = $array[$i];
                     for($j=$i-1;$j>=0;$j--){
                             if($temp<$array[$j]){
                                     $array[$j+1] = $array[$j];
                                     $array[$j] = $temp;
                             }
                             else{
                                     break;
                             }
                     }
             }
             var_dump($array);
     }

     ins_sort([3,1,2,5,7,10,9,8]);

直接选择排序:

function sel_sort($array){
             $len = count($array);
             for($i=0;$i<$len-1;$i++){
                     $p = $i;
                     for($j=$i+1;$j<$len;$j++){
                             if($array[$j]>$array[$p]){
                                     $p = $j;
                             }
                     }
                     $temp = $array[$p];
                     $array[$p] = $array[$i];
                     $array[$i] = $temp;
             }
             var_dump($array);
     }

     sel_sort([2,1,3,4,6,9,5,7,1]);

堆排序:

function swap(&$array,$a,$b){
        $temp = $array[$a];
        $array[$a] = $array[$b];
        $array[$b] = $temp;
}

function buildMaxHeap(&$array,$len){
        for($i=intval($len/2)-1;$i>=0;$i--){
                $l = $i*2 + 1;
                $max = $l;
                if($len>$l){
                        $r = $l+1;
                        if($len>$r){
                                if($array[$r]>$array[$l]){
                                        $max = $r;
                                }
                        }
                        if($array[$max]>$array[$i]){
                                swap($array,$max,$i);
                        }
                }
        }
}

$array = [3,2,4,5,7,1,8];
$len = count($array);
buildMaxHeap($array, $len);
for($i=$len-1;$i>0;$i--){
        swap($array,$i,0);
        $len--;
        buildMaxHeap($array,$len);
}

var_dump($array);

快速排序:

function quick_sort($array){
              $len = count($array);
              if($len<2){
                      return $array;
              }
              $right = $left = [];
              for($i=1;$i<$len;$i++){
                      if($array[$i]<$array[0]){
                              $left[] = $array[$i];
                      }
                      else{
                              $right[] = $array[$i];
                      }
              }
              $left = quick_sort($left);
              $right = quick_sort($right);
              return array_merge($left,[$array[0]],$right);
      }

      var_dump(quick_sort([2,1,2,3,6,5,7]));

归并排序:

$array = [5,4,3,8,8,1,6];
    function merge_sort(&$array){
            $len = count($array);
            if($len<=1){
                    return $array;
            }
            $middle = intval($len/2);
            $left = array_slice($array,0,$middle);
            $right = array_slice($array,$middle);
            merge_sort($left);
            merge_sort($right);
            $array = merge($right,$left);
    }

    function merge($right,$left){
            $merge = [];
            while(count($right) && count($left)){
                    if($right[0]>$left[0]){
                            $merge[] = array_shift($right);
                    }
                    else{
                            $merge[] = array_shift($left);
                    }
            }
            return array_merge($merge,$right,$left);
    }

    merge_sort($array);
    var_dump($array);

基数排序:把每位数分开,高位不存在的补零。从低位开始比较,比到高位完成排序:

  function base_sort(&$arr){//前提是数组都是正整数,且不为空

    $bit = 1;

    $len = count($arr);

    for($i=0; $i<$len; $i++){

       $strlen = strlen($arr[$i]);

       $bit = $strlen>$bit ? $strlen : $bit;

    }

    for($i=0; $i<$bit-1; $i++){

       $base = [];

       $divisor = pow(10,$i);

       for($j=0; $j<$len; $j++){

           $remain = $arr[$j]/$divisor%10;

           $base[$remain][] = $arr[$j];

       }

       $arr = [];

       for($k=0; $k<=9; $k++){

          if(isset($base[$k])){

              $arr = array_merge($arr,$base[$k]);

          }

       }

    }

}

$arr = [100,1,125,19999,9,808,28];

base_sort($arr);

var_dump($arr);
复杂度比较

二分查找(时间复杂度log2n):

function bin_sch($array,$start,$end,$value){
            if($start > $end){
                    var_dump('没有找到');
            }
            $mid =  intval(($start + $end) / 2);
            if($array[$mid] == $value){
                    var_dump($mid);
            }
            elseif($array[$mid] > $value){
                    bin_sch($array,$start,$mid-1,$value);
            }
            else{
                    bin_sch($array,$mid+1,$end,$value);
            }
    }

    bin_sch([1,2,3,4,6,8],0,5,6);

顺序查找:

seq_sch([3,2,5,6,1],5,6);
    function seq_sch($array,$n,$value){
            for($i=0; $i<$n; $i++){
                    if($array[$i] == $value){
                            var_dump($i);exit;
                    }
            }
            var_dump('没有找到');
    }

二维数组排序:

function two_array_sort($array,$key,$sort=SORT_ASC,$sort_type=SORT_NUMERIC){
            if(!is_array($array)){
                    return false;
            }
            $array_key = [];
            foreach($array as $value){
                    if(!is_array($value)){
                            return false;
                    }
                    $array_key[] = $value[$key];
            }
            array_multisort($array_key,$sort,$sort_type,$array);
            var_dump($array);
    }

    two_array_sort([['a'=>8,'b'=>2],['a'=>9,'b'=>2],['a'=>5,'b'=>2],['a'=>8,'b'=>2],['a'=>1,'b'=>2]], 'a');

抢红包:

function qhb($num,$money){
              if($money<$num*0.01){
                      return false;//保证每个人能有一分钱
              }
              for($i=1;$i<=$num;$i++){
                      if($i==$num){
                              $hb = $money;
                      }
                      else{
                              $max = round($money-($num-$i)*0.01, 2);//保证每个人能有一分钱
                              $max = round($max/($num-$i), 2);//让每个红包差距不是太大
                              $hb = mt_rand(0.01*100,$max*100)/100;
                              $money -= $hb;
                      }
                      var_dump([$i,$hb]);
              }
      }

      qhb(5,5);

php-fpm

cgi 公共网关接口 是http服务器和其他机器上的程序进行通信的接口,起程序运行在网络服务器上

fastcgi是常驻行的cgi,只要被激活一次,后面就不要每次都去fork一次,把cgi解释器保持在内存获得较高的效率,还支持分布式,可以放在网站服务器以外的主机上执行并且接受来自其他网站服务器的请求

cgi和fastcgi都独立与语言

php-fpm是FastCGI进程管理器

优点:fastcgi独立与服务器,提供了一个比api更安全的环境,sapi把程序的代码和核心web服务器链接在一起,这样一个错误的api会影响其他的应用程序和核心服务器,恶意的挨批应用程序会截取另外的应用程序和核心服务器的密钥,不依赖web服务器

缺点:因为是多进程的,所以比cgi多线程消耗内存(线程之间可共享),

原理:

1.Web服务器启动时,载入FastCGI进程管理器;

2.FastCGI进程管理器初始化,启动多个CGI解释器进程(PHP-CGI)并等待来自Web服务器的连接;

3.当客户端请求到达Web服务器时,FastCGI进程管理器选择并连接到一个CGI解释器,Web服务器将CGI环境变量和标准输入发送到FastCGI子进程PHP-CGI。

4.FastCGI子进程完成处理后将标准输出和错误信息从同一连接返回给Web服务器。当FastCGI子进程关闭连接时,请求便告知处理完成。FastCGI子进程接着等待并处理来自FastCGI进程管理器(运行在Web服务器中)的下一个连接。而在CGI模式中,PHP-CGI在此便退出了。

在上述情况中,可以想象CGI通常有多慢,每一个Web请求PHP都必须重新解析php.ini、重新载入全部扩展,并重初始化全部数据结构。而使用FastCGI,所有这些都只在进程启动时发生一次。另外,数据库持久连接可以工作。

PHP-CGI是PHP自带的FastCGI管理器。

PHP-CGI的不足:

1.php-cgi变更php.ini配置后需重启php-cgi才能让新的php-ini生效,不可以平滑重启。

2.直接杀死php-cgi进程,php就不能运行了(PHP-FPM和Spawn-FCGI就没有这个问题,守护进程会平滑重新生成新的子进程)。

PHP-FPM的使用非常方便,配置都是在PHP-FPM.ini的文件内,而启动、重启都可以从php/sbin/PHP-FPM中进行。更方便的是修改php.ini后可以直接使用PHP-FPM reload进行加载,无需杀掉进程就可以完成php.ini的修改加载

结果显示使用PHP-FPM可以使php有不小的性能提升。PHP-FPM控制的进程cpu回收的速度比较慢,内存分配的很均匀。

Nginx+PHP配置

1、进程数优化

pm = dynamic

pm.max_children = 300 最大进程数

pm.start_servers = 20 启动时的进程数

pm.min_spare_servers = 5 最小空闲进程数,少于这个会启动新的等待服务

pm.max_spare_servers = 35 最大空闲进程数 超过这个数会杀掉一部分

注: dynamic - 表示子进程的数量在下面配置的基础上动态设置,还有static和ondemand选项 static - 子进程的数量是固定的(pm.max_children) ondemand - 进程在有需求时才产生(当请求时,与 dynamic 相反,pm.start_servers 在服务启动时即启动max_children

2、最大请求数优化

pm.max_requests = 10240

NOTE:

这个用来处理因为PHP解析器或引用的第三方库时,造成的内存泄露问题。 一个进程处理的请求数超过这个,就不接受新的请求

3、最长执行时间优化(php.ini)

request_terminate_timeout = 20

NOTE:

这个是用来处理因为PHP执行时间超长而报502错误的解决。

这个时长配置可以在php.ini(max_execution_time)或php-fpm.conf中配置均可,为了不影响全局配置,可在php-fpm.conf中实现。

PHP-FPM设置的脚本最大执行时间已经够长了,但执行耗时PHP脚本时,发现Nginx报错变为504错误。这是因为我们修改的只是PHP的配置,Nginx中也有关于与上游服务器通信超时时间的配置factcgi_connect/read/send_timeout。

查看php进程数 ps aux | grep -c php-fpm

from OpenSSL._util import lib as pyOpenSSLlib ImportError: No module named _util

  • mac 报错 from OpenSSL._util import lib as pyOpenSSLlib ImportError: No module named _util
  • 该安装的都安装了,估计是版本的问题
  • 因为系统python默认是2.7,所以安装3,而且默认改成3
  • 然后重新安装 pip 和scrapy
  • 还是不行 默认还是使用2.7
  • 用百度 bing 谷歌搜索的方法 试了 还是不行
  • 最后 删掉所有python 然后安装python3 重新安装pip和scrapy
  • 然后可以了

scrapy爬豆瓣图书例子:https://github.com/dawnkeyan/dawnkeyan.github.io.git