eYoung的博客


  • Home

  • About

  • Archives

  • Commonweal 404

  • Tags

  • Categories

  • spring

  • redis

curl命令查看请求响应时间、返回状态码

Posted on 2021-03-02 | In Linux

shell curl 取得HTTP返回的状态码

1
curl -I -m 10 -o /dev/null -s -w %{http_code} www.baidu.com

-I 仅测试HTTP头
-m 10 最多查询10s
-o /dev/null 屏蔽原有输出信息,把curl 返回的html、js 写到垃圾回收站[/dev/null]
-s silent 模式,去掉所有状态,不输出任何东西
-w %{http_code} 控制额外输出

1
curl -w "%{time_namelookup}::%{time_connect}::%{time_starttransfer}::%{time_total}::%{speed_download}" "\n"

time_namelookup DNS解析域名时间
time_connect TCP连接的时间,三次握手的时间
time_starttransfer 从请求开始到第一个字节将要传输的时间
time_total 总时间
speed_download 下载速度,单位-字节每秒
time_appconnect SSL|SSH等上层连接建立的时间
time_pretransfer 从请求开始到响应开始传输的时间
time_redirect 从开始到最后一个请求事务的时间

理解OAuth 2.0

Posted on 2020-09-14 | In 开发者手册

  OAuth是一个关于授权(authorization)的开放网络标准,在全世界得到广泛应用,目前的版本是2.0版。
  本文对OAuth 2.0的设计思路和运行流程,做一个简明通俗的解释,主要参考材料为RFC 6749。

应用场景

  为了理解OAuth的适用场合,让我举一个假设的例子。
  有一个“云冲印”的网站,可以将用户储存在Google的照片,冲印出来。用户为了使用该服务,必须让“云冲印“读取自己储存在Google上的照片。
  问题是只有得到用户的授权,Google才会同意“云冲印”读取这些照片。那么,“云冲印”怎样获得用户的授权呢?
  传统方法是,用户将自己的Google用户名和密码,告诉“云冲印“,后者就可以读取用户的照片了。这样的做法有以下几个严重的缺点。

(1)“云冲印”为了后续的服务,会保存用户的密码,这样很不安全。
(2)Google不得不部署密码登录,而我们知道,单纯的密码登录并不安全。
(3)“云冲印”拥有了获取用户储存在Google所有资料的权力,用户没法限制“云冲印”获得授权的范围和有效期。
(4)用户只有修改密码,才能收回赋予“云冲印”的权力。但是这样做,会使得其他所有获得用户授权的第三方应用程序全部失效。
(5)只要有一个第三方应用程序被破解,就会导致用户密码泄漏,以及所有被密码保护的数据泄漏。

  OAuth就是为了解决上面这些问题而诞生的。

名词定义

  在详细讲解OAuth 2.0之前,需要了解几个专用名词。它们对读懂后面的讲解,尤其是几张图,至关重要。

(1)Third-party application:第三方应用程序,本文中又称“客户端”(client),即上一节例子中的“云冲印”。
(2)HTTP service:HTTP服务提供商,本文中简称“服务提供商”,即上一节例子中的Google。
(3)Resource Owner:资源所有者,本文中又称“用户”(user)。
(4)User Agent:用户代理,本文中就是指浏览器。
(5)Authorization server:认证服务器,即服务提供商专门用来处理认证的服务器。
(6)Resource server:资源服务器,即服务提供商存放用户生成的资源的服务器。它与认证服务器,可以是同一台服务器,也可以是不同的服务器。

  知道了上面这些名词,就不难理解,OAuth的作用就是让“客户端”安全可控地获取“用户”的授权,与“服务商提供商”进行互动。

OAuth的思路

  OAuth在“客户端”与“服务提供商”之间,设置了一个授权层(authorization layer)。“客户端”不能直接登录“服务提供商”,只能登录授权层,以此将用户与客户端区分开来。“客户端“登录授权层所用的令牌(token),与用户的密码不同。用户可以在登录的时候,指定授权层令牌的权限范围和有效期。
  “客户端”登录授权层以后,“服务提供商”根据令牌的权限范围和有效期,向“客户端”开放用户储存的资料。

运行流程

  OAuth 2.0的运行流程如下图,摘自RFC 6749。

Abstract Protocol Flow

(A)用户打开客户端以后,客户端要求用户给予授权。
(B)用户同意给予客户端授权。
(C)客户端使用上一步获得的授权,向认证服务器申请令牌。
(D)认证服务器对客户端进行认证以后,确认无误,同意发放令牌。
(E)客户端使用令牌,向资源服务器申请获取资源。
(F)资源服务器确认令牌无误,同意向客户端开放资源。

  不难看出来,上面六个步骤之中,B是关键,即用户怎样才能给于客户端授权。有了这个授权以后,客户端就可以获取令牌,进而凭令牌获取资源。
  下面一一讲解客户端获取授权的四种模式。

客户端的授权模式

  客户端必须得到用户的授权(authorization grant),才能获得令牌(access token)。OAuth 2.0定义了四种授权方式。

  • 授权码模式(authorization code)
  • 简化模式(implicit)
  • 密码模式(resource owner password credentials)
  • 客户端模式(client credentials)

    授权码模式

      授权码模式(authorization code)是功能最完整、流程最严密的授权模式。它的特点就是通过客户端的后台服务器,与“服务提供商”的认证服务器进行互动。 Authorization Code Flow 它的步骤如下:

    (A)用户访问客户端,后者将前者导向认证服务器。
    (B)用户选择是否给予客户端授权。
    (C)假设用户给予授权,认证服务器将用户导向客户端事先指定的“重定向URI”(redirection URI),同时附上一个授权码。
    (D)客户端收到授权码,附上早先的“重定向URI”,向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。
    (E)认证服务器核对了授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)。

  下面是上面这些步骤所需要的参数。
  A步骤中,客户端申请认证的URI,包含以下参数:

  • response_type:表示授权类型,必选项,此处的值固定为“code”
  • client_id:表示客户端的ID,必选项
  • redirect_uri:表示重定向URI,可选项
  • scope:表示申请的权限范围,可选项
  • state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。

  下面是一个例子。

1
2
3
GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com

  C步骤中,服务器回应客户端的URI,包含以下参数:

  • code:表示授权码,必选项。该码的有效期应该很短,通常设为10分钟,客户端只能使用该码一次,否则会被授权服务器拒绝。该码与客户端ID和重定向URI,是一一对应关系。
  • state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。

  下面是一个例子。

1
2
3
HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA
&state=xyz

  D步骤中,客户端向认证服务器申请令牌的HTTP请求,包含以下参数:

  • grant_type:表示使用的授权模式,必选项,此处的值固定为“authorization_code”。
  • code:表示上一步获得的授权码,必选项。
  • redirect_uri:表示重定向URI,必选项,且必须与A步骤中的该参数值保持一致。
  • client_id:表示客户端ID,必选项。

  下面是一个例子。

1
2
3
4
5
6
7
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb

  E步骤中,认证服务器发送的HTTP回复,包含以下参数:

  • access_token:表示访问令牌,必选项。
  • token_type:表示令牌类型,该值大小写不敏感,必选项,可以是bearer类型或mac类型。
  • expires_in:表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。
  • refresh_token:表示更新令牌,用来获取下一次的访问令牌,可选项。
  • scope:表示权限范围,如果与客户端申请的范围一致,此项可省略。

  下面是一个例子。

1
2
3
4
5
6
7
8
9
10
11
12
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}

  从上面代码可以看到,相关参数使用JSON格式发送(Content-Type: application/json)。此外,HTTP头信息中明确指定不得缓存。

简化模式

  简化模式(implicit grant type)不通过第三方应用程序的服务器,直接在浏览器中向认证服务器申请令牌,跳过了“授权码”这个步骤,因此得名。所有步骤在浏览器中完成,令牌对访问者是可见的,且客户端不需要认证。

Implicit Grant Flow

  它的步骤如下:

(A)客户端将用户导向认证服务器。
(B)用户决定是否给于客户端授权。
(C)假设用户给予授权,认证服务器将用户导向客户端指定的“重定向URI”,并在URI的Hash部分包含了访问令牌。
(D)浏览器向资源服务器发出请求,其中不包括上一步收到的Hash值。
(E)资源服务器返回一个网页,其中包含的代码可以获取Hash值中的令牌。
(F)浏览器执行上一步获得的脚本,提取出令牌。
(G)浏览器将令牌发给客户端。

  下面是上面这些步骤所需要的参数。
  A步骤中,客户端发出的HTTP请求,包含以下参数:

  • response_type:表示授权类型,此处的值固定为“token”,必选项。
  • client_id:表示客户端的ID,必选项。
  • redirect_uri:表示重定向的URI,可选项。
  • scope:表示权限范围,可选项。
  • state:表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。

  下面是一个例子。

1
2
HTTP/1.1 302 Found
Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA&state=xyz&token_type=example&expires_in=3600

  在上面的例子中,认证服务器用HTTP头信息的Location栏,指定浏览器重定向的网址。注意,在这个网址的Hash部分包含了令牌。
  根据上面的D步骤,下一步浏览器会访问Location指定的网址,但是Hash部分不会发送。接下来的E步骤,服务提供商的资源服务器发送过来的代码,会提取出Hash中的令牌。

密码模式

  密码模式(Resource Owner Password Credentials Grant)中,用户向客户端提供自己的用户名和密码。客户端使用这些信息,向“服务商提供商”索要授权。
  在这种模式中,用户必须把自己的密码给客户端,但是客户端不得储存密码。这通常用在用户对客户端高度信任的情况下,比如客户端是操作系统的一部分,或者由一个著名公司出品。而认证服务器只有在其他授权模式无法执行的情况下,才能考虑使用这种模式。

Resource Owner Password Credentials Flow

  它的步骤如下:

(A)用户向客户端提供用户名和密码。
(B)客户端将用户名和密码发给认证服务器,向后者请求令牌。
(C)认证服务器确认无误后,向客户端提供访问令牌。

  B步骤中,客户端发出的HTTP请求,包含以下参数:

  • grant_type:表示授权类型,此处的值固定为“password”,必选项。
  • username:表示用户名,必选项。
  • password:表示用户的密码,必选项。
  • scope:表示权限范围,可选项。

  下面是一个例子。

1
2
3
4
5
6
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded

grant_type=password&username=johndoe&password=A3ddj3w

  C步骤中,认证服务器向客户端发送访问令牌,下面是一个例子。

1
2
3
4
5
6
7
8
9
10
11
12
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache

{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}

  上面代码中,各个参数的含义参见《授权码模式》一节。
  整个过程中,客户端不得保存用户的密码。

客户端模式

  客户端模式(Client Credentials Grant)指客户端以自己的名义,而不是以用户的名义,向“服务提供商”进行认证。严格地说,客户端模式并不属于OAuth框架所要解决的问题。在这种模式中,用户直接向客户端注册,客户端以自己的名义要求“服务提供商“提供服务,其实不存在授权问题。

Client Credentials Flow

  它的步骤如下:

(A)客户端向认证服务器进行身份认证,并要求一个访问令牌。
(B)认证服务器确认无误后,向客户端提供访问令牌。

  A步骤中,客户端发出的HTTP请求,包含以下参数:

  • grant_type:表示授权类型,此处的值固定为“client_credentials”,必选项。
  • scope:表示权限范围,可选项。
    1
    2
    3
    4
    5
    6
    POST /token HTTP/1.1
    Host: server.example.com
    Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
    Content-Type: application/x-www-form-urlencoded

    grant_type=client_credentials
      认证服务器必须以某种方式,验证客户端身份。
      B步骤中,认证服务器向客户端发送访问令牌,下面是一个例子。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    HTTP/1.1 200 OK
    Content-Type: application/json;charset=UTF-8
    Cache-Control: no-store
    Pragma: no-cache

    {
    "access_token":"2YotnFZFEjr1zCsicMWpAA",
    "token_type":"example",
    "expires_in":3600,
    "example_parameter":"example_value"
    }
      上面代码中,各个参数的含义参见《授权码模式》一节。

    更新令牌

  如果用户访问的时候,客户端的“访问令牌”已经过期,则需要使用“更新令牌”申请一个新的访问令牌。
  客户端发出更新令牌的HTTP请求,包含以下参数:

  • grant_type:表示使用的授权模式,此处的值固定为“refresh_token”,必选项。
  • refresh_token:表示早前收到的更新令牌,必选项。
  • scope:表示申请的授权范围,不可以超出上一次申请的范围,如果省略该参数,则表示与上一次一致。

  下面是一个例子。

1
2
3
4
5
6
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded

grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA

* 本文章转载自阮一峰老师的文章理解OAuth 2.0 *

sublime text3 json格式化

Posted on 2020-09-08 | In 技巧

1.每次想将一个json字符串进行格式化时,总是想着在线上进行操作,但是由于工作原因,可能存在没法链接互联网,这时候想着电脑上装有强大的sublime text3,应该有相关的功能,试着在网络上搜索了一下,果然还是可以的。

安装Package control

  首先需要安装Package Control,如果已经安装请跳过此步骤。按Ctrl+Shift+p打开命令框,搜索PCI,点击图中条目安装,如下图:

安装Package control

  安装成功后:

安装Package control

通过Package Control安装Package

  按Ctrl+Shift+p打开命令框,搜索PCI,打开package安装框

安装Package

  安装成功后通用会弹出安装成功的弹窗

安装Pretty Json

  按Ctrl+Shift+p打开命令框,搜索Pretty Json,点击图中条目安装,如下图:

安装Package control

格式化

  按Ctrl+Alt+J就可格式化json数据了

ubuntu mysql 设置大小写不敏感

Posted on 2020-08-27 | In Linux , ubuntu

1.进入目录径:/etc/mysql/mysql.conf.d
2.修改mysqld.cnf文件,在标签[mysqld]下添加lower_case_table_names=1

1
2
3
4
5
6
7
8
9
10
11
[mysqld]
#skip-grant-tables
pid-file = /var/run/mysqld/mysqld.pid
socket = /var/run/mysqld/mysqld.sock
datadir = /var/lib/mysql
log-error = /var/log/mysql/error.log
# By default we only accept connections from localhost
bind-address = 127.0.0.1
# Disabling symbolic-links is recommended to prevent assorted security risks
symbolic-links=0
lower_case_table_names=1

注意: 该配置会强制将表名改为小写,如果当前存在大写的表,请将大写的表改为小写再改配置,否则原来大写的表无法删除,小写的表名也无法创建

3.重启mysql,使用命令:/etc/init.d/mysql restart

Linux服务器卡顿变慢诊断思路

Posted on 2020-08-14 | In Linux

  对于运维开发工程师来说,看到或者听到说生产服务器很卡顿或者访问系统很慢,是一件比较头疼得事,今天我们就根据这个来聊一聊当出现这个情况时,应该如何查看服务器。
  生产服务器变慢了,一般都是从这几点去分析:服务器整体情况, CPU 使用情况,内存,磁盘,磁盘 IO ,网络 IO

top

  看服务器整体使用情况,一般都是 top 命令搞定

top界面

top 界面详解
第 1 行:系统时间、运行时间、登录终端数、系统负载(三个数值分别为1分钟、5分钟、15分钟内的平均值,数值越小意味着负载越低)
第 2 行:进程总数、运行中的进程数、睡眠中的进程数、停止的进程数、僵死的进程数。一般情况下,只要没有僵死的进程,就没啥大问题。
第 3 行:用户占用资源百分比、系统内核占用资源百分比、改变过优先级的进程资源百分比、空闲的资源百分比等。
第 4 行:物理内存总量、内存空闲量、内存使用量、作为内核缓存的内存量
第 5 行:虚拟内存总量、虚拟内存空闲量、虚拟内存使用量、已被提前加载的内存量
第 6 行里面主要看 PID 和 COMMAND 这两个参数,其中 PID 就是进程 ID , COMMAND 就是执行的命令,能够看到比较靠前的两个进程都是 java 进程

  在top界面下,按下数字键盘 1 能够看到各个 CPU 的详细利用率

top界面

vmstat

  想要了解 CPU 使用情况的话,常用的命令就是 vmstat。

vmstat界面

  一般 vmstat 工具的使用是通过两个数字参数来完成的

  • 第一个参数是采样的时间间隔,单位是秒;
  • 第二个参数是采样的次数;
    vmstat -n 3 2 意思就是隔 3 秒取样一次,一共取样 2 次。

  其中主要关注 procs 和 cpu 这两个参数:
  procs

  • r :运行和等待 CPU 时间片的进程数,一般来说整个系统的运行队列不要超过总核数的 2 倍,要不然系统压力太大了
  • b : 等待资源的进程数,比如正在等待磁盘 IO ,网络 IO 这种

  cpu

  • us :用户进程消耗 CPU 时间百分比, us 值高的话,说明用户进程消耗 CPU 时间比较长,如果长期大于 50% 的话,那就说明程序还有需要优化的地方
  • sy :内核进程消耗的 CPU 时间百分比
  • us + sy 参考值为 80% ,如果大于 80% 的话,说明可能存在 CPU 不足

free

  查看内存情况用的就是 free , 它主要有三个命令:free free -g free -m ,在这里推荐 free -m 为啥呢,咱们瞅瞅它们各自的运行结果就知道了

free界面

  其中:free 命令运行结果显示的非常不友好,看到 16252964 可以快速告诉我它是多大吗?free -g 这个命令四舍五入了,明明给的内存是 16G ,结果使用 free -g 一查看,竟然成了 15G ?excuse me ?如果线上环境出问题了,你说因为内存给的不够,运维说,这锅我可不背。
  相对来说, free -m 是比较容易看,而且结果也是比较精确的。
  如果应用程序可用内存/系统物理内存大于 70% 的话,说明内存是充足的,没啥问题,但是如果小于 20% 的话,就要考虑增加内存了。

df

  如果排查磁盘问题的话,首先要看的就是磁盘空间够不够,最近笔者在多个项目中,均出现过一种情况,就是哪里都不报错,日志也不打印,访问就是很慢或者根本访问不了系统,排查到最后是磁盘空间不够…
  所以查磁盘问题时,第一就是看磁盘空间够不够!!!
  查看磁盘空间就是 df 或者 df -h 这两个命令了。

df界面

iostat

  说到磁盘 IO 相信你一定能够想到,在对数据库进行操作时,第一要考虑到的就是磁盘 IO 操作,因为相对来说,如果在某个时间段给磁盘进行大量的写入操作会造成程序等待时间长,导致客户端那边好久都没啥反应,用户体验就降低了吗
  检查磁盘 IO 情况的命令就是 iostat ,如果你用的时候发现提示:-bash: iostat: command not found ,那是因为没有安装 sysstat ,安装一下就可以了:yum install -y sysstat
  接下来运行命令:iostat -xdk 3 2 ,和 vmstat 命令很像有没有~

iostat界面

这么多指标咱们不需要都关注,只要看其中这几个就可以了:

  • rkB/s :每秒读取数据量 kB ;
  • wkB/s :每秒写入数据量 kB ;
  • svctm :I/O 请求的平均服务时间,单位毫秒;
  • util :一秒中有百分之几的时间用于 I/O 操作,如果接近 100% 说明磁盘带宽跑满了,这个时候就要优化程序或者增加磁盘了

sar

  网络 IO 的话,可以通过 sar -n DEV 3 2 这条命令来看,和上面的差不多,意思就是每隔 3 秒取样一次,一共取样 2 次。

sar界面

其中:

  • IFACE :LAN 接口
  • rxpck/s :每秒钟接收的数据包
  • txpck/s :每秒钟发送的数据包
  • rxKB/s :每秒接收的数据量,单位 KByte
  • txKB/s :每秒发出的数据量,单位 KByte
  • rxcmp/s :每秒钟接收的压缩数据包
  • txcmp/s :每秒钟发送的压缩数据包
  • rxmcst/s:每秒钟接收的多播数据包
    这种方式特别简单直观,对新手来说比较容易看到

   OK ,下次面试官问你生产服务器变慢了,你能谈谈诊断思路吗?咋不能呢,从服务器整体情况开始说,一直到网络 IO ,再也不怕和面试官扯皮了

ruby安装

Posted on 2020-08-12 | In redis , ruby

众所周知,redis在5.0版本之前,使用集群模式时,需要在服务器上安装ruby服务。

在线安装

操作系统为CentOS,Fedora,RHEL时

1
sudo yum install ruby  # CentOS, Fedora, 或 RHEL 系统

或者

1
2
3
yum install centos-release-scl-rh //会在/etc/yum.repos.d/目录下多出一个CentOS-SCLo-scl-rh.repo源
yum install rh-ruby23 -y //直接yum安装即可
scl enable rh-ruby23 bash //必要一步

操作系统为Debian,Ubuntu时

1
sudo apt-get install ruby-full # Debian 或 Ubuntu 系统

离线安装

备好安装包

从官网下载好安装包,下载链接 https://cache.ruby-lang.org/pub/ruby/2.5/ruby-2.5.7.tar.gz

解压编译安装

将下载好的ruby-2.5.7.tar.gz上传到服务器/opt/目录下,执行解压命令

1
[root@localhost opt] tar -zxf ruby-2.5.7.tar.gz

进入解压后的目录,执行编译命令

1
2
[root@localhost opt] cd ruby-2.5.7
[root@localhost ruby-2.5.7] ./configure --prefix=/usr/local/ruby

稍等一下,不出意外,编译完成需要一分钟左右,之后执行命令 make

1
[root@localhost ruby-2.5.7] make

此处执行时间较长,执行完成后,执行安装命令 make install

1
[root@localhost ruby-2.5.7] make install

执行完成后,即安装完成

配置环境变量

在当前用户环境变量配置文件配置如下信息

1
2
export RUBY_HOME=/usr/local/ruby
export PATH=$PATH:${RUBY_HOME}/bin

配置位置:

1
2
/etc/profile      #必须需要root权限  
~/.bash_profile #可以不需要root权限

配置完成后,记得执行source

1
2
source /etc/profile
source ~/.bash_profile

执行 ruby -v可查看ruby版本信息

redis集群安装(三主三从)

Posted on 2020-08-12 | In redis

redis集群

  在redis集群安装之前,需要先在服务器上安装好redis服务,redis集群三主三从,最少需要在三台服务器上安装好redis服务。安装redis说明可参考redis学习笔记(一)安装与配置
  在redis 5版本之前,需要依赖ruby,版本依赖问题不做深究,至于ruby的安装可参考ruby安装
  安装ruby后需要为ruby安装一下第三方接口,可在线执行安装命令

1
gem install redis

  如果服务器无网络链接,可预先在https://rubygems.org/downloads/redis-4.1.3.gem下载好redis-4.1.3.gem文件,然后上传到服务器,之后在文件所在目录执行一下

1
gem install -l ./redis-4.1.3.gem

接下来开始redis集群安装,假设服务器节点信息如下

10.195.173.29:7200
10.195.173.29:7201
10.195.173.36:7200
10.195.173.36:7201
10.195.173.40:7200
10.195.173.40:7201

在每一台服务器目录/usr/local/redis目录下批量创建redis-cluster/7200和redis-cluster/7201

1
[root@localhost redis] mkdir -p redis-cluster/7200 redis-cluster/7201

之后在7200和7201目录下分别创建redis-7200.conf、redis-7201.conf,建议从源文件包中拷贝一份文件到相应的目录中

1
2
[root@localhost 7200] cp /opt/redis-4.0.14/redis.conf redis-7200.conf
[root@localhost 7200] cp /opt/redis-4.0.14/redis.conf redis-7201.conf

修改redis-7200.conf redis-7201.conf文件,注意两个文件配置的端口不一样

1
2
3
4
5
6
7
8
9
10
11
12
port 7200
daemonize yes
protected-mode no
dir /usr/local/redis/redis-cluster/7200/
cluster-enabled yes
cluster-config-file nodes-7200.conf
cluster-node-timeout 5000
appendonly yes
pidfile redis_7200.pid
loglevel notice
logfile "notice.log"
#bind 127.0.0.1

三台服务器按照上述配置完成后,启动各个redis节点

1
2
[root@i-212a7852 redis-cluster]# /usr/local/redis/bin/redis-server /usr/local/redis/redis-cluster/7201/redis-7201.conf 
[root@i-212a7852 redis-cluster]# /usr/local/redis/bin/redis-server /usr/local/redis/redis-cluster/7202/redis-7202.conf

启动完成后,在其中一台服务器上启动搭建集群命令,Redis会给出一个预计的方案,对6个节点分配3主3从,如果认为没有问题,输入yes确认,另外注意用绝对IP,不要用127.0.0.1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
[root@i-212a7852 redis-cluster]# /usr/local/redis/bin/redis-trib.rb create --replicas 1 10.195.173.29:7200 10.195.173.29:7201 10.195.173.36:7200 10.195.173.36:7201 10.195.173.40:7200 10.195.173.40:7201
>>> Creating cluster
>>> Performing hash slots allocation on 6 nodes...
Using 3 masters:
10.195.173.29:7200
10.195.173.36:7200
10.195.173.40:7200
Adding replica 10.195.173.29:7201 to 10.195.173.29:7200
Adding replica 10.195.173.36:7201 to 10.195.173.36:7200
Adding replica 10.195.173.40:7201 to 10.195.173.40:7200
>>> Trying to optimize slaves allocation for anti-affinity
[WARNING] Some slaves are in the same host as their master
M: fb116678b41904d9fe458382cf0c4f1a135b3c81 10.195.173.29:7200
slots:0-5460 (5461 slots) master
M: b3abcdc8db3321032925ba67db8f2cfee53e038d 10.195.173.36:7200
slots:5461-10922 (5462 slots) master
M: 3b3a89b0324132f47a049a2aad0c7781ed4eb0de 10.195.173.40:7200
slots:10923-16383 (5461 slots) master
S: 585b94dc3cf3d18d12d8c21ccbe4080e9372e867 10.195.173.29:7201
replicates b3abcdc8db3321032925ba67db8f2cfee53e038d
S: ad8bc0cc83db06a68705e0127960654a7e9f7dc0 10.195.173.36:7201
replicates 3b3a89b0324132f47a049a2aad0c7781ed4eb0de
S: 4ba7b4503298f451da4f021857ec9e5136b4c492 10.195.173.40:7201
replicates fb116678b41904d9fe458382cf0c4f1a135b3c81
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 172.18.32.39:7201)
M: fb116678b41904d9fe458382cf0c4f1a135b3c81 10.195.173.29:7200
slots:0-5460 (5461 slots) master
1 additional replica(s)
M: b3abcdc8db3321032925ba67db8f2cfee53e038d 10.195.173.36:7200
slots:5461-10922 (5462 slots) master
1 additional replica(s)
S: ad8bc0cc83db06a68705e0127960654a7e9f7dc0 10.195.173.40:7200
slots: (0 slots) slave
replicates 3b3a89b0324132f47a049a2aad0c7781ed4eb0de
S: 4ba7b4503298f451da4f021857ec9e5136b4c492 10.195.173.29:7201
slots: (0 slots) slave
replicates fb116678b41904d9fe458382cf0c4f1a135b3c81
M: 3b3a89b0324132f47a049a2aad0c7781ed4eb0de 10.195.173.36:7201
slots:10923-16383 (5461 slots) master
1 additional replica(s)
S: 585b94dc3cf3d18d12d8c21ccbe4080e9372e867 10.195.173.40:7201
slots: (0 slots) slave
replicates b3abcdc8db3321032925ba67db8f2cfee53e038d
[OK] All nodes agree about slots configuration.
>>> Check for open slots...
>>> Check slots coverage...
[OK] All 16384 slots covered.

还有需要注意一点,从redis 5.x 版本开始,redis-trib.rb已经废弃了,直接用–cluster命令

1
[root@i-212a7852 redis-cluster]# /usr/local/redis/bin/redis-cli --cluster create --cluster-replicas 1 10.195.173.29:7200 10.195.173.29:7201 10.195.173.36:7200 10.195.173.36:7201 10.195.173.40:7200 10.195.173.40:7201

命令执行成功后,集群搭建成功。

附录:

集群命令

cluster info :打印集群的信息
cluster nodes :列出集群当前已知的所有节点(node),以及这些节点的相关信息。
cluster meet :将 ip 和 port 所指定的节点添加到集群当中,让它成为集群的一份子。
cluster forget :从集群中移除 node_id 指定的节点(保证空槽道)。
cluster replicate :将当前节点设置为 node_id 指定的节点的从节点。
cluster saveconfig :将节点的配置文件保存到硬盘里面。

槽slot命令

cluster addslots [slot …] :将一个或多个槽(slot)指派(assign)给当前节点。
cluster delslots [slot …] :移除一个或多个槽对当前节点的指派。
cluster flushslots :移除指派给当前节点的所有槽,让当前节点变成一个没有指派任何槽的节点。
cluster setslot node :将槽 slot 指派给 node_id 指定的节点,如果槽已经指派给另一个节点,那么先让另一个节点删除该槽>,然后再进行指派。
cluster setslot migrating :将本节点的槽 slot 迁移到 node_id 指定的节点中。
cluster setslot importing :从 node_id 指定的节点中导入槽 slot 到本节点。
cluster setslot stable :取消对槽 slot 的导入(import)或者迁移(migrate)。

键命令

cluster keyslot :计算键 key 应该被放置在哪个槽上。
cluster countkeysinslot :返回槽 slot 目前包含的键值对数量。
cluster getkeysinslot :返回 count 个 slot 槽中的键

Linux环境指定目录定时删除一个月前的文件

Posted on 2020-08-12 | In Linux

编写可执行脚本

创建脚本auto_del_one_month_before.sh

1
vi auto_del_one_month_before.sh

编写脚本信息

1
2
#!/bin/sh
find /home/capinfo/ydd/nginx_logs -mtime +31 -name "*.*" -exec rm -rf {} \;

保存脚本wq
注意:脚本保存的目录与需要删除文件的的目录不要放在一起,否则会出现执行脚本时,将脚本文件删除的风险

创建定时任务

使用crontab -e创建Linux定时任务,执行命令后,可使用vim的方式编写定时任务

1
02 00 * * * /bin/sh /usr/local/nginx/logs/auto_del_one_month_before.sh &>/dev/null

建议在编写定时任务前,最好能测试一下编写的脚本是否可正常使用,另外,手动执行一下定时任务也能避免一些问题

redis学习笔记(二)之字符串类型命令

Posted on 2020-08-11 | In redis

字符串类型

  字符串类型是redis中最基本的数据类型,他能存储任何形式的字符串,包括二进制数据。一个字符串类型键允许的数据的最大容量是512MB。

命令

SET和GET

类似于读和写变量

1
2
3
4
5
6
7
SET key value [EX seconds] [PX milliseconds] [NX|XX]
GET key
SET命令的参数:
EX seconds:以**秒**为单位设置键的key过期时间
PX millinseconds:以**毫秒**为单位设置过期时间
NX :只有键不存在的时候才可以设置成功
XX:只有键在已经存在的时候才可以设置成功

  举例:

1
2
3
4
5
6
7
8
9
10
11
12
127.0.0.1:6379> SET test1 "hello"
OK
127.0.0.1:6379> GET test1
"hello"
127.0.0.1:6379> GET test2
(nil)
//当GET 一个不存在的键会返回空结果。
127.0.0.1:6379> SET test1 "hello world"
OK
127.0.0.1:6379> GET test1
"hello world"
//多次SET同一个键时,键值会被覆盖。

GETRANGE

  用于获取存储在键的字符串值的子字符串,由偏移量的开始和结束(两者都包括)确定。可以使用负偏移,以便从字符串的末尾开始计算偏移

1
GETRANGE KEY_NAME start end

  举例:

1
2
3
4
5
6
127.0.0.1:6379> GETRANGE test1 0 4
"hello"
127.0.0.1:6379> GETRANGE test1 0 -1
"hello world"
127.0.0.1:6379> GETRANGE test1 6 -1
"world"

GETSET

  在Redis键中设置指定的字符串值,并返回其旧值,不存在返回空结果。

1
GETSET key value

  举例:

1
2
3
4
127.0.0.1:6379> GETSET test2 "first GETSET"
(nil)
127.0.0.1:6379> GETSET test2 "second GETSET"
"first GETSET"

MGET 和 MSET

  MGET命令用于获取所有指定键的值。对于不包含字符串值或不存在的每个键,返回空结果
  MSET命令用于一次多个键设置它们的值。

1
2
MGET key [key ...]
MSET key value [key value ...]

  举例:

1
2
3
4
5
6
7
127.0.0.1:6379> MSET test3 "hello" test4 "world" test5 "!!!"
OK
127.0.0.1:6379> MGET test3 test4 test5 test6
1) "hello"
2) "world"
3) "!!!"
4) (nil)    //不存在的键返回空结果

STRLEN

  用于获取存储在键中的字符串值的长度。当键包含非字符串值时返回错误

1
STRLEN key

  举例:

1
2
3
4
5
127.0.0.1:6379> STRLEN test5
(integer) 3
127.0.0.1:6379> STRLEN test6
(integer) 0
//不存在的键返回整数0

SETRANGE

  命令用于覆盖键的值,从指定偏移处开始的一部分字符串,返回字符串在修改后的长度。

1
SETRANGE key offset value

  举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
127.0.0.1:6379> GET test1
"hello redis"
127.0.0.1:6379> SETRANGE test1 6 "ubuntu"
(integer) 12
127.0.0.1:6379> GET test1
"hello ubuntu"

127.0.0.1:6379> GETSET test1 "abc"
"hello ubuntu"
127.0.0.1:6379> SETRANGE test1 4 "def"
(integer) 7
127.0.0.1:6379> GET test1
"abc\x00def"
//如果设置的key原来的字符串长度要比偏移量小,就会以零字节(\x00)来补充

SETNX

  命令用于在Redis键中设置某些字符串值(如果该键在Redis中不存在)。如果不存在,则SETNX的全形式是SET。

1
2
SETNX key value
//等价于 SET key value NX

  举例:

1
2
3
4
5
6
7
8
9
10
11
127.0.0.1:6379> EXISTS test6        //测试键是否存在,存在返回整数1,否则返回0
(integer) 0
127.0.0.1:6379> SETNX test6 "test6 is not exists"
(integer) 1         //设置成功
127.0.0.1:6379> GET test6
"test6 is not exists"

127.0.0.1:6379> EXISTS test5
(integer) 1
127.0.0.1:6379> SETNX test "test5 is exists"
(integer) 0     //test5设置设置失败

SETEX

  命令用于在Redis键中的指定超时,设置键的字符串值。
  SETEX是原子操作,相当于执行了SET键值又对key设置了过期时间。

1
2
SETEX key seconds value
//等价于 SET key value EX seconds

  举例:

1
2
3
4
5
6
127.0.0.1:6379> SETEX test1 30 "thirty"
OK
127.0.0.1:6379> TTL test1   //查看键的生存时间,test1已过期
(integer) -2
127.0.0.1:6379> GET test1  
(nil)

MSETNX

  用于为多个键设置多个值(仅当在键都不存在时)。如果当前操作中有任何一个存在于Redis中,那么MSETNX不执行任何操作。

1
MSETNX key value [key value ...]

  举例:

1
2
3
4
5
6
7
8
9
10
127.0.0.1:6379> MSETNX test7 "7" test8 "8"
(integer) 1     //返回1设置成功
127.0.0.1:6379> MGET test7 test8
1) "7"
2) "8"
127.0.0.1:6379> MSETNX test8 "8" test9 "9"
(integer) 0
127.0.0.1:6379> MGET test8 test9
1) "8"
2) (nil)        //test9设置失败

PSETEX

  命令用于设置键的值,以毫秒为单位指定过期时间

1
2
PSETEX key milliseconds value
//等价于 SET key value PX milliseconds

  举例:

1
2
3
4
5
6
127.0.0.1:6379> PSETEX test9 2000 "millinseconds"
OK
127.0.0.1:6379> PTTL test9  //PTTL获得毫秒级的生存时间
(integer) 624  
127.0.0.1:6379> GET test9
(nil)

INCR

  命令用于将键的整数值递增1。如果键不存在,则在执行操作之前将其设置为0。如果键包含错误类型的值或包含无法表示为整数的字符串,则会返回错误。此操作限于64位有符号整数。

1
INCR key

  举例:

1
2
3
4
5
6
127.0.0.1:6379> INCR counter    //如果key不存在,先初始化为0,在进行INCR操作
(integer) 1
127.0.0.1:6379> INCR counter
(integer) 2
127.0.0.1:6379> INCR counter
(integer) 3

INCRBY

  用于将存储在键上的数字按指定的值增加。 如果键不存在,则在执行操作之前将其设置为0。如果键包含错误类型的值或包含无法表示为整数的字符串,则会返回错误。

1
INCRBY key increment

  举例:

1
2
3
4
127.0.0.1:6379> GET counter
"3"
127.0.0.1:6379> INCRBY counter 10
(integer) 13

INCRBYFLOAT

  用于将递增的字符串表示为浮点数,该值存储在键上指定的增量。 如果键不存在,则在执行操作之前将其设置为0。 如果键包含错误类型的值或当前键内容或指定的增量不能解析为浮点数,则返回错误。
支持小数点往后17位的运算操作

1
INCRBYFLOAT key increment

  举例:

1
2
3
4
127.0.0.1:6379> INCRBYFLOAT linux 1
"1"
127.0.0.1:6379> INCRBYFLOAT linux 0.012345678901234567890123456789
"1.01234567890123457"

DECR

  用于将键的整数值减1。 如果键不存在,则在执行操作之前将其设置为0。 如果键包含错误类型的值或包含无法表示为整数的字符串,则会返回错误。 此操作限于64位有符号整数。

1
DECR key

  举例:

1
2
3
4
5
6
127.0.0.1:6379> DECR counter
(integer) -1
127.0.0.1:6379> DECR counter
(integer) -2
127.0.0.1:6379> DECR counter
(integer) -3

DECRBY

  将存储在键上的数字按指定的值减少。如果键不存在,则在执行操作之前将其设置为0。 如果键包含错误类型的值或包含无法表示为整数的字符串,则会返回错误。

1
DECRBY key decrement

  举例:

1
2
3
4
127.0.0.1:6379> DECRBY counter -10
(integer) 7
127.0.0.1:6379> DECRBY counter -10
(integer) 17

APPEND

  命令用于在键中添加一些值。返回追加后的字符串长度。

1
APPEND key value

  举例:

1
2
3
4
5
6
127.0.0.1:6379> SET say hello
OK
127.0.0.1:6379> APPEND say " world"
(integer) 11
127.0.0.1:6379> GET say
"hello world"

GETBIT

  可以获得一个字符串类型指定位置的二进制位的值(0或1),索引以0开始。

1
GETBIT key offset

  举例:

1
2
3
4
5
6
127.0.0.1:6379> SET foo bar //bar的二进制表示如下表
OK
127.0.0.1:6379> GETBIT foo 0    //下标为0的位值为0
(integer) 0
127.0.0.1:6379> GETBIT foo 6    //下标为6的位值为1
(integer) 1

  bar的二进制表示如下:

b a r
01100010 01100001 01110010

SETBIT

  设置字符串类型键指定位置的二进制位的值,返回该位置的旧值。

1
SETBIT key offset value

  举例:

1
2
3
4
5
6
127.0.0.1:6379> SETBIT foo 6 0
(integer) 1
127.0.0.1:6379> SETBIT foo 7 1
(integer) 0
127.0.0.1:6379> GET foo
"aar"

  将b的二进制码01100010的下标第6和第7位分别置为0和1,得到01100001是a的ASCLL码。

BITOP

  可以对多个字符串类型键进行位运算,并将结果存在destkey参数规定的键中。
  BITOP命令支持的运算操作有AND、OR、XOR和NOT

1
BITOP operation destkey key [key ...]

  举例:

1
2
3
4
127.0.0.1:6379> BITOP XOR res foo foo
(integer) 3
127.0.0.1:6379> GET res
"\x00\x00\x00"

  两个相同的值做异或运算结果为0。

BITPOS

  获得指定键的第一个位值是0或者1的位置。

1
2
BITPOS key bit [start] [end]
//start 和 end 位置以字节为单位

  举例:

1
2
3
4
127.0.0.1:6379> BITPOS foo 1    //第一个值为1的位下标为1
(integer) 1
127.0.0.1:6379> BITPOS foo 1 1 2    //下标为1到2的字节中,第一个值为1的下标为整个键值的第9位
(integer) 9

redis学习笔记(一)安装与配置

Posted on 2020-08-11 | In redis

redis简介

Redis是一个开源的、高性能的、基于键值对的缓存与存储系统,Redis是Remote DIctionary Server(远程字典服务器)的缩写。Redis支持五种数据类型:string(字符串),hash(哈希),list(列表),set(集合)及zset(sorted set:有序集合)。

离线安装

准备redis安装包

​ 准备好redis安装包,本项目使用的redis版本为4.0.14。redis官网下载地址为 http://download.redis.io/releases/redis-4.0.14.tar.gz

解压编译安装

​ 将下载好的安装包防止在服务器某个目录,并执行解压命令

1
[root@localhost /] tar -zxf redis-4.0.14.tar.gz

​ 进入解压目录

1
[root@localhost /] cd redis-4.0.14

​ 执行指定安装目录编译安装

1
[root@localhost redis-4.0.14] make PREFIX=/usr/local/redis install

​ 进入安装目录,准备配置文件redis.conf

1
2
3
[root@localhost redis-4.0.14] cd /usr/local/redis
[root@localhost redis] cp /opt/redis-4.0.14/redis.conf .
[root@localhost redis] cp /opt/redis-4.0.14/src/redis-trib.rb bin/

​ 修改redis部分配置信息,vi redis.conf 把daemonize no 改为 daemonize yes,即redis启动时以守护进程方式启动,新增设置参数requirepass (链接密码) ,即客户端链接客户端时,需要链接口令

启动redis

1
2
3
[root@localhost redis] pwd
/usr/local/redis
[root@localhost redis] bin/redis-server redis.conf

验证redis是否启动成功

1
2
[root@localhost redis] netstat -tulnp | grep 6379
tcp 0 0 127.0.0.1:6379 0.0.0.0:* LISTEN 14150/bin/redis-ser

显示redis的端口6379已正常启动并监听中

设置开机自启动

  • 在/etc/init.d/创建redis脚本
    redis脚本内容如下

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    #!/bin/bash
    #chkconfig: 22345 10 90
    #description: Start and Stop redis

    REDISPORT=6379
    EXEC="/usr/local/redis/bin/redis-server"
    CLIEXEC="/usr/local/redis/bin/redis-cli"
    PIDFILE="/var/run/redis_"$REDISPORT".pid"
    CONF="/usr/local/redis/redis.conf"
    PASSWORD="口令"

    case "$1" in
    start)
    if [ -f $PIDFILE ];then
    echo "$PIDFILE exists,process is already running or crashed"
    else
    echo "Starting Redis server..."
    $EXEC $CONF
    fi
    ;;
    stop)
    if [ ! -f $PIDFILE ];then
    echo "$PIDFILE does not exist,process is not running"
    else
    PID=$(cat $PIDFILE)
    echo "Stopping..."
    $CLIEXEC -p $REDISPORT -a $PASSWORD shutdown
    while [ -x /proc/${PID} ]
    do
    echo "Waiting for Redis to shutdown..."
    sleep 1
    done
    echo "Redis stopped"
    fi
    ;;
    restart)
    "$0" stop
    sleep 3
    "$0" start
    ;;
    *)
    echo "Please use start or stop or restart as first argument"
    ;;
    esac

    注意
    REDISPORT: redis端口
    EXEC:redis-server 目录
    CLIEXEC:redis-cli 目录
    PIDFILE:redis进程号存储目录
    CONF:redis配置文件目录
    PASSWORD:客户端链接服务端口令

    保存好退出,执行添加执行权限操作
    chmod a+x /etc/init.d/redis

  • 把脚本添加到系统服务列表

    1
    2
    3
    chkconfig --add redis
    chkconfig redis on
    chkconfig --list //查看所有注册的脚本文件

    至此设置完成,相关命令如下

    1
    2
    3
    4
    5
    6
    /etc/init.d/redis stop #关闭redis服务
    /etc/init.d/redis start #启动redis服务
    /etc/init.d/redis restart #重启redis服务
    service redis stop #关闭redis服务
    service redis start #启动redis服务
    service redis restart #重启redis服务
12<i class="fa fa-angle-right"></i>
eYoung

eYoung

16 posts
11 categories
12 tags
GitHub E-Mail gitee csdn zhihu qq weixin weibo
© 2021 eYoung
Powered by Hexo