早上在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 是否在运行中