JavaScript reduce 用法

reduce() 方法接收一个函数作为累加器,数组中的每个值(从左到右)开始缩减,最终计算为一个值。
reduce() 可以作为一个高阶函数,用于函数的 compose。
注意: reduce() 对于空数组是不会执行回调函数的。

语法

array.reduce(function(total, currentValue, currentIndex, arr), initialValue)

参数

参数 描述
total 必需。初始值, 或者计算结束后的返回值。
currentValue 必需。当前元素
currentIndex 可选。当前元素的索引
arr 可选。当前元素所属的数组对象。

initialValue可选。传递给函数的初始值

Flex布局语法介绍

指定使用Flex布局

.box{
  display: flex;
}

行内元素使用Flex布局

.box{
  display: inline-flex;
}

注意,设为 Flex 布局以后,子元素的float、clear和vertical-align属性将失效。

Flex的六个属性

    • flex-direction
    • flex-wrap
    • flex-flow
    • justify-content
    • align-items
    • align-content

flex-direction属性
flex-direction 设置项目的排列方向。

.box {
  flex-direction: row | row-reverse | column | column-reverse;
}

row(默认值):主轴为水平方向,起点在左端。
row-reverse:主轴为水平方向,起点在右端。
column:主轴为垂直方向,起点在上沿。
column-reverse:主轴为垂直方向,起点在下沿

See the Pen flex-direction: row by 06peng (@abswolf) on CodePen.

See the Pen flex-direction: row | row-reverse by 06peng (@abswolf) on CodePen.

See the Pen flex-direction: column by 06peng (@abswolf) on CodePen.

See the Pen flex-direction: column-reverse by 06peng (@abswolf) on CodePen.

flex-wrap属性
flex-wrap属性定义,如果一条轴线排不下,如何换行?它有三个值:
nowrap(默认):不换行。

See the Pen flex-wrap:nowrap by 06peng (@abswolf) on CodePen.


wrap:换行,第一行在上方。

See the Pen flex-wrap:wrap by 06peng (@abswolf) on CodePen.


wrap-reverse:换行,第一行在下方。

See the Pen flex-wrap:wrap-reverse by 06peng (@abswolf) on CodePen.

flex-flow属性
flex-flow属性是flex-direction属性和flex-wrap属性的简写形式,默认值为row和nowrap。

 
 .box { 
    flex-flow: <flex-direction> || <flex-wrap>; 
 }

justify-content属性
justify-content属性定义了项目水平对齐方式。

.box {
  justify-content: flex-start | flex-end | center | space-between | space-around;
}

flex-start(默认值):左对齐
flex-end:右对齐
center: 居中
space-between:两端对齐,项目之间的间隔都相等。
space-around:每个项目两侧的间隔相等。所以,项目之间的间隔比项目与边框的间隔大一倍。

See the Pen justify-content:flex-start by 06peng (@abswolf) on CodePen.

See the Pen justify-content:flex-end by 06peng (@abswolf) on CodePen.

See the Pen justify-content:center by 06peng (@abswolf) on CodePen.

See the Pen justify-content:space-between by 06peng (@abswolf) on CodePen.

See the Pen justify-content:space-around by 06peng (@abswolf) on CodePen.

align-items属性
align-items属性定义了项目垂直对齐方式。

.box {
  align-items: flex-start | flex-end | center | baseline | stretch;
}

flex-start:垂直起点对齐。
flex-end:垂直终点对齐。
center:垂直中间点对齐。
baseline: 项目的第一行文字的基线对齐。
stretch(默认值):如果项目未设置高度或设为auto,将占满整个容器的高度。

See the Pen align-items:flex-start by 06peng (@abswolf) on CodePen.

See the Pen align-items:flex-end by 06peng (@abswolf) on CodePen.

See the Pen align-items:center by 06peng (@abswolf) on CodePen.

See the Pen align-items:baseline by 06peng (@abswolf) on CodePen.

See the Pen align-items:stretch by 06peng (@abswolf) on CodePen.

align-content属性
align-content属性定义了不同方向的对齐方式(相当于换行,有横有竖)。如果项目只有单个方向,该属性不起作用。

.box {
  align-content: flex-start | flex-end | center | space-between | space-around | stretch;
}

flex-start:与起点对齐。
flex-end:与终点对齐。
center:与中中间点对齐。
space-between:与两端对齐,两端之间的间隔平均分布。
space-around:两侧的间隔都相等。间隔比轴线与边框的间隔大一倍。
stretch(默认值):占满整个空间。

See the Pen align-content:flex-start by 06peng (@abswolf) on CodePen.

See the Pen align-content:flex-end by 06peng (@abswolf) on CodePen.

See the Pen align-content:center by 06peng (@abswolf) on CodePen.

See the Pen align-content:space-between by 06peng (@abswolf) on CodePen.

See the Pen align-content:space-around by 06peng (@abswolf) on CodePen.

项目(item)的6个属性

    • order
    • flex-growp
    • flex-shrink
    • flex-basis
    • flex
    • align-self

order属性
order属性定义项目的排列顺序。数值越小,排列越靠前,默认为0

See the Pen flex-order by 06peng (@abswolf) on CodePen.


flex-grow属性
flex-grow属性定义项目的放大比例,默认为0,即如果存在剩余空间,也不放大。
如果所有项目的flex-grow属性都为1,则它们将等分剩余空间(如果有的话)。如果一个项目的flex-grow属性为2,其他项目都为1,则前者占据的剩余空间将比其他项多一倍。

See the Pen flex-grow by 06peng (@abswolf) on CodePen.


flex-shrink属性
flex-shrink属性定义了项目的缩小比例,默认为1,即如果空间不足,该项目将缩小。
如果所有项目的flex-shrink属性都为1,当空间不足时,都将等比例缩小。如果一个项目的flex-shrink属性为0,其他项目都为1,则空间不足时,前者不缩小。
负值对该属性无效。

See the Pen flex-shrink by 06peng (@abswolf) on CodePen.


flex-basis属性
flex-basis属性定义了在分配多余空间之前,项目占据的主轴空间(main size)。浏览器根据这个属性,计算主轴是否有多余空间。它的默认值为auto,即项目的本来大小。
它可以设为跟width或height属性一样的值(比如350px),则项目将占据固定空间。
flex属性
flex属性是flex-grow, flex-shrink 和 flex-basis的简写,默认值为0 1 auto。后两个属性可选。
该属性有两个快捷值:auto (1 1 auto) 和 none (0 0 auto)。
建议优先使用这个属性,而不是单独写三个分离的属性,因为浏览器会推算相关值。
align-self属性
align-self属性允许单个项目有与其他项目不一样的对齐方式,可覆盖align-items属性。默认值为auto,表示继承父元素的align-items属性,如果没有父元素,则等同于stretch。

.item {
  align-self: auto | flex-start | flex-end | center | baseline | stretch;
}

该属性可能取6个值,除了auto,其他都与align-items属性完全一致。

See the Pen align-self by 06peng (@abswolf) on CodePen.

SpringBoot应用安全停止

SpringBoot的启动我们可以在打包后用如下命令启动:

nohup java -jar springapplication.jar --spring.profiles.active=prod &

更多关于启动的参数请自行查阅。

SpringBoot的停止有两种方式,一种是通过http发送shutdown信号,另一种是通过service stop的方式来停止服务。

方式一:通过http发送shutdown信号
该方式主要依赖SpringBoot Actuator的endpoint特性,具体步骤如下:
添加依赖:

<dependency> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-actuator</artifactId> 
</dependency>

application.properties中添加:

#启用shutdown
endpoints.shutdown.enabled=true
#禁用密码验证
endpoints.shutdown.sensitive=false

执行关闭命令:

curl -X POST host:port/shutdown
例如:$ curl -X POST http://localhost:8080/shutdown

如果需要配置路径,则需要在application.properties中添加

management.context-path=/manage

则关闭命令变为

curl -X POST host:port/manage/shutdown

接下来说一下安全设置相关,远程执行命令的时候需要借助spring-boot-starter-security进行身份认证。
首先,添加security依赖:

<dependency> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-starter-security</artifactId> 
</dependency>

接着在application.properties中添加安全属性:

#开启shutdown的安全验证 
endpoints.shutdown.sensitive=true 
#验证用户名 
security.user.name=abswolf
#验证密码 
security.user.password=123456
#角色 
management.security.role=SUPERUSER

指定IP和端口

#指定管理端口和IP 
management.port=8080
management.address=127.0.0.1

执行命令

curl -u abswolf:123456 -X POST http://127.0.0.1:8081/shutdown

方式二:部署为Unix/Linux Service
该方式主要借助官方的spring-boot-maven-plugin创建”Fully executable” jar ,这中jar包内置一个shell脚本,可以方便的将该应用设置为Unix/Linux的系统服务(init.d service),官方对该功能在CentOS和Ubuntu进行了测试,对于OS X和FreeBSD,可能需要自定义。具体步骤如下:
引入插件:

<plugin> 
    <groupId>org.springframework.boot</groupId> 
    <artifactId>spring-boot-maven-plugin</artifactId> 
    <configuration> 
        <executable>true</executable> 
    </configuration> 
</plugin>

设置为系统服务:
将你的应用打成jar包,部署到服务器,假设部署路径为/var/app,包名为app.jar,通过如下方式将应该设置为一个系统服务:

sudo ln -s /var/app/app.jar /etc/init.d/app

赋予可执行权限:

chmod u+x app.jar

以系统服务的方式管理:

service foo start|stop|restart
默认PID文件路径:/var/run/appname/appname.pid
默认日志文件路径:/var/log/appname.log

自定义参数:
在这种方式下,我们还可以使用自定义的.conf文件来变更默认配置,方法如下:
1、在jar包相同路径下创建一个.conf文件,名称应该与.jar的名称相同,如appname.conf
2、在其中配置相关变量,如:

JAVA_HOME=/usr/local/jdk
JAVA_OPTS=-Xmx1024M
LOG_FOLDER=/custom/log

安全设置:
作为应用服务,安全性是一个不能忽略的问题,如下一些操作可以作为部分基础设置参考:
为服务创建一个独立的用户,同时最好将该用户的shell绑定为/usr/sbin/nologin
1、赋予最小范围权限:

chmod 500 app.jar

2、阻止修改:

sudo chattr +i app.jar

3、对.conf文件做类似的工作:

chmod 400 app.conf,sudo chown root:root app.conf

参考:正确、安全地停止SpringBoot应用服务

RxJava生命周期管理

当Activity或者fragment销毁的时候需要取消订阅,否则会消耗内存,导致OOM。这里推荐两种办法:
第一种:

 
CompositeDisposable mDisposables = new CompositeDisposable();
DisposableObserver mObserver = getObservable()//被观察者
        .subscribeOn(Schedulers.io())
        .observeOn(AndroidSchedulers.mainThread())
        .subscribe(mObserver);
mDisposables.add(mObserver);
当fragment或者activity销毁的时候,清空mDisposables.clear();

第二种使用rxlifecycle-components第三方框架

Activity需要继承RxAppcompatActivity,新建的Fragment则继承RxFragment。
myObservable
    .compose(RxLifecycle.bindUntilEvent(lifecycle, ActivityEvent.DESTROY))
    .subscribe();
具体可以查看官方GitHub

Git基本使用

一、先在第三方git平台上创建一个空的项目。

二、本地初始化项目

1、执行以下命令设置git的提交信息

git config --global user.name "your name"
git config --global user.email "your email"

2、在你的需要初始化版本库的文件夹中执行初始化命令

git init 
git remote add origin <你的项目地址>

3、执行以下命令提交本地代码

git pull origin master
git add .
git commit -m "first commit"
git push origin master

Mac Android Studio离线配置gradle

Android Studio每次大更新,基本Gradle也需要大更新。每次通过studio都下载半天,甚至下载不了。所以通过在Gradle官网下载并手动配置,几分钟就可以搞定。

Gradle官网下载

1、首先要知道你需要下载的Gradle版本号。

在项目目录下,找到该文件:

2、下载gradle-4.1-all.zip之后,Copy 到Gradle所在的目录。

这里推荐用命令行直接打开:

#open .gradle

把gradle-4.1-all.zip直接放到gradle-4.1-all目录下的那一长串目录下。然后重启Android Studio就可以了。

JedisCluster应用详解

Redis集群的搭建参考Redis Cluster安装配置

本文主要介绍JedisCluster客户端结合spring注解的使用。

1、rediscluster.properties

#redis的服务器地址
redis.host=172.18.209.168
#redis的服务端口
redis.port=6379
#密码
redis.password=×××××××
#最大空闲数
redis.maxIdle=100
#最大连接数
redis.maxActive=300
#最大建立连接等待时间
redis.maxWait=1000
#客户端超时时间单位是毫秒
redis.timeout=100000
redis.maxTotal=1000
redis.minIdle=8
#明是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个
redis.testOnBorrow=true
#连接耗尽时是否阻塞  false报异常,ture阻塞直到超时
redis.blockWhenExhausted=false
#当设置为true,且服务开启的jmx服务时,使用jconsole等工具将看到连接池的状态
redis.jmxEnabled=true
#向连接池归还链接时,是否检测链接对象的有效性
redis.testOnReturn=false
#对象空闲多久后逐出,当空闲时间>该值 且 空闲连接>最大空闲数 时直接逐出
redis.softMinEvictableIdleTimeMillis=10000

#jediscluster
cluster1.host.port=172.18.209.168:7001
cluster2.host.port=172.18.209.168:7002
cluster3.host.port=172.18.209.168:7003
cluster4.host.port=172.18.209.169:7004
cluster5.host.port=172.18.209.169:7005
cluster6.host.port=172.18.209.169:7006

#rediscluster
spring.redis.cluster.nodes=172.18.209.168:7001,172.18.209.168:7002,172.18.209.168:7003,172.18.209.169:7004,172.18.209.169:7005,172.18.209.169:7006
spring.redis.cluster.max-redirects=3  

2、spring-redis.xml

<bean id="propertyConfigurer"
      class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="location" value="classpath:rediscluster.properties" />
</bean>

<!-- 基础参数配置 -->
<bean id="jedisClusterPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
    <!-- 连接池最大允许连接数 -->
    <property name="maxTotal" value="${redis.maxTotal}"/>
    <!-- 对象空闲多久后逐出,当空闲时间>该值 且 空闲连接>最大空闲数 时直接逐出 -->
    <property name="softMinEvictableIdleTimeMillis" value="${redis.softMinEvictableIdleTimeMillis}"/>
    <!-- 向连接池归还链接时,是否检测链接对象的有效性 -->
    <property name="testOnReturn" value="${redis.testOnReturn}"/>
    <!-- 当设置为true,且服务开启的jmx服务时,使用jconsole等工具将看到连接池的状态 -->
    <property name="jmxEnabled" value="${redis.jmxEnabled}"/>
    <!-- 连接耗尽时是否阻塞  false报异常,ture阻塞直到超时 -->
    <property name="blockWhenExhausted" value="${redis.blockWhenExhausted}"/>
    <!--最大空闲数-->
    <property name="maxIdle" value="${redis.maxIdle}" />
    <!--最大建立连接等待时间-->
    <property name="maxWaitMillis" value="${redis.maxWait}" />
    <!--是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个-->
    <property name="testOnBorrow" value="${redis.testOnBorrow}" />
</bean>

<bean id="resourcePropertySource" class="org.springframework.core.io.support.ResourcePropertySource">
    <constructor-arg name="name" value="rediscluster.properties"/>
    <constructor-arg name="resource" value="classpath:rediscluster.properties"/>
</bean>

<bean id="redisClusterConfiguration" class="org.springframework.data.redis.connection.RedisClusterConfiguration">
    <constructor-arg name="propertySource" ref="resourcePropertySource"/>
</bean>

<!-- JedisCluster -->
<bean id="jedisCluster" class="*.*.jedis.JedisClusterFactory">
    <property name="addressConfig" value="classpath:rediscluster.properties" />
    <property name="addressKeyPrefix" value="cluster" />
    <property name="timeout" value="300000" />
    <property name="maxRedirections" value="6" />
    <property name="genericObjectPoolConfig" ref="jedisClusterPoolConfig" />
</bean>

<!-- 配置redis connection -->
<bean id="redisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
    <constructor-arg ref="redisClusterConfiguration"/>
    <constructor-arg ref="jedisClusterPoolConfig"/>
</bean>

<!-- 数据以字符串存储  -->
<bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/>

<!-- 数据以字节流存储 -->
<bean id="jdkRedisSerializer" class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>

<!--  redis String类型 访问模版本 -->
<bean id="stringRedisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
    <property name="connectionFactory" ref="redisConnectionFactory"/>
</bean>

<!-- redis 访问模版 -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
    <property name="connectionFactory" ref="redisConnectionFactory"/>
    <!-- 在hash数据结构中,hash-key的序列化策略 -->
    <property name="hashKeySerializer" ref="stringRedisSerializer"/>
    <!-- 对于普通K-V操作时,key采取的序列化策略 -->
    <property name="keySerializer" ref="stringRedisSerializer"/>
    <!-- value采取的序列化策略 -->
    <property name="valueSerializer" ref="jdkRedisSerializer"/>
</bean>

3、JedisClusterFactory.java

public class JedisClusterFactory implements FactoryBean, InitializingBean {

    private Resource addressConfig;
    private String addressKeyPrefix;

    private JedisCluster jedisCluster;
    private Integer timeout;
    private Integer maxRedirections;
    private GenericObjectPoolConfig genericObjectPoolConfig;

    private Pattern p = Pattern.compile("^.+[:]\\d{1,5}\\s*$");

    @Override
    public JedisCluster getObject() throws Exception {
        return jedisCluster;
    }

    @Override
    public Class<? extends JedisCluster> getObjectType() {
        return (this.jedisCluster != null ? this.jedisCluster.getClass() : JedisCluster.class);
    }

    @Override
    public boolean isSingleton() {
        return true;
    }

    private Set parseHostAndPort() throws Exception {
        try {
            Properties prop = new Properties();
            prop.load(this.addressConfig.getInputStream());
            Set haps = new HashSet<>();
            for (Object key : prop.keySet()) {
                if (!((String) key).startsWith(addressKeyPrefix)) {
                    continue;
                }
                String val = (String) prop.get(key);
                boolean isIpPort = p.matcher(val).matches();
                if (!isIpPort) {
                    throw new IllegalArgumentException("ip 或 port 不合法");
                }
                String[] ipAndPort = val.split(":");
                HostAndPort hap = new HostAndPort(ipAndPort[0], Integer.parseInt(ipAndPort[1]));
                haps.add(hap);
            }

            return haps;
        } catch (IllegalArgumentException ex) {
            throw ex;
        } catch (Exception ex) {
            throw new Exception("解析jedis配置文件失败", ex);
        }
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        Set haps = this.parseHostAndPort();
        jedisCluster = new JedisCluster(haps, timeout, maxRedirections, genericObjectPoolConfig);
    }

    public void setAddressConfig(Resource addressConfig) {
        this.addressConfig = addressConfig;
    }

    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    public void setMaxRedirections(int maxRedirections) {
        this.maxRedirections = maxRedirections;
    }

    public void setAddressKeyPrefix(String addressKeyPrefix) {
        this.addressKeyPrefix = addressKeyPrefix;
    }

    public void setGenericObjectPoolConfig(GenericObjectPoolConfig genericObjectPoolConfig) {
        this.genericObjectPoolConfig = genericObjectPoolConfig;
    }
}

Redis Cluster安装配置

Redis集群介绍

  • Redis 集群是一个提供在多个Redis间节点间共享数据的程序集。
  • Redis集群并不支持处理多个keys的命令,因为这需要在不同的节点间移动数据,从而达不到像Redis那样的性能,在高负载的情况下可能会导致不可预料的错误.
  • Redis 集群通过分区来提供一定程度的可用性,在实际环境中当某个节点宕机或者不可达的情况下继续处理命令.
  • Redis 集群有16384个哈希槽,每个key通过CRC16校验后对16384取模来决定放置哪个槽.集群的每个节点负责一部分hash槽,举个例子,比如当前集群有3个节点,那么: 节点 A 包含 0 到 5500号哈希槽. 节点 B 包含5501 到 11000 号哈希槽. 节点 C 包含11001 到 16384号哈希槽.

Redis Cluster集群的优势:

  • 自动分割数据到不同的节点上。
  • 整个集群的部分节点失败或者不可达的情况下能够继续处理命令。
  • 客户端与redis节点直连,不需要中间proxy层.客户端不需要连接集群所有节点,连接集群中任何一个可用节点即可。
  • 支持主从复制模型。(slave->master 选举,集群容错)

Redis Cluster集群的主从复制模型:

为了使在部分节点失败或者大部分节点无法通信的情况下集群仍然可用,所以集群使用了主从复制模型,假如有A,B,C三个节点的集群,在没有复制模型的情况下,如果节点B失败了,那么整个集群就会以为缺少5501-11000这个范围的槽而不可用.
然而如果在集群创建的时候我们为每个节点添加一个从节点A1,B1,C1,那么整个集群便有三个master节点和三个slave节点组成,这样在节点B失败后,集群便会选举B1为新的主节点继续服务,整个集群便不会因为槽找不到而不可用了。

Redis Cluster模型图

Redis Cluster的官方文档介绍

1、Redis Cluster集群配置

环境:CentOS7,两台服务器:172.18.209.168、172.18.209.168
Redis的安装步骤可以参考之前的文章 Linux安装配置Redis
我们需要创建三个主节点和三个从节点:

172.18.209.168:7001
172.18.209.168:7002
172.18.209.168:7003
172.18.209.169:7004
172.18.209.169:7005
172.18.209.169:7006

为了方便起见,我这里在168这台机器上创建所有的节点。

#cd /usr/local/redis-4.0.1
#mkdir /data/cluster
#cd /data/cluster
#mkdir 7001 7002 7003 7004 7005 7006

复制默认的配置文件到7001端口对应的目录下。

#cp ../../redis.conf 7001/
修改配置文件:
#vim 7001/redis.conf
port 7001
daemonize yes
cluster-enabled yes
cluster-config-file nodes.conf
cluster-node-timeout 5000
appendonly yes

然后分别copy到其他端口对应的目录下,再打开配置文件修改一下端口号,其他内容不变。
进入对应的端口目录下启动实例:

#redis-server redis.conf

查看进程:

#ps -ef | grep redis
root 5371 1 0 Sep07 ? 00:01:35 redis-server *:6379
root 11891 1 0 10:35 ? 00:00:17 redis-server 172.18.209.168:7002 [cluster]
root 11914 1 0 10:37 ? 00:00:17 redis-server 172.18.209.168:7003 [cluster]
root 11921 1 0 10:37 ? 00:00:17 redis-server 172.18.209.168:7004 [cluster]
root 11926 1 0 10:37 ? 00:00:17 redis-server 172.18.209.168:7005 [cluster]
root 11931 1 0 10:37 ? 00:00:17 redis-server 172.18.209.168:7006 [cluster]

ps:我这里没有7001,是因为我创建后测试被我杀掉了。
接下来就是创建集群了,首先要安装依赖:

#yum install ruby rubygems -y

再安装gem-redis,下载gem-redis-4.0.0
下载gem-redis-4.0.0后执行命令安装

#gem install -l redis-4.0.0.gem

不出意外的话会报错:
ERROR: Error installing redis-4.0.0.gem:
redis requires Ruby version >= 2.2.2.
解决办法参考:redis requires Ruby version >= 2.2.2
为了方便执行命令,copy redis-trib 到/usr/bin目录下。

#cp redis-4.0.0/src/redis-trib.rb /usr/local/bin/redis-trib

接着开始创建集群,执行命令:

#redis-trib create --replicas 1 172.18.209.168:7001 172.18.209.168:7002 172.18.209.168:7003 172.18.209.169:7004 172.18.209.169:7005 172.18.209.169:7006

ps:redis-trib.rb 程序的命令是 create,这表示创建一个新的集群。
–replicas 1 表示为集群中的每个主节点创建一个从节点。
然后redis-trib 会打印出详细配置,确认没问题的话,输入yes确定:

>>> Creating cluster
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
172.18.209.168:7001
172.18.209.169:7004
172.18.209.168:7002
Adding replica 172.18.209.169:7005 to 172.18.209.168:7001
Adding replica 172.18.209.168:7003 to 172.18.209.169:7004
Adding replica 172.18.209.169:7006 to 172.18.209.168:7002
M: 3e00a8c896fd0957e7d423e5b350415ba0572182 172.18.209.168:7001
slots:0-5460 (5461 slots) master
M: 28432a59f26a10f2c1eedad3f41c4ac47110d549 172.18.209.168:7002
slots:10923-16383 (5461 slots) master
S: 4806d7fb4c04880b3d7a6a20728088f243c52087 172.18.209.168:7003
replicates a59bef6cacd813b13742cdb22026bd167ef9aeaf
M: a59bef6cacd813b13742cdb22026bd167ef9aeaf 172.18.209.169:7004
slots:5461-10922 (5462 slots) master
S: f715ef8bcf25b1b7c0960c26b1e1b600c12ca09b 172.18.209.169:7005
replicates 3e00a8c896fd0957e7d423e5b350415ba0572182
S: dd39cd4b2b1ba8b34e0207023922f522ae72d2b6 172.18.209.169:7006
replicates 28432a59f26a10f2c1eedad3f41c4ac47110d549
Can I set the above configuration? (type 'yes' to accept):
>>> Nodes configuration updated
>>> Assign a different config epoch to each node
>>> Sending CLUSTER MEET messages to join the cluster
Waiting for the cluster to join...
>>> Performing Cluster Check (using node 172.18.209.168:7001)
M: 3e00a8c896fd0957e7d423e5b350415ba0572182 172.18.209.168:7001
   slots:0-5460 (5461 slots) master
   1 additional replica(s)
M: a59bef6cacd813b13742cdb22026bd167ef9aeaf 172.18.209.169:7004
   slots:5461-10922 (5462 slots) master
   1 additional replica(s)
S: 4806d7fb4c04880b3d7a6a20728088f243c52087 172.18.209.168:7003
   slots: (0 slots) slave
   replicates a59bef6cacd813b13742cdb22026bd167ef9aeaf
M: 28432a59f26a10f2c1eedad3f41c4ac47110d549 172.18.209.168:7002
   slots:10923-16383 (5461 slots) master
   1 additional replica(s)
S: dd39cd4b2b1ba8b34e0207023922f522ae72d2b6 172.18.209.169:7006
   slots: (0 slots) slave
   replicates 28432a59f26a10f2c1eedad3f41c4ac47110d549
S: f715ef8bcf25b1b7c0960c26b1e1b600c12ca09b 172.18.209.169:7005
   slots: (0 slots) slave
   replicates 3e00a8c896fd0957e7d423e5b350415ba0572182
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

这样就配置成功了。
可以使用命令验证:

#redis-cli -c -h 172.18.209.168 -p 7001
172.18.209.168:7001> set name "abswolf"
-> Redirected to slot [5798] located at 172.18.209.169:7004
OK
172.18.209.168:7001> get name
-> Redirected to slot [5798] located at 172.18.209.169:7004
"abswolf"
172.18.209.169:7004> 

ps:关于Redis集群的介绍来自Redis Cluster集群主从方案(附Jedis Cluster教程)

redis requires Ruby version >= 2.2.2

在做redis集群,安装redis-gem的时候出现该错误:

#gem install -l redis-4.0.0.gem
ERROR:  Error installing redis-4.0.0.gem:
redis requires Ruby version >= 2.2.2.

原来是因为CentOS7 yum库中ruby的版本支持到 2.0.0,可gem 安装redis需要最低是2.2.2。那么只能手动更新了。
解决步骤:

1、安装RVM

gpg2 --keyserver hkp://keys.gnupg.net --recv-keys D39DC0E3
curl -L get.rvm.io | bash -s stable
source /usr/local/rvm/scripts/rvm

2、安装Ruby新版本

rvm install 2.3.3

3、设置默认使用新版本

rvm use 2.3.3 --default

4、卸载旧版本

rvm remove 2.0.0

负载均衡使用nginx sticky实现session共享

nginx-sticky-module第三方模块主要用于基于cookie实现会话保持。

nginx sticky 模块工作流程图

下载nginx sticky

安装nginx+stiky

# wget http://nginx-sticky-module.googlecode.com/files/nginx-sticky-module-1.1.tar.gz
# tar -xzvf nginx-sticky-module-1.1.tar.gz
# wget http://nginx.org/download/nginx-1.8.1.tar.gz
# tar -xzvf nginx-1.8.1.tar.gz
# cd nginx-1.8.1
# ./configure --prefix=/usr/local/nginx --with-http_stub_status_module --with-http_ssl_module --with-http_realip_module --add-module=../nginx-sticky-module-1.1
# make
# make install

执行./configure的过程中可能会遇到以下错误:
./configure: error: the HTTP rewrite module requires the PCRE library.
You can either disable the module by using –without-http_rewrite_module
option, or install the PCRE library into the system, or build the PCRE library
statically from the source with nginx by using –with-pcre= option.

执行该命令解决:

yum -y install pcre-devel

./configure: error: SSL modules require the OpenSSL library.
You can either do not enable the modules, or install the OpenSSL library
into the system, or build the OpenSSL library statically from the source
with nginx by using –with-openssl= option.

执行该命令解决:

yum -y install openssl openssl-devel

在执行make的时候会报错:
../nginx-sticky-module-1.1/ngx_http_sticky_misc.c:281:2: error: passing argument 2 of ‘ngx_sock_ntop’ makes integer from pointer without a cast [-Werror]
digest->len = ngx_sock_ntop(in, digest->data, len, 1);

解决办法:

cd ../nginx-sticky-module-1.1
vim ngx_http_sticky_misc.c
将281行的digest->len = ngx_sock_ntop(in, digest->data, len, 1);改成
digest->len = ngx_sock_ntop(in, sizeof(struct sockaddr_in), digest->data, len, 1);

配置nginx sticky

upstream dispatch {
    sticky;
    server 192.168.100.100:8080;
    server 192.168.100.102:8080;
}
server {
        listen       80;
        server_name  abswolf.com;
        #charset koi8-r;
        #access_log  logs/host.access.log  main;
        location / {
                proxy_redirect off;
                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_pass http://dispatch;
        }
    }