首先在windows上安装好Redis,RabbitMQ Redis-cli使用示例 ModelContext.cs代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
public class ModelContext : DbContext { //您的上下文已配置为从您的应用程序的配置文件(App.config 或 Web.config) //连接字符串。 public ModelContext() : base("name=default") { } public virtual DbSet<Person> Person { get; set; } } public class Person { public int Id { get; set; } public string Id2 { get; set; } public string Name { get; set; } } |
在 Package Manager Console 下运行命令 Enable-Migrations 这个命令将在项目下创建文件夹 Migrations The Configuration class 这个类允许你去配置如何迁移,对于本文将使用默认的配置(在本文中因为只有一个 Context, Enable-Migrations 将自动对 context type 作出适配); An InitialCreate migration (本文为201702220232375_20170222.cs)这个迁移之所以存在是因为我们之前用 Code First 创建了数据库, 在启用迁移前,scaffolded migration 里的代码表示在数据库中已经创建的对象,本文中即为表 Person(列 Id 和 Name). 文件名包含一个 timestamp 以便排序(如果之前数据库没有被创建,那么 InitialCreate migration 将不会被创建,相反,当我们第一次调用 Add-Migration 的时候所有表都将归集到一个新的 migration 中) 多个实体锁定同一数据库 当使用 EF6 之前的版本时,只会有一个 Code First Model 被用来生成/管理数据库的 Schema, 这将导致每个数据库只会有一张 __MigrationsHistory 表,从而无法辨别实体与模型的对应关系。 从 EF6 开始,Configuration 类将会包含一个 ContextKey 属性,它将作为每一个 Code First Model 的唯一标识符, __MigrationsHistory 表中一个相应地的列允许来自多个模型(multiple models)的实体共享表(entries),默认情况下这个属性被设置成 context 的完全限定名。 定制化迁移 在 Package Manager Console 中运行命令 Add-Migration XXXXXXXXX 生成的迁移如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public partial class _20170222 : DbMigration { public override void Up() { CreateTable( "dbo.People", c => new { Id = c.Int(nullable: false, identity: true), Id2 = c.String(), Name = c.String(), }) .PrimaryKey(t => t.Id); } public override void Down() { DropTable("dbo.People"); } } |
Configuration.cs代码:
1 2 3 4 5 6 7 8 9 10 11 12 |
internal sealed class Configuration : DbMigrationsConfiguration<EF.ModelContext> { public Configuration() { AutomaticMigrationsEnabled = false; } protected override void Seed(EF.ModelContext context) { } } |
我们对迁移做些更改: […]
View DetailsAMQP AMQP协议是一个高级抽象层消息通信协议,RabbitMQ是AMQP协议的实现。它主要包括以下组件: 1.Server(broker): 接受客户端连接,实现AMQP消息队列和路由功能的进程。 2.Virtual Host:其实是一个虚拟概念,类似于权限控制组,一个Virtual Host里面可以有若干个Exchange和Queue,但是权限控制的最小粒度是Virtual Host 3.Exchange:接受生产者发送的消息,并根据Binding规则将消息路由给服务器中的队列。ExchangeType决定了Exchange路由消息的行为,例如,在RabbitMQ中,ExchangeType有direct、Fanout和Topic三种,不同类型的Exchange路由的行为是不一样的。 4.Message Queue:消息队列,用于存储还未被消费者消费的消息。 5.Message: 由Header和Body组成,Header是由生产者添加的各种属性的集合,包括Message是否被持久化、由哪个Message Queue接受、优先级是多少等。而Body是真正需要传输的APP数据。 6.Binding:Binding联系了Exchange与Message Queue。Exchange在与多个Message Queue发生Binding后会生成一张路由表,路由表中存储着Message Queue所需消息的限制条件即Binding Key。当Exchange收到Message时会解析其Header得到Routing Key,Exchange根据Routing Key与Exchange Type将Message路由到Message Queue。Binding Key由Consumer在Binding Exchange与Message Queue时指定,而Routing Key由Producer发送Message时指定,两者的匹配方式由Exchange Type决定。 7.Connection:连接,对于RabbitMQ而言,其实就是一个位于客户端和Broker之间的TCP连接。 8.Channel:信道,仅仅创建了客户端到Broker之间的连接后,客户端还是不能发送消息的。需要为每一个Connection创建Channel,AMQP协议规定只有通过Channel才能执行AMQP的命令。一个Connection可以包含多个Channel。之所以需要Channel,是因为TCP连接的建立和释放都是十分昂贵的,如果一个客户端每一个线程都需要与Broker交互,如果每一个线程都建立一个TCP连接,暂且不考虑TCP连接是否浪费,就算操作系统也无法承受每秒建立如此多的TCP连接。RabbitMQ建议客户端线程之间不要共用Channel,至少要保证共用Channel的线程发送消息必须是串行的,但是建议尽量共用Connection。 9.Command:AMQP的命令,客户端通过Command完成与AMQP服务器的交互来实现自身的逻辑。例如在RabbitMQ中,客户端可以通过publish命令发送消息,txSelect开启一个事务,txCommit提交一个事务。 在了解了AMQP模型以后,需要简单介绍一下AMQP的协议栈,AMQP协议本身包括三层: 1.Module Layer,位于协议最高层,主要定义了一些供客户端调用的命令,客户端可以利用这些命令实现自己的业务逻辑,例如,客户端可以通过queue.declare声明一个队列,利用consume命令获取一个队列中的消息。 2.Session Layer,主要负责将客户端的命令发送给服务器,在将服务器端的应答返回给客户端,主要为客户端与服务器之间通信提供可靠性、同步机制和错误处理。 3.Transport Layer,主要传输二进制数据流,提供帧的处理、信道复用、错误检测和数据表示。 RabbitMQ使用场景 学习RabbitMQ的使用场景,来自官方教程:https://www.rabbitmq.com/getstarted.html 场景1:单发送单接收 使用场景:简单的发送与接收,没有特别的处理。 Producer:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.Connection; import com.rabbitmq.client.Channel; public class Send { private final static String QUEUE_NAME = "hello"; public static void main(String[] argv) throws Exception { ConnectionFactory factory = new ConnectionFactory(); factory.setHost("localhost"); Connection connection = factory.newConnection(); Channel channel = connection.createChannel(); channel.queueDeclare(QUEUE_NAME, false, false, false, null); String message = "Hello World!"; channel.basicPublish("", QUEUE_NAME, null, message.getBytes()); System.out.println(" [x] Sent '" + message + "'"); channel.close(); connection.close(); } } |
Consumer:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.Connection; import com.rabbitmq.client.Channel; import com.rabbitmq.client.QueueingConsumer; public class Recv { private final static String QUEUE_NAME = "hello"; public static void main(String[] argv) throws Exception { ConnectionFactory factory = new ConnectionFactory(); factory.setHost("localhost"); Connection connection = factory.newConnection(); Channel channel = connection.createChannel(); channel.queueDeclare(QUEUE_NAME, false, false, false, null); System.out.println(" [*] Waiting for messages. To exit press CTRL+C"); QueueingConsumer consumer = new QueueingConsumer(channel); channel.basicConsume(QUEUE_NAME, true, consumer); while (true) { QueueingConsumer.Delivery delivery = consumer.nextDelivery(); String message = new String(delivery.getBody()); System.out.println(" [x] Received '" + message + "'"); } } } |
场景2:单发送多接收 使用场景:一个发送端,多个接收端,如分布式的任务派发。为了保证消息发送的可靠性,不丢失消息,使消息持久化了。同时为了防止接收端在处理消息时down掉,只有在消息处理完成后才发送ack消息。 Producer:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
import com.rabbitmq.client.ConnectionFactory; import com.rabbitmq.client.Connection; import com.rabbitmq.client.Channel; import com.rabbitmq.client.MessageProperties; public class NewTask { private static final String TASK_QUEUE_NAME = "task_queue"; public static void main(String[] argv) throws Exception { ConnectionFactory factory = new ConnectionFactory(); factory.setHost("localhost"); Connection connection = factory.newConnection(); Channel channel = connection.createChannel(); channel.queueDeclare(TASK_QUEUE_NAME, true, false, false, null); String message = getMessage(argv); channel.basicPublish( "", TASK_QUEUE_NAME, MessageProperties.PERSISTENT_TEXT_PLAIN, message.getBytes()); System.out.println(" [x] Sent '" + message + "'"); channel.close(); connection.close(); } private static String getMessage(String[] strings){ if (strings.length < 1) return "Hello World!"; return joinStrings(strings, " "); } private static String joinStrings(String[] strings, String delimiter) { int length = strings.length; if (length == 0) return ""; StringBuilder words = new StringBuilder(strings[0]); for (int i = 1; i < length; i++) { words.append(delimiter).append(strings[i]); } return words.toString(); } } |
发送端和场景1不同点: 1、使用“task_queue”声明了另一个Queue,因为RabbitMQ不容许声明2个相同名称、配置不同的Queue 2、使"task_queue"的Queue的durable的属性为true,即使消息队列durable 3、使用MessageProperties.PERSISTENT_TEXT_PLAIN使消息durable When RabbitMQ quits or crashes it will forget the queues and messages unless you tell it not to. Two things are required to make sure that messages aren’t lost: we need to mark both the queue […]
View Details上次我们介绍了在单机、集群下高并发场景可以选择的一些方案,传送门:高并发场景之一般解决方案 但是也发现了一些问题,比如集群下使用ConcurrentQueue或加锁都不能解决问题,后来采用Redis队列也不能完全解决问题, 因为使用Redis要自己实现分布式锁 这次我们来了解一下一个专门处理队列的组件:RabbitMQ,这个东西天生支持分布式队列。 下面我们来用RabbitMQ来实现上一篇的场景 一、新建RabbitMQ.Receive
1 2 |
private static ConnectionFactory factory = new ConnectionFactory { HostName = "192.168.1.109", UserName = "ljr", Password = "root", VirtualHost = "/" }; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
1 static void Main(string[] args) 2 { 3 using (var connection = factory.CreateConnection()) 4 { 5 using (var channel = connection.CreateModel()) 6 { 7 var consumer = new EventingBasicConsumer(); 8 consumer.Received += (model, ea) => 9 { 10 var body = ea.Body; 11 var message = Encoding.UTF8.GetString(body); 12 Console.WriteLine(" [x] Received {0}", message); 13 14 var total = DbHelper.ExecuteScalar("Select Total from ConCurrency where Id = 1", null).ToString(); 15 var value = int.Parse(total) + 1; 16 17 DbHelper.ExecuteNonQuery(string.Format("Update ConCurrency Set Total = {0} where Id = 1", value.ToString()), null); 18 }; 19 20 channel.QueueDeclare(queue: "queueName", durable: false, exclusive: false, autoDelete: false, arguments: null); 21 channel.BasicConsume(queue: "queueName", noAck: true, consumer: consumer); 22 23 Console.WriteLine(" Press [enter] to exit."); 24 Console.ReadLine(); 25 } 26 } 27 } |
二、新建RabbitMQ.Send
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
1 static void Main(string[] args) 2 { 3 for (int i = 1; i <= 500; i++) 4 { 5 Task.Run(async () => 6 { 7 await Produce(); 8 }); 9 10 Console.WriteLine(i); 11 } 12 13 Console.ReadKey(); 14 } 15 16 public static Task Produce() 17 { 18 return Task.Factory.StartNew(() => 19 { 20 using (var connection = factory.CreateConnection()) 21 { 22 using (var channel = connection.CreateModel()) 23 { 24 var body = Encoding.UTF8.GetBytes(Guid.NewGuid().ToString()); 25 channel.QueueDeclare(queue: "queueName", durable: false, exclusive: false, autoDelete: false, arguments: null); 26 channel.BasicPublish(exchange: "", routingKey: "queueName", basicProperties: null, body: body); 27 } 28 } 29 }); 30 } |
这里是模拟500个用户请求,正常的话最后Total就等于500 我们来说试试看,运行程序 2.1、打开接收端 2.2 运行客户端 2.3、可以看到2边几乎是实时的,再去看看数据库 三、我们在集群里执行 最后数据是1000 完全没有冲突,好了,就是这样 。 from: https://www.cnblogs.com/lanxiaoke/p/6659548.html
View DetailsAdd the dotnet product feed Before installing .NET, you’ll need to register the Microsoft key, register the product repository, and install required dependencies. This only needs to be done once per machine. Open a terminal and run the following commands:
1 |
sudo rpm -Uvh https://packages.microsoft.com/config/rhel/7/packages-microsoft-prod.rpm |
Install the .NET Runtime Update the products available for installation, then install the .NET Runtime. In your terminal, run the following commands:
1 2 3 4 |
sudo yum update sudo yum install aspnetcore-runtime-2.2 也可以安装SDK yum install dotnet-sdk-2.2 |
The previous command will install the .NET Core Runtime Bundle, which includes the .NET Core runtime and the ASP.NET Core runtime. To […]
View Details安装过程参考官网: Installing on RPM-based Linux (RHEL, CentOS, Fedora, openSUSE) 首先需要安装erlang,参考:http://fedoraproject.org/wiki/EPEL/FAQ#howtouse
1 2 |
rpm -Uvh https://mirrors.tuna.tsinghua.edu.cn/epel/epel-release-latest-7.noarch.rpm yum install erlang |
安装过程中会有提示,一路输入“y”即可。 完成后安装RabbitMQ: 先下载rpm:
1 |
wget http://www.rabbitmq.com/releases/rabbitmq-server/v3.6.6/rabbitmq-server-3.6.6-1.el7.noarch.rpm |
下载完成后安装:
1 |
yum install rabbitmq-server-3.6.6-1.el7.noarch.rpm |
完成后启动服务:
1 |
service rabbitmq-server start |
可以查看服务状态:
1 |
service rabbitmq-server status |
这里可以看到log文件的位置,转到文件位置,打开文件: 这里显示的是没有找到配置文件,我们可以自己创建这个文件
1 2 |
cd /etc/rabbitmq/ vi rabbitmq.config |
编辑内容如下:
1 |
[{rabbit, [{loopback_users, []}]}]. |
这里的意思是开放使用,rabbitmq默认创建的用户guest,密码也是guest,这个用户默认只能是本机访问,localhost或者127.0.0.1,从外部访问需要添加上面的配置。 保存配置后重启服务:
1 2 |
service rabbitmq-server stop service rabbitmq-server start |
此时就可以从外部访问了,但此时再看log文件,发现内容还是原来的,还是显示没有找到配置文件,可以手动删除这个文件再重启服务,不过这不影响使用
1 2 3 |
rm rabbit\@mythsky.log service rabbitmq-server stop service rabbitmq-server start |
开放5672端口:
1 2 |
firewall-cmd --zone=public --add-port=5672/tcp --permanent firewall-cmd --reload |
在Windows上进行测试: 新建.net core控制台项目,引用RabbitMQ.Client包:
1 |
Install-Package RabbitMQ.Client |
测试代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
public static void Main(string[] args) { ConnectionFactory factory = new ConnectionFactory(); factory.UserName = "guest"; factory.Password = "guest"; factory.VirtualHost = "/"; factory.HostName = "localhost"; //factory.HostName = "10.255.19.111"; try { IConnection conn = factory.CreateConnection(); IModel model = conn.CreateModel(); string exchangeName = "test"; string queueName = "testq"; string routingKey = "first"; model.ExchangeDeclare(exchangeName, ExchangeType.Direct); model.QueueDeclare(queueName, false, false, false, null); model.QueueBind(queueName, exchangeName, routingKey, null); byte[] messageBodyBytes = System.Text.Encoding.UTF8.GetBytes("Hello, world!"); model.BasicPublish(exchangeName, routingKey, null, messageBodyBytes); Console.WriteLine("message sended."); bool noAck = false; BasicGetResult result = model.BasicGet(queueName, noAck); if (result == null) { Console.Write("no message."); } else { IBasicProperties props = result.BasicProperties; byte[] body = result.Body; model.BasicAck(result.DeliveryTag, false); string message = System.Text.Encoding.UTF8.GetString(body); Console.Write(message); } } catch (Exception ex) { Console.Write(ex.Message); } } |
也可以使用官网的例子(这里更清晰): http://www.rabbitmq.com/tutorials/tutorial-one-dotnet.html 发送端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
using System; using System.Text; using RabbitMQ.Client; namespace rabbitMQ { public class Send { public static void Main() { var factory = new ConnectionFactory() { HostName = "192.168.0.169", UserName = "user", Password = "pass" }; using (var connection = factory.CreateConnection()) using (var channel = connection.CreateModel()) { channel.QueueDeclare( queue: "hello", durable: false, exclusive: false, autoDelete: false, arguments: null); string message = "Hello World!" + DateTime.Now; var body = Encoding.UTF8.GetBytes(message); channel.BasicPublish(exchange: "", routingKey: "hello", basicProperties: null, body: body); Console.WriteLine(" [x] Sent {0}", message); } Console.WriteLine(" Press [enter] to exit."); Console.ReadLine(); } } } |
接收端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
using System; using System.Collections.Generic; using System.Text; using System.Threading; using RabbitMQ.Client; using RabbitMQ.Client.Events; namespace rabbitMQ { class Receive { public static void Main() { var factory = new ConnectionFactory() { HostName = "192.168.0.169", UserName = "user", Password = "pass" }; using (var connection = factory.CreateConnection()) using (var channel = connection.CreateModel()) { channel.QueueDeclare( queue: "hello", durable: false, exclusive: false, autoDelete: false, arguments: null); var consumer = new EventingBasicConsumer(channel); consumer.Received += (model, ea) => { var body = ea.Body; var message = Encoding.UTF8.GetString(body); Console.WriteLine(" [x] Received {0}", message); }; channel.BasicConsume(queue: "hello", autoAck: true, consumer: consumer); Console.WriteLine(" Press [enter] to exit."); Console.ReadLine(); } } } } |
在Windows上发送,在CentOS上接收,效果如图: 开启管理UI:
1 2 3 |
rabbitmq-plugins enable rabbitmq_management firewall-cmd --zone=public --add-port=15672/tcp --permanent firewall-cmd --reload |
在Windows下打开地址:
1 |
http://10.255.19.111:15672 |
用户名和密码都是 guest 这样就可以方便管理RabbitMQ了。 from:https://www.cnblogs.com/uptothesky/p/6094357.html
View Details用户角色分类 none:无法登录控制台 不能访问 management plugin,通常就是普通的生产者和消费者。 management:普通管理者。 仅可登陆管理控制台(启用management plugin的情况下),无法看到节点信息,也无法对policies进行管理。用户可以通过AMQP做的任何事外加: 列出自己可以通过AMQP登入的virtual hosts 查看自己的virtual hosts中的queues, exchanges 和 bindings 查看和关闭自己的channels 和 connections 查看有关自己的virtual hosts的“全局”的统计信息,包含其他用户在这些virtual hosts中的活动。 policymaker:策略制定者。 management可以做的任何事外加: 查看、创建和删除自己的virtual hosts所属的policies和parameters monitoring:监控者。 management可以做的任何事外加: 列出所有virtual hosts,包括他们不能登录的virtual hosts 查看其他用户的connections和channels 查看节点级别的数据如clustering和memory使用情况 查看真正的关于所有virtual hosts的全局的统计信息 同时可以查看rabbitmq节点的相关信息(进程数,内存使用情况,磁盘使用情况等) administrator:超级管理员。 policymaker和monitoring可以做的任何事外加: 创建和删除virtual hosts 查看、创建和删除users 查看创建和删除permissions 关闭其他用户的connections 创建用户
1 2 3 4 |
rabbitmqctl add_user {用户名} {密码} // 设置权限 rabbitmqctl set_user_tags {用户名} {权限} |
例:创建一个超级用户
1 2 |
rabbitmqctl add_user admin1 admin1 rabbitmqctl set_user_tags admin1 administrator |
查看用户列表
1 |
rabbitmqctl list_users |
为用户赋权
1 2 3 4 5 6 7 8 9 10 |
// 使用户user1具有vhost1这个virtual host中所有资源的配置、写、读权限以便管理其中的资源 rabbitmqctl set_permissions -p vhost1 user1 '.*' '.*' '.*' // 查看权限 rabbitmqctl list_user_permissions user1 rabbitmqctl list_permissions -p vhost1 // 清除权限 rabbitmqctl clear_permissions [-p VHostPath] User |
删除用户
1 |
rabbitmqctl delete_user Username |
修改用户的密码
1 |
rabbitmqctl change_password Username Newpassword |
from: https://www.cnblogs.com/xinxiucan/p/7940953.html
View Details安装脚本
1 2 3 4 5 6 7 8 9 10 |
yum install wget -y #Download RabbitMQ and Erlang wget https://www.rabbitmq.com/releases/rabbitmq-server/v3.6.9/rabbitmq-server-3.6.9-1.el6.noarch.rpm wget https://www.rabbitmq.com/releases/erlang/erlang-19.0.4-1.el6.x86_64.rpm #Install Erlang and RabbitMQ rpm -ivh erlang-19.0.4-1.el6.x86_64.rpm rpm --import http://www.rabbitmq.com/rabbitmq-signing-key-public.asc yum install rabbitmq-server-3.6.9-1.el6.noarch.rpm -y |
发现错误
1 2 |
1. 安装依赖Requires: socat 2. 安装socat的时候提示需要tcp_wrappers |
解决方案
1 2 3 4 |
wget –no-cache http://www.convirture.com/repos/definitions/rhel/6.x/convirt.repo -O /etc/yum.repos.d/convirt.repo yum install socat -y 使用https://rpmfind.net/linux/rpm2html/search.php搜索tcp_wrappers,下载,rpm -ivh tcp_wrappers.version |
启动RabbitMQ
1 2 3 4 5 6 |
chkconfig rabbitmq-server on /sbin/service rabbitmq-server start # 修改密码 rabbitmqctl change_password guest welcome123 # 启动管理界面 rabbitmq-plugins enable rabbitmq_management |
使用过程错误小记 user ‘guest’ – User can only log in via localhost 登录响应如下:
1 |
{"error":"not_authorised","reason":"User can only log in via localhost"} |
我实在docker中创建rabbitmq的,然后将端口15672映射到宿主机器上的15672,所以也算是远程登录,而guest用户要求只能使用localhost登录,所以要想远程登录必须新建用户。
1 2 3 |
rabbitmqctl add_user {username} {password} # 例:创建admin用户 rabbitmqctl add_user admin 123456 |
新建用户无法登录
1 |
{"error":"not_authorised","reason":"Not management user"} |
需要授予用户角色
1 2 3 |
rabbitmqctl set_user_tags {username} {role} # 例 rabbitmqctl set_user_tags admin administrator |
用户授权
1 2 |
rabbitmqctl set_permissions [-p vhostpath] {user} {conf} {write} {read} rabbitmqctl set_permissions -p / admin ".*" ".*" ".*" |
关于RabbitMQ权限和角色管理 参考:http://blog.csdn.net/zyz511919766/article/details/42292655 from:https://www.dev-heaven.com/posts/1914.html
View DetailsRedis服务器设置密码后,使用service redis stop 会出现以下信息: service redis stop Stopping … OK (error) NOAUTH Authentication required. Waiting for Redis to shutdown … Waiting for Redis to shutdown … Waiting for Redis to shutdown … Waiting for Redis to shutdown … Waiting for Redis to shutdown … Waiting for Redis to shutdown … Waiting for Redis to shutdown … Waiting for Redis to shutdown … 出现这样的错误信息,redis 这时是没有停止服务的。可以使用ps -ef | grep redis 查进程号 然后kill 掉,如果在deamon下还需要去删除pid文件,有点繁琐。 解决办法: 用redis-cli 密码登陆(redis-cli -a password)就OK了。 再用ps -ef | grep redis 可以看到redis进程已经正常退出。 修改redis服务脚本,加入如下所示的红色授权信息即可: vi /etc/init.d/redis $CLIEXEC -a "password" -p $REDISPORT shutdown from:https://www.cnblogs.com/jeffen/p/6068745.html
View Details一、安装redis 第一步:下载redis安装包 wget http://download.redis.io/releases/redis-4.0.6.tar.gz
1 2 3 4 5 6 7 8 9 10 11 |
[root@iZwz991stxdwj560bfmadtZ local]# wget http://download.redis.io/releases/redis-4.0.6.tar.gz --2017-12-13 12:35:12-- http://download.redis.io/releases/redis-4.0.6.tar.gz Resolving download.redis.io (download.redis.io)... 109.74.203.151 Connecting to download.redis.io (download.redis.io)|109.74.203.151|:80... connected. HTTP request sent, awaiting response... 200 OK Length: 1723533 (1.6M) [application/x-gzip] Saving to: ‘redis-4.0.6.tar.gz’ 100%[==========================================================================================================>] 1,723,533 608KB/s in 2.8s 2017-12-13 12:35:15 (608 KB/s) - ‘redis-4.0.6.tar.gz’ saved [1723533/1723533] |
第二步:解压压缩包 tar -zxvf redis-4.0.6.tar.gz
1 |
[root@iZwz991stxdwj560bfmadtZ local]# tar -zxvf redis-4.0.6.tar.gz |
第三步:yum安装gcc依赖 yum install gcc
1 |
[root@iZwz991stxdwj560bfmadtZ local]# yum install gcc |
遇到选择,输入y即可 第四步:跳转到redis解压目录下 cd redis-4.0.6
1 |
[root@iZwz991stxdwj560bfmadtZ local]# cd redis-4.0.6 |
第五步:编译安装 make MALLOC=libc
1 |
[root@iZwz991stxdwj560bfmadtZ redis-4.0.6]# make MALLOC=libc |
将/usr/local/redis-4.0.6/src目录下的文件加到/usr/local/bin目录 cd src && make install
1 2 3 4 5 6 7 8 9 10 |
[root@iZwz991stxdwj560bfmadtZ redis-4.0.6]# cd src && make install CC Makefile.dep Hint: It's a good idea to run 'make test' ;) INSTALL install INSTALL install INSTALL install INSTALL install INSTALL install |
二、启动redis的三种方式 先切换到redis src目录下
1 |
[root@iZwz991stxdwj560bfmadtZ redis-4.0.6]# cd src |
1、直接启动redis ./redis-server
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
[root@iZwz991stxdwj560bfmadtZ src]# ./redis-server 18685:C 13 Dec 12:56:12.507 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo 18685:C 13 Dec 12:56:12.507 # Redis version=4.0.6, bits=64, commit=00000000, modified=0, pid=18685, just started 18685:C 13 Dec 12:56:12.507 # Warning: no config file specified, using the default config. In order to specify a config file use ./redis-server /path/to/redis.conf _._ _.-``__ ''-._ _.-`` `. `_. ''-._ Redis 4.0.6 (00000000/0) 64 bit .-`` .-```. ```\/ _.,_ ''-._ ( ' , .-` | `, ) Running in standalone mode |`-._`-...-` __...-.``-._|'` _.-'| Port: 6379 | `-._ `._ / _.-' | PID: 18685 `-._ `-._ `-./ _.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | http://redis.io `-._ `-._`-.__.-'_.-' _.-' |`-._`-._ `-.__.-' _.-'_.-'| | `-._`-._ _.-'_.-' | `-._ `-._`-.__.-'_.-' _.-' `-._ `-.__.-' _.-' `-._ _.-' `-.__.-' 18685:M 13 Dec 12:56:12.508 # WARNING: The TCP backlog setting of 511 cannot be enforced because /proc/sys/net/core/somaxconn is set to the lower value of 128. 18685:M 13 Dec 12:56:12.508 # Server initialized 18685:M 13 Dec 12:56:12.508 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect. 18685:M 13 Dec 12:56:12.508 # WARNING you have Transparent Huge Pages (THP) support enabled in your kernel. This will create latency and memory usage issues with Redis. To fix this issue run the command 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' as root, and add it to your /etc/rc.local in order to retain the setting after a reboot. Redis must be restarted after THP is disabled. 18685:M 13 Dec 12:56:12.508 * Ready to accept connections |
如上图:redis启动成功,但是这种启动方式需要一直打开窗口,不能进行其他操作,不太方便。 按 ctrl + c可以关闭窗口。 2、以后台进程方式启动redis 第一步:修改redis.conf文件 将
1 |
daemonize no |
修改为
1 |
daemonize yes |
第二步:指定redis.conf文件启动 1 ./redis-server /usr/local/redis-4.0.6/redis.conf
1 2 3 4 |
[root@iZwz991stxdwj560bfmadtZ src]# ./redis-server /usr/local/redis-4.0.6/redis.conf 18713:C 13 Dec 13:07:41.109 # oO0OoO0OoO0Oo Redis is starting oO0OoO0OoO0Oo 18713:C 13 Dec 13:07:41.109 # Redis version=4.0.6, bits=64, commit=00000000, modified=0, pid=18713, just started 18713:C 13 Dec 13:07:41.109 # Configuration loaded |
第三步:关闭redis进程 首先使用ps -aux | grep redis查看redis进程
1 2 3 |
[root@iZwz991stxdwj560bfmadtZ src]# ps -aux | grep redis root 18714 0.0 0.1 141752 2008 ? Ssl 13:07 0:00 ./redis-server 127.0.0.1:6379 root 18719 0.0 0.0 112644 968 pts/0 R+ 13:09 0:00 grep --color=auto redis |
使用kill命令杀死进程
1 |
[root@iZwz991stxdwj560bfmadtZ src]# kill -9 18714 |
3、设置redis开机自启动 1、在/etc目录下新建redis目录 mkdir redis
1 |
[root@iZwz991stxdwj560bfmadtZ etc]# mkdir redis |
2、将/usr/local/redis-4.0.6/redis.conf 文件复制一份到/etc/redis目录下,并命名为6379.conf
1 |
[root@iZwz991stxdwj560bfmadtZ redis]# cp /usr/local/redis-4.0.6/redis.conf /etc/redis/6379.conf |
[…]
View DetailsLinux 的软件安装目录是也是有讲究的,理解这一点,在对系统管理是有益的 /usr:系统级的目录,可以理解为C:/Windows/,/usr/lib理解为C:/Windows/System32。 /usr/local:用户级的程序目录,可以理解为C:/Progrem Files/。用户自己编译的软件默认会安装到这个目录下。 /opt:用户级的程序目录,可以理解为D:/Software,opt有可选的意思,这里可以用于放置第三方大型软件(或游戏),当你不需要时,直接rm -rf掉即可。在硬盘容量不够时,也可将/opt单独挂载到其他磁盘上使用。 源码放哪里? /usr/src:系统级的源码目录。 /usr/local/src:用户级的源码目录。 —————--翻译——————- /opt Here’s where optional stuff is put. Trying out the latest Firefox beta? Install it to /opt where you can delete it without affecting other settings. Programs in here usually live inside a single folder whick contains all of their data, libraries, etc. 这里主要存放那些可选的程序。你想尝试最新的firefox测试版吗?那就装到/opt目录下吧,这样,当你尝试完,想删掉firefox的时候,你就可 以直接删除它,而不影响系统其他任何设置。安装到/opt目录下的程序,它所有的数据、库文件等等都是放在同个目录下面。 举个例子:刚才装的测试版firefox,就可以装到/opt/firefox_beta目录下,/opt/firefox_beta目录下面就包含了运 行firefox所需要的所有文件、库、数据等等。要删除firefox的时候,你只需删除/opt/firefox_beta目录即可,非常简单。 /usr/local This is where most manually installed(ie. outside of your package manager) software goes. It has the same structure as /usr. It is a good idea to leave /usr to your package manager […]
View Details