redis使用介绍
《redis使用介绍》要点:
Redis本身没有办法支持存储对象类型的接口,只能存储字节类型的数据,因此redis在存储任何类型的数据结构时都要先将其序列化. 当一个类实现了Serializable接口(该接口仅为标记接口,不包含任何办法定义),表示该类可以序列化.序列化的目的是将一个实现了Serializable接口的对象转换成一个字节序列,可以.把该字节序列保存起来(例如:保存在一个文件里),以后可以随时将该字节序列恢复为原来的对象.甚至可以将该字节序列放到其他计算机上或者通过网络传输到其他计算机上恢复,只要该计算机平台存在相应的类就可以正常恢复为原来的对象. 快速序列化工具介绍: 公司封装的序列化和反序列化工具:org.springframework.core.serializer.support. DeserializingConverter类的convert办法 但实际底层最后用的还是Java的ByteArrayInputStream byteStream = new ByteArrayInputStream(source); ObjectInputStream objectInputStream = new ObjectInputStream(inputStream); ObjectInputStream. readObject() 1.2五种数据结构应用 String,hash,set,list 参考: zhuanlan.zhihu.com/p/21368183?refer=zhangtielei blog.csdn.net/a809146548/article/category/2915269/2 上面四种数据结构的实现分别是: 1). Dict :是key和value映射关系的数据结构,基于hash表的算法采用某个哈希函数从key计算得到在哈希表中的位置,如图: 2). Quicklist : 双向链表,quicklist的每个节点都是一个ziplist .双链表,这是在存储效率和查询时间上的折中设计.因为其在每个节点上除了要保留数据之外,还要额外保留两个指针;其次,双向链表的各个节点是单独的内存块,地址不连续,节点多了容易产生内存碎片.所有其长度的设计需要根据不同情况具体定义, Redis提供了一个配置参数 · -5: 每个quicklist节点上的ziplist大小不能超过64 Kb.(注:1kb => 1024 bytes) · -4: 每个quicklist节点上的ziplist大小不能超过32 Kb. · -3: 每个quicklist节点上的ziplist大小不能超过16 Kb. · -2: 每个quicklist节点上的ziplist大小不能超过8 Kb.(-2是Redis给出的默认值)
1.3 redis的持久化 作用主要是防止redis应用挂掉之后重启服务重新加载redis内存数据库. 1.3.1 第一种是快照形式的:依照改动频率存储,存储规则:save N M表示在N秒之内,redis至少发生M次修改则redis抓快照到磁盘.这样的好处是保证大部分数据完整,效率高,但是数据不是完全同步的,在redis应用停掉后最近的数据会丢失. 第二种是AOF持久化:可以做到每次修改都记录到aof文件,但这样影响效率,也可以每秒同步变化的数据到aof文件,这样不影响效率但有可以会丢失一秒内的数据. 2.redis 惊群处理 2.1 方案的由来 Redis的缓存数据库是为快速响应客户端减轻数据库压力的有效手段之一,其中有一种功能是失效缓存,其优点是可以不定期的释放使用频率低的业务空间而增加有限的内存,但对于同步数据库和缓存之间的数据来说需要面临一个问题就是:在并发量比较大的情况下当一个缓存数据失效之后会导致同时有多个并发线程去向后端数据库发起哀求去获取同一业务数据,这样如果在一段时间内同时生成了大量的缓存,然后在另外一段时间内又有大量的缓存失效,这样就会导致后端数据库的压力陡增,这种现象就可以称为“缓存过期产生的惊群现象”! 2.2 处理逻辑 缓存内真实失效时间time1 缓存value中存放人为失效时间戳 :time2 ( time2 永远小于time1 ) 缓存value对应的lock锁 (便是一个与value 对应的 另一个key),主要用于判断是第几个线程来读取redis的value 当把数据库的数据写入缓存后,这时有客户端第一次来读取缓存,取当前系统时间:system_time 如果system_time >= time2 则认为默认缓存已过期(如果system_time < time1 则还没真实失效 ),这时再获取value的lock锁,调用redis的incr函数(单线程自增函数)判断是第几个获取锁的线程,当且仅当是第一个线程时返回1,以后都逐渐递增.第一个拜访的线程到数据库中获取最新值重新放入缓存并删除lock锁的key,并重新设置时间戳;在删除lock之前所有拜访value客户端线程获取lock的value都大于1,这些线程仍然读取redis中的旧值,而不会集中拜访数据库. 2.3 伪代码 private long expirt_time = 1000 * 40 ;//人为过期时间 private long time = 1000 * 60;//一分钟 private long second = 60 * 6;//六分钟 KooJedisClient client = SpringContextUtils.getBean("redisClient",KooJedisClient.class); private final String user_key = "USER_REDIS"; private final String user_key_lock = "USER_REDIS_lock"; public void setExpireTime( HttpServletRequest request ){ String userId = request.getParameter( "userId"); //数组里存放:1:真实value,2:过期时间 String key = org.apache.commons.lang3.StringUtils.join(new Object[]{user_key,userId}); String[] info = client.get( key,String[].class); long nowTime = System.currentTimeMillis(); if( null != info ){ long expireRealTime = new Long( info[1] ); //如果已过期并且是第一个拜访的线程 if( nowTime >= expireRealTime ){ Long lockNum = client.incr( user_key_lock+userId ); // 可以实现原子性的递增,可应用于高并发的秒杀活动、分布式序列号生成等场景 if( ( lockNum == 1 || lockNum == null )){ //重新从数据库获取 User user = teacherDataMaintain.findUserInfo(new Integer(userId)); info[ 0 ] = user.getUserName(); info[ 1 ] = org.apache.commons.lang3.StringUtils.join(new Object[]{(nowTime + expirt_time),""}); client.setex( key,60,info );//六分后过期 client.del( user_key_lock+userId ); }else{ System.out.println( "缓存过期但不是第一个线程,返回旧值" ); } }else{ //返回缓存中旧值 System.out.println( "缓存未过期" ); } }else{ User user = teacherDataMaintain.findUserInfo(new Integer(userId)); String[] userInfo = { user.getUserName(),(nowTime + expirt_time ) + "" }; client.setex( key,userInfo );//过期 } } 3.redis 分布式锁应用 3.1 分布式锁主要是解决分布式环境对共享资源的同步拜访 在但进程的环境下程序上完全可以用synchronized同步锁来限制多线程对共享资源的拜访,但在分布式环境下同步锁无法控制不同进程之间的线程,这种情况下就需要找一种单进程可串行处理的“锁”,redis 就是其中的一种选择, 3.2. 应用场景: 例如:秒杀,一个官网售卖的视频课程,这个课程只有若干个名单可以售卖,每个课程对应具体的库存,怎样让每个客户端获取课程的的库存都是准确实时的, Redis 缓存中与数据库的库存在秒杀前是一样的,当秒杀开始的时候,同一时间点会有很多客户端拜访缓存和数据库,不同的进程同时拜访缓存或者数据库,当缓存中的数据变化后并且没被修改之前有可能又被另一个线程获取,数据有可能出现脏读和数据被覆盖的可能.(脏读 < 不可重复读 < 幻读) 3.3 解决方法: 对共享资源的操作要是互斥且良性的竞争,即在分布式条件下怎样做到一次只能有一个线程来处理共享资源?且线程之间不会出现死锁的情况. 3.3.1 几个基本的函数: Setnx key value :如果没有key 则可以获得锁并返回1,如果已存在key 则不做操作并返回0 . Getset key value :设置value,并返回key的旧值,若key不存在则返回null Get key : 3.3.2 死锁 Setnx是单线程处理的,但仍有可能出现死锁 Eg:thread0 操作超时了,但它还持有着锁,thread 1 和thread 2 读取lock.foo检查时间戳,然后发现超时了; thread 1 发送DEL lock.foo; thread 1 发送SETNX lock.foo 并且成功了; thread 2 发送DEL lock.foo; thread 2 发送SETNX lock.foo 并且成功了. 这样一来,thread 1、thread 2都拿到了锁!锁平安性被破坏了! 3.3.3 办理死锁
3.4 伪代码 public synchronized boolean acquire(Jedis jedis,String lockKey,long expires) throws InterruptedException { int timeoutMsecs = 10 * 1000; int timeout = timeoutMsecs; while ( timeout >= 0 ) { String expiresStr = String.valueOf( expires ); //锁到期时间 if ( jedis.setnx( lockKey,expiresStr ) == 1 ) { // lock acquired return true; } String currentValueStr = jedis.get(lockKey); //redis里的时间 if(currentValueStr!=null&& Long.parseLong(currentValueStr) < System.currentTimeMillis()) { //判断是否为空,不为空的情况下,如果被其他线程设置了值,则第二个条件判断是过不去的 // lock is expired //Getset命令用于设置指定key的值,并返回key旧的值. String oldValueStr = jedis.getSet(lockKey,expiresStr); //获取上一个锁到期时间,并设置现在的锁到期时间 //只有一个线程才能获取上一个线上的设置时间,因为jedis.getSet是同步的 if (oldValueStr != null && oldValueStr.equals(currentValueStr)) { //如过这个时候,多个线程恰好都到了这里,但是只有一个线程的设置值和当前值相同,他才有权利获取锁 // lock acquired return true; } } timeout -= 100; Thread.sleep(100); //每100毫秒重试一次,直至timeout用尽 } //Expire命令用于设定键有效期.到期时间后键不会在Redis中使用. return false; } 以下是redis的配置文件Redis.conf的参数说明: # By default Redis does not run as a daemon. Use 'yes' if you need it. # Note that Redis will write a pid file in /var/run/redis.pid when daemonized. #Redis默认不是以守护进程的方式运行,可以通过该配置项修改,使用yes启用守护进程 daemonize no # When running daemonized,Redis writes a pid file in /var/run/redis.pid by # default. You can specify a custom pid file location here. #当 Redis 以守护进程的方式运行的时候,Redis 默认会把 pid 文件放在/var/run/redis.pid #可配置到其他地址,当运行多个 redis 服务时,必要指定不同的 pid 文件和端口 pidfile /var/run/redis.pid # Accept connections on the specified port,default is 6379. # If port 0 is specified Redis will not listen on a TCP socket. #端口 port 6379 # If you want you can bind a single interface,if the bind option is not # specified all the interfaces will listen for incoming connections. #指定Redis可接收哀求的IP地址,不设置将处理所有哀求,建议生产环境中设置 # bind 127.0.0.1 # Close the connection after a client is idle for N seconds (0 to disable) #客户端连接的超时时间,单位为秒,超时后会关闭连接 timeout 0 # Set server verbosity to 'debug' # it can be one of: # debug (a lot of information,useful for development/testing) # verbose (many rarely useful info,but not a mess like the debug level) # notice (moderately verbose,what you want in production probably) # warning (only very important / critical messages are logged) #日志记录等级,4个可选值 loglevel notice # Specify the log file name. Also 'stdout' can be used to force # Redis to log on the standard output. Note that if you use standard # output for logging but daemonize,logs will be sent to /dev/null #配置 log 文件地址,默认打印在命令行终端的窗口上,也可设为/dev/null屏蔽日志、 logfile stdout # Set the number of databases. The default database is DB 0,you can select # a different one on a per-connection basis using SELECT where # dbid is a number between 0 and 'databases'-1 #设置数据库的个数,可以使用 SELECT 命令来切换数据库. databases 16 # # Save the DB on disk: # # save # # Will save the DB if both the given number of seconds and the given # number of write operations against the DB occurred. # # In the example below the behaviour will be to save: # after 900 sec (15 min) if at least 1 key changed # after 300 sec (5 min) if at least 10 keys changed # after 60 sec if at least 10000 keys changed # # Note: you can disable saving at all commenting all the "save" lines. #设置 Redis 进行数据库镜像的频率.保留数据到disk的策略 #900秒之内有1个keys发生变化时 #30秒之内有10个keys发生变化时 #60秒之内有10000个keys发生变化时 save 900 1 save 300 10 save 60 10000 # Compress string objects using LZF when dump .rdb databases? # For default that's set to 'yes' as it's almost always a win. # If you want to save some CPU in the saving child set it to 'no' but # the dataset will likely be bigger if you have compressible values or keys. #在进行镜像备份时,是否进行压缩 rdbcompression yes # The filename where to dump the DB #镜像备份文件的文件名 dbfilename dump.rdb # The working directory. # # The DB will be written inside this directory,with the filename specified # above using the 'dbfilename' configuration directive. # # Also the Append Only File will be created inside this directory. # # Note that you must specify a directory here,not a file name. #数据库镜像备份的文件放置的路径 #路径跟文件名分开配置是因为 Redis 备份时,先会将当前数据库的状态写入到一个临时文件 #等备份完成时,再把该临时文件替换为上面所指定的文件 #而临时文件和上面所配置的备份文件都会放在这个指定的路径当中 #默认值为 ./ dir /var/lib/redis/ # Master-Slave replication. Use slaveof to make a Redis instance a copy of # another Redis server. Note that the configuration is local to the slave # so for example it is possible to configure the slave to save the DB with a # different interval,or to listen to another port,and so on. #设置该数据库为其他数据库的从数据库 #slaveof <masterip> <masterport> 当本机为从服务时,设置主服务的IP及端口 # slaveof # If the master is password protected (using the "requirepass" configuration # directive below) it is possible to tell the slave to authenticate before # starting the replication synchronization process,otherwise the master will # refuse the slave request. #指定与主数据库连接时需要的暗码验证 #masterauth <master-password> 当本机为从服务时,设置主服务的连接暗码 # masterauth # When a slave lost the connection with the master,or when the replication # is still in progress,the slave can act in two different ways: # # 1) if slave-serve-stale-data is set to 'yes' (the default) the slave will # still reply to client requests,possibly with out of data data,or the # data set may just be empty if this is the first synchronization. # # 2) if slave-serve-stale data is set to 'no' the slave will reply with # an error "SYNC with master in progress" to all the kind of commands # but to INFO and SLAVEOF. #当slave丢失与master的连接时,或slave仍然在于master进行数据同步时(未与master坚持一致) #slave可有两种方式来响应客户端哀求: #1)如果 slave-serve-stale-data 设置成 'yes'(默认),slave仍会响应客户端哀求,此时可能会有问题 #2)如果 slave-serve-stale-data 设置成 'no',slave会返回"SYNC with master in progress"错误信息,但 INFO 和SLAVEOF命令除外. slave-serve-stale-data yes # Require clients to issue AUTH before processing any other # commands. This might be useful in environments in which you do not trust # others with access to the host running redis-server. # # This should stay commented out for backward compatibility and because most # people do not need auth (e.g. they run their own servers). # # Warning: since Redis is pretty fast an outside user can try up to # 150k passwords per second against a good box. This means that you should # use a very strong password otherwise it will be very easy to break. #设置客户端连接后进行任何其他指定前需要使用的暗码 #redis速度相当快,一个外部用户在一秒钟进行150K次暗码尝试,需指定强大的暗码来防止暴力破解 # requirepass foobared # Set the max number of connected clients at the same time. By default there # is no limit,and it's up to the number of file descriptors the Redis process # is able to open. The special value '0' means no limits. # Once the limit is reached Redis will close all the new connections sending # an error 'max number of clients reached'. #限制同时连接的客户数量. #当连接数超过这个值时,redis 将不再接收其他连接哀求,客户端尝试连接时将收到 error 信息 # maxclients 128 # Don't use more memory than the specified amount of bytes. # When the memory limit is reached Redis will try to remove keys # accordingly to the eviction policy selected (see maxmemmory-policy). # # If Redis can't remove keys according to the policy,or if the policy is # set to 'noeviction',Redis will start to reply with errors to commands # that would use more memory,like SET,LPUSH,and so on,and will continue # to reply to read-only commands like GET. # # This option is usually useful when using Redis as an LRU cache,or to set # an hard memory limit for an instance (using the 'noeviction' policy). # # WARNING: If you have slaves attached to an instance with maxmemory on, # the size of the output buffers needed to feed the slaves are subtracted # from the used memory count,so that network problems / resyncs will # not trigger a loop where keys are evicted,and in turn the output # buffer of slaves is full with DELs of keys evicted triggering the deletion # of more keys,and so forth until the database is completely emptied. # # In short... if you have slaves attached it is suggested that you set a lower # limit for maxmemory so that there is some free RAM on the system for slave # output buffers (but this is not needed if the policy is 'noeviction'). #设置redis能够使用的最大内存. #达到最大内存设置后,Redis会先尝试清除已到期或即将到期的Key(设置过期信息的key) #在删除时,依照过期时间进行删除,最早将要被过期的key将最先被删除 #如果已到期或即将到期的key删光,仍进行set操作,那么将返回错误 #此时redis将不再接收写哀求,只接收get哀求. #maxmemory的设置比拟适合于把redis当作于类似memcached 的缓存来使用 # maxmemory <bytes> # By default Redis asynchronously dumps the dataset on disk. If you can live # with the idea that the latest records will be lost if something like a crash # happens this is the preferred way to run Redis. If instead you care a lot # about your data and don't want to that a single record can get lost you should # enable the append only mode: when this mode is enabled Redis will append # every write operation received in the file appendonly.aof. This file will # be read on startup in order to rebuild the full dataset in memory. # # Note that you can have both the async dumps and the append only file if you # like (you have to comment the "save" statements above to disable the dumps). # Still if append only mode is enabled Redis will load the data from the # log file at startup ignoring the dump.rdb file. # # IMPORTANT: Check the BGREWRITEAOF to check how to rewrite the append # log file in background when it gets too big. #redis 默认每次更新操作后会在后台异步的把数据库镜像备份到磁盘,但该备份非常耗时,且备份不宜太频繁 #redis 同步数据文件是按上面save条件来同步的 #如果发生诸如拉闸限电、拔插头等状况,那么将造成比拟大范围的数据丢失 #所以redis提供了另外一种更加高效的数据库备份及灾难恢复方式 #开启append only 模式后,redis 将每一次写操作哀求都追加到appendonly.aof 文件中 #redis重新启动时,会从该文件恢复出之前的状态. #但可能会造成 appendonly.aof 文件过大,所以redis支持BGREWRITEAOF 指令,对appendonly.aof重新整理 appendonly no # The name of the append only file (default: "appendonly.aof") ##更新日志文件名,默认值为appendonly.aof # appendfilename appendonly.aof # The fsync() call tells the Operating System to actually write data on disk # instead to wait for more data in the output buffer. Some OS will really flush # data on disk,some other OS will just try to do it ASAP. # # Redis supports three different modes: # # no: don't fsync,just let the OS flush the data when it wants. Faster. # always: fsync after every write to the append only log . Slow,Safest. # everysec: fsync only if one second passed since the last fsync. Compromise. # # The default is "everysec" that's usually the right compromise between # speed and data safety. It's up to you to understand if you can relax this to # "no" that will will let the operating system flush the output buffer when # it wants,for better performances (but if you can live with the idea of # some data loss consider the default persistence mode that's snapshotting), # or on the contrary,use "always" that's very slow but a bit safer than # everysec. # # If unsure,use "everysec". #设置对 appendonly.aof 文件进行同步的频率 #always 表现每次有写操作都进行同步,everysec 表现对写操作进行累积,每秒同步一次. #no表现等操作系统进行数据缓存同步到磁盘,都进行同步,每秒同步一次 # appendfsync always appendfsync everysec # appendfsync no # Virtual Memory allows Redis to work with datasets bigger than the actual # amount of RAM needed to hold the whole dataset in memory. # In order to do so very used keys are taken in memory while the other keys # are swapped into a swap file,similarly to what operating systems do # with memory pages. # # To enable VM just set 'vm-enabled' to yes,and set the following three # VM parameters accordingly to your needs. #是否开启虚拟内存支持. #redis 是一个内存数据库,当内存满时,无法接收新的写哀求,所以在redis2.0后,提供了虚拟内存的支持 #但必要注意的,redis 所有的key都会放在内存中,在内存不够时,只把value 值放入交换区 #虽使用虚拟内存,但性能基本不受影响,必要注意的是要把vm-max-memory设置到足够来放下所有的key vm-enabled no # vm-enabled yes # This is the path of the Redis swap file. As you can guess,swap files # can't be shared by different Redis instances,so make sure to use a swap # file for every redis process you are running. Redis will complain if the # swap file is already in use. # # The best kind of storage for the Redis swap file (that's accessed at random) # is a Solid State Disk (SSD). # # *** WARNING *** if you are using a shared hosting the default of putting # the swap file under /tmp is not secure. Create a dir with access granted # only to Redis user and configure Redis to create the swap file there. #设置虚拟内存的交换文件路径,不可多个Redis实例共享 vm-swap-file /tmp/redis.swap # vm-max-memory configures the VM to use at max the specified amount of # RAM. Everything that deos not fit will be swapped on disk *if* possible,that # is,if there is still enough contiguous space in the swap file. # # With vm-max-memory 0 the system will swap everything it can. Not a good # default,just specify the max amount of RAM you can in bytes,but it's # better to leave some margin. For instance specify an amount of RAM # that's more or less between 60 and 80% of your free RAM. #设置开启虚拟内存后,redis将使用的最大物理内存大小. #默认为0,redis将把他所有能放到交换文件的都放到交换文件中,以尽量少的使用物理内存 #即当vm-max-memory设置为0的时候,其实是所有value都存在于磁盘 #在生产环境下,必要根据实际情况设置该值,最好不要使用默认的 0 vm-max-memory 0 # Redis swap files is split into pages. An object can be saved using multiple # contiguous pages,but pages can't be shared between different objects. # So if your page is too big,small objects swapped out on disk will waste # a lot of space. If you page is too small,there is less space in the swap # file (assuming you configured the same number of total swap file pages). # # If you use a lot of small objects,use a page size of 64 or 32 bytes. # If you use a lot of big objects,use a bigger page size. # If unsure,use the default :) #设置虚拟内存的页大小 如果 value 值比拟大,如要在 value 中放置博客、新闻之类的所有文章内容,就设大一点 vm-page-size 32 # Number of total memory pages in the swap file. # Given that the page table (a bitmap of free/used pages) is taken in memory, # every 8 pages on disk will consume 1 byte of RAM. # # The total swap size is vm-page-size * vm-pages # # With the default of 32-bytes memory pages and 134217728 pages Redis will # use a 4 GB swap file,that will use 16 MB of RAM for the page table. # # It's better to use the smallest acceptable value for your application, # but the default is large in order to work in most conditions. #设置交换文件的总的 page 数量 #注意page table信息是放在物理内存中,每8个page 就会占据RAM中的 1 个 byte #总的虚拟内存大小 = vm-page-size * vm-pages vm-pages 134217728 # Max number of VM I/O threads running at the same time. # This threads are used to read/write data from/to swap file,since they # also encode and decode objects from disk to memory or the reverse,a bigger # number of threads can help with big objects even if they can't help with # I/O itself as the physical device may not be able to couple with many # reads/writes operations at the same time. # # The special value of 0 turn off threaded I/O and enables the blocking # Virtual Memory implementation. #设置 VM IO 同时使用的线程数量. vm-max-threads 4 # Hashes are encoded in a special way (much more memory efficient) when they # have at max a given numer of elements,and the biggest element does not # exceed a given threshold. You can configure this limits with the following # configuration directives. #redis 2.0后引入了 hash 数据结构. #hash 中包括超过指定元素个数并且最大的元素当没有超过临界时,hash 将以zipmap来存储 #zipmap又称为 small hash,可大大减少内存的使用 hash-max-zipmap-entries 512 hash-max-zipmap-value 64 # Active rehashing uses 1 millisecond every 100 milliseconds of CPU time in # order to help rehashing the main Redis hash table (the one mapping top-level # keys to values). The hash table implementation redis uses (see dict.c) # performs a lazy rehashing: the more operation you run into an hash table # that is rhashing,the more rehashing "steps" are performed,so if the # server is idle the rehashing is never complete and some more memory is used # by the hash table. # # The default is to use this millisecond 10 times every second in order to # active rehashing the main dictionaries,freeing memory when possible. # # If unsure: # use "activerehashing no" if you have hard latency requirements and it is # not a good thing in your environment that Redis can reply form time to time # to queries with 2 milliseconds delay. # # use "activerehashing yes" if you don't have such hard requirements but # want to free memory asap when possible. #是否重置Hash表 #设置成yes后redis将每100毫秒使用1毫秒CPU时间来对redis的hash表重新hash,可降低内存的使用 #当使用场景有较为严格的实时性需求,不能接受Redis时不时的对哀求有2毫秒的延迟的话,把这项配置为no. #如果没有这么严格的实时性要求,可以设置为 yes,以便能够尽可能快的释放内存 activerehashing yes Redis官方文档对VM的使用提出了一些建议:
redis数据存储 redis的存储分为内存存储、磁盘存储和log文件三部分,配置文件中有三个参数对其进行配置.
《redis使用介绍》是否对您有启发,欢迎查看更多与《redis使用介绍》相关教程,学精学透。编程之家PHP学院为您提供精彩教程。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |