如何用命令将本地项目上传到git

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

 

laravel5集成angular2

这个问题我之前一直在思考

学习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应用

image.png

我们需要获取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文件夹

image.png

完成之后,我们要添加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

image.png

修改如下文件 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));


   })

如果不修改会出现下面的错误

image.png

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

image.png

全部执行完成

修改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>

成功了!!!

image.png

我把它放在了这里

https://git.oschina.net/iamleokim/larangular.git

ng2-admin分析

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' }
    ]
  }
];

nginx、swoole高并发原理初探

一、阅前热身

为了更加形象的说明同步异步、阻塞非阻塞,我们以小明去买奶茶为例。

1、同步与异步

①同步与异步的理解

同步与异步的重点在消息通知的方式上,也就是调用结果通知的方式。

  • 同步当一个同步调用发出去后,调用者要一直等待调用结果的通知后,才能进行后续的执行

  • 异步:当一个异步调用发出去后,调用者不能立即得到调用结果的返回。

异步调用,要想获得结果,一般有两种方式:
1、主动轮询异步调用的结果;
2、被调用方通过callback来通知调用方调用结果。

②:生活实例

同步买奶茶:小明点单交钱,然后等着拿奶茶;异步买奶茶:小明点单交钱,店员给小明一个小票,等小明奶茶做好了,再来取。

异步买奶茶,小明要想知道奶茶是否做好了,有两种方式:
1、小明主动去问店员,一会就去问一下:“奶茶做好了吗?”…直到奶茶做好。
2、等奶茶做好了,店员喊一声:“小明,奶茶好了!”,然后小明去取奶茶。


2、阻塞与非阻塞

①阻塞与非阻塞的理解

阻塞与非阻塞的重点在于进/线程等待消息时候的行为,也就是在等待消息的时候,当前进/线程是挂起状态,还是非挂起状态。

  • 阻塞阻塞调用在发出去后,在消息返回之前,当前进/线程会被挂起,直到有消息返回,当前进/线程才会被激活.

  • 非阻塞非阻塞调用在发出去后,不会阻塞当前进/线程,而会立即返回。

②:生活实例

阻塞买奶茶:小明点单交钱,干等着拿奶茶,什么事都不做;非阻塞买奶茶:小明点单交钱,等着拿奶茶,等的过程中,时不时刷刷微博、朋友圈…


3、总结

通过上面的分析,我们可以得知:

同步与异步,重点在于消息通知的方式;阻塞与非阻塞,重点在于等消息时候的行为。

所以,就有了下面4种组合方式

  • 同步阻塞:小明在柜台干等着拿奶茶;

  • 同步非阻塞:小明在柜台边刷微博边等着拿奶茶;

  • 异步阻塞:小明拿着小票啥都不干,一直等着店员通知他拿奶茶;

  • 异步非阻塞:小明拿着小票,刷着微博,等着店员通知他拿奶茶。


二、Nginx如何处理高并发

1、Apache面对高并发,为什么很无力?

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是同步阻塞的多进程模式,面对高并发等一些场景,是很苍白的。


2、Nginx何以问鼎高并发?

传统的服务器模型就是这样,因为其同步阻塞的多进程模型,无法面对高并发。
那么,有没有一种方式,可以让我们在一个进程处理所有的并发I/O呢?
答案是有的,这就是I/O复用技术。

①、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事件的时候,这个进程处于阻塞状态;当有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的Nginx

有了epoll,理论上1个进程就可以无限数量的连接,而且无需轮询,真正解决了c10k的问题。

Nginx是基于epoll的,异步非阻塞的服务器程序。自然,Nginx能够轻松处理百万级的并发连接,也就无可厚非了。

三、swoole如何处理高并发以及异步I/O的实现

1、swoole介绍

swoole是PHP的一个扩展。
简单理解:swoole=异步I/O+网络通信
PHPer可以基于swoole去实现过去PHP无法实现的功能。
具体请参考swoole官网:swoole官网


2、swoole如何处理高并发

①Reactor模型介绍

IO复用异步非阻塞程序使用经典的Reactor模型,Reactor顾名思义就是反应堆的意思,它本身不处理任何数据收发。只是可以监视一个socket(也可以是管道、eventfd、信号)句柄的事件变化。

注:什么是句柄?句柄英文为handler,可以形象的比喻为锅柄、勺柄。也就是资源的唯一标识符、资源的ID。通过这个ID可以操作资源。

Reactor只是一个事件发生器,实际对socket句柄的操作,如connect/accept、send/recv、close是在callback中完成的。

②swoole的架构

swoole采用 多线程Reactor+多进程Worker

swoole的架构图如下:

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

当请求到达时,swoole是这样处理的:

请求到达 Main Reactor        |
        |Main Reactor根据Reactor的情况,将请求注册给对应的Reactor
(每个Reactor都有epoll。用来监听客户端的变化)        |
        |客户端有变化时,交给worker来处理        |
        |worker处理完毕,通过进程间通信(比如管道、共享内存、消息队列)发给对应的reactor。        |
        |reactor将响应结果发给相应的连接        |
        |
    请求处理完成

因为reactor基于epoll,所以每个reactor可以处理无数个连接请求。 如此,swoole就轻松的处理了高并发。

3、swoole如何实现异步I/O

基于上面的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中响水壶是异步的,可对于立等的老张没有太大的意义。所以一般异步是配合非阻塞使用的,这样才能发挥异步的效用。

PHP使用Redis来存储session

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数据前必须选择数据库,redis数据库默认16个,下标0~15,默认使用第0个,存放数据前可以使用select N选择数据库。

Redis数据库在redis.conf中配置如下:

#redis.conf#
databases 16

你可以根据实际需要更改数据库个数,但一般不建议修改。

*持久化功能

redis(nosql产品)为了内部数据的安全考虑,会把本身的数据以文件形式保存到硬盘中一份,在服务器重启之后会自动把硬盘的数据恢复到内存(redis)的里边。

数据保存到硬盘的过程就称为“持久化”效果。

Redis快照持久化(snap shotting或称RDB持久化)配置:

该持久化默认开启,一次性把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

Redis AOF(append only file)持久化配置:

本质:把用户执行的每个“写”指令(添加、修改、删除)都备份到文件中,还原数据的时候就是执行具体写指令而已。

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备份文件做优化压缩处理:

AOF记录用户的每个操作,但是有些操作例如对某个key的多个同类型操作是可以合并为一个,从而做到压缩文件大小的效果。例如多次incr一个整型key,可以直接合并为set key N。

压缩优化(AOF重写)命令:

./redis-cli bgrewriteaof

AOF自动重写:

当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主从模式

为了降低每个redis服务器的负载,可以多设置几个,并做主从模式,一个服务器负载“写”(添加、修改、删除)数据,其他服务器负载“读”数据,主服务器数据会“自动”同步给从服务器

905655-20160422212934835-967833038.png

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 服务,则从服务器设置成功。

905655-20160423130828023-2066105402.png

在一台服务器上部署多个Redis服务节点(启动多端口,运行多实例)方式: 

假设你只有一台电脑,但又想实现redis的主从部署,你考虑使用诸如6380,6381…等端口创建从节点,那么问题来了,改怎么设置呢?

 如果要在一台服务器上运行多个redis实例,必须满足以下3点:

  1. 使用不同的端口

  2. 分别配置每个实例(服务)的pid和log文件

  3. 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详细配置信息,可以参考以下博客:

1Redis配置文件详解 

2Redis配置文件详解 

http://www.cnblogs.com/GaZeon/p/5422078.html

Centos7下配置Redis开机自启动

设置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 是否在运行中