ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

spring cloud多模块项目框架搭建-Redis-Cluster集群搭建及系统集成

2020-12-19 11:01:50  阅读:209  来源: 互联网

标签:15 centos spring redis VM cluster Redis root 搭建


第九章 Redis-Cluster集群搭建及系统集成

本系列博客旨在搭建一套能用于实际开发使用的spring cloud多模块微服务项目框架,并不是一个spring cloud的demo而已,提供系统的开发规范限制,微服务注册中心,配置中心,负载均衡,熔断,redis缓存,分布式事务,kafka服务消息通信,系统安全(sql注入攻击,xxs攻击等等),多数据源切换,全局异常处理等等。

 目录顺风车:

spring cloud多模块项目框架搭建 :https://blog.csdn.net/lingyancangqiong/article/details/109841353

本章接着上章《spring cloud多模块项目框架搭建-集成Redis连接客户端及连接池Lettuce》来说,搭建Redis-Cluster模式高可用集群示例,并在本系统中用Lettuce连接池连接。

一.Redis主从模式,哨兵模式,Redis-Cluster模式三种Redis集群模式的区别?

1.什么是redis主从模式?

 redis主从集群分为一主一从,一主多从,级联三种模式,级联就是一主(master)多从(slave),从节点再有多个从节点,主节点可以有多个从节点,但从节点只能有一个主节点。主要实现读写分离,容灾恢复。一台服务器通过执行slaveof命令或设置slaveof选项,复制同步到另一个服务器,就形成了主从集群,被复制的叫做master主节点,复制的成为slave从节点。问题是当master节点挂了,整个集群就无法写入了,但还是能slave节点读取,这时需要手动将一台slave节点使用slaveof no one提升为master。

        

实现原理步骤:

  1. 从服务器向主服务器发送SYNC命令
  2. 主服务器收到SYNC命令后,执行BGSAVE命令,在后台生成RDB文件,使用缓冲区记录从现在开始执行的所有的写命令。
  3. 当主服务器的BGSAVE命令执行完毕后,主服务器后将BGSAVE命令生成的RDB文件发送给从服务器,从服务器接收并载入这个RDB文件,将自己的数据库状态更新至主服务器执行BGSAVE命令时的数据库状态。
  4. 主服务器将记录在缓冲区里面的所有写命令发送给从服务器,从服务器执行这些写命令,将自己的数据库状态更新至主服务器数据库当前所处的状态。

2.  什么是哨兵模式(Sentinel)?

上面说到主从模式当主节点挂了之后,需要人为的切换,这就无法达到高可用;于是哨兵模式(Sentinel)应运而生,可以抠字眼,当主节点挂了,由Sentinel像个哨兵一样自动的发现并根据配置规则提升一个slave节点为新的master节点,是redis主从的模式的高可用解决方案,一般的中小型系统中对内存存储数量不多的情况下使用较多,但是Sentinel本身也可能挂掉,实际使用中Sentinel也会集群。

实现原理步骤:

  1. 每个Sentinel(哨兵)进程以每秒钟一次的频率向整个集群中的Master主服务器,Slave从服务器以及其他Sentinel(哨兵)进程发送一个 PING 命令。
  2. 如果一个实例(instance)距离最后一次有效回复 PING 命令的时间超过 down-after-milliseconds 选项所指定的值,则这个实例会被 Sentinel(哨兵)进程标记为主观下线SDOWN)。
  3. 如果一个Master主服务器被标记为主观下线(SDOWN),则正在监视这个Master主服务器的所有
    Sentinel(哨兵)
    进程要以每秒一次的频率确认Master主服务器的确进入了主观下线状态
  4. 有足够数量的 Sentinel(哨兵)进程(大于等于配置文件指定的值)在指定的时间范围内确认Master主服务器进入了主观下线状态(SDOWN), 则Master主服务器会被标记为客观下线(ODOWN)
  5. 在一般情况下, 每个Sentinel(哨兵)进程会以每 10 秒一次的频率向集群中的所有Master主服务器、Slave从服务器发送 INFO 命令。
  6. 当Master主服务器被 Sentinel(哨兵)进程标记为客观下线(ODOWN)时,Sentinel(哨兵)进程向下线的 Master主服务器的所有 Slave从服务器发送 INFO 命令的频率会从 10 秒一次改为每秒一次。
  7. 若没有足够数量的 Sentinel(哨兵)进程同意 Master主服务器下线, Master主服务器的客观下线状态就会被移除。若 Master主服务器重新向 Sentinel(哨兵)进程发送 PING 命令返回有效回复,Master主服务器的主观下线状态就会被移除。
  8. 当master节点被下线以后,再次上线,将不再是master节点,变成slave节点中的一员。

3.什么是Redis-Cluster模式?

高可用Redis(十二):Redis Cluster,什么是Redis-Cluster模式及实现原理?可以看看这位大神的这篇讲解,讲的非常到位。总结来讲,Redis-Cluster翻译就是redis集群嘛,实现了去中心化,不在依赖于主节点,而是将存储的key通过hash值运算平均分配已知的节点上,每个节点的权重是一样的,同时每个节点都至少有一个备用节点(主节点、备份节点由redis-cluster集群确定),当主节点挂了,备份节点之一自动补上,你在使用时也无需去寻找你的key存在哪个节点上,你只要查询集群其中一个节点,Redis-Cluster会自动去寻找在哪个节点并返回数据。Redis-Cluster模式主要用于分布式和对内存容量有要求的大型系统中,在我看来他还是主从,只是拆成了多个组,高可用实现的优雅了许多,可以理解为主从是普通版,哨兵为plus版,Cluster模式为pro版。

二.  搭建Redis-Cluster集群

 集群中至少应该有2n+1(n不为0)奇数个节点,所以至少有三个节点,每个节点至少有一个备份节点,所以下面使用6节点(主节点、备份节点由redis-cluster集群确定),由于没有6台服务器,我们示例就在一台服务器上开6个端口,作为集群的6个节点。为了方便日常开发,文末也提供了windows版本的集群下载。


  1. 下载redis,并上传到服务器,编译安装,我下载的是最新的redis

[root@VM-0-15-centos redis-3.2.0]# tar xzf redis-6.0.9.tar.gz
[root@VM-0-15-centos redis-3.2.0]# cd redis-6.0.9
[root@VM-0-15-centos redis-3.2.0]# make
[root@VM-0-15-centos redis01]# make install PREFIX=/usr/andy/redis-cluster

make 这里可能报错:erver.c:4511:19: error: ‘struct redisServer’ has no member named ‘stat_total_writes_processed’,参考这位老兄的博客解决:https://blog.csdn.net/qq_45069833/article/details/108762535

2. 在/usr/andy/redis-cluster下 ,创建目录7000 7001 7002 7003 7004 7005共6个目录,复制解压目录下的redis.conf配置文件到/usr/andy/redis-cluster下,再复制到刚才创建的这六个文件下,并在最后追加如下内容,把原内容的protected-mode yes改为protected-mode no(在没有密码的情况下,关闭保护模式),把daemonize no改为daemonize yes   (是否为进程守护,关闭ssh窗口后即是否在后台继续运行),注释掉bind 127.0.0.1 (取消绑定本地地址)或者改成bind 0.0.0.0:

        daemonize yes #后台启动
        port 7000 #修改端口号,从7000到7005
        cluster-enabled yes #开启cluster,去掉注释
        cluster-config-file nodes.conf #自动生成
        cluster-node-timeout 15000 #节点通信时间
        appendonly yes #持久化方式

这里中文注释可能报错,去掉即可,这里命令就是基本的vi,就不写了,不会的同学自行问度娘。

3.复制redis解压文件src下的redis-trib.rb文件到/usr/andy/redis-cluster目录并安装gem

[root@VM-0-15-centos redis-cluster]# gem install redis

这里可能报这两个错:1. bash: gem: command not found    和  2. ERROR: Could not find a valid gem 'redis' (>= 0) in any repository ,这是因为ruby 版本太低,遇到错,就要勇于解决,不要害怕,恐惧报错,这也是我近两年才学会,以前一报错就是求爹爹告奶奶,或者逃避去选择其他的实现方法,现在养成解决bug的习惯后,除了一些问题很耗时间外,其他一般的问题好好思考,勇于解决还是不难的。

解决办法:

[root@VM-0-15-centos redis-cluster]# yum install -y ruby 
[root@VM-0-15-centos redis-cluster]# yum install -y rubygems
[root@VM-0-15-centos redis-cluster]# echo "source $HOME/.rvm/scripts/rvm" >> ~/.bash_profile
[root@VM-0-15-centos redis-cluster]#
[root@VM-0-15-centos redis-cluster]#

再次执行gem又报错:Error installing redis: redis requires Ruby version >= 2.3.0 ,解决方案:先安装rvm,再把ruby版本提升至2.6.5

[root@VM-0-15-centos redis-cluster]# yum install curl
[root@VM-0-15-centos redis-cluster]# curl -L get.rvm.io | bash -s stable
[root@VM-0-15-centos redis-cluster]# 
[root@VM-0-15-centos redis-cluster]# 

到这步有可能报错,第一次在腾讯云安然无事,这是我第二次在阿里云搭的时候报的:curl: (7) Failed connect to raw.githubusercontent.com:443; Connection refused ,原因是被墙了,解决如下:

 修改hosts

[root@VM-0-15-centos redis-cluster]# vi /etc/hosts

末尾添加如下内容:

199.232.28.133 raw.githubusercontent.com

然后接着上面来再次执行

[root@VM-0-15-centos redis-cluster]# curl -L get.rvm.io | bash -s stable

这里注意看提示,它有可能像下面这样提示你用密钥下载

这里先执行下它提示的这个密钥命令,再把上面的curl命令执行下,就会发现执行成功了。

[root@VM-0-15-centos redis-cluster]# curl -L get.rvm.io | bash -s stable
[root@VM-0-15-centos redis-cluster]# source /usr/local/rvm/scripts/rvm

 查看ruby版本,有很多版本

[root@VM-0-15-centos redis-cluster]# rvm list known

安装一个ruby版本,我安装的2.6.5,这里安装要很久,慢慢等着吧

[root@VM-0-15-centos redis-cluster]# rvm install 2.6.5

使用一个ruby版本

[root@VM-0-15-centos redis-cluster]# rvm use 2.6.5

设置默认版本

[root@VM-0-15-centos redis-cluster]# ruby --version

卸载一个已知版本

[root@VM-0-15-centos redis-cluster]# rvm remove 2.0.0

 再次gem安装,ok了

[root@VM-0-15-centos redis-cluster]# gem install redis
Successfully installed redis-4.2.5
Parsing documentation for redis-4.2.5
Done installing documentation for redis after 0 seconds
1 gem installed
[root@VM-0-15-centos redis-cluster]#

4. 在/usr/andy/redis-cluster下创建并编写启动文件start.sh,内容如下:

cd 7000
redis-server redis.conf
cd ..
cd 7001
redis-server redis.conf
cd ..
cd 7002
redis-server redis.conf
cd ..
cd 7003
redis-server redis.conf
cd ..
cd 7004
redis-server redis.conf
cd ..
cd 7005
redis-server redis.conf
cd ..

5.  设置权限,并启动:chmod 777是设置所有人可以读 + 写 + 执行。

[root@VM-0-15-centos redis-cluster]# chmod 777 start.sh 
[root@VM-0-15-centos redis-cluster]# sh start-all.sh 

这里可能会报错,原因:这是因为在系统的/usr/bin目录下没有命令文件

解决办法:将redis-cluster/bin目录下的redis-server、redis-cli、redis-benchmark、redis-check-aof、redis-check-rdb、redis-sentinel这些可执行文件复制到/usr/bin下

[root@VM-0-15-centos redis-cluster]#  ls
7000  7001  7002  7003  7004  7005  bin  redis.conf  redis-trib.rb  start.sh
[root@VM-0-15-centos redis-cluster]#  cd bin
[root@VM-0-15-centos bin]#  ls
redis-benchmark  redis-check-aof  redis-check-rdb  redis-cli  redis-sentinel  redis-server
[root@VM-0-15-centos bin]#  cp redis-benchmark /usr/bin
[root@VM-0-15-centos bin]#  cp redis-check-aof /usr/bin/
[root@VM-0-15-centos bin]#  cp redis-check-rdb /usr/bin/
[root@VM-0-15-centos bin]#  cp redis-cli /usr/bin/
[root@VM-0-15-centos bin]#  cp redis-sentinel /usr/bin/
[root@VM-0-15-centos bin]#  cp redis-server /usr/bin/
[root@VM-0-15-centos bin]#  

6. 再次执行sh脚本

[root@VM-0-15-centos bin]# cd ..
[root@VM-0-15-centos redis-cluster]# ls
7000  7001  7002  7003  7004  7005  bin  redis.conf  redis-trib.rb  start.sh
[root@VM-0-15-centos redis-cluster]# sh start.sh 

7.  查看redis启动的情况,可以看到redis的6个节点已经启动成功

[root@VM-0-15-centos redis-cluster]# ps -ef|grep cluster
root      54956      1  0 19:17 ?        00:00:00 redis-server *:7000 [cluster]
root      54961      1  0 19:17 ?        00:00:00 redis-server *:7001 [cluster]
root      54966      1  0 19:17 ?        00:00:00 redis-server *:7002 [cluster]
root      54971      1  0 19:17 ?        00:00:00 redis-server *:7003 [cluster]
root      54976      1  0 19:17 ?        00:00:00 redis-server *:7004 [cluster]
root      54981      1  0 19:17 ?        00:00:00 redis-server *:7005 [cluster]
root      55071  24089  0 19:24 pts/0    00:00:00 grep --color=auto cluster

8.  使用redis-cli命令创建集群,以前使用的./redis-trib.rb create已经废弃了,这里ip 127.0.0.1最好是改成你的服务器ip

[root@VM-0-15-centos redis-cluster]# redis-cli --cluster create 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7000
>>> Performing hash slots allocation on 6 nodes...
Master[0] -> Slots 0 - 2730
Master[1] -> Slots 2731 - 5460
Master[2] -> Slots 5461 - 8191
Master[3] -> Slots 8192 - 10922
Master[4] -> Slots 10923 - 13652
Master[5] -> Slots 13653 - 16383
M: ff5bae64ce3aa0ee89f3d8813b155b45ff97788a 127.0.0.1:7001
   slots:[0-2730] (2731 slots) master
M: 634c92d72d4a657102583f6ff81e46e9aaf8bc6f 127.0.0.1:7002
   slots:[2731-5460] (2730 slots) master
M: 691743965bd6a300ffe84740077797cefc403f67 127.0.0.1:7003
   slots:[5461-8191] (2731 slots) master
M: 0a099c363e9e9cadb83f1215658ee01b2645c7dc 127.0.0.1:7004
   slots:[8192-10922] (2731 slots) master
M: ea521ddcdef20d0fc924d4e862035a7232456c75 127.0.0.1:7000
   slots:[10923-13652] (2730 slots) master
M: 8386f6314894649b15463c72d44f2b05d752f798 127.0.0.1:7005
   slots:[13653-16383] (2731 slots) master
Can I set the above configuration? (type 'yes' to accept): yes
>>> 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 127.0.0.1:7001)
M: ff5bae64ce3aa0ee89f3d8813b155b45ff97788a 127.0.0.1:7001
   slots:[0-2730] (2731 slots) master
M: 0a099c363e9e9cadb83f1215658ee01b2645c7dc 127.0.0.1:7004
   slots:[8192-10922] (2731 slots) master
M: 8386f6314894649b15463c72d44f2b05d752f798 127.0.0.1:7000
   slots:[13653-16383] (2731 slots) master
M: 634c92d72d4a657102583f6ff81e46e9aaf8bc6f 127.0.0.1:7002
   slots:[2731-5460] (2730 slots) master
M: 691743965bd6a300ffe84740077797cefc403f67 127.0.0.1:7003
   slots:[5461-8191] (2731 slots) master
M: ea521ddcdef20d0fc924d4e862035a7232456c75 127.0.0.1:7005
   slots:[10923-13652] (2730 slots) master
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

至此集群就搭建好了,测试下

[root@VM-0-15-centos redis-cluster]# redis-cli -c -p 7001
127.0.0.1:7001> set name 11
-> Redirected to slot [5798] located at 127.0.0.1:7003
OK
127.0.0.1:7003> get name
"11"
127.0.0.1:7003> 

二,系统集成连接

1. 我们还是在第八章《spring cloud多模块项目框架搭建-集成Redis连接客户端及连接池Lettuce》的代码基础上进行集成,将dream.order.web和dream.activity.web下的application.yml里的redis的配置改成如下即可.

redis:
    database: 2
    cluster:
      nodes:
        - 192.168.10.185:7001
        - 192.168.10.185:7002
        - 192.168.10.185:7003
        - 192.168.10.185:7004
        - 192.168.10.185:7005
        - 192.168.10.185:7000
      max-redirects: 3 # 获取失败 最大重定向次数
    timeout: 6000ms  # 连接超时时长(毫秒)
    lettuce:
      pool:
        max-active: 100  # 连接池最大连接数(使用负值表示没有限制)
        max-wait: -1ms      # 连接池最大阻塞等待时间(使用负值表示没有限制)
        max-idle: 10      # 连接池中的最大空闲连接
        min-idle: 1       # 连接池中的最小空闲连接
        timeout: 6000

2.  将dream父模块的jar 包版本升级为如下,之前的低版本使用的Lettuce会出现连接池拓扑图不自动刷新,连接超时问题。

   <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
<properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <spring-boot-starter.version>2.3.7.RELEASE</spring-boot-starter.version>
        <spring-boot-starter-test.version>2.3.7.RELEASE</spring-boot-starter-test.version>
        <spring-boot-starter-web.version>2.3.7.RELEASE</spring-boot-starter-web.version>
        <spring-cloud-starter.version>2.2.5.RELEASE</spring-cloud-starter.version>
        <mysql-connector-java.version>8.0.19</mysql-connector-java.version>
        <mybatis-plus-boot-starter.version>3.4.0</mybatis-plus-boot-starter.version>
        <lombok.version>1.18.16</lombok.version>
        <druid.version>1.2.3</druid.version>
        <spring-boot-starter-log4j2.version>2.3.5.RELEASE</spring-boot-starter-log4j2.version>
        <slf4j-log4j12.version>2.0.0-alpha1</slf4j-log4j12.version>
        <spring-boot-starter-data-redis.version>2.4.0</spring-boot-starter-data-redis.version>
        <commons-pool2.version>2.8.1</commons-pool2.version>
    </properties>

3. 将dream.order.common和dream.activity.common下的RedisConfig分别改成如下:

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.HashSet;
import java.util.Set;


/**
 * redis配置
 *
 * @AutoConfigureAfter(RedisAutoConfiguration.class) 是让我们这个配置类在内置的配置类之后在配置,
 * <p>
 * 这样就保证我们的配置类生效,并且不会被覆盖配置  选择性配置
 * @Author: renkj
 * @Version 1.0.0
 */

@Configuration
@EnableCaching
//@AutoConfigureAfter(RedisAutoConfiguration.class)
public class RedisConfig extends CachingConfigurerSupport {

    @Resource
    private LettuceConnectionFactory lettuceConnectionFactory;


    @Bean
    public KeyGenerator keyGenerator() {
        return new KeyGenerator() {
            @Override
            public Object generate(Object target, Method method, Object... params) {
                StringBuffer sb = new StringBuffer();
                sb.append(target.getClass().getName());
                sb.append(method.getName());
                for (Object obj : params) {
                    sb.append(obj.toString());
                }
                return sb.toString();
            }
        };
    }


    // 缓存管理器
    @Bean
    public CacheManager cacheManager() {
        RedisCacheManager.RedisCacheManagerBuilder builder = RedisCacheManager.RedisCacheManagerBuilder
                .fromConnectionFactory(lettuceConnectionFactory);
        @SuppressWarnings("serial")
        Set<String> cacheNames = new HashSet<String>() {
            {
                add("codeNameCache");
            }
        };
        builder.initialCacheNames(cacheNames);
        return builder.build();
    }


    /**
     * 配置自定义redisTemplate
     *
     * @return
     */

    @Bean
    RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {


        RedisTemplate<String, Object> template = new RedisTemplate<>();

        template.setConnectionFactory(redisConnectionFactory);


        //使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值

        Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);


        ObjectMapper mapper = new ObjectMapper();

        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);

        mapper.activateDefaultTyping(

                LaissezFaireSubTypeValidator.instance,
                ObjectMapper.DefaultTyping.NON_FINAL,

                JsonTypeInfo.As.WRAPPER_ARRAY);

        serializer.setObjectMapper(mapper);


        template.setValueSerializer(serializer);

        //使用StringRedisSerializer来序列化和反序列化redis的key值

        template.setKeySerializer(new StringRedisSerializer());

        template.setHashKeySerializer(new StringRedisSerializer());

        template.setHashValueSerializer(serializer);

        template.afterPropertiesSet();

        return template;

    }


}

4. 用第八章redis的测试代码测试下,完美的取到了值,第一次请求会有点慢,应该是进行初始化,第二次之后就很快了。

 

到此Redis-Cluster集群搭建及系统集成就完成了,为了方便在本地开发使用,我也搭建了一套windows版的Redis-Cluster集群,包括启动脚本都放在csdn资源https://download.csdn.net/download/lingyancangqiong/13701164)了,下载下来按使用说明修改下启动脚本盘符路径,双击启动脚本就能使用了。本章更新的有些久了,原因是两周前我的电脑硬盘坏了,在jd买的才用了五个月,这两周一直在扯皮和维权,后面实在等不了,自己买了个固态换上。坏掉的固态客服连型号都不知道,拆下一看生产厂家,批次,日期,型号啥也没有,京东处理的也比较消极,到今日也没个初步处理结果,每次都是升级专员处理,京东再也不是当年那个绝无假货的京东了。

 

本章代码我放在了蓝奏云,可以下载下来对照对照:  (https://wws.lanzous.com/b01hweach 密码:2vx3 )

 

上面所写内容如有不足和纰漏,欢迎留言或私聊指正批评。如果需要转载,也是欢迎,不甚荣幸,但请把《spring cloud多模块项目框架搭建》这一系列博客全部一起转载,这一系列博客毕竟是个整体教程,如果别人只看到一部分,那就是个残次品,谢谢,鞠躬。

标签:15,centos,spring,redis,VM,cluster,Redis,root,搭建
来源: https://blog.csdn.net/lingyancangqiong/article/details/110530657

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有