最近工作总结(七)

2017/08/03 Work
使用正则快速获取括号内的字符串

result = file_name.match(/\A.((\S+)).\Z/) result1 = file_name.match(/\A.[(\S+)].\Z/) p $1 p result.to_a

构建了一个sidekiq worker的思考

当你新建了一个sidekiq worker,需要思考这个sidekiq woker 是否在你的使用环境需要真的被新建, 是否有条件满足的时候才需要新建这个worker,比如某个开关,或某个实例对象存在。

当新建出一个sidekiq worker,思考其中的代码逻辑,是否不再满足某种条件的时候,就直接return,而不再让代码继续执行。

思考上面的两点,可以减少worker的新建次数,可以然后worker真正有效的执行,减少不必要的执行次数

使用sendcloud API发送邮件

阿里云机器把25端口封了,导致smtp发送邮件需要使用25端口,而无法发送邮件。sendcloud提供了API的方式调用发送邮件, 使用sendcloud API发送邮件,解决这个问题

何时需要消息队列

做业务解耦/最终一致性/广播/错峰流控等。反之,如果需要强一致性,关注业务逻辑的处理结果,则RPC显得更为合适

Kafka为什么那么快

Kafka速度的秘诀在于,它把所有的消息都变成一个的文件。通过mmap(Memory Mapped Files)提高I/O速度,写入数据的时候它是末尾添加(顺序写入)所以速度最优;读取数据的时候配合sendfile直接暴力输出。阿里的RocketMQ也是这种模式,只不过是用Java写的

增加edge_ngram tokenizer, 优化前缀搜索

rails_script1.rb

# rails r rails_script1.rb
# 为索引增加一个新的analyzer

new_settings = {
  analysis: {
    analyzer: {
      edge_prefix_split: {
        type: 'custom',
        tokenizer: 'edge_ngram_tokenizer'
      }
    },
    tokenizer: {
      edge_ngram_tokenizer: {
        type: 'edge_ngram',
        min_gram: 1,
        max_gram: 10,
        token_chars: ['letter','digit']
      }
    }
  }
}

client = Elasticsearch::Model.client.indices
timestamp = Time.now
client.close index: 'customers'
client.put_settings index: 'customers', body: new_settings
client.open index: 'customers'

rails_script2.rb

# rails r rails_script2.rb
# 在原来索引基础上,增加一个field
indexes :nick_name, type: 'multi_field' do
  indexes :prefix, analyer: 'edge_prefix_split'
end

client = Elasticsearch::Model.client
client.indices.put_mapping index: "users", type: "user", body: {
  user: {
    properties:{
      name: {
        type: "string",
        index: "no",
        fields: {
          prefix: {
            type: "string",
            analyzer: "edge_prefix_split"
          }
        }
      }
    }
  }
}

如果你没有使用multi_fiel(elasticsearch 5.0以上已经废弃了),你需要

indexes :name do
  indexes :prefix, type: :string, analyzer: 'edge_prefix_split'
end

client = Elasticsearch::Model.client
client.indices.put_mapping index: "users", type: "user", body: {
  user: {
    properties:{
      name:{
        type: :string, analyzer: :edge_prefix_split
      }
    }
  }
}

最后,再慢慢的为所有记录执行: elasticsearch.index_document。 将每个记录的nick_name.prefix,使用 analyzer edge_prefix_split进行分词。

在搜索的时候,使用 {prefix: {“name.prefix”=>”#{search_value}”}} 就可以了。

edge_ngram 真的是天生用于前缀搜索的tokenizer

关于服务器TCP最大连接数

ulimit -n 65536 设为65536

服务端的最大TCP连接数没有这个限制

服务器中的客户端TCP连接数有这个限制。比如:nginx的处理连接数,使用数据库的TCP连接数

Vistor项目出现端口无法访问的阿里云报错

原因是,服务器TCP最大连接数为65536,并发数高的时候,TCP连接数达到了上限,使得新的TCP请求该端口没有可用的连接数文件符,使得产生了大量的半连接。 而这些请求自然是无法连接成功。

使用JWT官网推荐的jwt包

如果JWT的其他参数都对了,但是,加密得到的最后的jwt值还是不对,就是你的加密算法不对了。一种可能是你所用的加密算法的包和官方使用的包的算法不一致。这时候,需要到JWT官方网址, https://jwt.io/. 在 Libraries 项目有推荐的jwt包。请使用这些推荐的jwt包。

使用inject、reduce 方法的坑

最近在使用inject的时候遇到了一个问题。我的代码例子是:

[1,2,3,4,5,6].inject([]) do |sum, i|
  if i > 1
    sum << i
  end
end

结果报错:

NoMethodError: undefined method `<<' for nil:NilClass

一开始很奇怪,在inject([])的时候,我给sum赋值初始值为数组了,报错信息怎么会报 sum是一个 nil:NilClass呢?

打断点

def test_inject
  [1,2,3,4,5,6].inject([]) do |sum, i|
    if i > 1
      binding.pry
      sum << i
    end
    sum
  end
end

发现确实 sum是nil。想到了可能是if i > 1 这个条件判断的影响。修改一下测试代码

def test_inject_0
  [1,2,3,4,5,6].inject([]) do |sum, i|
    if i > 0
      sum << i
    end
  end
end

def test_inject_3
  [4,5,6,1,2,3].inject([]) do |sum, i|
    binding.pry
    if i > 3
      sum << i
    end
  end
end
test_inject_0  # [1, 2, 3, 4, 5, 6]

test_inject_3  
sum
# []
# [4]
# [4,5]
# [4,5,6]
# NoMethodError: undefined method `<<' for nil:NilClass

根据test_inject_3 , 当i的值不满足 if i > 3 的条件的时候,sum的值就被置为nil了。

如果你需要在inject的block中进行对操作元素的条件过滤操作,你会将sum变为nil。

所以建议不在inject的block中进行条件过滤操作,而是在inject方法之前过滤好。

同理reduce方法。

Ruby 版本: ruby 2.4.0p0 (2016-12-24 revision 57164) [x86_64-linux]

解决方法

[1,2,3,4,5,6].inject([]) do |sum, i|
  if i > 1
    sum << i
  end
  sum
end

在最后返回 sum,因为 inject方法会将最后的返回值赋值给sum。如果在if 判断条件没有通过的情况下,会将nil值返回给sum

控制elasticsearch启动、关闭、重启shell脚本
APP_EXEC="/usr/local/service/elasticsearch/bin/elasticsearch"
LOG_FILE="/mnt/log/elasticsearch.log"
PID_FILE="/mnt/run/elasticsearch.pid"
PID_DIR="$APP_DIR/pid"
LOG_DIR="$APP_DIR/log"

USAGE="Usage: $0 {start|stop|restart|status} [--force]"
FORCE_OP=false

start_it() {
    echo "Starting Elasticsearch..."
    $APP_EXEC 1>"$LOG_FILE" 2>&1 &
    echo $! > "$PID_FILE"
    echo "Elasticsearch started with pid $!"
}

pid_file_exists() {
    [ -f "$PID_FILE" ]
}

get_pid() {
    echo "$(cat "$PID_FILE")"
}

is_running() {
    PID=$(get_pid)
    ! [ -z "$(ps aux | awk '{print $2}' | grep "^$PID$")" ]
}

remove_pid_file() {
    echo "Removing pid file"
    rm -f "$PID_FILE"
}

start_app() {
    if pid_file_exists
    then
        if is_running
        then
            PID=$(get_pid)
            echo "Elasticsearch already running with pid $PID"
            exit 1
        else
            echo "Elasticsearch stopped, but pid file exists"
            if [ $FORCE_OP = true ]
            then
                echo "Forcing start anyways"
                remove_pid_file
                start_it
            fi
        fi
    else
        start_it
    fi
}
stop_process() {
    PID=$(get_pid)
    echo "Killing process $PID"
    kill $PID
}

stop_app() {
    if pid_file_exists
    then
        if is_running
        then
            echo "Stopping Elasticsearch ..."
            stop_process
            remove_pid_file
            echo "Elasticsearch stopped"
        else
            echo "Elasticsearch already stopped, but pid file exists"
            if [ $FORCE_OP = true ]
            then
                echo "Forcing stop anyways ..."
                remove_pid_file
                echo "Elasticsearch stopped"
            else
                exit 1
            fi
        fi
    else
        echo "Elasticsearch already stopped, pid file does not exist"
        exit 1
    fi
}
status_app() {
    if pid_file_exists
    then
        if is_running
        then
            PID=$(get_pid)
            echo "Elasticsearch running with pid $PID"
        else
            echo "Elasticsearch stopped, but pid file exists"
        fi
    else
        echo "Elasticsearch stopped"
    fi
}
case "$2" in
--force)
    FORCE_OP=true
    ;;
"")
    ;;
*)
    echo $USAGE
    exit 1
    ;;
esac

case "$1" in
start)
    start_app
    ;;
stop)
    stop_app
    ;;
restart)
    stop_app
    start_app
    ;;
status)
    status_app
    ;;
*)
    echo $USAGE
    exit 1
    ;;
esac
类方法中的实例变量别用 ||= 方法

rials 4.0.3 unicorn服务 model中类方法中的实例变量,

当使用 @user   = User.find id

不同的请求,传的id不同的时候。比如第一个请求传id=1, 第二个请求传id=2。 结果第二个请求得到了 @user 是id=1 的。

所以,在类方法中 别使用   = 方法,否则会出现上面的情况

Search

    Table of Contents