nginx跨域设置

2018年6月27日 没有评论

跨域问题在现在前后端分离的项目中是一个很常见的问题,以前我写过一篇《nginx反向代理解决跨域问题》的文章。前段时间在做nginx配置允许跨域时一直失败,参考的是segmentflaut上面的一篇文章,尝试了许久都没有成功,搞的我都有点开始怀疑人生了。

后来我去查看了一下nginx官方add_header的文档,发现它教程中放在location块中是没有问题的,add_header支持放在”httpserverlocationif in location“,也就是不仅可以放在location中,也可以放在location中的if块里面。那么到底哪里出了问题哪?

在一篇叫《Using CORS》文章中,作者提到”Access-Control-Allow-Origin (required) – This header must be included in all valid CORS responses。”,也就是说我们必须要保证所有cors请求都要返回我们设置的header,而”location /”是一个默认的匹配块,如果匹配到其他块,那么 我们设置在location中的跨域header设置就会无效了,于是就做了下面的改动。

在nginx配置文件下面增加cors.conf配置文件,内容如下:

add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';

if ($request_method = 'OPTIONS') {
    return 204;
}

然后在server块中include进来跨域配置文件:

location / {
       index  index.html index.htm index.php;
       autoindex on;
       try_files $uri $uri/ /index.php?$query_string;
}

include cors.conf;

这样在其他的网站配置文件中只需要 “include cors.conf”即可。当然如果你也可以直接用cors.conf配置文件里面的内容替换”include cors.conf”。重启nginx,就成功可以让js跨域请求了啊!

mac安装openresty

2018年6月12日 没有评论

OpenResty( 也称为 ngx_openresty) 是一个全功能的 Web 应用服务器。它打包了标准的Nginx 核心,很多的常用的第三方模块,以及它们的大多数依赖项。通过揉和众多设计良好的 Nginx 模块,OpenResty 有效地把 Nginx 服务器转变为一个强大的Web 应用服务器,基于它开发人员可以使用 Lua 编程语言对 Nginx 核心以及现有的各种Nginx C 模块进行脚本编程,构建出可以处理一万以上并发请求的极端高性能的 Web 应用。OpenResty 致力于将你的服务器端应用完全运行于 Nginx 服务器中,充分利用 Nginx 的事件模型来进行非阻塞 I/O 通信。不仅仅是和 HTTP 客户端间的网络通信是非阻塞的,与MySQL、PostgreSQL、Memcached 以及 Redis 等众多远方后端之间的网络通信也是非阻塞的。

Brew安装

brew tap homebrew/nginx
brew install homebrew/nginx/openresty

这是官方给的通过brew方式安装的方法,可惜我没有安装成功。

编译安装

利用brew安装openresty依赖。

brew update
brew install pcre openssl curl

下载openresty源码,然后解压编译安装。

./configure --prefix=/usr/local/opt/openresty \
--with-cc-opt="-I/usr/local/opt/openssl/include/ -I/usr/local/opt/pcre/include/" \
--with-luajit \
--without-http_redis2_module \
--with-ld-opt="-L/usr/local/opt/openssl/lib/ -L/usr/local/opt/pcre/lib/"
make -j2
sudo make install

我在安装的时候最开始没有用 “–with-cc-opt”来新增openssl和pcre头文件的位置,导致在make阶段总是报错,提示找不到”ssl.h”头文件。

openresty的nginx文件在/usr/local/opt/openresty/nginx/sbin/nginx,如果你没有安装其他版本的nginx,可以将/usr/local/opt/openresty/nginx/sbin/加入path目录,就可以使用nginx命令了。如果之前已有安装其他版本的nginx,就不建议在将openresty中nginx的sbin目录加入到PATH中,可以给openresty内置的nginx起个别名,方便以后使用。

export PATH=$PATH:/usr/local/opt/openresty/nginx/sbin
alias nginx_lua="/usr/local/opt/openresty/nginx/sbin/nginx"

 

 

分类: Mac, nginx 标签: ,

swoole_process源码读解-构造析构函数

2018年5月16日 没有评论

php源码对大部分php程序员来说都是神秘的,因为php本身是一门神奇伟大的语音。它可以让没有什么编程基础的人可以编程,而且偏向于应用。而swoole是php中一个非常不错的扩展,它让php对异步编程更容易,对高并发做了很多的支持。而我想抽时间写一个针对swoole源码解读的文章,来让我们更深入的了解理解swoole,更好的在项目中使用它。

适合人群

那么这个系列文章比较适合哪些程序员哪?对php扩展开发有一定了解,有c/c++语言功底的。如果你对php扩展开发不是很了解,可以查看一下我以前写过php扩展开发的文章,或者看一下《PHP扩展开发及内核应用》这本书。

源码版本

php版本:7.1.11

swoole版本:2.1.2

下面将进入正题,我们将一起来查看swoole_process是如何实现的。

swoole_process构造函数

构造函数源码实现在swoole_process.c:239

static PHP_METHOD(swoole_process, __construct)
{
    zend_bool redirect_stdin_and_stdout = 0;
    long pipe_type = 2;
    zval *callback;
    
    //判断当前是不是命令行模式
    if (!SWOOLE_G(cli))
    {
        swoole_php_fatal_error(E_ERROR, "swoole_process only can be used in PHP CLI mode.");
        RETURN_FALSE;
    }

    //当前是否server中的master进程中
    if (SwooleG.serv && SwooleGS->start == 1 && swIsMaster())
    {
        swoole_php_fatal_error(E_ERROR, "swoole_process can't be used in master process.");
        RETURN_FALSE;
    }

    //解析参数,具体的请查看swoole官方手册中各参数含义
    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|bl", &callback, &redirect_stdin_and_stdout, &pipe_type) == FAILURE)
    {
        RETURN_FALSE;
    }

    char *func_name = NULL;
    //检查传入的回调函数是否可以执行
    if (!sw_zend_is_callable(callback, 0, &func_name TSRMLS_CC))
    {
        swoole_php_fatal_error(E_ERROR, "function '%s' is not callable", func_name);
        efree(func_name);
        RETURN_FALSE;
    }
    efree(func_name);

    //分配process所需的内存
    swWorker *process = emalloc(sizeof(swWorker));
    bzero(process, sizeof(swWorker));

    int base = 1;
    //计算当前已启动process数量
    if (SwooleG.serv && SwooleGS->start)
    {
        base = SwooleG.serv->worker_num + SwooleG.task_worker_num + SwooleG.serv->user_worker_num;
    }
    if (php_swoole_worker_round_id == 0)
    {
        php_swoole_worker_round_id = base;
    }
    //设置当前process id,注意这里不是进程pid
    process->id = php_swoole_worker_round_id++;

    //输出重定向
    if (redirect_stdin_and_stdout)
    {
        process->redirect_stdin = 1;
        process->redirect_stdout = 1;
        process->redirect_stderr = 1;
        /**
         * Forced to use stream pipe
         */
        pipe_type = 1;
    }
    
    //使用管道,创建管道
    if (pipe_type > 0)
    {
        swPipe *_pipe = emalloc(sizeof(swWorker));
        int socket_type = pipe_type == 1 ? SOCK_STREAM : SOCK_DGRAM;
        if (swPipeUnsock_create(_pipe, 1, socket_type) < 0)
        {
            RETURN_FALSE;
        }

        process->pipe_object = _pipe;
        process->pipe_master = _pipe->getFd(_pipe, SW_PIPE_MASTER);
        process->pipe_worker = _pipe->getFd(_pipe, SW_PIPE_WORKER);
        process->pipe = process->pipe_master;
        //设置process对象的pipe属性
        zend_update_property_long(swoole_process_class_entry_ptr, getThis(), ZEND_STRL("pipe"), process->pipe_master TSRMLS_CC);
    }
    
    //将当前对象加入到swoole全局的对象管理当中
    swoole_set_object(getThis(), process);
    //设置process对象的callback属性
    zend_update_property(swoole_process_class_entry_ptr, getThis(), ZEND_STRL("callback"), callback TSRMLS_CC);
}

 

这里面有调用swoole_set_object函数,getThis函数获得当前对象指针,可以理解为php中常用的$this关键字,下面我们看一下swoole_set_object是如何实现的。

swoole_set_object在swoole.c:699

void swoole_set_object(zval *object, void *ptr)
{
    SWOOLE_GET_TSRMLS;
    int handle = sw_get_object_handle(object);
    assert(handle < SWOOLE_OBJECT_MAX);
    
    //是否需要为swoole_objects重新分配内存
    if (handle >= swoole_objects.size)
    {
        uint32_t old_size = swoole_objects.size;
        //新swoole_objects大小
        uint32_t new_size = swoole_get_new_size(old_size, handle TSRMLS_CC);

        void *old_ptr = swoole_objects.array;
        void *new_ptr = NULL;
        
        //重新分配内存
        new_ptr = realloc(old_ptr, sizeof(void*) * new_size);
        if (!new_ptr)
        {
            swoole_php_fatal_error(E_ERROR, "malloc(%d) failed.", (int )(new_size * sizeof(void *)));
            return;
        }
        bzero(new_ptr + (old_size * sizeof(void*)), (new_size - old_size) * sizeof(void*));
        swoole_objects.array = new_ptr;
        swoole_objects.size = new_size;
    }
    swoole_objects.array[handle] = ptr;
}

sw_get_object_handle是1个宏函数,最终展开结果是((*(object)).value.obj)->handle。其作用是获得当前对象的handle,也就是它的索引。

typedef struct _zval_struct     zval; //zend_types.h:84
typedef struct _zend_object     zend_object; //zend_types.h:89

struct _zend_object { //zend_types.h:277
	zend_refcounted_h gc;
	uint32_t          handle; // TODO: may be removed ???
	zend_class_entry *ce;
	const zend_object_handlers *handlers;
	HashTable        *properties;
	zval              properties_table[1];
};

typedef union _zend_value { //zend_types.h:101
	zend_long         lval;				/* long value */
	double            dval;				/* double value */
	zend_refcounted  *counted;
	zend_string      *str;
	zend_array       *arr;
	zend_object      *obj;
	zend_resource    *res;
	zend_reference   *ref;
	zend_ast_ref     *ast;
	zval             *zv;
	void             *ptr;
	zend_class_entry *ce;
	zend_function    *func;
	struct {
		uint32_t w1;
		uint32_t w2;
	} ww;
} zend_value;

struct _zval_struct {   //zend_types.h:121
	zend_value        value;			/* value */
	union {
		struct {
			ZEND_ENDIAN_LOHI_4(
				zend_uchar    type,			/* active type */
				zend_uchar    type_flags,
				zend_uchar    const_flags,
				zend_uchar    reserved)	    /* call info for EX(This) */
		} v;
		uint32_t type_info;
	} u1;
	union {
		uint32_t     next;                 /* hash collision chain */
		uint32_t     cache_slot;           /* literal cache slot */
		uint32_t     lineno;               /* line number (for ast nodes) */
		uint32_t     num_args;             /* arguments number for EX(This) */
		uint32_t     fe_pos;               /* foreach position */
		uint32_t     fe_iter_idx;          /* foreach iterator index */
		uint32_t     access_flags;         /* class constant access flags */
		uint32_t     property_guard;       /* single property guard */
		uint32_t     extra;                /* not further specified */
	} u2;
};

#define sw_get_object_handle(object)        Z_OBJ_HANDLE_P(object)
#define Z_OBJ_HANDLE_P(zval_p)      Z_OBJ_HANDLE(*(zval_p))
#define Z_OBJ_HANDLE(zval)          (Z_OBJ((zval)))->handle
#define Z_OBJ(zval)					(zval).value.obj

 析构函数

析构函数实现在swoole_process.c:318

static PHP_METHOD(swoole_process, __destruct)
{
    swWorker *process = swoole_get_object(getThis());
    swPipe *_pipe = process->pipe_object;
    if (_pipe)
    {
        _pipe->close(_pipe);
        efree(_pipe);
    }
    if (process->queue)
    {
        efree(process->queue);
    }
    efree(process);
}

析构函数主要判断是否使用管道和队列,然后关闭管道和释放管道队列占用的内存,然后释放进程占用内存。

swoole process父子进程使用队列通信

2018年5月11日 没有评论

最近在研究一点swoole一方面的东西,打算用swoole process做一个工具,而且想用里面的queue作为父子进程通信的方式。看了官方的文档,发现使用useQueue的时候,这个并没有给样例,在push里面看到了一个例子,但是发现它实现的方式和文档对useQueue的介绍有些不一致。文档里面说useQueue如果将mode设置为2时(默认就是2),所有创建的子进程都会从队列中争抢消息的。但是push中给的例子却是遍历所有worker,向队列里面插入消息。感觉这方面怪怪的,在swoole群里面问了一下,几个人在聊开车,对我的问题不知道太简单还是不屑一顾,没有一个人回答。求人不如求己,于是就去看了一下useQueue、push、pop相关的源码,发现了官方文档上面说的还是对的,push里面的例子却是有些问题,感觉官方文档的例子放这么久一个不合适的例子有点不应该,不过开源的东西,靠大家自发的贡献,我们也不能要求太多了。

下面是我自己写的一个使用消息队列并设置为非阻塞模式的例子,同时已经更新到swoole process useQueue文档的示例中去了。

<?php
$worker_num = 2;
$process_pool = [];

$process= null;
$pid = posix_getpid();

function sub_process(swoole_process $worker)
{
    sleep(1); //防止父进程还未往消息队列中加入内容直接退出
    echo "worker ".$worker->pid." started".PHP_EOL;
    while($msg = $worker->pop()){
        if ($msg === false) {
            break;
        }
        $sub_pid = $worker->pid;
        echo "[$sub_pid] msg : $msg".PHP_EOL;
        sleep(1);//这里的sleep模拟必须,否则可能1个worker就把所有信息全接受了
    }
    echo "worker ".$worker->pid." exit".PHP_EOL;
    $worker->exit(0);
}

$customMsgKey = 1;//默认为空,这个地方可以随便填的
$mod = 2 | swoole_process::IPC_NOWAIT;//这里设置队列为非阻塞模式

//创建worker进程
for($i=0;$i<$worker_num; $i++) {
    $process=new swoole_process('sub_process');
    $process->useQueue($customMsgKey, $mod);
    $process->start();
    $pid = $process->pid;
    $process_pool[$pid] = $process;
}

$messages = [
    "Hello World!",
    "Hello Cat!",
    "Hello King",
    "Hello Leon",
    "Hello Rose"
];
//由于所有进程是共享使用1个消息队列,所以只需向一个字进程发送消息即可
$process = current($process_pool);
foreach ($messages as $msg) {
    $process->push($msg);
}

swoole_process::wait();
swoole_process::wait();

echo "master exit".PHP_EOL;

如有问题请大家指正,useQueue文档地址

分类: PHP 标签:

lumen数据库时区设置

2018年5月10日 没有评论

前段时间写过一篇关于日期选择使用的问题博客,其实说起来也惭愧,用mysql的timestamp做日期我已经有2年多的使用经验了,以前一直不了解timestamp里面居然保存的居然是带时区的。今天就是记录一下laravel/lumen里面怎么设置连接时的时区问题。

那么是如何发现这个问题lumen/laravel里面需要设置数据库时区的哪?

最近公司使用lumen在做一下项目,下单的时间在app里面看着是正常的,但是我通过一些mysql工具连接时,发现时间却是+8小时以后的时间.

查看ORM源码,它的注释里面说日期类型的字符创会转化成“DateTime/Carbon”实例,然后再进一步处理是输出或者存入数据库。

我们可以通过在.env中设置”DB_TIMEZONE”来解决时区不一致的问题。

DB_TIMEZONE=+8:00

一般来说要保证我们设置DB_TIMEZONE和APP_TIMEZONE一致的,所以一般配置文件都是这样的。

APP_TIMEZONE=Asia/Shanghai
DB_TIMEZONE=+8:00

 

docker exec进入容器

2018年5月9日 没有评论

docker技术原来越普及,那么我们怎么进入一个正在运行中的docker容器哪?

目前常用的有4种方式:

1、docker attach
2、SSH
3、nsenter
4、docker exec

目前比较推荐使用第4中docker exec的方式,当然这篇博客主要目的是学习记忆,我自己也是这方面的新人。

启动php-fpm容器

docker run -d --name="king_php72" php:7.2.4-fpm

进入容器

上面的命令我们在启动时已经给docker命名了,所以可以直接通过名字的方式通过exec进入。

docker exec -it king_php72 /bin/bash

如果我们不清楚docker容器的名字,我们可以通过docker ps来获取容器的ID,通过容器ID进入容器。

# docker ps
CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                    NAMES
76c6cbb1a025        php:7.2.4-fpm       "docker-php-entrypoi…"   5 minutes ago       Up 5 minutes        9000/tcp                 king_php72
# docker exec -it 76c6cbb1a025 /bin/bash

参考文章:《如何进入Docker容器》

 

mysql中的数据存储选择

2018年5月3日 没有评论

MySQl中有多种表示日期和时间的数据类型。其中YEAR表示年份,DATE表示日期,TIME表示时间,DATETIME和TIMESTAMP表示日期和实践。它们的对比如下

YEAR ,字节数为1,取值范围为“1901——2155”
DATE,字节数为4,取值范围为“1000-01-01——9999-12-31”
TIME,字节数为3,取值范围为“-838:59:59——838:59:59”
DATETIME,字节数为8,取值范围为“1000-01-01 00:00:00——9999-12-31 23:59:59”
TIMESTAMP,字节数为4,取值范围为“19700101080001——20380119111407”.

以前经常看到有人说时间存储为int类型的时候查询会比timestamp类型快很多,到底有多大的差别哪?我动手测试了一下,给大家分享一下测试结果。

一、表结构

test1表为时间存储为int类型,test2表为存储为timestamp类型。

CREATE TABLE `test1` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(30) NOT NULL DEFAULT '',
  `address` varchar(100) NOT NULL DEFAULT '',
  `email` varchar(50) NOT NULL DEFAULT '',
  `created_at` int(11) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_createdat` (`created_at`),
  KEY `idx_name_time` (`name`,`created_at`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE `test2` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `name` varchar(30) NOT NULL DEFAULT '',
  `address` varchar(100) NOT NULL DEFAULT '',
  `email` varchar(50) NOT NULL DEFAULT '',
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  KEY `idx_createdat` (`created_at`),
  KEY `idx_name_time` (`name`,`email`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

 二、生成测试数据

我是自己写的python脚本,利用了python的faker库。

import faker
import time
import pymysql

def timestamp_datetime(value):
    format = '%Y-%m-%d %H:%M:%S'
    # value为传入的值为时间戳(整形),如:1332888820
    value = time.localtime(value)
    ## 经过localtime转换后变成
    ## time.struct_time(tm_year=2012, tm_mon=3, tm_mday=28, tm_hour=6, tm_min=53, tm_sec=40, tm_wday=2, tm_yday=88, tm_isdst=0)
    # 最后再经过strftime函数转换为正常日期格式。
    dt = time.strftime(format, value)
    return dt

def gen_sql(max=1000):
    sqlData = []
    i=0
    while i < max :
        name = generator.name()
        email = generator.email()
        unix_time=generator.unix_time()
        address = generator.address()
        time=timestamp_datetime(unix_time)
        sql = "INSERT INTO test1 (`name`,`address`,`email`,`created_at`) VALUE ('%s','%s','%s',%d);" % (name,address,email,unix_time)
        sql2 = "INSERT INTO test2 (`name`,`address`,`email`,`created_at`) VALUE ('%s','%s','%s','%s');" % (name,address,email,time)
        i=i+1
        sqlData.append(sql)
        sqlData.append(sql2)
    return sqlData

start_time = time.time()

generator = faker.Faker(locale="zh-cn")
total = 1000000*2
one_time=1000
times=total/one_time
print("start generating data")

conn = pymysql.connect(
    host = "127.0.0.1",
    user = "root",
    password = "123456",
    database = "sql_test",
    charset = 'utf8',
    cursorclass = pymysql.cursors.DictCursor)


cursor = conn.cursor()

i=0
while i < times:
    sql_data = gen_sql(one_time)
    for sql in sql_data:
        cursor.execute(sql)
    #commit以后更新才会提交到数据库
    conn.commit()
    i=i+1
    print("add records : %d" % (i*one_time))

cursor.close()
conn.close()
use_time=time.time()-start_time
print("done,use time:%f" % (use_time))

 三、占用空间

由于innodb的show table status from db中的值不准确,所以这里我们可以当做相等。

四、查询性能

#43ms
 select SQL_NO_CACHE * from test1 where created_at > 1025340225 limit 10; 
# 82ms
 select SQL_NO_CACHE * from test2 where created_at > '2002-06-29 16:43:45' limit 10;

单一索引查询,从结果来看差距是很大的,几乎有一倍了,但是就看这点损耗你可以接受吗?

 

分类: Mysql 标签:

nginx反向代理解决跨域问题

2018年3月28日 没有评论

现在随着前端技术的发展,前端渲染模板越来成熟,前后端的分离就变得越来越普遍了。其中一个很目标的问题就是跨域问题,这里就不展开跨域问题了。以前常见的解决办法是在返回的header部分增加”‘Access-Control-Allow-*”系列header来解决问题。以前我也写过一篇类似的文章《ajax跨域解决方案-Cross Origin Resource Sharing》,感兴趣的话可以去看看一下。今天要说的是利用nginx的反向代理来解决这个问题。

现在我们有2个站点,front.aaa.com和api.aaa.com。假设这里我们2个站点都用nginx搭建,front.aaa.com的nginx配置文件为front.conf,api.aaa.com的nginx的配置文件为api.conf。当front站点的页面ajax访问api站点的时候就会起因这个跨域问题。我们在front站点配置1个针对api的反向代理,配置如下:

server {
     ....
       location /api/ {
            rewrite ^/api/(.*) /$1 break;
            proxy_pass http://api.aaa.com;
        }
        ....

}

如此一来所有访问api的接口我们可以同构http://front.aaa.com/api/{realApi}来实现对后端接口的访问。

分类: Linux, nginx, Web 标签:

yum安装elasticsearch

2018年3月13日 没有评论

centos环境下面安装elasticsearch(后面用es代称)有多重方法,可以yum、rpm包或者源码。今天就简单说一下yum安装es的过程,而且也推荐这么做,可以方便的通过systemd系列命令管理es。

安装依赖

这里面真正需要的是java,但是如果你不安装java其实也可以安装成功,不过安装插件时会有问题,所以我们先安装java。

yum install java

 配置官方yum源

我们可以通过官方提供的源来安装,所以我们先配置官方源。

[elasticsearch-6.x]
name=Elasticsearch repository for 6.x packages
baseurl=https://artifacts.elastic.co/packages/6.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md

安装Elasticsearch

然后更新本地yum缓存,安装es。

yum makecache
yum install elasticsearch

 安装中文分词插件

这里的中文分词插件选择analysis-ik,我们通过elasticsearch-plugin命令来安装。首先我们需要知道命令的位置,默认是在”/usr/share/elasticsearch/bin/elasticsearch-plugin”.

cd /usr/share/elasticsearch
./bin/elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.2.2/elasticsearch-analysis-ik-6.2.2.zip

  启动ES

下面我们启动es,查看是否安装成功。

 systemctl start elasticsearch

用curl访问9200端口,查看服务是否正常。

curl http://127.0.0.1:9200
#看到下面内容,说明es启动正常
{
  "name" : "id7JTQQ",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "0JLalDUYS_y1FFEsLFsqlg",
  "version" : {
    "number" : "6.2.2",
    "build_hash" : "10b1edd",
    "build_date" : "2018-02-16T19:01:30.685723Z",
    "build_snapshot" : false,
    "lucene_version" : "7.2.1",
    "minimum_wire_compatibility_version" : "5.6.0",
    "minimum_index_compatibility_version" : "5.0.0"
  },
  "tagline" : "You Know, for Search"
}

 查看ES安装插件

访问“http://127.0.0.1:9200/_cat/plugins”可以查看es安装的插件。

curl http://127.0.0.1:9200/_cat/plugins

至此,我们的es安装初步完成了,开始使用它吧!

分类: Linux 标签:

Brew安装指定版本软件

2018年2月28日 没有评论

今天想安装一下elasticsearch,顺便安装一下ik中文分词,可惜用brew搞了好久也没装好。用brew装的elasticsearch是最新版的6.2.2,但是ik插件目前缺只支持6.2.1,就想着用brew安装指定版本的elasticsearch。但是目前网上的中文教程貌似都失效了,幸亏找到一篇英文的文章帮忙解决了问题。

想要通过brew安装指定版本的软件,我们可以利用brew install远程url方式来实现这个目的。brew允许的url格式是什么样子哪?类似以下这种:

brew install ${BREWURL}/{HASH}/Formula/{NAME}.rb
BREWURL=https://raw.githubusercontent.com/Homebrew/homebrew-core

上面命令有3个变量,不过BREWURL算是1个常量,已经给出了,目前来看是不变的,但是我们想要完成上面的目的,还有2个变量要找到,就是HASH和NAME了。NAME比较简单,一般就是软件名字,例如我这里就是elasticsearch,那么接下来只要找到HASH就可以了。
找HASH有2中方式,一种是通过brew log本地查找,另一种方式就是在github上面找了。这里面2中方式都提一下。

brew本地的方式,可以通过一下命令查看git log。

brew log -p NAME

里面有commit记录,找到对应版本的commit id,前7位就是我们需要的hash了。

分类: Mac 标签: