springboot第64集:Netty的底层实现机制,熟练运用群集,一文让你走出微服务迷雾架构周刊...

46824d81ed64368feea520611b7e61ef.png

image.png
e33c04c516a0043765a0919a351b1c59.png
image.png
d56750cbc56744b349504b83ed6109f7.png
image.png
35c48a5cdc27a52f8a9edbf7cf635dae.png
image.png
9ad9dee92fe631be403bb0cac4ec48b0.png
image.png
54f89c720166048abce2754c891c3574.png
image.png
<select id="selectHistoryList" parameterType="com.webVueBlog.iot.domain.DeviceLog" resultMap="HistoryResult">
    select log_value,            -- 日志数值
           ts,                   -- 时间戳
           identity              -- 设备标识
    from ${database}.device_log
    <where>
        <if test="device.beginTime != null and device.beginTime != '' and device.endTime != null and device.endTime != ''">
            and ts between #{device.beginTime} and #{device.endTime}  -- 根据时间范围筛选
        </if>
        <if test="device.serialNumber != null and device.serialNumber !=''">
            and serial_number = #{device.serialNumber}                   -- 根据设备序列号筛选
        </if>
    </where>
    order by ts desc    -- 按时间戳倒序排序
</select>
<insert id="save" parameterType="com.webVueBlog.iot.domain.DeviceLog">
    INSERT INTO ${database}.device_${device.serialNumber} USING  device_log
    TAGS (#{device.serialNumber})
    VALUES (
        now(),                      -- 插入当前时间
        #{device.logValue},         -- 日志数值
        #{device.isMonitor},        -- 是否监控
        #{device.logType},          -- 日志类型
        #{device.identity},         -- 设备标识
        #{device.mode},             -- 设备模式
        #{device.remark}            -- 备注
    );
</insert>
domain是实体类,entity是数据传输对象,dto是数据传输对象
<mapper namespace="com.webVueBlog.system.mapper.SysUserMapper">

    <resultMap type="SysUser" id="SysUserResult">
        <id     property="userId"       column="user_id"      />
        <result property="deptId"       column="dept_id"      />
        <result property="userName"     column="user_name"    />
        <result property="nickName"     column="nick_name"    />
        <result property="email"        column="email"        />
        <result property="phonenumber"  column="phonenumber"  />
        <result property="sex"          column="sex"          />
        <result property="avatar"       column="avatar"       />
        <result property="password"     column="password"     />
        <result property="status"       column="status"       />
        <result property="delFlag"      column="del_flag"     />
        <result property="loginIp"      column="login_ip"     />
        <result property="loginDate"    column="login_date"   />
        <result property="createBy"     column="create_by"    />
        <result property="createTime"   column="create_time"  />
        <result property="updateBy"     column="update_by"    />
        <result property="updateTime"   column="update_time"  />
        <result property="remark"       column="remark"       />
        <association property="dept"    column="dept_id" javaType="SysDept" resultMap="deptResult" />
        <collection  property="roles"   javaType="java.util.List"           resultMap="RoleResult" />
    </resultMap>

    <resultMap id="deptResult" type="SysDept">
        <id     property="deptId"    column="dept_id"     />
        <result property="parentId"  column="parent_id"   />
        <result property="deptName"  column="dept_name"   />
        <result property="ancestors" column="ancestors"   />
        <result property="orderNum"  column="order_num"   />
        <result property="leader"    column="leader"      />
        <result property="status"    column="dept_status" />
    </resultMap>

    <resultMap id="RoleResult" type="SysRole">
        <id     property="roleId"       column="role_id"        />
        <result property="roleName"     column="role_name"      />
        <result property="roleKey"      column="role_key"       />
        <result property="roleSort"     column="role_sort"      />
        <result property="dataScope"     column="data_scope"    />
        <result property="status"       column="role_status"    />
    </resultMap>

   <sql id="selectUserVo">
        select u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.avatar, u.phonenumber, u.password, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark,
        d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.status as dept_status,
        r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status
        from sys_user u
          left join sys_dept d on u.dept_id = d.dept_id
          left join sys_user_role ur on u.user_id = ur.user_id
          left join sys_role r on r.role_id = ur.role_id
    </sql>

    <select id="selectUserList" parameterType="SysUser" resultMap="SysUserResult">
      select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name, d.leader from sys_user u
      left join sys_dept d on u.dept_id = d.dept_id
      where u.del_flag = '0'
      <if test="userId != null and userId != 0">
         AND u.user_id = #{userId}
      </if>
      <if test="userName != null and userName != ''">
         AND u.user_name like concat('%', #{userName}, '%')
      </if>
      <if test="status != null and status != ''">
         AND u.status = #{status}
      </if>
      <if test="phonenumber != null and phonenumber != ''">
         AND u.phonenumber like concat('%', #{phonenumber}, '%')
      </if>
      <if test="params.beginTime != null and params.beginTime != ''"><!-- 开始时间检索 -->
         AND date_format(u.create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
      </if>
      <if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
         AND date_format(u.create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
      </if>
      <if test="deptId != null and deptId != 0">
         AND (u.dept_id = #{deptId} OR u.dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE find_in_set(#{deptId}, ancestors) ))
      </if>
      <!-- 数据范围过滤 -->
      ${params.dataScope}
   </select>

   <select id="selectAllocatedList" parameterType="SysUser" resultMap="SysUserResult">
       select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.create_time
       from sys_user u
          left join sys_dept d on u.dept_id = d.dept_id
          left join sys_user_role ur on u.user_id = ur.user_id
          left join sys_role r on r.role_id = ur.role_id
       where u.del_flag = '0' and r.role_id = #{roleId}
       <if test="userName != null and userName != ''">
         AND u.user_name like concat('%', #{userName}, '%')
      </if>
      <if test="phonenumber != null and phonenumber != ''">
         AND u.phonenumber like concat('%', #{phonenumber}, '%')
      </if>
      <!-- 数据范围过滤 -->
      ${params.dataScope}
   </select>

   <select id="selectUnallocatedList" parameterType="SysUser" resultMap="SysUserResult">
       select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.create_time
       from sys_user u
          left join sys_dept d on u.dept_id = d.dept_id
          left join sys_user_role ur on u.user_id = ur.user_id
          left join sys_role r on r.role_id = ur.role_id
       where u.del_flag = '0' and (r.role_id != #{roleId} or r.role_id IS NULL)
       and u.user_id not in (select u.user_id from sys_user u inner join sys_user_role ur on u.user_id = ur.user_id and ur.role_id = #{roleId})
       <if test="userName != null and userName != ''">
         AND u.user_name like concat('%', #{userName}, '%')
      </if>
      <if test="phonenumber != null and phonenumber != ''">
         AND u.phonenumber like concat('%', #{phonenumber}, '%')
      </if>
      <!-- 数据范围过滤 -->
      ${params.dataScope}
   </select>

   <select id="selectUserByUserName" parameterType="String" resultMap="SysUserResult">
       <include refid="selectUserVo"/>
      where u.user_name = #{userName} and u.del_flag = '0'
   </select>

   <select id="selectUserById" parameterType="Long" resultMap="SysUserResult">
      <include refid="selectUserVo"/>
      where u.user_id = #{userId}
   </select>

   <select id="checkUserNameUnique" parameterType="String" resultMap="SysUserResult">
      select user_id, user_name from sys_user where user_name = #{userName} and del_flag = '0' limit 1
   </select>

   <select id="checkPhoneUnique" parameterType="String" resultMap="SysUserResult">
      select user_id, phonenumber from sys_user where phonenumber = #{phonenumber} and del_flag = '0' limit 1
   </select>

   <select id="checkEmailUnique" parameterType="String" resultMap="SysUserResult">
      select user_id, email from sys_user where email = #{email} and del_flag = '0' limit 1
   </select>

    <select id="selectUserByPhoneNumber" parameterType="String" resultMap="SysUserResult">
      <include refid="selectUserVo"/>
      where u.phonenumber = #{phoneNumber} and u.del_flag = '0'
   </select>

    <insert id="insertUser" parameterType="SysUser" useGeneratedKeys="true" keyProperty="userId">
      insert into sys_user(
         <if test="userId != null and userId != 0">user_id,</if>
         <if test="deptId != null and deptId != 0">dept_id,</if>
         <if test="userName != null and userName != ''">user_name,</if>
         <if test="nickName != null and nickName != ''">nick_name,</if>
         <if test="email != null and email != ''">email,</if>
         <if test="avatar != null and avatar != ''">avatar,</if>
         <if test="phonenumber != null and phonenumber != ''">phonenumber,</if>
         <if test="sex != null and sex != ''">sex,</if>
         <if test="password != null and password != ''">password,</if>
         <if test="status != null and status != ''">status,</if>
         <if test="createBy != null and createBy != ''">create_by,</if>
         <if test="remark != null and remark != ''">remark,</if>
         create_time
      )values(
         <if test="userId != null and userId != ''">#{userId},</if>
         <if test="deptId != null and deptId != ''">#{deptId},</if>
         <if test="userName != null and userName != ''">#{userName},</if>
         <if test="nickName != null and nickName != ''">#{nickName},</if>
         <if test="email != null and email != ''">#{email},</if>
         <if test="avatar != null and avatar != ''">#{avatar},</if>
         <if test="phonenumber != null and phonenumber != ''">#{phonenumber},</if>
         <if test="sex != null and sex != ''">#{sex},</if>
         <if test="password != null and password != ''">#{password},</if>
         <if test="status != null and status != ''">#{status},</if>
         <if test="createBy != null and createBy != ''">#{createBy},</if>
         <if test="remark != null and remark != ''">#{remark},</if>
         sysdate()
      )
   </insert>

   <update id="updateUser" parameterType="SysUser">
      update sys_user
      <set>
         <if test="deptId != null and deptId != 0">dept_id = #{deptId},</if>
         <if test="userName != null and userName != ''">user_name = #{userName},</if>
         <if test="nickName != null and nickName != ''">nick_name = #{nickName},</if>
         <if test="email != null ">email = #{email},</if>
         <if test="phonenumber != null ">phonenumber = #{phonenumber},</if>
         <if test="sex != null and sex != ''">sex = #{sex},</if>
         <if test="avatar != null and avatar != ''">avatar = #{avatar},</if>
         <if test="password != null and password != ''">password = #{password},</if>
         <if test="status != null and status != ''">status = #{status},</if>
         <if test="loginIp != null and loginIp != ''">login_ip = #{loginIp},</if>
         <if test="loginDate != null">login_date = #{loginDate},</if>
         <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
         <if test="remark != null">remark = #{remark},</if>
         update_time = sysdate()
      </set>
      where user_id = #{userId}
   </update>

   <update id="updateUserStatus" parameterType="SysUser">
      update sys_user set status = #{status} where user_id = #{userId}
   </update>

   <update id="updateUserAvatar" parameterType="SysUser">
      update sys_user set avatar = #{avatar} where user_name = #{userName}
   </update>

   <update id="resetUserPwd" parameterType="SysUser">
      update sys_user set password = #{password} where user_name = #{userName}
   </update>

   <delete id="deleteUserById" parameterType="Long">
      update sys_user set del_flag = '2' where user_id = #{userId}
   </delete>

   <delete id="deleteUserByIds" parameterType="Long">
      update sys_user set del_flag = '2' where user_id in
      <foreach collection="array" item="userId" open="(" separator="," close=")">
         #{userId}
        </foreach>
   </delete>

   <delete id="deleteBySysUserIdAndSourceClient">
      update iot_social_user
      set del_flag = 1,
      update_time = now()
      where sys_user_id = #{sysUserId}
      and source_client in
      <foreach item="sourceClient" collection="sourceClientList" open="(" separator="," close=")">
         #{sourceClient}
      </foreach>
   </delete>

   <delete id="deleteBySysUserIdsAndSourceClient">
      update iot_social_user
      set del_flag = 1,
      update_time = now()
      where sys_user_id in
      <foreach item="sysUserId" collection="sysUserIds" open="(" separator="," close=")">
         #{sysUserId}
      </foreach>
      and source_client in
      <foreach item="sourceClient" collection="sourceClientList" open="(" separator="," close=")">
         #{sourceClient}
      </foreach>
   </delete>

</mapper>
<mapper namespace="com.webVueBlog.system.mapper.SysUserPostMapper">

   <resultMap type="SysUserPost" id="SysUserPostResult">
      <result property="userId"     column="user_id"      />
      <result property="postId"     column="post_id"      />
   </resultMap>

   <delete id="deleteUserPostByUserId" parameterType="Long">
      delete from sys_user_post where user_id=#{userId}
   </delete>
   
   <select id="countUserPostById" resultType="Integer">
       select count(1) from sys_user_post where post_id=#{postId}  
   </select>
   
   <delete id="deleteUserPost" parameterType="Long">
      delete from sys_user_post where user_id in
      <foreach collection="array" item="userId" open="(" separator="," close=")">
         #{userId}
        </foreach> 
   </delete>
   
   <insert id="batchUserPost">
      insert into sys_user_post(user_id, post_id) values
      <foreach item="item" index="index" collection="list" separator=",">
         (#{item.userId},#{item.postId})
      </foreach>
   </insert>
   
</mapper>
<mapper namespace="com.webVueBlog.system.mapper.SysUserRoleMapper">

   <resultMap type="SysUserRole" id="SysUserRoleResult">
      <result property="userId"     column="user_id"      />
      <result property="roleId"     column="role_id"      />
   </resultMap>

   <delete id="deleteUserRoleByUserId" parameterType="Long">
      delete from sys_user_role where user_id=#{userId}
   </delete>
   
   <select id="countUserRoleByRoleId" resultType="Integer">
       select count(1) from sys_user_role where role_id=#{roleId}  
   </select>
   
   <delete id="deleteUserRole" parameterType="Long">
      delete from sys_user_role where user_id in
      <foreach collection="array" item="userId" open="(" separator="," close=")">
         #{userId}
        </foreach> 
   </delete>
   
   <insert id="batchUserRole">
      insert into sys_user_role(user_id, role_id) values
      <foreach item="item" index="index" collection="list" separator=",">
         (#{item.userId},#{item.roleId})
      </foreach>
   </insert>
   
   <delete id="deleteUserRoleInfo" parameterType="SysUserRole">
      delete from sys_user_role where user_id=#{userId} and role_id=#{roleId}
   </delete>
   
   <delete id="deleteUserRoleInfos">
       delete from sys_user_role where role_id=#{roleId} and user_id in
       <foreach collection="userIds" item="userId" open="(" separator="," close=")">
           #{userId}
            </foreach> 
   </delete>
</mapper>
modules-user-entity-User

@Data
@TableName("test_user")
public class TestUser implements Serializable {
 private static final long serialVersion = 11;
 @TableId(value="id",type=IdTYpe.ASSIGN_ID)
 private Long id;
}

mapper
public interface TestUserMapper extends BaseMapper<TestUser> {
}

mapper.xml
<?xml version="1.0" encoding="UTF-8">
<!DOCTYPE mapper PUBLIC "...?>
<mapper namespace = "org.spriing.modules.user.mapper.TestUserMapper">
</mapper>
新建Service文件,整合mybatis-plus

public interface TestUserService extends IService<TestUser> {}

@Service
@AllArgsConstructor
public class TestUserServiceImpl extends ServiceImpl<TestUserMapper, TestUser> implements TestUserService {}
新建Controller文件,接收前端发送的请求

controller

@RestController
@RequestMapping("user")
@AllArgsConstructor // 自动添加@Autowired注解
public class DemoController {
 private TestUserService test_user_service;
 @PostMapping("save")
 public R save(@RequestBody TestUser test_user) {
  boolean bool = user_service.save(test_user);
  return R.status(bool);
 }
}
5e3786e506896a6edfd97879f0b03678.png
image.png

Zuul网关性能调优:网关的两层超时调优

5f0cfcfcefc1b1e5196e1d874b187ab1.png
image.png
5060ddbb10874ac8f18c8b5b242c8b0d.png
image.png
fda9154eef27ac83151d61246bf21ae9.png
image.png
0ebe8f1efeca573e09216e6eb663a43c.png
image.png

当请求通过zuul网关路由到服务,并等待服务返回响应,这个过程中zuul也有超时控制。zuul的底层使用的是Hystrix+ribbon来实现请求路由。

a5ea67513594066172a31a89690f8b5c.png
image.png
7bd52640921e6f96d8c3c3dc346b68d6.png
image.png
84d687992f9e19d705e65bd7eb1a0abb.png
image.png
0c19a3e6b1f0fec419e6166671a52d7f.png
image.png

注解配置

column:需要过滤的数据库字段-type:数据权限过滤的类型-value:当数据权限类型为自定义的时候,配置的sql条件语句

// 所在机构可见
@DataAuth(type=DataScopeEnum.OWN_DEPT)
List<NoticeVO> selectNoticePage(IPage page,NoticeVO notice);
dd06a3ce4cde66944766134ffb6aa6e2.png
image.png
  • elastisearch 存储收集到的日志

  • kibana 可视化收集到的日志

  • logstash 汇总处理日志发送给elastisearch 存储

  • filebeat 读取容器或者应用日志文件处理发送给elastisearch或者logstash,也可用于汇总日志

  • fluentd 读取容器或者应用日志文件处理发送给elastisearch,也可用于汇总日志

  • fluent-bit 读取容器或者应用日志文件处理发送给elastisearch或者fluentd

k8s集群搭建

git clone https://github.com/qxl1231/2019-k8s-centos.git

cd 2019-k8s-centos

安装完master后,还要安装下dashboard

centos7 部署 k8s 集群

安装docker-ce

# 卸载原来的docker
sudo yum remove docker \
                  docker-client \
                  docker-client-latest \
                  docker-common \
                  docker-latest \
                  docker-latest-logrotate \
                  docker-logrotate \
                  docker-engine

# 安装依赖
sudo yum update -y && sudo yum install -y yum-utils \
  device-mapper-persistent-data \
  lvm2
  
# 添加官方yum库
sudo yum-config-manager \
    --add-repo \
    https://download.docker.com/linux/centos/docker-ce.repo
    
# 安装docker
sudo yum install docker-ce docker-ce-cli containerd.io

# 查看docker版本
docker --version

# 开机启动
systemctl enable --now docker

# 修改docker cgroup驱动:native.cgroupdriver=systemd
cat > /etc/docker/daemon.json <<EOF
{
  "exec-opts": ["native.cgroupdriver=systemd"],
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m"
  },
  "storage-driver": "overlay2",
  "storage-opts": [
    "overlay2.override_kernel_check=true"
  ]
}
EOF

systemctl restart docker  # 重启使配置生效

k8s-一键部署vue项目

  • 传统的前后端分离部署架构

b6a753b90c9ccef8d7f9bbecc6732595.png
  • 使用k8s后的前后端分离部署架构

ddb87e7534b6b03de8c862fbe0f00d0b.png

RDB优缺点:

  • 优点:使用单独子进程来进行持久化,主进程不会进行任何 IO 操作,保证了 Redis 的高性能;而且RDB文件存储的是压缩的二进制文件,适用于备份、全量复制,可用于灾难备份,同时RDB文件的加载速度远超于AOF文件。

Redis为了保证性能会将所有数据放在内存,那么机器突然断电或宕机需要重启,内存中的数据岂不是没有了?

Redis的确是将数据存储在内存的,但是也会有相关的持久化机制将内存持久化备份到磁盘,以便于重启时数据能够重新恢复到内存中,避免数据丢失的风险。而Redis持久化机制由三种,在4.X版本之前Redis只支持AOF以及RDB两种形式持久化,但是因为AOFRDB都存在各自的缺陷,所以在4.x版本之后Redis还提供一种新的持久化机制:混合型持久化(但是最终生成的文件还是.AOF)。

  • Redis默认采用定期+惰性删除策略。

使用 docker 搭建 clickhouse 集群

分别配置hostname为server01、server02、server03

所有服务器的/etc/hosts都加上

$ip1 server01
$ip2 server02
$ip3 server03

这里的、ip2、$ip3代表的是你三台服务器的ip

安装 docker

执行命令 yum list | grep docker

注意 docker 的版本

一致了之后执行yum install -y docker

安装 clickhouse-server 和 clickhouse-client

执行命令 yum list | grep clickhouse

yum pull docker.io/yandex/clickhouse-server;
yum pull docker.io/yandex/clickhouse-client;

安装 zookeeper 集群

启动clickhouse-server

创建对应本地路径

在三台服务器

创建配置存储目录:  mkdir /etc/clickhouse-server

创建数据存储目录:  mkdir /opt/clickhouse

docker命令启动一下

docker run -d --name clickhouse-server --ulimit nofile=262144:262144 --volume=/opt/clickhouse/:/var/lib/clickhouse yandex/clickhouse-server

启动完成了后,我们需要复制容器内的配置文件到本机目录下

docker cp clickhouse-server:/etc/clickhouse-server/ /etc/clickhouse-server/

Redis群集有三种模式:

  • 主从同步/复制

  • 哨兵模式

  • Cluster

通过持久化功能,redis保证了即使在服务器重启的情况下也不会丢失(或少量丢失)数据,因为持久化会把内存中的数据保存到硬盘上,重启会从硬盘上加载数据,但是由于数据是存储在一台服务器上的,如果这台服务器出现硬盘故障等问题,也会导致数据丢失。为了避免单点故障,通常的做法是将数据库复制多个副本以部署在不同的服务器上,这样即使有一台服务器出现故障,其他服务器依然可以继续提供服务,为此,redis提供了复制(replication)功能,可以实现当一台数据库中的数据更新后,自动将更新的数据同步到其他数据库上。 在复制的概念中,数据库分为两类,一类是主数据库(master),另一类是从数据(slave)。主数据可以进行读写操作,当写操做导致数据变化时自动把数据同步给从数据库,而从数据库一般是只读的,并接收主数据同步过来的数据。一个主数据库可以拥有多个从数据库,而一个从数据库只能拥有一个主数据库

主从复制流\程 redis-主
1、缓存写入操作的命令
2、主redis派生一个子进程,触发RDB持久化,生成RDB快照文件
在触发RDB持久化到完成的过程中,客户端在持续写入,这段数据是保存在内 存、缓存,这类的数据,靠AOF进行持久化
3、在ADB持久化完成,生成.rdb文件后,主会将.rdb文件和aof持久化的缓存 命令,全部交给redis-从服务
4、在持续的主从同步过程中,客户端会持续进行写入命令操作,命令操作也会 由主安按照一定的规则来同步给从服务器
redis-从
rdb文件和缓存的命令
基于以上部分进行加载以达到与master趋于一致的状态

主节点负责读写请求和集群信息的维护,从节点只进行主节点数据和状态信息的复制

2bd67684166ce76a8180231208646708.png
image.png
>>>>>>   master 节点:

vim /etc/ redis/ 6379. conf
70 bind 0.0.0.0  ##修改监听地址为0.0.0.0
137 daemonize yes  ##开启守护进程
172 logfile /var/log/redis_6379.log  ##指定日志文件目录
264 dir /var/lib/redis/6379  ##指定工作目录
700 appendonly yes   ##开启AOF持久化功能
/etc/init.d/redis_6379 restart  ##重启服务使配置生效
-------------------->Slave1/2节点<-----------------------------
vim /etc/redis/6379.conf
70 bind 0.0.0.0   ##修改监听地址为0.0.0.0
137 daemonize yes  ##开启守护进程
172 logfile/var/log/redis_6379.log
264 dir /var/lib/redis/6379  ##指定工作目录
288 replicaof 192.168.35.40 6379  ##添加一条指定要同步的Master节点IP和端口
700 appendonly yes  ##开启AOF持久化功能
/etc/init.d/redis_6379 restart ##重启服务使使配置生效
38d06a87da4ee19d8c711e63eed1ff04.png
image.png
redis-cli info replication
 # Replication
 role:master  ##角色是master
 connected_slaves:2  ##连接从服务器2个
 slave0:ip=192.168.35.10,port=6379,state=online,offset=238,lag=0 
 slave1:ip=192.168.35.20,port=6379,state=online,offset=238,lag=0 ##master启动时生成的40位16进制的随机字符串,用来标识master节点
 master_replid:772983217a6c859cf43f95ddcca57f78ab306c55 ##切换主从的时候master节点标识会有更改 
 master_replid2:0000000000000000000000000000000000000000 ##复制流中的一个偏移量,master处理完写入命令后,会把命令的字节长度做累加记录,统计在该字段。该字段也是实现部分复制的关键字段
 master_repl_offset:238 
------>无论主从,以下内容都表示自己上次主实例repid1和复制偏移量;用于兄弟实例或级联复制,主库故障切换<------------
 second_repl_offset:-1
 repl_backlog_active:1
 repl_backlog_size:1048576
 repl_backlog_first_byte_offset:1
 repl_backlog_histlen:238
[root@msater ~]# redis-cli  ##master登录创建kl键
 127.0.0.1:6379> keys *
 (empty list or set)
 127.0.0.1:6379> set kl 1
 OK
 127.0.0.1:6379> get kl
 "1"

哨兵的启动依赖于主从模式,所以须把主从模式安装好的情况下再去做哨兵模式,所以节点上都需要部署哨兵模式,哨兵模式会监控所有的Redis 工作节点是否正常

0b7be9b4d55f3d5b75ff696f059969f9.png三台服务器均需要更改

vim /opt/redis-5.0.7/sentinel.conf
17 protected-mode no  ##关闭保护模式
21 port 26379  ##Redis哨兵默认的监听端口
26 daemonize yes  ##开启守护进程
36 logfile "/var/log/sentinel.log"  ##指定日志存放路径
65 dir /var/lib/redis/6379  ##指定数据库存放路径
84 sentinel monitor mymaster 192.168.35.40 6379 2 ##指定哨兵节点;2:至少需要2个哨兵节点同意,才能判定主节点故障并进行故障转移
113 sentinel down-after-milliseconds mymaster 3000  ##判定服务器down掉的时间周期,默认30000毫秒 (30秒)
146 sentinel failover- timeout mymaster 180000  ##故障节点的最大超时时间为180000 (180秒)

启动哨兵模式

各服务器先启动主节点在启动从节点

cd /opt/redis-5.0.7/
redis-sentinel sentinel.conf &  ##使用redis-sentinel启动,再使用sentinel.conf,&:放在在后台启动
d76d339cd6d905e7575f59008d92d902.png
image.png
redis-cli -p 26379 info sentinel  ##查看哨兵信息;哨兵端口26379
 # Sentinel
 sentinel_masters:1
 sentinel_tilt:0
 sentinel_running_scripts:0
 sentinel_scripts_queue_length:0
 sentinel_simulate_failure_flags:0
 master0:name=mymaster,status=ok,address=192.168.35.40:6379,slaves=2,sentinels=3
[3]   完成                  redis-sentinel sentinel.conf
### 模拟故障

netstat -antp | grep redis  ##查看redis-server的进程号
kill -9 94948  ##杀死Master 节点_上的redis-server 的进程号
7474646c482729b2260ab44180270fdd.png
image.png

tail -f /var/log/sentinel.log

①:status=sdown ##s表示主观下线
②:status=odown ##o即objectively客观下线

redis的集群一般需要6个节点,3主3从。

以端口号进行区分: 3个主节点端口号: 6001/6002/6003, 对应的从节点端口号: 6004/ 6005/ 6006

ee1d4da198ffb3311939688a6a96a59c.png
image.png
cd /opt/redis-5.0.7/utils/
./install_server.sh ##回车,直到出现以下选项,手动修改为"/usr/local/redis/bin/redis-server"
Please select the redis executable path [ ] /usr/local/redis/bin/redis-server
ln -s /usr/local/redis/bin/* /usr/local/bin/
cd /etc/redis/
mkdir -p redis-cluster/redis600{1..6} ###创建redis 6个端口的工作目录


vim /opt/redis.sh
 #!/bin/bash
 for i in {1..6}
 do
 cp /opt/redis-5.0.7/redis.conf /etc/redis/redis-cluster/redis600$i
 cp /opt/redis-5.0.7/src/redis-cli /opt/redis-5.0.7/src/redis-server /etc/redis/redis- cluster/redis600$i
 done
sh -x /opt/redis.sh

修改6个redis的配置文件

cd /etc/redis/redis-cluster/redis6001
vim redis.conf
 69 bind 127.0.0.1  ##注释掉bind项或不修改,默认监听所有网卡
 88 protected -mode no  ##修改,关闭保护模式
 92 port 6001  ##修改,redis监听端口
 136 daemonize yes  ##开启守护进程,以独立进程启动
 832 cluster-enabled yes  ## 取消注释,开启群集功能
 840 cluster-config-file nodes-6001.conf  ##取消注释,群集名称文件设置
 846 cluster-node-timeout 15000  ##取消注释群集超时时间设置
其他五个配置文件除端口号和文件名称外其余改动相同,复制redis6001至redis6002-6006
13e49a25ef4c08f9e0ce5f91a96634a8.png
image.png
922611bcb88d3ccfeea29593983319ce.png
image.png
-------------->手动启动六次<------------------
cd /etc/redis/redis-cluster/redis6001
redis-server redis.conf  ###启动服务
-------------->写入脚本执行脚本<------------------
vim /opt/redis_start.sh ##根据对应配置文件启动redis
 #!/bin/bash
 for d in {1..6}
 do
 cd /etc/redis/redis-cluster/redis600$d
 redis-server redis.conf
 done
sh -x /opt/redis_start.sh
ps -ef | grep redis
cde82bad1e7783d1387cb486b371a0b7.png
image.png

六个实例分为三组,每组一主一从,前面的做主节点,后面的做从节点;下面交互的时候需要输入yes才可以创建;-replicas 1表示每个主节点有一个从节点\

redis-cli --cluster create 127.0.0.1:6001 127.0.0.1:6002 127.0.0.1:6003 127.0.0.1:6004 127.0.0.1:6005 127.0.0.1:6006 --cluster-replicas 1

fd2259a0e36d7379568d9c47dc1bfa4f.png
image.png

搭建 MySQL 主从复制

setenforce 0 是一个 Linux 命令,用于临时将 SELinux(Security-Enhanced Linux)设置为 Permissive 模式,即不执行强制访问控制,只进行记录,并且不阻止任何操作。 在 Permissive 模式下,SELinux 仍然会生成警告和日志,但不会阻止对系统资源的访问。这对于调试和排除与 SELinux 相关的问题非常有用,因为您可以查看访问请求是否会被 SELinux 拒绝,而无需禁用 SELinux。 请注意,setenforce 0 命令是临时性的,重启系统后会恢复为 SELinux 的默认模式。如果您需要永久关闭 SELinux,可以通过修改配置文件 /etc/selinux/config 来实现。

环境搭建:
Master 服务器:192.168.80.10  mysql5.7
Slave1 服务器:192.168.80.11  mysql5.7
Slave2 服务器:192.168.80.12  mysql5.7
Amoeba 服务器:192.168.80.20  jdk1.6、Amoeba
客户端 服务器:192.168.80.30         mysql

systemctl stop firewalld
systemctl disable firewalld
setenforce 0

## 主服务器设置 ##
yum install -y ntp
vim /etc/ntp.conf
  ## 在末尾添加下面两行 ##
  server 127.127.80.0           ##设置本地时钟源;127.127是固定格式,后面80是虚拟机网段,注意修改!
  fudge 127.127.80.0 stratum 8  ##设置时间层级为 8 (限制范围在15以内)

systemctl start ntpd    ##启动服务


## 从服务器设置 (两个从服务器执行相同操作)##
yum install -y ntp ntpdate

systemctl start ntpd
ntpdate 192.168.80.10   ##进行时间同步,ip是主服务器地址

crontab -e
 */30 * * * * /usr/sbin/ntpdate 192.168.80.10
 
主服务器的MySQL配置


vim /etc/my.cnf
 server-id = 1                ## 相当于集群id,此id唯一,不能跟其他MySQL服务器id冲突
 log-bin = mysql-bin          ## 主服务器开启二进制日志
 binlog_format = MIXED        ## 二进制日志保存格式:混合
 log-slave-updates = true     ## 允许slave从master复制数据时可以写入自己的二进制日志
 expire_logs_days = 7         ## 设置二进制日志文件过期时间,默认值为0,表示logs不过期
 max_binlog_size = 500M       ## 设置二进制日志限制大小,如果超出给定值,日志就会发生滚动,默认为1GB
 
systemctl restart mysqld

## 如果是yum安装的mysql,登录MySQL前,需要如下操作流程:
## grep password /var/log/mysqld.log    #查看默认密码
## mysql -u root -p'34/Jeoiq0fZb'       #登录MySQL,默认密码需使用单引号括起来
## set global validate_password_policy=low;  ## 降低密码等级
## set global validate_password_length=6;    ## 更改密码长度
## alter user  'root'@'localhost' identified by 'abc123';  ## 修改自己想要的root密码
## 然后重新登录,就可以正常授权了!
mysql -uroot -pabc123         ## 进入数据库
grant replication slave on *.* to 'myslave'@'192.168.80.%' identified by '123456';  ## 给从服务器授权

## replication slave:主从同步的权限
## *.* :所有库的所有表
## 'myslave'@'192.168.80.%':可以从"192.168.80.%" 这些主机登录的一个用户,名叫:myslave
## '123456':myslave用户的密码,从服务器可以使用myslave用户验证,并且只能从192.168.80网段上登录的才行

flush privileges;             ## 刷新权限

show master status;           ## 查看主服务器状态
## Position :偏移量,主从复制的依据
+------------------+----------+--------------+------------------+-------------------+
| File             | Position | Binlog_Do_DB | Binlog_Ignore_DB | Executed_Gtid_Set |
+------------------+----------+--------------+------------------+-------------------+
| mysql-bin.000001 |      847 |              |                  |                   |
+------------------+----------+--------------+------------------+-------------------+


从服务器的MySQL配置(两个从服务器都需要配置,server-id 不能一样!)

vim /etc/my.cnf
 server-id = 2                ## 用于区分主从复制集群中的每个服务器,不同服务器id不能相同
 relay-log=relay-log-bin      ## 开启中继日志,从主服务器上同步日志文件到本地
 relay-log-index=slave-relay-bin.index  ## 定义中继日志文件的位置和名称,一般和relay-log在同一目录
 relay_log_recovery = 1       ## 当从库宕机后,假如relay-log损坏,则自动放弃所有未执行的relay-log,
                              ## 并重新从master上获取日志,保证relay-log的完整性,值=1,表示开启。
systemctl restart mysqld

## 如果是yum安装的mysql,登录MySQL前,需要如下操作流程:
## grep password /var/log/mysqld.log    #查看默认密码
## mysql -u root -p'34/Jeoiq0fZb'       #登录MySQL,默认密码需使用单引号括起来
## set global validate_password_policy=low;  ## 降低密码等级
## set global validate_password_length=6;    ## 更改密码长度
## alter user  'root'@'localhost' identified by 'abc123';  ## 修改自己想要的root密码
## 退出,重新登录

mysql -uroot -pabc123

change master to              ## 换行编写的话,to后面需要有空格
master_host='192.168.80.10',master_user='myslave',master_password='123456',master_log_file='mysql-bin.000001',
master_log_pos=847;              
                              ## 配置同步,注意 'master_log_file'、'master_log_pos'的值是自己
                              ## master 主服务器上查询的结果; master_user是主服务器授权时的用户名

start slave;                  ## 启动同步,如有报错执行 reset slave;
show slave status\G           ## 查看 slave 状态
## Slave_IO_Running:yes      ## 负责与主机的io通信
## Slave_SQL_Running:yes     ## 负责自己的slave mysql进程

Amoeba服务器配置

Modbus 协议是一种通信协议,允许设备通过各种类型的介质进行通信,如串行线和以太网。 它是由生产可编程逻辑控制器(PLC)的Modicon 公司于1979 年开发的。 该协议的初衷是为了与其所生产的可编程逻辑控制器配套使用,而可编程逻辑控制器在制造业中广泛应用于工业机电过程的自动化。

加群联系作者vx:xiaoda0423

仓库地址:https://github.com/webVueBlog/JavaGuideInterview

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值