早上在centos7 上安装comporser 怎么都装不上 常规方法会报如下错误
Failed to decode zlib stream
最后是下载了https://getcomposer.org/composer.phar
然后设置全局就可以了
mv composer.phar /usr/local/bin/composer

去芜存菁
早上在centos7 上安装comporser 怎么都装不上 常规方法会报如下错误
Failed to decode zlib stream
最后是下载了https://getcomposer.org/composer.phar
然后设置全局就可以了
mv composer.phar /usr/local/bin/composer

1、(先进入项目文件夹)通过命令 git init 把这个目录变成git可以管理的仓库
git init
2、把文件添加到版本库中,使用命令 git add .添加到暂存区里面去,不要忘记后面的小数点“.”,意为添加文件夹下的所有文件
git add .
3、用命令 git commit告诉Git,把文件提交到仓库。引号内为提交说明
git commit -m 'first commit'
4、关联到远程库
git remote add origin 你的远程库地址
如:
git remote add origin https://github.com/cade8800/ionic-demo.git
5、获取远程库与本地同步合并(如果远程库不为空必须做这一步,否则后面的提交会失败)
git pull --rebase origin master
6、把本地库的内容推送到远程,使用 git push命令,实际上是把当前分支master推送到远程。执行此命令后会要求输入用户名、密码,验证通过后即开始上传。
git push -u origin master
*、状态查询命令
git status
备:详细请参考 http://www.cnblogs.com/tugenhua0707/p/4050072.html
这个问题我之前一直在思考
学习angular的过程中都是把angular视为一个完整的前端存在
也就是脱离了后端的独立存在
在代码里不去插入动态语言
在前端完成数据的存储,通信,绑定,修改
与后端可以用http协议交互,像app一样只做展示的前端操作
angular2通过ng server创建http服务
我想要把angular2结合laravel5一起使用
开始我觉得是不是angular2就像上面说的那样还是通过ng server创建服务
运行在4200端口 然后nginx反向代理到4200端口访问angular
然后angular通过http协议与laravel后端通信
google了之后发现使用angular2的开发模式(development mode)可以直接使用
而之前ng server只是单独为了让程序跑起来提供的一个服务
如今又laravel了 就可以不用创建那个服务 直接在这个上面跑
哎 还是基础不好思维有限 慢慢补吧
让我们开始吧!首先要安装基础laravel应用

我们需要获取angular2和typescript源码
在新创建的文件夹(larangular)中可以看到package.json文件
修改
{
"private": true,
"scripts": {
"dev": "npm run development",
"development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
"watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
"watch-poll": "npm run watch -- --watch-poll",
"hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
"prod": "npm run production",
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
},
"devDependencies": {
"axios": "^0.15.3",
"bootstrap-sass": "^3.3.7",
"cross-env": "^3.2.3",
"jquery": "^3.1.1",
"laravel-mix": "0.*",
"lodash": "^4.17.4",
"vue": "^2.1.10",
"concurrently": "^1.0.0",
"del": "^2.2.0",
"gulp": "^3.8.8"
},
"dependencies": {
"angular2": "2.0.0-beta.0",
"bootstrap-sass": "^3.0.0",
"elixir-typescript": "^1.1.2",
"es6-promise": "^3.0.2",
"es6-shim": "^0.33.3",
"laravel-elixir": "^4.0.0",
"reflect-metadata": "0.1.2",
"rxjs": "5.0.0-beta.0",
"systemjs": "0.19.6",
"zone.js": "0.5.10"
}
}
现在执行npm install,所需要的文件将被下载到node_modules文件夹

完成之后,我们要添加Typescript在laravel项目的resouce/assets目录
在这个文件夹里我们要创建2个文件app.component.ts 和 boot.ts
import {Component} from 'angular2/core';
@Component({
selector: 'my-app',
template: '<h1>My First Angular 2 App</h1>'
})
export class AppComponent { }
import {bootstrap} from 'angular2/platform/browser'
import {AppComponent} from './app.component'
bootstrap(AppComponent);
下面我们需要编写一个简单的Elixir task来完成Typescript
在主文件夹中创建gulpfile.js
var elixir = require('laravel-elixir');
var elixirTypscript = require('elixir-typescript');
/*
|--------------------------------------------------------------------------
| Elixir Asset Management
|--------------------------------------------------------------------------
|
| Elixir provides a clean, fluent API for defining some basic Gulp tasks
| for your Laravel application. By default, we are compiling the Sass
| file for our application, as well as publishing vendor resources.
|
*/
elixir(function(mix) {
mix.sass('app.scss');
mix.copy('node_modules/angular2', 'public/angular2');
mix.copy('node_modules/rxjs', 'public/rxjs');
mix.copy('node_modules/systemjs', 'public/systemjs');
mix.copy('node_modules/es6-promise', 'public/es6-promise');
mix.copy('node_modules/es6-shim', 'public/es6-shim');
mix.copy('node_modules/zone.js', 'public/zone.js');
mix.typescript('app.js','public/','/**/*.ts',{
"target": "ES5",
"module": "system",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"removeComments": false,
"noImplicitAny": false,
});
});
然后安装gulp

修改如下文件 node_modules/elixir_typescript/index.js
new Task(pluginName, function () {
var tsResult = gulp.src(assetPath + search)
.pipe(ts(options, undefined, _laravelReporter.ElixirMessage()));
return tsResult
// .pipe(concat(outputFileName))
.pipe(gulp.dest(outputFolder));
})
如果不修改会出现下面的错误

现在在程序根目录下执行gulp

全部执行完成
修改views
<!doctype html>
<html lang="{{ config('app.locale') }}">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Laravel</title>
<!-- Fonts -->
<link href="https://fonts.googleapis.com/css?family=Raleway:100,600" rel="stylesheet" type="text/css">
<!-- Styles -->
<style>
html, body {
background-color: #fff;
color: #636b6f;
font-family: 'Raleway', sans-serif;
font-weight: 100;
height: 100vh;
margin: 0;
}
.full-height {
height: 100vh;
}
.flex-center {
align-items: center;
display: flex;
justify-content: center;
}
.position-ref {
position: relative;
}
.top-right {
position: absolute;
right: 10px;
top: 18px;
}
.content {
text-align: center;
}
.title {
font-size: 84px;
}
.links > a {
color: #636b6f;
padding: 0 25px;
font-size: 12px;
font-weight: 600;
letter-spacing: .1rem;
text-decoration: none;
text-transform: uppercase;
}
.m-b-md {
margin-bottom: 30px;
}
</style>
<script src="es6-shim/es6-shim.min.js"></script>
<script src="systemjs/dist/system-polyfills.js"></script>
<script src="angular2/bundles/angular2-polyfills.js"></script>
<script src="systemjs/dist/system.src.js"></script>
<script src="rxjs/bundles/Rx.js"></script>
<script src="angular2/bundles/angular2.dev.js"></script>
<script>
System.config({
"defaultJSExtensions": true,
packages: {
app: {
format: 'register',
defaultExtension: 'js'
}
}
});
System.import('typescript/boot')
.then(null, console.error.bind(console));
</script>
</head>
<body>
<div class="flex-center position-ref full-height">
@if (Route::has('login'))
<div class="top-right links">
@if (Auth::check())
<a href="{{ url('/home') }}">Home</a>
@else
<a href="{{ url('/login') }}">Login</a>
<a href="{{ url('/register') }}">Register</a>
@endif
</div>
@endif
<div>
<div class="title m-b-md">
Laravel
</div>
<my-app>Loading...</my-app>
<div>
<a href="https://laravel.com/docs">Documentation</a>
<a href="https://laracasts.com">Laracasts</a>
<a href="https://laravel-news.com">News</a>
<a href="https://forge.laravel.com">Forge</a>
<a href="https://github.com/laravel/laravel">GitHub</a>
</div>
</div>
</div>
</body>
</html>
成功了!!!

我把它放在了这里
https://git.oschina.net/iamleokim/larangular.git
ng2-admin\src\index.html
通过<app></app>作为容器
<body> <app> </app> <div id="preloader"> <div></div> </div> </body>
ng2-admin\src\app\app.routing.ts
可以看到这里用的是HashLocationStrategy(路由策略)
export const routes: Routes = [
{ path: '', redirectTo: 'pages', pathMatch: 'full' },
{ path: '**', redirectTo: 'pages/dashboard' }
];
export const routing: ModuleWithProviders = RouterModule.forRoot(routes, { useHash: true });
ng2-admin\src\app\app.component.ts
Conponent 的 selector选择‘app’
template 里写了外层div class=“addtional-bg”
设置子路由 router-outlet
@Component({
selector: 'app',
styleUrls: ['./app.component.scss'],
template: `
<main [class.menu-collapsed]="isMenuCollapsed" baThemeRun>
<div class="additional-bg"></div>
<router-outlet></router-outlet>
</main>
`
})
ng2-admin\src\app\pages\pages.routing.ts
export const routes: Routes = [
{
path: 'login',
loadChildren: 'app/pages/login/login.module#LoginModule'
},
{
path: 'register',
loadChildren: 'app/pages/register/register.module#RegisterModule'
},
{
path: 'pages',
component: Pages,
children: [
{ path: '', redirectTo: 'dashboard', pathMatch: 'full' },
{ path: 'dashboard', loadChildren: './dashboard/dashboard.module#DashboardModule' },
{ path: 'editors', loadChildren: './editors/editors.module#EditorsModule' },
{ path: 'components', loadChildren: './components/components.module#ComponentsModule' },
{ path: 'charts', loadChildren: './charts/charts.module#ChartsModule' },
{ path: 'ui', loadChildren: './ui/ui.module#UiModule' },
{ path: 'forms', loadChildren: './forms/forms.module#FormsModule' },
{ path: 'tables', loadChildren: './tables/tables.module#TablesModule' },
{ path: 'maps', loadChildren: './maps/maps.module#MapsModule' }
]
}
];
为了更加形象的说明同步异步、阻塞非阻塞,我们以小明去买奶茶为例。
同步与异步的重点在消息通知的方式上,也就是调用结果通知的方式。
同步当一个同步调用发出去后,调用者要一直等待调用结果的通知后,才能进行后续的执行
异步:当一个异步调用发出去后,调用者不能立即得到调用结果的返回。
异步调用,要想获得结果,一般有两种方式:
1、主动轮询异步调用的结果;
2、被调用方通过callback来通知调用方调用结果。
同步买奶茶:小明点单交钱,然后等着拿奶茶;异步买奶茶:小明点单交钱,店员给小明一个小票,等小明奶茶做好了,再来取。
异步买奶茶,小明要想知道奶茶是否做好了,有两种方式:
1、小明主动去问店员,一会就去问一下:“奶茶做好了吗?”…直到奶茶做好。
2、等奶茶做好了,店员喊一声:“小明,奶茶好了!”,然后小明去取奶茶。
阻塞与非阻塞的重点在于进/线程等待消息时候的行为,也就是在等待消息的时候,当前进/线程是挂起状态,还是非挂起状态。
阻塞阻塞调用在发出去后,在消息返回之前,当前进/线程会被挂起,直到有消息返回,当前进/线程才会被激活.
非阻塞非阻塞调用在发出去后,不会阻塞当前进/线程,而会立即返回。
阻塞买奶茶:小明点单交钱,干等着拿奶茶,什么事都不做;非阻塞买奶茶:小明点单交钱,等着拿奶茶,等的过程中,时不时刷刷微博、朋友圈…
通过上面的分析,我们可以得知:
同步与异步,重点在于消息通知的方式;阻塞与非阻塞,重点在于等消息时候的行为。
所以,就有了下面4种组合方式
同步阻塞:小明在柜台干等着拿奶茶;
同步非阻塞:小明在柜台边刷微博边等着拿奶茶;
异步阻塞:小明拿着小票啥都不干,一直等着店员通知他拿奶茶;
异步非阻塞:小明拿着小票,刷着微博,等着店员通知他拿奶茶。
Apache处理一个请求是同步阻塞的模式。

每到达一个请求,Apache都会去fork一个子进程去处理这个请求,直到这个请求处理完毕。
面对低并发,这种模式没什么缺点,但是,面对高并发,就是这种模式的软肋了。
1个客户端占用1个进程,那么,进程数量有多少,并发处理能力就有多少,但操作系统可以创建的进程数量是有限的。
多进程就会有进程间的切换问题,而进程间的切换调度势必会造成CPU的额外消耗。当进程数量达到成千上万的时候,进程间的切换就占了CPU大部分的时间片,而真正进程的执行反而占了CPU的一小部分,这就得不偿失了。
下面,举例说明这2种场景是多进程模式的软肋:
及时消息通知程序比如及时聊天程序,一台服务器可能要维持数十万的连接(典型的C10K问题),那么就要启动数十万的进程来维持。这显然不可能。
调用外部Http接口时假设Apache启动100个进程来处理请求,每个请求消耗100ms,那么这100个进程能提供1000qps。
但是,在我们调用外部Http接口时,比如QQ登录、微博登录,耗时较长,假设一个请求消耗10s,也就是1个进程1s处理0.1个请求,那么100个进程只能达到10qps,这样的处理能力就未免太差了。
注:什么是C10K问题?网络服务在处理数以万计的客户端连接时,往往出现效率低下甚至完全瘫痪,这被称为C10K问题。(concurrent 10000 connection)
综上,我们可以看出,Apache是同步阻塞的多进程模式,面对高并发等一些场景,是很苍白的。
传统的服务器模型就是这样,因为其同步阻塞的多进程模型,无法面对高并发。
那么,有没有一种方式,可以让我们在一个进程处理所有的并发I/O呢?
答案是有的,这就是I/O复用技术。
所谓的I/O复用,就是多个I/O可以复用一个进程。
上面说的同步阻塞的多进程模型不适合处理高并发,那么,我们再来考虑非阻塞的方式。
采用非阻塞的模式,当一个连接过来时,我们不阻塞住,这样一个进程可以同时处理多个连接了。
比如一个进程接受了10000个连接,这个进程每次从头到尾的问一遍这10000个连接:“有I/O事件没?有的话就交给我处理,没有的话我一会再来问一遍。”
然后进程就一直从头到尾问这10000个连接,如果这1000个连接都没有I/O事件,就会造成CPU的空转,并且效率也很低,不好不好。
上面虽然实现了基础版的I/O复用,但是效率太低了。于是伟大的程序猿们日思夜想的去解决这个问题…终于!
我们能不能引入一个代理,这个代理可以同时观察许多I/O流事件呢?
当没有I/O事件的时候,这个进程处于阻塞状态;当有I/O事件的时候,这个代理就去通知进程醒来?
于是,早期的程序猿们发明了两个代理—select、poll。
select、poll代理的原理是这样的:
当连接有I/O流事件产生的时候,就会去唤醒进程去处理。
但是进程并不知道是哪个连接产生的I/O流事件,于是进程就挨个去问:“请问是你有事要处理吗?”……问了99999遍,哦,原来是第100000个进程有事要处理。那么,前面这99999次就白问了,白白浪费宝贵的CPU时间片了!痛哉,惜哉…
注:select与poll原理是一样的,只不过select只能观察1024个连接,poll可以观察无限个连接。
上面看了,select、poll因为不知道哪个连接有I/O流事件要处理,性能也挺不好的。
那么,如果发明一个代理,每次能够知道哪个连接有了I/O流事件,不就可以避免无意义的空转了吗?
于是,超级无敌、闪闪发光的epoll被伟大的程序员发明出来了。
epoll代理的原理是这样的:
当连接有I/O流事件产生的时候,epoll就会去告诉进程哪个连接有I/O流事件产生,然后进程就去处理这个进程。
如此,多高效!
有了epoll,理论上1个进程就可以无限数量的连接,而且无需轮询,真正解决了c10k的问题。
Nginx是基于epoll的,异步非阻塞的服务器程序。自然,Nginx能够轻松处理百万级的并发连接,也就无可厚非了。
swoole是PHP的一个扩展。
简单理解:swoole=异步I/O+网络通信
PHPer可以基于swoole去实现过去PHP无法实现的功能。
具体请参考swoole官网:swoole官网
IO复用异步非阻塞程序使用经典的Reactor模型,Reactor顾名思义就是反应堆的意思,它本身不处理任何数据收发。只是可以监视一个socket(也可以是管道、eventfd、信号)句柄的事件变化。
注:什么是句柄?句柄英文为handler,可以形象的比喻为锅柄、勺柄。也就是资源的唯一标识符、资源的ID。通过这个ID可以操作资源。

Reactor只是一个事件发生器,实际对socket句柄的操作,如connect/accept、send/recv、close是在callback中完成的。
swoole采用 多线程Reactor+多进程Worker
swoole的架构图如下:

swoole的处理连接流程图如下:

当请求到达时,swoole是这样处理的:
请求到达 Main Reactor | |Main Reactor根据Reactor的情况,将请求注册给对应的Reactor (每个Reactor都有epoll。用来监听客户端的变化) | |客户端有变化时,交给worker来处理 | |worker处理完毕,通过进程间通信(比如管道、共享内存、消息队列)发给对应的reactor。 | |reactor将响应结果发给相应的连接 | | 请求处理完成
因为reactor基于epoll,所以每个reactor可以处理无数个连接请求。 如此,swoole就轻松的处理了高并发。
基于上面的Swoole结构图,我们看到swoole的worker进程有2种类型:
一种是 普通的worker进程,一种是 task worker进程。
worker进程是用来处理普通的耗时不是太长的请求;task worker进程用来处理耗时较长的请求,比如数据库的I/O操作。
我们以异步Mysql举例:
耗时较长的Mysql查询进入worker | |worker通过管道将这个请求交给taskworker来处理 | |worker再去处理其他请求 | |task worker处理完毕后,处理结果通过管道返回给worker | |worker 将结果返回给reactor | |reactor将结果返回给请求方
如此,通过worker、task worker结合的方式,我们就实现了异步I/O。
Nginx 多进程模型是如何实现高并发的?
PHP并发IO编程之路
epoll 或者 kqueue 的原理是什么?
IO 多路复用是什么意思?
进程(process)和线程(thread)是操作系统的基本概念,但是它们比较抽象,不容易掌握。
最近,我读到一篇材料,发现有一个很好的类比,可以把它们解释地清晰易懂。
1.

计算机的核心是CPU,它承担了所有的计算任务。它就像一座工厂,时刻在运行。
2.

假定工厂的电力有限,一次只能供给一个车间使用。也就是说,一个车间开工的时候,其他车间都必须停工。背后的含义就是,单个CPU一次只能运行一个任务。
3.

进程就好比工厂的车间,它代表CPU所能处理的单个任务。任一时刻,CPU总是运行一个进程,其他进程处于非运行状态。
4.

一个车间里,可以有很多工人。他们协同完成一个任务。
5.

线程就好比车间里的工人。一个进程可以包括多个线程。
6.

车间的空间是工人们共享的,比如许多房间是每个工人都可以进出的。这象征一个进程的内存空间是共享的,每个线程都可以使用这些共享内存。
7.

可是,每间房间的大小不同,有些房间最多只能容纳一个人,比如厕所。里面有人的时候,其他人就不能进去了。这代表一个线程使用某些共享内存时,其他线程必须等它结束,才能使用这一块内存。
8.

一个防止他人进入的简单方法,就是门口加一把锁。先到的人锁上门,后到的人看到上锁,就在门口排队,等锁打开再进去。这就叫"互斥锁"(Mutual exclusion,缩写 Mutex),防止多个线程同时读写某一块内存区域。
9.

还有些房间,可以同时容纳n个人,比如厨房。也就是说,如果人数大于n,多出来的人只能在外面等着。这好比某些内存区域,只能供给固定数目的线程使用。
10.

这时的解决方法,就是在门口挂n把钥匙。进去的人就取一把钥匙,出来时再把钥匙挂回原处。后到的人发现钥匙架空了,就知道必须在门口排队等着了。这种做法叫做"信号量"(Semaphore),用来保证多个线程不会互相冲突。
不难看出,mutex是semaphore的一种特殊情况(n=1时)。也就是说,完全可以用后者替代前者。但是,因为mutex较为简单,且效率高,所以在必须保证资源独占的情况下,还是采用这种设计。
11.

操作系统的设计,因此可以归结为三点:
(1)以多进程形式,允许多个任务同时运行;
(2)以多线程形式,允许单个任务分成不同的部分运行;
(3)提供协调机制,一方面防止进程之间和线程之间产生冲突,另一方面允许进程之间和线程之间共享资源。
(完)
http://www.ruanyifeng.com/blog/2013/04/processes_and_threads.html
老张爱喝茶,废话不说,煮开水。
出场人物:老张,水壶两把(普通水壶,简称水壶;会响的水壶,简称响水壶)。
1 老张把水壶放到火上,立等水开。(同步阻塞)
老张觉得自己有点傻
2 老张把水壶放到火上,去客厅看电视,时不时去厨房看看水开没有。(同步非阻塞)
老张还是觉得自己有点傻,于是变高端了,买了把会响笛的那种水壶。水开之后,能大声发出嘀~~~~的噪音。
3 老张把响水壶放到火上,立等水开。(异步阻塞)
老张觉得这样傻等意义不大
4 老张把响水壶放到火上,去客厅看电视,水壶响之前不再去看它了,响了再去拿壶。(异步非阻塞)
老张觉得自己聪明了。
所谓同步异步,只是对于水壶而言。
普通水壶,同步;响水壶,异步。
虽然都能干活,但响水壶可以在自己完工之后,提示老张水开了。这是普通水壶所不能及的。
同步只能让调用者去轮询自己(情况2中),造成老张效率的低下。
所谓阻塞非阻塞,仅仅对于老张而言。
立等的老张,阻塞;看电视的老张,非阻塞。
情况1和情况3中老张就是阻塞的,媳妇喊他都不知道。虽然3中响水壶是异步的,可对于立等的老张没有太大的意义。所以一般异步是配合非阻塞使用的,这样才能发挥异步的效用。
Redis是一个高性能的key-value数据库,在部分场合可以对关系数据库起到很好的补充作用。现在越来越多的网站为了达到一个更高的可用性把session储存在Memcache、Redis等NoSQL数据库中。
方法一:修改php.ini的设置
session.save_handler = redis session.save_path = "tcp://127.0.0.1:8089"#Redis服务的地址和端口
方法二:如果不想修改php.ini,可在代码中使用ini_set()方法:修改后重启php-fpm,phpinfo()可以查看到session存储在redis中。
ini_set("session.save_handler","redis");
ini_set("session.save_path","tcp://127.0.0.1:8089");
查看redis存储session的值:如果redis.conf设置了连接密码(requirepass),session的save_path需修改为:tcp://127.0.0.1:8089?auth=requirepass的值。如果选择redis数据库,session.save_path = “tcp://xx.xx.xx.xx:8089?database=11″,诸如此类。
session_start();
$_SESSION['website'] = 'www.leokim.cn';
$redis = new redis();
$redis->connect('192.168.31.102',8089);
echo $_SESSION['website']; //输出www.leokim.cn
存入redis数据前必须选择数据库,redis数据库默认16个,下标0~15,默认使用第0个,存放数据前可以使用select N选择数据库。
Redis数据库在redis.conf中配置如下:
#redis.conf# databases 16
你可以根据实际需要更改数据库个数,但一般不建议修改。
redis(nosql产品)为了内部数据的安全考虑,会把本身的数据以文件形式保存到硬盘中一份,在服务器重启之后会自动把硬盘的数据恢复到内存(redis)的里边。
数据保存到硬盘的过程就称为“持久化”效果。
该持久化默认开启,一次性把redis中全部的数据保存一份存储在硬盘中,如果数据非常多(10-20G)就不适合频繁进行该持久化操作。快照持久化会根据配置条件定期生成二进制备份文件,默认文件名dump.rdb。
redis.conf 中关于快照的配置:
#快照写入文件名dbfilename dump.rdb #快照保存目录dir ./ #快照写入频率 save 900 1 #900 秒内如果超过 1 个 key 被修改,则发起快照保存 save 300 10 #300秒超过10个key被修改,发起快照 save 60 10000 #60秒超过10000个key被修改,发起快照 #以上三个备份频率需要同时存在: #数据变化非常快的时候,就快点做备份(保证数据安全) #数据变化慢的时候,就慢点做备份(节省服务器资源)
快照持久化默认开启,并定时执行,你也可以通过redis-cli客户端使用bgsave命令手动发起。
./redis-cli bgsave
本质:把用户执行的每个“写”指令(添加、修改、删除)都备份到文件中,还原数据的时候就是执行具体写指令而已。
AOF默认关闭,默认保存文件名append.aof,默认每秒执行一次,具体参数如下
#开启/关闭AOF appendonly yes #保存文件名 appendfilename "appendonly.aof" #AOF保存频率 # appendfsync always #每次收到写命令就立即强制写入磁盘,最慢的,但是保证完全的持久化,不推荐使用 appendfsync everysec #每秒钟强制写入磁盘一次,在性能和持久化方面做了很好的折中,推荐 # appendfsync no #完全依赖 os,性能最好,持久化没保证 #上面三种选项数据安全性及服务性能情况 #数据最安全 服务器性能低 #数据较安全 服务器性能中等 #数据不安全 服务器性能高(优良)
AOF策略设置为always或者everysec时,后台处理进程(后台保存或者AOF日志重写)会执行大量的I/O操作,在某些Linux配置中会阻止过长的fsync()请求。注意现在没有任何修复,即使fsync在另外一个线程进行处理。
为了减缓这个问题,可以设置下面这个参数no-appendfsync-on-rewrite:
#redis.conf# no-appendfsync-on-rewrite yes
AOF记录用户的每个操作,但是有些操作例如对某个key的多个同类型操作是可以合并为一个,从而做到压缩文件大小的效果。例如多次incr一个整型key,可以直接合并为set key N。
压缩优化(AOF重写)命令:
./redis-cli bgrewriteaof
当AOF文件增长到一定大小的时候Redis能够调用 BGREWRITEAOF 对日志文件进行重写,它是这样工作的:Redis会记住上次进行些日志后文件的大小(如果从开机以来还没进行过重写,那日子大小在开机的时候确定)基础大小会同现在的大小进行比较。如果现在的大小比基础大小大制定的百分比,重写功能将启动,同时需要指定一个最小大小用于AOF重写,这个用于阻止即使文件很小但是增长幅度很大也去重写AOF文件的情况,设置 percentage 为0就关闭这个重写特性。
#redis.conf #auto-aof-rewrite-percentage 100 auto-aof-rewrite-min-size 64mb
save (客户端命令行内)前台备份数据(快照保存) bgsave 异步保存数据到磁盘(快照保存) lastsave 返回上次成功保存到磁盘的unix时间戳 shutdown 同步保存到服务器并关闭redis服务器 bgrewriteaof 当日志文件过长时优化AOF日志文件存储 redis 127.0.0.1:6379> SAVE #前台备份数据 ./redis-cli bgrewriteaof ./redis-cli bgsave ./redis-cli -h 127.0.0.1 -p 6379 bgsave #手动发起快照
如果需要恢复数据,只需将备份文件 (dump.rdb) 移动到 redis 快照保存目录 并启动服务即可。要查看快照保存目录,可以查看redis.conf的dir配置。
为了降低每个redis服务器的负载,可以多设置几个,并做主从模式,一个服务器负载“写”(添加、修改、删除)数据,其他服务器负载“读”数据,主服务器数据会“自动”同步给从服务器

1.master可以有多个slave
2.除了多个slave连接到master外,slave也可以连接到其他slave,形成网状结构
3.可以让slave做读请求,master做写操作
(假定局域网IP为192.168.1.101)
#redis.conf# #配置主服务器密码 requirepass admin123 #自定义端口 port 6379
#redis.conf# #主服务器连接密码 masterauth admin123 #自定义端口 port 6380 #设置成为192.168.1.101的从服务器 slaveof 192.168.1.101 6379 #取消从服务器只读 slave-read-only no
重新开启redis-server 服务,则从服务器设置成功。

假设你只有一台电脑,但又想实现redis的主从部署,你考虑使用诸如6380,6381…等端口创建从节点,那么问题来了,改怎么设置呢?
如果要在一台服务器上运行多个redis实例,必须满足以下3点:
使用不同的端口
分别配置每个实例(服务)的pid和log文件
RDB和AOF持久化到每个实例(服务)的rdb和aof文件中
每个实例必须对应一个配置文件,配置文件按照上面3点设置:
cp redis.conf redis_6380.conf vi redis_6380.conf port 6380 #设置端口 pidfile /var/run/redis/redis_6380.pid #设置pid文件 logfile /var/log/redis/redis_6380.log #设置log文件 dbfilename dump_6380.rdb #设置RDB持久化文件 appendfilename "appendonly_6380.aof" #设置aof持久化文件
其他配置文件按此修改,至于从节点配置,回上面看。
启动多个redis实例:
./redis-server redis_6380.conf ./redis-server redis_6381.conf
配置好从节点后,./redis-cli 开启客户端,auth 密码 登入,再输入info命令,可以查看redis主节点状态,其中该主节点的从节点信息如下:
# Replication role:master connected_slaves:2 slave0:ip=127.0.0.1,port=6380,state=online,offset=1037,lag=1 slave1:ip=127.0.0.1,port=6381,state=online,offset=1037,lag=0 master_repl_offset:1037 repl_backlog_active:1 repl_backlog_size:1048576 repl_backlog_first_byte_offset:2 repl_backlog_histlen:1036
*关于Redis详细配置信息,可以参考以下博客:
http://www.cnblogs.com/GaZeon/p/5422078.html
设置redis.conf中daemonize为yes,确保守护进程开启。
编写开机自启动脚本
基本原理为:
系统开机启动时会去加载/etc/init.d/下面的脚本,通常而言每个脚本文件会自定义实现程序的启动;若想将新的程序开机自启动,只需在该目录下添加一个自定义启动程序的脚本,然后设置相应规则即可。
如在这里我们在/etc/init.d/下新建一个 redis 的脚本,开机启动时会去加载执行该脚本。
vim /etc/init.d/redis
在该脚本中添加一下内容:
参数要根据自己的配置改
# chkconfig: 2345 10 90
#redis服务必须在运行级2,3,4,5下被启动或关闭,启动的优先级是90,关闭的优先级是10。
# description: Start and Stop redis
PATH=/usr/local/bin:/sbin:/usr/bin:/bin
export PATH
REDISPORT=6379 #端口号,这是默认的,如果你安装的时候不是默认端口号,则需要修改
EXEC=/usr/local/redis/bin/redis-server
#redis-server启动脚本的位置,你如果忘了可以用find或whereis找到
REDIS_CLI=/usr/redisbin/redis-cli
#redis-cli客户端启动脚本的位置,你如果忘了可以用find或whereis找到
PIDFILE=/run/redis.pid #这个也可以用find或whereis找到
CONF="/usr/local/redis/etc/redis.conf" #redis.conf配置文件的位置,你如果忘了可以用find或whereis找到
AUTH="1234"
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
if [ "$?"="0" ]
then
echo "Redis is running..."
fi
;;
stop)
if [ ! -f $PIDFILE ]
then
echo "$PIDFILE exists, process is not running."
else
PID=$(cat $PIDFILE)
echo "Stopping..."
$REDIS_CLI -p $REDISPORT SHUTDOWN
sleep 2
while [ -x $PIDFILE ]
do
echo "Waiting for Redis to shutdown..."
sleep 1
done
echo "Redis stopped"
fi
;;
restart|force-reload)
${0} stop
${0} start
;;
*)
echo "Usage: /etc/init.d/redis {start|stop|restart|force-reload}" >&2
exit 1 esac
写完后保存退出
设置可执行权限:
chmod 755 redis
启动测试:
/etc/init.d/redis start
启动成功会提示如下信息:
Starting Redis server... Redis is running...
使用redis-cli测试:
[root@localhost ~]# /usr/local/redis/bin/redis-cli127.0.0.1:6379> set foo bar OK127.0.0.1:6379> get foo"bar"127.0.0.1:6379> exit
设置开机自启动:
chkconfig redis on
关机重启测试:
reboot
开机完之后可以用 redis-cli 测试,或者用 ps -ef | grep redis 看看redis 是否在运行中