tusi

tusi 查看完整档案

南充编辑  |  填写毕业院校  |  填写所在公司/组织填写个人主网站
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 该用户太懒什么也没留下

个人动态

tusi 赞了回答 · 7月13日

解决Centos7下安装mysql,卸载mariadb库文件

是装完mysql就有这个吗?
安装方法推荐使用yum方式安装.mysql稳定性较好

关注 3 回答 2

tusi 赞了文章 · 6月22日

PHP yield 高级用法——同步编码,异步执行

开篇

刚开始接触PHPyield 的时候,感觉,yield 是什么黑科技,百度一下:yield——协程,生成器。很多文章都在讲 IteratorGenerater, 蛤~,这东西是 PHP 迭代器的一个补充。再翻几页,就是Go 协程。我出于好奇点开看了下Go 协程, 里面都是 并发线程管道通讯这类字眼,wc,nb, 这tm才是黑科技啊,再回来看PHP,分分钟想转 Go

你能得到

通过这篇文章,你能学会如何写一个简单的socket server,PHP yield 的综合应用,以及协程版的Workerman。

四部曲

yield 语法加入 PHP

yield语法是在版本5.5加入PHP的,配合迭代器使用,功能上就是 流程控制 代码,和gotoreturn 类似。

以下就是官方提供的 yield 小例子,通过执行结果,我们可分析当代码执行到 yield $i 时,他会进行 return $i, 待 echo "$value\n" 后, gotofor ($i = 1; $i <= 3; $i++) {, 对!PHP 的 yield 就是一个能出能进的语法。在z代码中七进七出,把 $i 平平安安得送了出来。

<?php
function gen_one_to_three() {
    for ($i = 1; $i <= 7; $i++) {
        //注意变量$i的值在不同的yield之间是保持传递的。
        yield $i;
    }
}

$generator = gen_one_to_three();
foreach ($generator as $value) {
    echo "$value\n";
}

// output
1
2
...
6
7

我们遇到了什么问题

写代码就是解决问题。我们来看看他们遇到了什么问题:php官方呢,需要言简意赅地把yield介绍给大家。一部分网友呢,需要在有限的资源内完成大文件操作。而我们的鸟哥。面对的一群对当下yield的教程停留于初级而不满意的phper,就以一个任务调度器作为例子,给大家讲了一种yield高级用法。

php.net:生成器语法,
PHP如何读取大文件
风雪之隅:在PHP中使用协程实现多任务调度.

提出问题,再用yield来解答,看到以上答案,我觉得呢,这PHP协程不过如此(Go协程相比 )。

有句话——一个好问题比答案更重要,目前广大网友还没有给yield提出更好,更困难的问题。

yield这个进进出出的语法,很多举例都是再让yield做迭代器啊,或者利用低内存读取超大文本的Excelcsv什么的,再高级就是用它实现一个简单的任务调度器,并且这个调度器,一看代码都差不多。

我来出道题

正如一个好的问题,比答案更有价值
  1. 用PHP实现一个 Socket Server,他能接收请求,并返回Server的时间。

好,这是第一个问题,铺垫。 官方答案

  1. 在原来的代码上,我们加个需求,该Socket Server 处理请求时,依赖其他 Socket Server,还需要有 Client 功能。也就是他能接收请求,向其它Server发起请求。

这是第二个问题,也是铺垫。

  1. 原来的Socket Server同一时间只能服务一个客户,希望能实现一个 非阻塞I/O Socket Server, 这个 Server 内有 Socket Client 功能,支持并发处理收到的请求,和主动发起的请求。要求不用多线程,多进程。

这个问题,还是铺垫,这几个问题很干,大家可以想一想,2,3题的答案,都放在一个脚本里了:nio_server.php

以上这段代码,我列举了一个具体的业务,就是用户请求购物车加购动作, 而购物车服务呢,又需要和 产品服务,库存服务,优惠服务 交互,来验证加购动作可行性。有同步,异步方式请求,并做对比。

后续还有很多代码,我都放gitee链接了。使用方法,见readme.md
  1. 最后一个问题:在PHP中,用同步写代码,程序呢异步执行?需要怎么调整代码。

.
.
.
.
.
.

提示:这个和 PHPyield 语法有关。

.
.
.
.
.
.

再提示:yield 语法特征是什么,进进出出!

看着我们的代码,同步, 异步,进进出出 你想到了什么?

.
.
.
.
.
.

看到代码,同步处理模式下,这三个函数checkInventorycheckProductcheckPromo 时,发起请求,并依次等待返回的结果,这三个函数执行后,再响应客户请求。

异步处理模式下,这三个函数发起请求完毕后,代码就跳出循环了,然后是在select()下的一个代码分支中接收请求, 并收集结果。每次收到结果后判断是否完成,完成则响应客户端。

那么能不能这样:在异步处理的流程中,当 Server 收到 自己发起的 client 有数据响应后,代码跳到 nio_server.php 的 247行呢,这样我们的收到请求校验相关的代码就能放到这里,编码能就是同步,容易理解。不然,client 的响应处理放在 280 行以后,不通过抓包,真的很难理解,执行了第 247 行代码后,紧接着是从 280 行开始的。

.
.
.
.
.
.
.
.

诶~这里是不是有 进进出出 那种感觉了~ 代码从 247 行出去,开始监听发出 Client 响应,收到返回数据,带着数据再回到 247 行,继续进行逻辑校验,综合结果后,再响应给客户端。

用yield来解决问题

基于 yield 实现的,同步编码,"异步"I/OSocket Server 就实现了。代码。

这里 "异步" 打了引号,大佬别扣这个字眼了。 该是非阻塞I/O

不等大家的答案了,先上我的结果代码吧,代码呢都放在这个目录下了。

gitee https://gitee.com/xupaul/PHP-generator-yield-Demo/tree/master/yield-socket

运行测试代码

clone 代码到本地后,需要拉起4个 command 命令程序:

拉起3个第三方服务

## 启动一个处理耗时2s的库存服务
$ php ./other_server.php 8081 inventory 2

## 启动一个处理耗时4s的产品服务
$ php ./other_server.php 8082 product 4

## 监听8083端口,处理一个请求 耗时6s的 promo 服务
$ php ./other_server.php 8083 promo 6

启动购物车服务

## 启动一个非阻塞购物车服务
$ php ./async_cart_server.php 

## 或者启动一个一般购物车服务
$ php ./cart_server.php 

发起用户请求

$ php ./user_client.php

运行结果呢如下,通过执行的时间日志,可得这三个请求是并发发起的,不是阻塞通讯。

在看我们的代码,三个函数,发起socket请求,没有设置callback,而是通过yield from 接收了三个socket的返回结果。

也就是达到了,同步编码,异步执行的效果。

运行结果

非阻塞模式

client 端日志:

通过以上 起始时间结束时间 ,就看到这三个请求耗时总共就6s,也就按照耗时最长的promo服务的耗时来的。也就是说三个第三方请求都是并发进行的。

cart server 端日志:

而 cart 打印的日志,可以看到三个请求一并发起,并一起等待结果返回。达到非阻塞并发请求的效果。

阻塞模式

client 端日志:

以上是阻塞方式请求,可以看到耗时 12s。也就是三个服务加起来的耗时。

cart server 端日志:

cart 服务,依次阻塞方式请求第三方服务,顺序执行完毕后,共耗时12s,当然如果第一个,获第二个服务报错的话,会提前结束这个检查。会节约一点时间。

工作原理

这里就是用到了 yield 的工作特点——进进出出,在发起非阻塞socket请求后,不是阻塞方式等待socket响应,而是使用yield跳出当前执行生成器,等待有socket响应后,在调用生成器的send方法回到发起socket请求的函数内,在 yield from Async::all() 接收数据响应数据搜集完毕后,返回。

当初我在写这篇文章时——NIO、BIO、AIO 与 PHP 实现, 用到很多回调函数,事件轮训,就为了高性能,写出来的代码可读性太差。那么有没有两全其美的办法,当我遇到协程后,我的脑子里就迸发出了这个灵感。

和Golang比一比

考虑到网速原因,我这就放上一个国内教程链接:Go 并发 教程

php的协程是真协程,而Go是披着协程外衣的轻量化线程(“协程”里,都玩上“锁”了,这就是线程)。

我个人偏爱,协程的,觉得线程的调度有一定随机性,因此需要锁机制来保证程序的正确,带来了额外开销。协程的调度(换入换出)交给了用户,保证了一段代码执行连续性(当然进程级上,还是会有换入换出的,除非是跨进程的资源访问,或者跨机器的资源访问,这时,就要用到分布式锁了,这里不展开讨论),同步编码,异步执行,只需要考虑那个哪个方法会有IO交互会协程跳出即可。

和NodeJS比划一下

Javascript 和 PHP 两个脚本语言有很多相似的地方,弱类型,动态对象,单线程,在Web领域生态丰富。不同的是,Javascript在浏览器端一开始就是异步的(如果js发起网络请求只能同步进行,那么你的网页渲染线程会卡住),例如AjaxsetTimeoutsetInterval,这些都是异步+回调的方式工作。

基于V8引擎而诞生的NodeJS,天生就是异步的,在提供高性能网络服务有很大的优势,不过它的IO编码范式么。。。刚开始是 回调——毁掉地狱,后来有了Promise——屏幕竖起来看,以及Generator——遇事不绝yield一下吧,到现在的Async/Await——语法糖?真香!

可以说JS的委员非常勤快,在异步编程范式的标准制定也做的很好(以前我尝试写NodeJS时,几个回调就直接把我劝退了),2009年诞生的NodeJS有点后来居上的意思。目前PHP只是赶上了协程,期待PHP的Async/Await语法糖的实现吧。

PHP yield 使用注意事项

一旦使用上 yield 后,就必须注意调用函数是,会得到函数结果,还是 生成器对象。PHP 不会自动帮你区别,需要你手动代码判断结果类型—— if ($re instanceof \Generator) {}, 如果你得到的是 生成器,但不希望去手动调用 current() 去执行它,那么在生成器前 使用 yield from 交给上游(框架)来解决。

爆改 Workerman

博客写到这,就开始手痒痒了,看到Workerman框架,我在基础上二开,使其能——同步编码,异步执行

代码已放到:PaulXu-cn/CoWorkerman.git

目前还是dev阶段,大家喜欢可以先 体验一波。

$ composer require paulxu-cn/co-workerman

一个简单的单线程 TCP Server

<?php
// file: ./examples/example2/coWorkermanServer.php , 详细代码见github
$worker = new CoWorker('tcp://0.0.0.0:8080');
// 设置fork一个子进程
$worker->count = 1;

$worker->onConnect = function (CoTcpConnection  $connection) {
    try {
        $conName = "{$connection->getRemoteIp()}:{$connection->getRemotePort()}";
        echo PHP_EOL . "New Connection, {$conName} \n";

        $re = yield from $connection->readAsync(1024);
        CoWorker::safeEcho('get request msg :' . $re . PHP_EOL );

        yield from CoTimer::sleepAsync(1000 * 2);

        $connection->send(json_encode(array('productId' => 12, 're' =>true)));

        CoWorker::safeEcho('Response to :' . $conName . PHP_EOL . PHP_EOL);
    } catch (ConnectionCloseException $e) {
        CoWorker::safeEcho('Connection closed, ' . $e->getMessage() . PHP_EOL);
    }
};

CoWorker::runAll();

这里设置fork 一个worker线程,处理逻辑中带有一个sleep()2s的操作,依然不影响他同时响应多个请求。

启动测试程序

## 启动CoWorker服务
$ php ./examples/example2/coWorkermanServer.php start

## 启动请求线程
$ php ./examples/example2/userClientFork.php

运行结果

WX20200619-212005@2x.png

绿色箭头——新的请求,红色箭头——响应请求

从结果上看到,这一个worker线程,在接收新的请求同时,还在回复之前的请求,各个连接交错运行。而我们的代码呢,看样子就是同步的,没有回调。

CoWorker购物车服务

好的,这里我们做几个简单的微服务模拟实际应用,这里模拟 用户请求端购物车服务库存服务产品服务。 模拟用户请求加购动作,购物车去分别请求 库存,产品 校验用户是否可以加购,并响应客户请求是否成功。

代码我就不贴了,太长了,麻烦移步 CoWorkerman/example/example5/coCartServer.php

运行命令

## 启动库存服务
$ php ./examples/example5/otherServerFork.php 8081 inventory 1
## 启动产品服务
$ php ./examples/example5/otherServerFork.php  8082 product 2
## 启动CoWorker 购物车服务
$ php ./examples/example5/coCartServer.php start
## 用户请求端
$ php ./examples/example5/userClientFork.php

运行结果

WX20200619-214858.png

黄色箭头——新的用户请求,蓝色箭头——购物车发起库存,产品检查请求,红色箭头——响应用户请求

从图中看到也是用1个线程服务多个连接,交错运行。

好的,那么PHP CoWorkerman 也能像 NodeJS 那样用 Async/Await 那样同步编码,异步运行了。

快来试试这个 CoWorkerman 吧:

$ composer require paulxu-cn/co-workerman

工作原理

先上图:

gaitubao_coworkerman图解.png

图的上部是Workerman 的工作泳道图,图下部是CoWorkerman的工作泳道图。

workerman内的worker进程遇到阻塞函数的处理方式时,会等待IO返回,如果这个时候,又有了新的请求,那么闲的worker会竞争到这个新的连接。

我在上图worker5中,描述了一个AsyncTCPConnection使用情况,woker内发起了一个非阻塞请求,并注册了回调函数,然后程序继续运行到结束。当异步请求响应时,就需要通过其他方式去响应(如自己再发起一个请求告知请求方)。

在下图中CoWorkerman,也是多个Worker竞争新的请求,当worker1收到一个新的请求,会产生一个生成器,生成器内发起异步请求,并注册响应回调,请求响应后,回到该生成器跳出(yield)的地方,继续执行代码。

发起异步请求,并注册回调函数,这些默认工作CoWorkerman框架内已做了,回调函数内工作是:收到数据,并发给 发起该请求的生成器。

这例子中,通过调用 Promise:all() 发起多个请求,并监听结果返回,待所有的响应返回再继续运行生成器

在程序yield跳出后,该worker就处于事件循环状态($event->loop()),也就是多路监听:请求端口,第三方客户端请求响应端口。这个时候如果:

  1. 有新的请求来,他和其他 worker 竞争新的请求,如果竞争到了,则该worker内又产生一个新的 生成器。
  2. 客户端有响应,则调用回调函数
  3. 客户端都响应了,继续运行 生成器程序。

从1中,我们可假设,如果就一个 Worker,那么该 Worker 可以在上一个请求未完成情况下,继续接受处理下一个请求。也就是 CoWorkerman 可以在单 Worker 下运行,并发处理多个请求。

当然,这里也有个前提,单 Worker 模式内不能运行阻塞函数,一旦阻塞,后续请求就会堵在网卡。所以,除非对自己的代码非常了解,如果用到第三方库,那么我还是建议你在多 Worker 模式下运行 CoWorkerman,阻塞时,还有其他Worker兜住新请求。

CoWorkerman 的意义

  1. 用同步的代码,发起异步请求,多个请求可并发,从IO串行等待,改为并行等待,减少无畏的等待时间。提高业务程序的效率同时,不降低代码可读性。
  2. 在一个线程内通过事件循环,尽可能处理多个请求,缓解了一个请求一个线程带来的频繁线程切换,从核心上提高运行效率。

CoWorkerman 生态位

适合处理纯Socket请求的应用,如Workerman Gateway,或者是 大前端 整合多个服务RPC结果, 综合后返给前三页这样的场景.

日志记录是每个程序最基本需求,由于写文件函数是阻塞的,建议用消息队列,或者redis队列,更或者跳过Logstash直接丢Elasticsearch.

CoWorkerman有他的局限性,也有他自己位置。

总结

好~PHP 协程编码到 网络异步编码就到此结束了,如果看到本文章有很多疑惑,欢迎留言提问,如果是 yield 语法不太记得,可以先读一读这个系列前几篇文章复习一下。

如果行,请三连。CoWorkerman 谢谢!

参考

查看原文

赞 22 收藏 16 评论 6

tusi 回答了问题 · 6月13日

解决mysql数据库字段设计问题

文章和博客,如果文章只有一个分类,则文章和分类是多对一关系。
表结构可以这样建立:

内容表

键名 类型 属性 解释
cid int(10) 主键,非负,自增 post表主键
mid int(9) 非负,可为空 与项目主键对应
title varchar(200) 可为空 内容标题
slug varchar(200) 索引,可为空 内容缩略名
created int(10) 索引,非负,可为空 内容生成时的GMT unix时间戳
modified int(10) 非负,可为空 内容更改时的GMT unix时间戳
text text 可为空 内容文字
order int(10) 非负,可为空 排序
authorId int(10) 非负,可为空 内容所属用户id
template varchar(32) 可为空 内容使用的模板
type varchar(16) 可为空 内容类别
status varchar(16) 可为空 内容状态
password varchar(32) 可为空 受保护内容,此字段对应内容保护密码
commentsNum int(10) 非负,可为空 内容所属评论数,冗余字段
allowComment char(1) 可为空 是否允许评论
allowPing char(1) 可为空 是否允许ping
allowFeed char(1) 可为空 允许出现在聚合中

项目表

键名 类型 属性 解释
mid int(10) 主键,非负 项目主键
name varchar(200) 可为空 名称
slug varchar(200) 索引,可为空 项目缩略名
type varchar(32) 可为空 项目类型
description varchar(200) 可为空 选项描述
count int(10) 非负,可为空 项目所属内容个数
order int(10) 非负,可为空 项目排序

文章和博客,如果文章有多个分类,则文章和分类是多对多关系。
表结构可以这样建立:

内容表

键名 类型 属性 解释
cid int(10) 主键,非负,自增 post表主键
title varchar(200) 可为空 内容标题
slug varchar(200) 索引,可为空 内容缩略名
created int(10) 索引,非负,可为空 内容生成时的GMT unix时间戳
modified int(10) 非负,可为空 内容更改时的GMT unix时间戳
text text 可为空 内容文字
order int(10) 非负,可为空 排序
authorId int(10) 非负,可为空 内容所属用户id
template varchar(32) 可为空 内容使用的模板
type varchar(16) 可为空 内容类别
status varchar(16) 可为空 内容状态
password varchar(32) 可为空 受保护内容,此字段对应内容保护密码
commentsNum int(10) 非负,可为空 内容所属评论数,冗余字段
allowComment char(1) 可为空 是否允许评论
allowPing char(1) 可为空 是否允许ping
allowFeed char(1) 可为空 允许出现在聚合中

内容-项目对应表

键名 类型 属性 解释
cid int(10) 主键,非负 内容主键
mid int(10) 主键,非负 项目主键

项目表

键名 类型 属性 解释
mid int(10) 主键,非负 项目主键
name varchar(200) 可为空 名称
slug varchar(200) 索引,可为空 项目缩略名
type varchar(32) 可为空 项目类型
description varchar(200) 可为空 选项描述
count int(10) 非负,可为空 项目所属内容个数
order int(10) 非负,可为空 项目排序

具体可参见typecho的数据库表结构设计:
http://docs.typecho.org/datab...

关注 3 回答 2

tusi 赞了文章 · 4月29日

Redis快速入门,学会这15点,真的够用了!

1、Redis简介

     REmote DIctionary Server(Redis)是一个由Salvatore Sanfilippo写的key-value存储系统。Redis是一个开源的使用ANSI C语言编写、遵守BSD协议、支持网络、可基于内存可持久化的日志型、Key-Value数据库,并提供多种语言的API。它通常被称为数据结构服务器,因为值(value)可以是 字符串(String), 哈希(Map), 列表(list), 集合(sets) 和 有序集合(sorted sets)等类型。

大家都知道了redis是基于key-value的no sql数据库,因此,先来了解一下关于key相关的知识点

1、任何二进制的序列都可以作为key使用
2、Redis有统一的规则来设计key
3、对key-value允许的最大长度是512MB

2、支持的语言

ActionScript Bash  C  C#  C++  Clojure Common LispCrystal  D  Dart  Elixir  emacs  lisp  Erlang  Fancy  gawk  GNU Prolog  Go  Haskell  Haxe  Io Java  Javascript  Julia  Lua  Matlab  mruby  Nim  Node.js  Objective-C  OCaml Pascal  Perl  PHP  Pure Data  Python  R  Racket  Rebol  Ruby  Rust Scala  Scheme  Smalltalk  Swift  Tcl  VB  VCL

3、Redis的应用场景到底有哪些??

1、最常用的就是会话缓存
2、消息队列,比如支付
3、活动排行榜或计数
4、发布、订阅消息(消息通知)
5、商品列表、评论列表

4、Redis安装

关于redis安装与相关的知识点介绍请参考 Nosql数据库服务之redis

安装的大概步骤如下:

Redis是c语言开发的,安装redis需要c语言的编译环境

如果没有gcc需要在线安装:yum install gcc-c++

第一步:获取源码包:wget http://download.redis.io/rele...

第二步:解压缩redis:tar zxvf redis-3.0.0.tar.gz

第三步:编译。进入redis源码目录(cd redis-3.0.0)。执行 make

第四步:安装。make install PREFIX=/usr/local/redis

PREFIX参数指定redis的安装目录

5、Redis数据类型

Redis一共支持五种数据类型

1、string(字符串)
2、hash(哈希)
3、list(列表)
4、set(集合)
5、zset(sorted set 有序集合)

string(字符串)
它是redis最基本的数据类型,一个key对应一个value,需要注意是一个键值最大存储512MB。

127.0.0.1:6379> set key "hello world"
OK
127.0.0.1:6379> get key
"hello world"
127.0.0.1:6379> getset key "nihao"
"hello world"
127.0.0.1:6379> mset key1 "hi" key2 "nihao" key3 "hello"
OK
127.0.0.1:6379> get key1
"hi"
127.0.0.1:6379> get key2
"nihao"
127.0.0.1:6379> get key3
"hello"
相关命令介绍
set 为一个Key设置value(值)
get 获得某个key对应的value(值)
getset 为一个Key设置value(值)并返回对应的值
mset 为多个key设置value(值)

hash(哈希)
redis hash是一个键值对的集合, 是一个string类型的field和value的映射表,适合用于存储对象

127.0.0.1:6379> hset redishash 1 "001"
(integer) 1
127.0.0.1:6379> hget redishash 1
"001"
127.0.0.1:6379> hmset redishash 1 "001" 2 "002"
OK
127.0.0.1:6379> hget redishash 1
"001"
127.0.0.1:6379> hget redishash 2
"002"
127.0.0.1:6379> hmget redishash 1 2
1) "001"
2) "002"
相关命令介绍
hset 将Key对应的hash中的field配置为value,如果hash不存则自动创建,
hget 获得某个hash中的field配置的值
hmset 批量配置同一个hash中的多个field值
hmget 批量获得同一个hash中的多个field值

list(列表)
是redis简单的字符串列表,它按插入顺序排序

127.0.0.1:6379> lpush word  hi
(integer) 1
127.0.0.1:6379> lpush word  hello
(integer) 2
127.0.0.1:6379> rpush word  world
(integer) 3
127.0.0.1:6379> lrange word 0 2
1) "hello"
2) "hi"
3) "world"
127.0.0.1:6379> llen word
(integer) 3
相关命令介绍
lpush 向指定的列表左侧插入元素,返回插入后列表的长度
rpush 向指定的列表右侧插入元素,返回插入后列表的长度
llen  返回指定列表的长度
lrange 返回指定列表中指定范围的元素值

set(集合)
是string类型的无序集合,也不可重复

127.0.0.1:6379> sadd redis redisset
(integer) 1
127.0.0.1:6379> sadd redis redisset1
(integer) 1
127.0.0.1:6379> sadd redis redisset2
(integer) 1
127.0.0.1:6379> smembers redis
1) "redisset1"
2) "redisset"
3) "redisset2"
127.0.0.1:6379> sadd redis redisset2
(integer) 0
127.0.0.1:6379> smembers redis
1) "redisset1"
2) "redisset"
3) "redisset2"
127.0.0.1:6379> smembers redis
1) "redisset1"
2) "redisset3"
3) "redisset"
4) "redisset2"
127.0.0.1:6379> srem redis redisset
(integer) 1
127.0.0.1:6379> smembers redis
1) "redisset1"
2) "redisset3"
3) "redisset2"
相关命令介绍
sadd 添加一个string元素到key对应的set集合中,成功返回1,如果元素存在返回0
smembers 返回指定的集合中所有的元素
srem 删除指定集合的某个元素

zset(sorted set 有序集合)
是string类型的有序集合,也不可重复
sorted set中的每个元素都需要指定一个分数,根据分数对元素进行升序排序,如果多个元素有相同的分数,则以字典序进行升序排序,sorted set 因此非常适合实现排名

127.0.0.1:6379> zadd nosql 0 001
(integer) 1
127.0.0.1:6379> zadd nosql 0 002
(integer) 1
127.0.0.1:6379> zadd nosql 0 003
(integer) 1
127.0.0.1:6379> zcount nosql 0 0 
(integer) 3
127.0.0.1:6379> zcount nosql 0 3
(integer) 3
127.0.0.1:6379> zrem nosql 002
(integer) 1
127.0.0.1:6379> zcount nosql 0 3
(integer) 2
127.0.0.1:6379> zscore nosql 003
"0"
127.0.0.1:6379> zrangebyscore nosql 0 10
1) "001"
2) "003"
127.0.0.1:6379> zadd nosql 1 003
(integer) 0
127.0.0.1:6379> zadd nosql 1 004
(integer) 1
127.0.0.1:6379> zrangebyscore nosql 0 10
1) "001"
2) "003"
3) "004"
127.0.0.1:6379> zadd nosql 3 005
(integer) 1
127.0.0.1:6379> zadd nosql 2 006
(integer) 1
127.0.0.1:6379> zrangebyscore nosql 0 10
1) "001"
2) "003"
3) "004"
4) "006"
5) "005"
相关命令介绍
zadd  向指定的sorteset中添加1个或多个元素
zrem  从指定的sorteset中删除1个或多个元素
zcount 查看指定的sorteset中指定分数范围内的元素数量
zscore 查看指定的sorteset中指定分数的元素
zrangebyscore 查看指定的sorteset中指定分数范围内的所有元素

6、键值相关的命令

127.0.0.1:6379> exists key
(integer) 1
127.0.0.1:6379> exists key1
(integer) 1
127.0.0.1:6379> exists key100
(integer) 0
127.0.0.1:6379> get key
"nihao,hello"
127.0.0.1:6379> get key1
"hi"
127.0.0.1:6379> del key1
(integer) 1
127.0.0.1:6379> get key1
(nil)
127.0.0.1:6379> rename key key0
OK
127.0.0.1:6379> get key(nil)
127.0.0.1:6379> get key0
"nihao,hello"
127.0.0.1:6379> type key0
string
exists       #确认key是否存在
del           #删除key
expire       #设置Key过期时间(单位秒)
persist     #移除Key过期时间的配置
rename     #重命名key
type         #返回值的类型

7、Redis服务相关的命令

127.0.0.1:6379> select 0
OK
127.0.0.1:6379> info
# Server
redis_version:3.0.6
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:347e3eeef5029f3
redis_mode:standalone
os:Linux 3.10.0-693.el7.x86_64 x86_64
arch_bits:64
multiplexing_api:epoll
gcc_version:4.8.5
process_id:31197
run_id:8b6ec6ad5035f5df0b94454e199511084ac6fb12
tcp_port:6379
uptime_in_seconds:8514
uptime_in_days:0
hz:10
lru_clock:14015928
config_file:/usr/local/redis/redis.conf
-------------------省略N行
127.0.0.1:6379> CONFIG GET 0
(empty list or set)
127.0.0.1:6379> CONFIG GET 15
(empty list or set)
slect           #选择数据库(数据库编号0-15)
quit             #退出连接
info             #获得服务的信息与统计
monitor       #实时监控
config get   #获得服务配置
flushdb       #删除当前选择的数据库中的key
flushall       #删除所有数据库中的key

8、Redis的发布与订阅

Redis发布与订阅(pub/sub)是它的一种消息通信模式,一方发送信息,一方接收信息。
下图是三个客户端同时订阅同一个频道

下图是有新信息发送给频道1时,就会将消息发送给订阅它的三个客户端

9、Redis事务

Redis事务可以一次执行多条命令

1、发送exec命令前放入队列缓存,结束事务
2、收到exec命令后执行事务操作,如果某一命令执行失败,其它命令仍可继续执行
3、一个事务执行的过程中,其它客户端提交的请求不会被插入到事务执行的命令列表中

一个事务经历三个阶段
  开始事务(命令:multi)
  命令执行
  结束事务(命令:exec)

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379> set key key1
QUEUED
127.0.0.1:6379> get key
QUEUED
127.0.0.1:6379> rename key key001
QUEUED
127.0.0.1:6379> exec
1) OK
2) "key1"
3) OK

10、Redis安全配置

可以通过修改配置文件设备密码参数来提高安全性

 #requirepass foobared

去掉注释#号就可以配置密码
没有配置密码的情况下查询如下

127.0.0.1:6379> CONFIG GET requirepass
1) "requirepass"
2) ""

配置密码之后,就需要进行认证

127.0.0.1:6379> CONFIG GET requirepass
(error) NOAUTH Authentication required.
127.0.0.1:6379> AUTH foobared 
#认证OK
127.0.0.1:6379> CONFIG GET requirepass
1) "requirepass"
2) "foobared"

11、Redis持久化

Redis持久有两种方式:Snapshotting(快照),Append-only file(AOF)

Snapshotting(快照)

1、将存储在内存的数据以快照的方式写入二进制文件中,如默认dump.rdb中
2、save 900 1 

#900秒内如果超过1个Key被修改,则启动快照保存
3、save 300 10 

#300秒内如果超过10个Key被修改,则启动快照保存
4、save 60 10000 

#60秒内如果超过10000个Key被修改,则启动快照保存

Append-only file(AOF)

1、使用AOF持久时,服务会将每个收到的写命令通过write函数追加到文件中(appendonly.aof)
2、AOF持久化存储方式参数说明
   appendonly yes  

#开启AOF持久化存储方式
    appendfsync always 

#收到写命令后就立即写入磁盘,效率最差,效果最好
    appendfsync everysec

 #每秒写入磁盘一次,效率与效果居中
    appendfsync no 

#完全依赖OS,效率最佳,效果没法保证

12、Redis 性能测试

自带相关测试工具

[root@test ~]# redis-benchmark --help

Usage: redis-benchmark [-h <host>] [-p <port>] [-c <clients>] [-n <requests]> [-k <boolean>] 

-h <hostname>      Server hostname (default 127.0.0.1) 
-p <port>          Server port (default 6379) 
-s <socket>        Server socket (overrides host and port) -a <password>      Password for Redis Auth 
-c <clients>       Number of parallel connections (default 50) 
-n <requests>      Total number of requests (default 100000) 
-d <size>          Data size of SET/GET value in bytes (default 2) 
-dbnum <db>        SELECT the specified db number (default 0) 
-k <boolean>       1=keep alive 0=reconnect (default 1) 
-r <keyspacelen>   Use random keys for SET/GET/INCR, random values for SADD  Using this option the benchmark will expand the string __rand_int__  inside an argument with a 12 digits number in the specified range  from 0 to keyspacelen-1. The substitution changes every time a command  is executed. Default tests use this to hit random keys in the  specified range. 
-P <numreq>        Pipeline <numreq> requests. Default 1 (no pipeline). 
-q                 Quiet. Just show query/sec values --csv              Output in CSV format 
-l                 Loop. Run the tests forever 
-t <tests>         Only run the comma separated list of tests. The test                    names are the same as the ones produced as output. 
-I                 Idle mode. Just open N idle connections and wait.

Examples: 

Run the benchmark with the default configuration against 127.0.0.1:6379:   
$ redis-benchmark

Use 20 parallel clients, for a total of 100k requests, against 192.168.1.1:   
$ redis-benchmark -h 192.168.1.1 -p 6379 -n 100000 -c 20 

Fill 127.0.0.1:6379 with about 1 million keys only using the SET test:   
$ redis-benchmark -t set -n 1000000 -r 100000000 

Benchmark 127.0.0.1:6379 for a few commands producing CSV output:   
$ redis-benchmark -t ping,set,get -n 100000 --csv 

Benchmark a specific command line:   
$ redis-benchmark -r 10000 -n 10000 eval 'return redis.call("ping")' 0 

Fill a list with 10000 random elements:   
$ redis-benchmark -r 10000 -n 10000 lpush mylist __rand_int__ 

On user specified command lines __rand_int__ is replaced with a random integer with a range of values selected by the -r option.

实际测试同时执行100万的请求

[root@test ~]# redis-benchmark -n 1000000 -q
PING_INLINE: 152578.58 requests per second
PING_BULK: 150308.14 requests per second
SET: 143266.47 requests per second
GET: 148632.58 requests per second
INCR: 145857.64 requests per second
LPUSH: 143781.45 requests per second
LPOP: 147819.66 requests per second
SADD: 138350.86 requests per second
SPOP: 134282.27 requests per second
LPUSH (needed to benchmark LRANGE): 141302.81 requests per second
LRANGE_100 (first 100 elements): 146756.67 requests per second
LRANGE_300 (first 300 elements): 148104.27 requests per second
LRANGE_500 (first 450 elements): 152671.75 requests per second
LRANGE_600 (first 600 elements): 148104.27 requests per second
MSET (10 keys): 132731.62 requests per second

13、Redis的备份与恢复

Redis自动备份有两种方式
第一种是通过dump.rdb文件实现备份
第二种使用aof文件实现自动备份

dump.rdb备份
Redis服务默认的自动文件备份方式(AOF没有开启的情况下),在服务启动时,就会自动从dump.rdb文件中去加载数据。
**具体配置在redis.conf
save 900 1
save 300 10
save 60 10000**
也可以手工执行save命令实现手动备份

127.0.0.1:6379> set name key
OK
127.0.0.1:6379> SAVE
OK
127.0.0.1:6379> set name key1
OK
127.0.0.1:6379> BGSAVE
Background saving started

redis快照到dump文件时,会自动生成dump.rdb的文件

# The filename where to dump the DB
dbfilename dump.rdb
-rw-r--r-- 1 root root   253 Apr 17 20:17 dump.rdb

SAVE命令表示使用主进程将当前数据库快照到dump文件
BGSAVE命令表示,主进程会fork一个子进程来进行快照备份
两种备份不同之处,前者会阻塞主进程,后者不会。

恢复举例

# Note that you must specify a directory here, not a file name.dir 
/usr/local/redisdata/
#备份文件存储路径
127.0.0.1:6379> CONFIG GET dir
1) "dir"
2) "/usr/local/redisdata"
127.0.0.1:6379> set key 001
OK
127.0.0.1:6379> set key1 002
OK
127.0.0.1:6379> set key2 003
OK
127.0.0.1:6379> save
OK

将备份文件备份到其它目录

[root@test ~]# ll /usr/local/redisdata/
total 4
-rw-r--r-- 1 root root 49 Apr 17 21:24 dump.rdb

[root@test ~]# date
Tue Apr 17 21:25:38 CST 2018
[root@test ~]# cp ./dump.rdb /tmp/

删除数据

127.0.0.1:6379> del key1
(integer) 1
127.0.0.1:6379> get key1
(nil)

关闭服务,将原备份文件拷贝回save备份目录

[root@test ~]# redis-cli -a foobared shutdown
[root@test ~]# lsof -i :6379
[root@test ~]# cp /tmp/dump.rdb /usr/local/redisdata/
cp: overwrite ‘/usr/local/redisdata/dump.rdb’? y
[root@test ~]# redis-server /usr/local/redis/redis.conf &
[1] 31487

登录查看数据是否恢复

[root@test ~]# redis-cli -a foobared
127.0.0.1:6379> mget key key1 key2
1) "001"
2) "002"
3) "003"

AOF自动备份
redis服务默认是关闭此项配置

###### APPEND ONLY MODE ##########
appendonly no

# The name of the append only file (default: "appendonly.aof")
appendfilename "appendonly.aof"

# appendfsync always
appendfsync everysec

# appendfsync no

配置文件的相关参数,前面已经详细介绍过。
AOF文件备份,是备份所有的历史记录以及执行过的命令,和mysql binlog很相似,在恢复时就是重新执次一次之前执行的命令,需要注意的就是在恢复之前,和数据库恢复一样需要手工删除执行过的del或误操作的命令。

AOF与dump备份不同
1、aof文件备份与dump文件备份不同
2、服务读取文件的优先顺序不同,会按照以下优先级进行启动
   如果只配置AOF,重启时加载AOF文件恢复数据
    如果同时 配置了RBD和AOF,启动是只加载AOF文件恢复数据
    如果只配置RBD,启动时将加载dump文件恢复数据

注意:只要配置了aof,但是没有aof文件,这个时候启动的数据库会是空的

14、Redis 生产优化介绍

1、内存管理优化 

hash-max-ziplist-entries 512  
 hash-max-ziplist-value 64  
 list-max-ziplist-entries 512  
 list-max-ziplist-value 64
 #list的成员与值都不太大的时候会采用紧凑格式来存储,相对内存开销也较小
在linux环境运行Redis时,如果系统的内存比较小,这个时候自动备份会有可能失败,需要修改系统的vm.overcommit_memory 参数,这个参数是linux系统的内存分配策略
   0 表示内核将检查是否有足够的可用内存供应用进程使用;如果有足够的可用内存,内存申请允许;否则,内存申请失败,并把错误返回给应用进程。
    1 表示内核允许分配所有的物理内存,而不管当前的内存状态如何。
    2 表示内核允许分配超过所有物理内存和交换空间总和的内存
 Redis官方的说明是,建议将vm.overcommit_memory的值修改为1,可以用下面几种方式进行修改:
(1)编辑/etc/sysctl.conf 改vm.overcommit_memory=1,然后sysctl -p 使配置文件生效
(2)sysctl vm.overcommit_memory=1
 (3)echo 1 > /proc/sys/vm/overcommit_memory

**2、内存预分配
3、持久化机制**
   定时快照:效率不高,会丢失数据
    AOF:保持数据完整性(一个实例的数量不要太大2G最大)

优化总结
1)根据业务需要选择合适的数据类型
2)当业务场景不需持久化时就关闭所有持久化方式(采用ssd磁盘来提升效率)
3)不要使用虚拟内存的方式,每秒实时写入AOF
4)不要让REDIS所在的服务器物理内存使用超过内存总量的3/5
5)要使用maxmemory
6)大数据量按业务分开使用多个redis实例

15、Redis集群应用

集群是将多个redis实例集中在一起,实现同一业务需求,或者实现高可用与负载均衡

到底有哪些集群方案呢??
1、haproxy+keepalived+redis集群

1)通过redis的配置文件,实现主从复制、读写分离
2)通过haproxy的配置,实现负载均衡,当从故障时也会及时从集群中T除
3)利用keepalived来实现负载的高可用

2、redis官方Sentinel集群管理工具

Redis集群生产环境高可用方案实战过程

1)sentinel负责对集群中的主从服务监控、提醒和自动故障转移
2)redis集群负责对外提供服务
关于redis sentinel cluster集群配置可参考

3、Redis Cluster
Redis Cluster是Redis的分布式解决方案,在Redis 3.0版本正式推出的,有效解决了Redis分布式方面的需求。当遇到单机内存、并发、流量等瓶颈时,可以采用Cluster架构达到负载均衡的目的。

1)官方推荐,毋庸置疑。
2)去中心化,集群最大可增加1000个节点,性能随节点增加而线性扩展。
3)管理方便,后续可自行增加或摘除节点,移动分槽等等。
4)简单,易上手。

查看原文

赞 83 收藏 58 评论 0

tusi 赞了文章 · 4月3日

为避免政治风险,开源指令集 RISC-V 基金会总部正式迁移至瑞士

图片描述

据 RISC-V 基金会首席执行官卡利斯塔·雷德蒙德(Calista Redmond)近日发布的会员内部邮件表示,RISC-V 基金会已从美国本土正式迁移至瑞士。

在去年 12 月路透社的一次采访中,Redmond 就曾提及计划将RISC-V基金会迁至中立国瑞士,以确保美国之外的大学、政府及公司可以使用开源的 RISC-V,而不会受到政治因素的影响。此次正式迁移,表示基金会的法律实体已经过渡到瑞士,并不再续签美国基金会的会员资格。到2020年9月1日,基金会会将美国的基金会实体转变为一个非会员组织。同时将单独联系哪些尚未转为瑞士基金会组织会员的剩余会员。

而此次的正式迁址,对于 RISC-V 整个生态体系意义重大,将对RISC-V全球化的持续发展产生深远的影响。对于国内的企业来说,也是重大的利好,这就意味着,采用开源RISC-V指令集、开源软件和公开标准进行开发将没有后顾之忧。


RISC-V 是一个基于精简指令集原则的开源指令集架构(ISA),首次出现于加州大学伯克利分校,后经志愿者和行业工作者的贡献,才得以持续发展。RISC-V 基于小型、快速、低功耗等现实情况设计,而且其设计者也并没有对特定的微架构进行过度的设计。

RISC-V基金会是一家由其会员控制的非营利性组织,负责指导未来的发展并推动RISC-V 指令集的采用。RISC-V基金会的成员可以得到并参与RISC-V 指令集规范和相关软硬件生态系统的开发。基金会的董事会由来自Bluespec、谷歌、Microsemi、 NVIDIA、NXP、加州大学伯克利分校和西部数据的七名代表组成。

此外,华为也是基金会的成员之一,在去年12月路透社对于RISC-V迁移的采访中华为发言人表示:“我们支持RISC-V基金会,将瑞士确定为开源开发的中立场所。对业界来说,使开源尽可能开放是重要的。”他说,RISC-V“很适合华为关于这个异构开放世界的愿景。”

2019 年 6 月,图灵奖得主、RISC-V 基金会创始人之一大卫·帕特森(David Patterson)在瑞士宣布,将依托清华-伯克利深圳学院(TBSI),在内部建设 RISC-V 国际开源实验室(RISC-V International Open Source Laboratory),又称大卫帕特森 RIOS 图灵实验室。清华大学在发布会中称实验室将瞄准世界 CPU 产业战略发展新方向和粤港澳大湾区产业创新需求,聚焦于开源指令集 CPU 研究,建设以深圳为根节点的 RISC-V 全球创新网络和以技术成果转移为主要使命的非营利组织,全面提升 RISC-V 生态系至最先进可商用水平。

clipboard.png

查看原文

赞 7 收藏 0 评论 0

tusi 赞了文章 · 3月24日

神秘的.user.ini文件

神秘的.user.ini文件

.user.ini究竟是个神秘东东?

我们看看官方怎么说:

http://php.net/manual/zh/conf...

自 PHP 5.3.0 起,PHP 支持基于每个目录的 .htaccess 风格的 INI 文件。此类文件仅被 CGI/FastCGI SAPI 处理。此功能使得 PECL 的 htscanner 扩展作废。如果使用 Apache,则用 .htaccess 文件有同样效果。

小白表示没看懂~

众所周知,php.ini是php的核心配置文件,在 PHP 启动时被读取,那么web目录的其他ini文件也是可以被php识别,官方还说了

除了主 php.ini 之外,PHP 还会在每个目录下扫描 INI 文件,从被执行的 PHP 文件所在目录开始一直上升到 web 根目录($_SERVER['DOCUMENT_ROOT'] 所指定的)。如果被执行的 PHP 文件在 web 根目录之外,则只扫描该目录。

这样说的话,所有的配置都可以被.user.ini重新配置修改?噢,麦噶的

你想多了,官方还说了:

在 .user.ini 风格的 INI 文件中只有具有 PHP_INI_PERDIRPHP_INI_USER 模式的 INI 设置可被识别。

小白,又举手了,什么是PHP_INI_*模式呢?

官方是这样说的:

配置可被指定的范围(http://php.net/manual/zh/conf...

这些模式决定着一个 PHP 的指令在何时何地,是否能够被设定。手册中的每个指令都有其所属的模式。例如有些指令可以在 PHP 脚本中用 ini_set() 来设定,而有些则只能在 php.ini 或 httpd.conf 中。

例如 output_buffering 指令是属于 PHP_INI_PERDIR,因而就不能用 ini_set() 来设定。但是 display_errors 指令是属于 PHP_INI_ALL 因而就可以在任何地方被设定,包括 ini_set()

PHP_INI_*模式的定义

模式    含义
PHP_INI_USER    可在用户脚本(例如 ini_set())或 Windows 注册表(自 PHP 5.3 起)以及 .user.ini 中设定
PHP_INI_PERDIR    可在 php.ini,.htaccess 或 httpd.conf 中设定
PHP_INI_SYSTEM    可在 php.ini 或 httpd.conf 中设定
PHP_INI_ALL    可在任何地方设定

也就是说只有PHP_INI_USER模式,才可以在 .user.ini 中设定,那么哪些配置可以在 .user.ini 中设定呢?

php.ini配置选项列表(http://php.net/manual/zh/ini....

有点意思,并不是所有的配置 .user.ini 都能修改,比如 disable_functionsupload_max_filesize

千年未解之谜,是不是在这里找到了答案?

  • 访问php页面出现“No input file specified”,尝试各种办法(https://jingyan.baidu.com/art... ) 无果,你是否开始怀疑自己人品,是否开始怀疑肾亏了,是否觉得自己这么年轻就不行了?

    绝望中,你是否发现你的网站目录中有个叫 .user.ini 的文件,一气之下,决定删了它,哦,没错,是个办法。
  • 啥? .user.ini 删不掉,是不是觉得自己真的不行了?

    [root@Tech1024]# rm -rf .user.ini 
    rm: cannot remove ‘.user.ini’: Operation not permitted

    来看一下,该文件的属性

    [root@Tech1024]# lsattr .user.ini 
    ----i--------e-- .user.ini

    没错,文件被锁定了,不能修改,那么我们去除文件锁定属性

    [root@Tech1024]# chattr -i .user.ini

    是不是可以删除了,你是不是喜极而泣,啊,自己终于又行了。

  • 哎,小白可能觉得自己又不行了,怎么还是“No input file specified”啊?

    年轻人,别着急,看看官方吧(http://php.net/manual/zh/conf... )。

    user_ini.cache_ttl 控制着重新读取用户 INI 文件的间隔时间。默认是 300 秒(5 分钟)。

    ……

    5分钟艰难的过去了,你是否再一次喜极而泣:哎,自己终究还是行了。

.user.ini有什么用呢?

好奇请猛戳 https://lnmp.org/faq/lnmp-vho...

最后

作为一个IT职业人,不论从事什么行业,铭记两点 技术和态度,技术决定了你的存在,态度决定了你能存在多久。

原文 http://tech1024.com/original/...
查看原文

赞 20 收藏 17 评论 9

tusi 赞了文章 · 3月23日

docker 安装部署 redis(配置文件启动)

安装 docker

[修订]docker 已分为 ce/ee 直接yum版本较低 请使用下方安装最新版

docker-ce yum 安装:https://www.cnblogs.com/Peter...(转)或使用 daocloud 安装:http://get.daocloud.io/#insta...

# 2019-1-24 注明:
#安装 docker
yum install docker -y

systemctl start docker.service

获取 redis 镜像

docker search redis

docker pull redis:latest

docker images

创建容器

创建宿主机 redis 容器的数据和配置文件目录

# 这里我们在 /home/docker 下创建
mkdir /home/docker/redis/{conf,data} -p
cd /home/docker/redis

获取 redis 的默认配置模版

# 获取 redis 的默认配置模版
# 这里主要是想设置下 redis 的 log / password / appendonly
# redis 的 docker 运行参数提供了 --appendonly yes 但没 password
wget https://raw.githubusercontent.com/antirez/redis/4.0/redis.conf -O conf/redis.conf

# 直接替换编辑
sed -i 's/logfile ""/logfile "access.log"/' conf/redis.conf
sed -i 's/# requirepass foobared/requirepass 123456/' conf/redis.conf
sed -i 's/appendonly no/appendonly yes/' conf/redis.conf

# 这里可能还需配置一些 bind protected-mode

protected-mode 是在没有显示定义 bind 地址(即监听全网断),又没有设置密码 requirepass
时,protected-mode 只允许本地回环 127.0.0.1 访问。
也就是说当开启了 protected-mode 时,如果你既没有显示的定义了 bind 监听的地址,同时又没有设置 auth 密码。那你只能通过 127.0.0.1 来访问 redis 服务。

创建并运行一个名为 myredis 的容器

# 创建并运行一个名为 myredis 的容器
docker run \
-p 6379:6379 \
-v $PWD/data:/data \
-v $PWD/conf/redis.conf:/etc/redis/redis.conf \
--privileged=true \
--name myredis \
-d redis redis-server /etc/redis/redis.conf

# 命令分解
docker run \
-p 6379:6379 \ # 端口映射 宿主机:容器
-v $PWD/data:/data:rw \ # 映射数据目录 rw 为读写
-v $PWD/conf/redis.conf:/etc/redis/redis.conf:ro \ # 挂载配置文件 ro 为readonly
--privileged=true \ # 给与一些权限
--name myredis \ # 给容器起个名字
-d redis redis-server /etc/redis/redis.conf # deamon 运行容器 并使用配置文件启动容器内的 redis-server 

查看活跃的容器

# 查看活跃的容器
docker ps
# 如果没有 myredis 说明启动失败 查看错误日志
docker logs myredis
# 查看 myredis 的 ip 挂载 端口映射等信息
docker inspect myredis
# 查看 myredis 的端口映射
docker port myredis

外部访问 redis 容器服务

# redis-cli 访问
docker run -it --link myredis:redis --rm redis redis-cli -h redis -p 6379
# -it 交互的虚拟终端
# --rm 退出是删除此容器

或者使用 shell 登录容器内操作

docker exec -it myredis bash
redis-cli

配置完成

主从配置

新建容器 redis-slave
查看 redis master 的内部 ip

docker inspect redis #Networks
可以得到 redis master 的 ip 地址
"NetworkSettings": {
            "Ports": {
                "6379/tcp": [
                    {
                        "HostIp": "0.0.0.0",
                        "HostPort": "6379"
                    }
                ]
            },
            ...
            "Gateway": "192.168.0.1",
            ...
            "IPAddress": "192.168.0.3",#ip
            ...
            "Networks": {
                "bridge": {
                    ...
                    "Gateway": "192.168.0.1",
                    "IPAddress": "192.168.0.3",#ip
                    ...
                }
            }
        }


修改 redis-slave 的配置文件
# 主地址
slaveof master-ip master-port
# 主认证
masterauth

重启 redis-slave

docker restart redis-slave

登录 redis master 使用 info 命令查看从的状态

如果配置不成功记得检查 redis master 的 bind 和 protected-mode 的设置,看下有没有监听内网地址,否则 redis-slave 没办法通过 redis master 的地址做数据同步

查看原文

赞 16 收藏 13 评论 10

tusi 发布了文章 · 3月15日

开启和禁用hyper-v

Hyper-V会和Vmware,VirtualBox产生冲突,hyper-v和Vmware等只能开启一个。使用vmware产品时必须禁用hyper-v,使用hyper-v时必须开启hyper-v,否则在bios里已经启用了虚拟硬件并开启了hyper-v组件启动Docker时也会提示:Hardware assisted virtualization and data execution protection must be enabled in the BIOS

禁掉 Hyper-V

管理员模式运行 CMD:

//To disable:
bcdedit /set hypervisorlaunchtype off

开启Hyper-V

//To enable:
bcdedit /set hypervisorlaunchtype auto

附赠一条开启hyper-v组件的命令(需管理员模式下运行CMD或POWERSHELL):

dism.exe /Online /Enable-Feature:Microsoft-Hyper-V /All

参考文章
docker desktop : Hardware assisted virtualization and data execution protection must be enabled
如何 禁掉 Hyper-V && 如何解决禁不掉 Hyper-V 的问题

查看原文

赞 0 收藏 0 评论 0

tusi 发布了文章 · 3月6日

Linux 正确设置站点权限

目的:为了保证网站不遭受木马入侵上传及修改文件。
相对安全的权限

1、站点内所有目录和文件的用户和组都应该是root 
2、所有目录权限默认的755 
3、所有文件权限默认的644 (不能改文件)
4、对于缓存目录,上传目录,把目录权限所有者、所有组改为nginx。

1+2实现,网站服务用户(nginx)不能往目录里面写文件,即nginx用户就不能在里面写文件了,木马就杜绝了。
注意:网站服务的程序使用的用户不能用root,可以用nginx

对于上传目录这样优化根优雅:

1、动态web集群只负责:帖子和博文的发布和存取,上传后直接跳转到上传的服务器,上传服务器把图片文件放到存储服务器
2、文件上传到对象存储,如七牛云,阿里云的。

参考文档:
Linux基础_网站权限规划
Linux 正确设置站点权限
Linux Web站点目录以及文件的安全权限设置

查看原文

赞 0 收藏 0 评论 0

tusi 提出了问题 · 3月4日

tp3的应用部署了负载均衡服务,index.php后带路由访问报错502

我使用宝塔的负载均衡插件搭建了负载均衡服务,运用服务器只有一台。
这样访问会报错502:
https://www.examp.com/index.p...
这样访问正常:
https://www.examp.com/server/

应用后台生成的url都会带上index.php文件,请问这是负载均衡服务器部署有问题,还是代码的问题呢?

关注 3 回答 1

认证与成就

  • 获得 17 次点赞
  • 获得 12 枚徽章 获得 0 枚金徽章, 获得 1 枚银徽章, 获得 11 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2017-05-06
个人主页被 562 人浏览